diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-10-24 11:30:15 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-10-30 12:56:19 +0000 |
commit | 6036726eb981b6c4b42047513b9d3f4ac865daac (patch) | |
tree | 673593e70678e7789766d1f732eb51f613a2703b /chromium/components/autofill | |
parent | 466052c4e7c052268fd931888cd58961da94c586 (diff) | |
download | qtwebengine-chromium-6036726eb981b6c4b42047513b9d3f4ac865daac.tar.gz |
BASELINE: Update Chromium to 70.0.3538.78
Change-Id: Ie634710bf039e26c1957f4ae45e101bd4c434ae7
Reviewed-by: Michael Brüning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/components/autofill')
219 files changed, 10046 insertions, 3551 deletions
diff --git a/chromium/components/autofill/android/BUILD.gn b/chromium/components/autofill/android/BUILD.gn index fea72723c6e..cd72694f8a0 100644 --- a/chromium/components/autofill/android/BUILD.gn +++ b/chromium/components/autofill/android/BUILD.gn @@ -59,6 +59,7 @@ android_resources("autofill_java_resources") { resource_dirs = [ "java/res" ] deps = [ ":autofill_strings_grd", + "//ui/android:ui_java_resources", ] } @@ -78,6 +79,7 @@ android_library("autofill_java") { ] java_files = [ "java/src/org/chromium/components/autofill/AutofillDelegate.java", + "java/src/org/chromium/components/autofill/AutofillDropdownAdapter.java", "java/src/org/chromium/components/autofill/AutofillPopup.java", "java/src/org/chromium/components/autofill/AutofillSuggestion.java", ] diff --git a/chromium/components/autofill/android/autofill_provider_android.cc b/chromium/components/autofill/android/autofill_provider_android.cc index 644270cb779..a930d663e0e 100644 --- a/chromium/components/autofill/android/autofill_provider_android.cc +++ b/chromium/components/autofill/android/autofill_provider_android.cc @@ -92,9 +92,15 @@ void AutofillProviderAndroid::StartNewSession(AutofillHandlerProxy* handler, return; } + FormStructure* form_structure = nullptr; + AutofillField* autofill_field = nullptr; + if (!handler->GetCachedFormAndField(form, field, &form_structure, + &autofill_field)) { + form_structure = nullptr; + } gfx::RectF transformed_bounding = ToClientAreaBound(bounding_box); - ScopedJavaLocalRef<jobject> form_obj = form_->GetJavaPeer(); + ScopedJavaLocalRef<jobject> form_obj = form_->GetJavaPeer(form_structure); handler_ = handler->GetWeakPtr(); Java_AutofillProvider_startAutofillSession( env, obj, form_obj, index, transformed_bounding.x(), diff --git a/chromium/components/autofill/android/form_data_android.cc b/chromium/components/autofill/android/form_data_android.cc index 3addcce6ffb..f1af3d53a5b 100644 --- a/chromium/components/autofill/android/form_data_android.cc +++ b/chromium/components/autofill/android/form_data_android.cc @@ -6,6 +6,7 @@ #include "base/android/jni_string.h" #include "components/autofill/android/form_field_data_android.h" +#include "components/autofill/core/browser/form_structure.h" #include "jni/FormData_jni.h" using base::android::AttachCurrentThread; @@ -30,7 +31,10 @@ FormDataAndroid::~FormDataAndroid() { Java_FormData_onNativeDestroyed(env, obj); } -ScopedJavaLocalRef<jobject> FormDataAndroid::GetJavaPeer() { +ScopedJavaLocalRef<jobject> FormDataAndroid::GetJavaPeer( + const FormStructure* form_structure) { + // |form_structure| is ephemeral and shouldn't be used outside this call + // stack. JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); if (obj.is_null()) { @@ -38,6 +42,8 @@ ScopedJavaLocalRef<jobject> FormDataAndroid::GetJavaPeer() { fields_.push_back(std::unique_ptr<FormFieldDataAndroid>( new FormFieldDataAndroid(&form_.fields[i]))); } + if (form_structure) + ApplyHeuristicFieldType(*form_structure); ScopedJavaLocalRef<jstring> jname = ConvertUTF16ToJavaString(env, form_.name); ScopedJavaLocalRef<jstring> jhost = @@ -95,4 +101,17 @@ bool FormDataAndroid::SimilarFormAs(const FormData& form) { return form_.SimilarFormAs(form); } +void FormDataAndroid::ApplyHeuristicFieldType( + const FormStructure& form_structure) { + DCHECK(form_structure.field_count() == fields_.size()); + auto form_field_data_android = fields_.begin(); + for (const auto& autofill_field : form_structure) { + DCHECK(form_field_data_android->get()->SimilarFieldAs(*autofill_field)); + form_field_data_android->get()->set_heuristic_type( + AutofillType(autofill_field->heuristic_type())); + if (++form_field_data_android == fields_.end()) + break; + } +} + } // namespace autofill diff --git a/chromium/components/autofill/android/form_data_android.h b/chromium/components/autofill/android/form_data_android.h index 81059fcba48..b54928f76d4 100644 --- a/chromium/components/autofill/android/form_data_android.h +++ b/chromium/components/autofill/android/form_data_android.h @@ -12,6 +12,7 @@ namespace autofill { class FormFieldDataAndroid; +class FormStructure; // This class is native peer of FormData.java, to make autofill::FormData // available in Java. @@ -20,7 +21,8 @@ class FormDataAndroid { FormDataAndroid(const FormData& form); virtual ~FormDataAndroid(); - base::android::ScopedJavaLocalRef<jobject> GetJavaPeer(); + base::android::ScopedJavaLocalRef<jobject> GetJavaPeer( + const FormStructure* form_structure); // Get autofill values from Java side and return FormData. const FormData& GetAutofillValues(); @@ -46,6 +48,8 @@ class FormDataAndroid { // |value|. void OnFormFieldDidChange(size_t index, const base::string16& value); + void ApplyHeuristicFieldType(const FormStructure& form); + const FormData& form_for_testing() { return form_; } private: diff --git a/chromium/components/autofill/android/form_field_data_android.cc b/chromium/components/autofill/android/form_field_data_android.cc index e44e88ece75..e4f841873be 100644 --- a/chromium/components/autofill/android/form_field_data_android.cc +++ b/chromium/components/autofill/android/form_field_data_android.cc @@ -22,7 +22,7 @@ using base::android::ToJavaArrayOfStrings; namespace autofill { FormFieldDataAndroid::FormFieldDataAndroid(FormFieldData* field) - : field_ptr_(field) {} + : heuristic_type_(AutofillType(UNKNOWN_TYPE)), field_ptr_(field) {} ScopedJavaLocalRef<jobject> FormFieldDataAndroid::GetJavaPeer() { JNIEnv* env = AttachCurrentThread(); @@ -46,12 +46,17 @@ ScopedJavaLocalRef<jobject> FormFieldDataAndroid::GetJavaPeer() { ToJavaArrayOfStrings(env, field_ptr_->option_values); ScopedJavaLocalRef<jobjectArray> joption_contents = ToJavaArrayOfStrings(env, field_ptr_->option_contents); + ScopedJavaLocalRef<jstring> jheuristic_type; + if (!heuristic_type_.IsUnknown()) + jheuristic_type = + ConvertUTF8ToJavaString(env, heuristic_type_.ToString()); obj = Java_FormFieldData_createFormFieldData( env, jname, jlabel, jvalue, jautocomplete_attr, field_ptr_->should_autocomplete, jplaceholder, jtype, jid, joption_values, joption_contents, IsCheckable(field_ptr_->check_status), - IsChecked(field_ptr_->check_status), field_ptr_->max_length); + IsChecked(field_ptr_->check_status), field_ptr_->max_length, + jheuristic_type); java_ref_ = JavaObjectWeakGlobalRef(env, obj); } return obj; @@ -88,4 +93,8 @@ void FormFieldDataAndroid::OnFormFieldDidChange(const base::string16& value) { ConvertUTF16ToJavaString(env, value)); } +bool FormFieldDataAndroid::SimilarFieldAs(const FormFieldData& field) const { + return field_ptr_->SimilarFieldAs(field); +} + } // namespace autofill diff --git a/chromium/components/autofill/android/form_field_data_android.h b/chromium/components/autofill/android/form_field_data_android.h index 2cb598ec4c5..e882bb49704 100644 --- a/chromium/components/autofill/android/form_field_data_android.h +++ b/chromium/components/autofill/android/form_field_data_android.h @@ -7,6 +7,7 @@ #include "base/android/jni_weak_ref.h" #include "base/android/scoped_java_ref.h" +#include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/common/form_field_data.h" namespace autofill { @@ -21,8 +22,14 @@ class FormFieldDataAndroid { base::android::ScopedJavaLocalRef<jobject> GetJavaPeer(); void GetValue(); void OnFormFieldDidChange(const base::string16& value); + bool SimilarFieldAs(const FormFieldData& field) const; + + void set_heuristic_type(const AutofillType& heuristic_type) { + heuristic_type_ = heuristic_type; + } private: + AutofillType heuristic_type_; // Not owned. FormFieldData* field_ptr_; JavaObjectWeakGlobalRef java_ref_; diff --git a/chromium/components/autofill/android/java/res/layout/autofill_dropdown_item.xml b/chromium/components/autofill/android/java/res/layout/autofill_dropdown_item.xml new file mode 100644 index 00000000000..93512e2012a --- /dev/null +++ b/chromium/components/autofill/android/java/res/layout/autofill_dropdown_item.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2018 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. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:orientation="horizontal" > + + <!-- These layout params are overwritten in DropdownAdapter.java --> + <ImageView + android:id="@+id/start_dropdown_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="@dimen/autofill_dropdown_icon_margin" + tools:ignore="ContentDescription" /> + + <LinearLayout + android:id="@+id/dropdown_label_wrapper" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_weight="1" + android:gravity="center_vertical" + android:orientation="vertical" > + + <TextView + android:id="@+id/dropdown_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/autofill_dropdown_item_label_margin" + android:layout_marginStart="@dimen/autofill_dropdown_item_label_margin" + android:ellipsize="end" + android:includeFontPadding="false" + android:singleLine="true" + android:textAlignment="viewStart" + android:textAppearance="@style/BlackTitle1" /> + + <TextView + android:id="@+id/dropdown_sublabel" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/autofill_dropdown_item_label_margin" + android:layout_marginStart="@dimen/autofill_dropdown_item_label_margin" + android:ellipsize="end" + android:includeFontPadding="false" + android:singleLine="true" + android:textAlignment="viewStart" + android:textAppearance="@style/BlackCaption" /> + </LinearLayout> + + <ImageView + android:id="@+id/end_dropdown_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="8dp" + tools:ignore="ContentDescription" /> + +</LinearLayout>
\ No newline at end of file diff --git a/chromium/components/autofill/android/java/res/layout/autofill_dropdown_item_refresh.xml b/chromium/components/autofill/android/java/res/layout/autofill_dropdown_item_refresh.xml new file mode 100644 index 00000000000..4287074b5f8 --- /dev/null +++ b/chromium/components/autofill/android/java/res/layout/autofill_dropdown_item_refresh.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2018 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. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingEnd="@dimen/autofill_dropdown_refresh_horizontal_padding" + android:paddingStart="@dimen/autofill_dropdown_refresh_horizontal_padding" + android:gravity="center_vertical" + android:orientation="horizontal" + tools:ignore="UnusedResources" > + + <LinearLayout + android:id="@+id/dropdown_label_wrapper" + android:layout_width="0dp" + android:layout_height="@dimen/autofill_dropdown_refresh_item_height" + android:layout_weight="1" + android:gravity="center_vertical" + android:orientation="vertical" > + + <TextView + android:id="@+id/dropdown_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ellipsize="end" + android:includeFontPadding="false" + android:singleLine="true" + android:textAppearance="@style/BlackBodyDefault" /> + + <TextView + android:id="@+id/dropdown_sublabel" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ellipsize="end" + android:includeFontPadding="false" + android:singleLine="true" + android:textAlignment="viewStart" + android:textAppearance="@style/BlackCaption" /> + </LinearLayout> + + <ImageView + android:id="@+id/end_dropdown_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/autofill_dropdown_refresh_icon_margin" + android:layout_marginEnd="0dp" + tools:ignore="ContentDescription" /> + +</LinearLayout>
\ No newline at end of file diff --git a/chromium/components/autofill/android/java/res/values/dimens.xml b/chromium/components/autofill/android/java/res/values/dimens.xml index 1327d16ea44..ed876f854d2 100644 --- a/chromium/components/autofill/android/java/res/values/dimens.xml +++ b/chromium/components/autofill/android/java/res/values/dimens.xml @@ -5,4 +5,15 @@ found in the LICENSE file. --> <resources> + <!-- Dimens for legacy UI + TODO(crbug.com/874077): Remove once refresh UI is fully rolled out. --> + <dimen name="autofill_dropdown_item_height">50dp</dimen> + <dimen name="autofill_dropdown_item_divider_height">1dp</dimen> + <dimen name="autofill_dropdown_item_label_margin">10dp</dimen> + <dimen name="autofill_dropdown_icon_margin">8dp</dimen> + + <!-- Dimens for refresh UI --> + <dimen name="autofill_dropdown_refresh_item_height">48dp</dimen> + <dimen name="autofill_dropdown_refresh_horizontal_padding">16dp</dimen> + <dimen name="autofill_dropdown_refresh_icon_margin">24dp</dimen> </resources> diff --git a/chromium/components/autofill/content/browser/BUILD.gn b/chromium/components/autofill/content/browser/BUILD.gn index 877af89df15..0d8a0b42348 100644 --- a/chromium/components/autofill/content/browser/BUILD.gn +++ b/chromium/components/autofill/content/browser/BUILD.gn @@ -2,9 +2,10 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/jumbo.gni") import("//third_party/protobuf/proto_library.gni") -static_library("browser") { +jumbo_static_library("browser") { sources = [ "content_autofill_driver.cc", "content_autofill_driver.h", diff --git a/chromium/components/autofill/content/browser/DEPS b/chromium/components/autofill/content/browser/DEPS index c9b21e464f1..847530b9afd 100644 --- a/chromium/components/autofill/content/browser/DEPS +++ b/chromium/components/autofill/content/browser/DEPS @@ -4,6 +4,7 @@ include_rules = [ "+gpu/config/gpu_info.h", "+services/device/public", "+services/service_manager/public/mojom", + "+third_party/blink/public/common", "+third_party/blink/public/platform/web_rect.h", ] diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.cc b/chromium/components/autofill/content/browser/content_autofill_driver.cc index fb8391c870f..944b69b2ea2 100644 --- a/chromium/components/autofill/content/browser/content_autofill_driver.cc +++ b/chromium/components/autofill/content/browser/content_autofill_driver.cc @@ -24,7 +24,7 @@ #include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" #include "content/public/common/origin_util.h" -#include "services/service_manager/public/cpp/interface_provider.h" +#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" #include "ui/gfx/geometry/size_f.h" namespace autofill { @@ -64,7 +64,8 @@ ContentAutofillDriver* ContentAutofillDriver::GetForRenderFrameHost( return factory ? factory->DriverForFrame(render_frame_host) : nullptr; } -void ContentAutofillDriver::BindRequest(mojom::AutofillDriverRequest request) { +void ContentAutofillDriver::BindRequest( + mojom::AutofillDriverAssociatedRequest request) { binding_.Bind(std::move(request)); } @@ -285,10 +286,11 @@ void ContentAutofillDriver::SetAutofillManager( autofill_manager_->SetExternalDelegate(autofill_external_delegate_.get()); } -const mojom::AutofillAgentPtr& ContentAutofillDriver::GetAutofillAgent() { +const mojom::AutofillAgentAssociatedPtr& +ContentAutofillDriver::GetAutofillAgent() { // Here is a lazy binding, and will not reconnect after connection error. if (!autofill_agent_) { - render_frame_host_->GetRemoteInterfaces()->GetInterface( + render_frame_host_->GetRemoteAssociatedInterfaces()->GetInterface( mojo::MakeRequest(&autofill_agent_)); } diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.h b/chromium/components/autofill/content/browser/content_autofill_driver.h index 83c9d743c57..248daefe0ea 100644 --- a/chromium/components/autofill/content/browser/content_autofill_driver.h +++ b/chromium/components/autofill/content/browser/content_autofill_driver.h @@ -15,7 +15,7 @@ #include "components/autofill/core/browser/autofill_driver.h" #include "components/autofill/core/browser/autofill_external_delegate.h" #include "components/autofill/core/browser/autofill_manager.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/associated_binding.h" namespace content { class NavigationHandle; @@ -46,7 +46,7 @@ class ContentAutofillDriver : public AutofillDriver, static ContentAutofillDriver* GetForRenderFrameHost( content::RenderFrameHost* render_frame_host); - void BindRequest(mojom::AutofillDriverRequest request); + void BindRequest(mojom::AutofillDriverAssociatedRequest request); // AutofillDriver: bool IsIncognito() const override; @@ -118,7 +118,7 @@ class ContentAutofillDriver : public AutofillDriver, AutofillManager* autofill_manager() { return autofill_manager_; } content::RenderFrameHost* render_frame_host() { return render_frame_host_; } - const mojom::AutofillAgentPtr& GetAutofillAgent(); + const mojom::AutofillAgentAssociatedPtr& GetAutofillAgent(); // Methods forwarded to key_press_handler_manager_. void RegisterKeyPressHandler( @@ -160,9 +160,9 @@ class ContentAutofillDriver : public AutofillDriver, KeyPressHandlerManager key_press_handler_manager_; - mojo::Binding<mojom::AutofillDriver> binding_; + mojo::AssociatedBinding<mojom::AutofillDriver> binding_; - mojom::AutofillAgentPtr autofill_agent_; + mojom::AutofillAgentAssociatedPtr autofill_agent_; }; } // namespace autofill diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc b/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc index f67d15c2a7f..6825bcf6749 100644 --- a/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc +++ b/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc @@ -79,7 +79,7 @@ ContentAutofillDriverFactory* ContentAutofillDriverFactory::FromWebContents( // static void ContentAutofillDriverFactory::BindAutofillDriver( - mojom::AutofillDriverRequest request, + mojom::AutofillDriverAssociatedRequest request, content::RenderFrameHost* render_frame_host) { content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(render_frame_host); diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_factory.h b/chromium/components/autofill/content/browser/content_autofill_driver_factory.h index 1bcb2f909f3..2ff9b3352ab 100644 --- a/chromium/components/autofill/content/browser/content_autofill_driver_factory.h +++ b/chromium/components/autofill/content/browser/content_autofill_driver_factory.h @@ -45,9 +45,8 @@ class ContentAutofillDriverFactory : public AutofillDriverFactory, static ContentAutofillDriverFactory* FromWebContents( content::WebContents* contents); - static void BindAutofillDriver( - mojom::AutofillDriverRequest request, - content::RenderFrameHost* render_frame_host); + static void BindAutofillDriver(mojom::AutofillDriverAssociatedRequest request, + content::RenderFrameHost* render_frame_host); // Gets the |ContentAutofillDriver| associated with |render_frame_host|. // |render_frame_host| must be owned by |web_contents()|. diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc b/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc index bb199189394..b883e961a5c 100644 --- a/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc +++ b/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc @@ -28,11 +28,11 @@ #include "content/public/browser/web_contents.h" #include "content/public/common/frame_navigate_params.h" #include "content/public/test/test_renderer_host.h" -#include "mojo/public/cpp/bindings/binding_set.h" +#include "mojo/public/cpp/bindings/associated_binding_set.h" #include "net/base/net_errors.h" -#include "services/service_manager/public/cpp/interface_provider.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" namespace autofill { @@ -52,8 +52,9 @@ class FakeAutofillAgent : public mojom::AutofillAgent { ~FakeAutofillAgent() override {} - void BindRequest(mojo::ScopedMessagePipeHandle handle) { - bindings_.AddBinding(this, mojom::AutofillAgentRequest(std::move(handle))); + void BindRequest(mojo::ScopedInterfaceEndpointHandle handle) { + bindings_.AddBinding( + this, mojom::AutofillAgentAssociatedRequest(std::move(handle))); } void SetQuitLoopClosure(base::Closure closure) { quit_closure_ = closure; } @@ -210,7 +211,7 @@ class FakeAutofillAgent : public mojom::AutofillAgent { void SetQueryPasswordSuggestion(bool query) override{}; - mojo::BindingSet<mojom::AutofillAgent> bindings_; + mojo::AssociatedBindingSet<mojom::AutofillAgent> bindings_; base::Closure quit_closure_; @@ -285,12 +286,12 @@ class ContentAutofillDriverTest : public content::RenderViewHostTestHarness { driver_.reset(new TestContentAutofillDriver(web_contents()->GetMainFrame(), test_autofill_client_.get())); - service_manager::InterfaceProvider* remote_interfaces = - web_contents()->GetMainFrame()->GetRemoteInterfaces(); - service_manager::InterfaceProvider::TestApi test_api(remote_interfaces); - test_api.SetBinderForName(mojom::AutofillAgent::Name_, - base::Bind(&FakeAutofillAgent::BindRequest, - base::Unretained(&fake_agent_))); + blink::AssociatedInterfaceProvider* remote_interfaces = + web_contents()->GetMainFrame()->GetRemoteAssociatedInterfaces(); + remote_interfaces->OverrideBinderForTesting( + mojom::AutofillAgent::Name_, + base::BindRepeating(&FakeAutofillAgent::BindRequest, + base::Unretained(&fake_agent_))); } void TearDown() override { diff --git a/chromium/components/autofill/content/browser/risk/fingerprint.cc b/chromium/components/autofill/content/browser/risk/fingerprint.cc index 5b8edff8583..e6fd9107e60 100644 --- a/chromium/components/autofill/content/browser/risk/fingerprint.cc +++ b/chromium/components/autofill/content/browser/risk/fingerprint.cc @@ -289,9 +289,10 @@ FingerprintDataLoader::FingerprintDataLoader( weak_ptr_factory_(this) { DCHECK(!install_time_.is_null()); - timeout_timer_.Start(FROM_HERE, timeout, - base::Bind(&FingerprintDataLoader::MaybeFillFingerprint, - weak_ptr_factory_.GetWeakPtr())); + timeout_timer_.Start( + FROM_HERE, timeout, + base::BindOnce(&FingerprintDataLoader::MaybeFillFingerprint, + weak_ptr_factory_.GetWeakPtr())); // Load GPU data if needed. if (gpu_data_manager_->GpuAccessAllowed(nullptr) && @@ -302,17 +303,15 @@ FingerprintDataLoader::FingerprintDataLoader( #if BUILDFLAG(ENABLE_PLUGINS) // Load plugin data. - content::PluginService::GetInstance()->GetPlugins( - base::Bind(&FingerprintDataLoader::OnGotPlugins, - weak_ptr_factory_.GetWeakPtr())); + content::PluginService::GetInstance()->GetPlugins(base::BindOnce( + &FingerprintDataLoader::OnGotPlugins, weak_ptr_factory_.GetWeakPtr())); #else waiting_on_plugins_ = false; #endif // Load font data. - content::GetFontListAsync( - base::Bind(&FingerprintDataLoader::OnGotFonts, - weak_ptr_factory_.GetWeakPtr())); + content::GetFontListAsync(base::BindOnce(&FingerprintDataLoader::OnGotFonts, + weak_ptr_factory_.GetWeakPtr())); // Load geolocation data. DCHECK(connector); diff --git a/chromium/components/autofill/content/common/autofill_agent.mojom b/chromium/components/autofill/content/common/autofill_agent.mojom index 891f2b86ea0..e3fc0feb404 100644 --- a/chromium/components/autofill/content/common/autofill_agent.mojom +++ b/chromium/components/autofill/content/common/autofill_agent.mojom @@ -122,7 +122,4 @@ interface PasswordGenerationAgent { // Sent when Autofill manager gets the query response from the Autofill server // and there are fields classified for password generation in the response. FoundFormsEligibleForGeneration(array<PasswordFormGenerationData> forms); - - // Tells the renderer to enable the form classifier. - AllowToRunFormClassifier(); }; diff --git a/chromium/components/autofill/content/common/autofill_driver.mojom b/chromium/components/autofill/content/common/autofill_driver.mojom index 34be2a1e28e..5f8af515d83 100644 --- a/chromium/components/autofill/content/common/autofill_driver.mojom +++ b/chromium/components/autofill/content/common/autofill_driver.mojom @@ -124,11 +124,6 @@ interface PasswordManagerDriver { mojo_base.mojom.String16 typed_username, int32 options, gfx.mojom.RectF bounds); - // Sends the outcome of HTML parsing based form classifier that detects the - // forms where password generation should be available. - SaveGenerationFieldDetectedByClassifier( - PasswordForm password_form, mojo_base.mojom.String16 generation_field); - // Checks the safe browsing reputation of the website where the focused // username/password field is on. CheckSafeBrowsingReputation( diff --git a/chromium/components/autofill/content/common/autofill_types.mojom b/chromium/components/autofill/content/common/autofill_types.mojom index c9ecc5760f8..546c8bca5f0 100644 --- a/chromium/components/autofill/content/common/autofill_types.mojom +++ b/chromium/components/autofill/content/common/autofill_types.mojom @@ -130,7 +130,6 @@ struct FormFieldData { mojo_base.mojom.TextDirection text_direction; bool is_enabled; bool is_readonly; - bool is_default; mojo_base.mojom.String16 typed_value; array<mojo_base.mojom.String16> option_values; @@ -180,7 +179,6 @@ struct PasswordAndRealm { // autofill::PasswordFormFillData struct PasswordFormFillData { uint32 form_renderer_id; - mojo_base.mojom.String16 name; url.mojom.Url origin; url.mojom.Url action; FormFieldData username_field; @@ -189,7 +187,6 @@ struct PasswordFormFillData { string preferred_realm; map<mojo_base.mojom.String16, PasswordAndRealm> additional_logins; bool wait_for_username; - bool is_possible_change_password_form; bool has_renderer_ids; }; @@ -232,10 +229,8 @@ struct PasswordForm { bool form_has_autofilled_value; mojo_base.mojom.String16 password_element; mojo_base.mojom.String16 password_value; - bool password_value_is_default; mojo_base.mojom.String16 new_password_element; mojo_base.mojom.String16 new_password_value; - bool new_password_value_is_default; bool new_password_marked_by_site; mojo_base.mojom.String16 confirmation_password_element; bool preferred; diff --git a/chromium/components/autofill/content/common/autofill_types_struct_traits.cc b/chromium/components/autofill/content/common/autofill_types_struct_traits.cc index fad95dddd5c..77f14cdadcd 100644 --- a/chromium/components/autofill/content/common/autofill_types_struct_traits.cc +++ b/chromium/components/autofill/content/common/autofill_types_struct_traits.cc @@ -614,7 +614,6 @@ bool StructTraits< out->is_enabled = data.is_enabled(); out->is_readonly = data.is_readonly(); - out->is_default = data.is_default(); if (!data.ReadValue(&out->typed_value)) return false; @@ -711,8 +710,7 @@ bool StructTraits<autofill::mojom::PasswordFormFillDataDataView, autofill::PasswordFormFillData>:: Read(autofill::mojom::PasswordFormFillDataDataView data, autofill::PasswordFormFillData* out) { - if (!data.ReadName(&out->name) || !data.ReadOrigin(&out->origin) || - !data.ReadAction(&out->action) || + if (!data.ReadOrigin(&out->origin) || !data.ReadAction(&out->action) || !data.ReadUsernameField(&out->username_field) || !data.ReadPasswordField(&out->password_field) || !data.ReadPreferredRealm(&out->preferred_realm) || @@ -721,8 +719,6 @@ bool StructTraits<autofill::mojom::PasswordFormFillDataDataView, out->form_renderer_id = data.form_renderer_id(); out->wait_for_username = data.wait_for_username(); - out->is_possible_change_password_form = - data.is_possible_change_password_form(); out->has_renderer_ids = data.has_renderer_ids(); out->username_may_use_prefilled_placeholder = data.username_may_use_prefilled_placeholder(); @@ -789,13 +785,11 @@ bool StructTraits< return false; out->form_has_autofilled_value = data.form_has_autofilled_value(); - out->password_value_is_default = data.password_value_is_default(); if (!data.ReadNewPasswordElement(&out->new_password_element) || !data.ReadNewPasswordValue(&out->new_password_value)) return false; - out->new_password_value_is_default = data.new_password_value_is_default(); out->new_password_marked_by_site = data.new_password_marked_by_site(); if (!data.ReadConfirmationPasswordElement( diff --git a/chromium/components/autofill/content/common/autofill_types_struct_traits.h b/chromium/components/autofill/content/common/autofill_types_struct_traits.h index 68d03e0ec10..dcc44134d8e 100644 --- a/chromium/components/autofill/content/common/autofill_types_struct_traits.h +++ b/chromium/components/autofill/content/common/autofill_types_struct_traits.h @@ -216,10 +216,6 @@ struct StructTraits<autofill::mojom::FormFieldDataDataView, return r.is_readonly; } - static bool is_default(const autofill::FormFieldData& r) { - return r.is_default; - } - static const base::string16& typed_value(const autofill::FormFieldData& r) { return r.typed_value; } @@ -366,10 +362,6 @@ struct StructTraits<autofill::mojom::PasswordFormFillDataDataView, return r.form_renderer_id; } - static const base::string16& name(const autofill::PasswordFormFillData& r) { - return r.name; - } - static const GURL& origin(const autofill::PasswordFormFillData& r) { return r.origin; } @@ -407,11 +399,6 @@ struct StructTraits<autofill::mojom::PasswordFormFillDataDataView, return r.wait_for_username; } - static bool is_possible_change_password_form( - const autofill::PasswordFormFillData& r) { - return r.is_possible_change_password_form; - } - static bool has_renderer_ids(const autofill::PasswordFormFillData& r) { return r.has_renderer_ids; } @@ -545,10 +532,6 @@ struct StructTraits<autofill::mojom::PasswordFormDataView, return r.password_value; } - static bool password_value_is_default(const autofill::PasswordForm& r) { - return r.password_value_is_default; - } - static const base::string16& new_password_element( const autofill::PasswordForm& r) { return r.new_password_element; @@ -559,10 +542,6 @@ struct StructTraits<autofill::mojom::PasswordFormDataView, return r.new_password_value; } - static bool new_password_value_is_default(const autofill::PasswordForm& r) { - return r.new_password_value_is_default; - } - static bool new_password_marked_by_site(const autofill::PasswordForm& r) { return r.new_password_marked_by_site; } diff --git a/chromium/components/autofill/content/common/autofill_types_struct_traits_unittest.cc b/chromium/components/autofill/content/common/autofill_types_struct_traits_unittest.cc index f0f8abfdea2..943acf02b1b 100644 --- a/chromium/components/autofill/content/common/autofill_types_struct_traits_unittest.cc +++ b/chromium/components/autofill/content/common/autofill_types_struct_traits_unittest.cc @@ -37,7 +37,6 @@ void CreateTestFieldDataPredictions(const std::string& signature, void CreateTestPasswordFormFillData(PasswordFormFillData* fill_data) { fill_data->form_renderer_id = 1234; - fill_data->name = base::ASCIIToUTF16("TestName"); fill_data->origin = GURL("https://foo.com/"); fill_data->action = GURL("https://foo.com/login"); test::CreateTestSelectField("TestUsernameFieldLabel", "TestUsernameFieldName", @@ -60,7 +59,6 @@ void CreateTestPasswordFormFillData(PasswordFormFillData* fill_data) { fill_data->additional_logins[name] = pr; fill_data->wait_for_username = true; - fill_data->is_possible_change_password_form = false; } void CreateTestPasswordForm(PasswordForm* form) { @@ -84,10 +82,8 @@ void CreateTestPasswordForm(PasswordForm* form) { form->form_has_autofilled_value = true; form->password_element = base::ASCIIToUTF16("password"); form->password_value = base::ASCIIToUTF16("test"); - form->password_value_is_default = true; form->new_password_element = base::ASCIIToUTF16("new_password"); form->new_password_value = base::ASCIIToUTF16("new_password_value"); - form->new_password_value_is_default = false; form->new_password_marked_by_site = false; form->new_password_element = base::ASCIIToUTF16("confirmation_password"); form->preferred = false; @@ -157,7 +153,6 @@ void CreatePasswordGenerationUIData( void CheckEqualPasswordFormFillData(const PasswordFormFillData& expected, const PasswordFormFillData& actual) { EXPECT_EQ(expected.form_renderer_id, actual.form_renderer_id); - EXPECT_EQ(expected.name, actual.name); EXPECT_EQ(expected.origin, actual.origin); EXPECT_EQ(expected.action, actual.action); EXPECT_EQ(expected.username_field, actual.username_field); @@ -181,8 +176,6 @@ void CheckEqualPasswordFormFillData(const PasswordFormFillData& expected, } EXPECT_EQ(expected.wait_for_username, actual.wait_for_username); - EXPECT_EQ(expected.is_possible_change_password_form, - actual.is_possible_change_password_form); } void CheckEqualPasswordFormGenerationData( diff --git a/chromium/components/autofill/content/renderer/BUILD.gn b/chromium/components/autofill/content/renderer/BUILD.gn index 94cc1648850..f0b3b85b830 100644 --- a/chromium/components/autofill/content/renderer/BUILD.gn +++ b/chromium/components/autofill/content/renderer/BUILD.gn @@ -2,16 +2,18 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -static_library("renderer") { +import("//build/config/jumbo.gni") + +jumbo_static_library("renderer") { sources = [ "autofill_agent.cc", "autofill_agent.h", + "field_data_manager.cc", + "field_data_manager.h", "form_autofill_util.cc", "form_autofill_util.h", "form_cache.cc", "form_cache.h", - "form_classifier.cc", - "form_classifier.h", "form_tracker.cc", "form_tracker.h", "html_based_username_detector.cc", @@ -56,6 +58,7 @@ static_library("renderer") { "//services/service_manager/public/cpp", "//skia", "//third_party/blink/public:blink", + "//third_party/blink/public/common", "//third_party/re2", "//ui/base", ] @@ -64,7 +67,7 @@ static_library("renderer") { configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] } -static_library("test_support") { +jumbo_static_library("test_support") { testonly = true sources = [ "test_password_autofill_agent.cc", diff --git a/chromium/components/autofill/content/renderer/autofill_agent.cc b/chromium/components/autofill/content/renderer/autofill_agent.cc index 2476e264b9f..759abc427a3 100644 --- a/chromium/components/autofill/content/renderer/autofill_agent.cc +++ b/chromium/components/autofill/content/renderer/autofill_agent.cc @@ -45,6 +45,7 @@ #include "content/public/renderer/render_view.h" #include "net/cert/cert_status_flags.h" #include "services/service_manager/public/cpp/interface_provider.h" +#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" #include "third_party/blink/public/platform/web_keyboard_event.h" #include "third_party/blink/public/platform/web_url_request.h" #include "third_party/blink/public/web/web_console_message.h" @@ -132,7 +133,7 @@ AutofillAgent::ShowSuggestionsOptions::ShowSuggestionsOptions() AutofillAgent::AutofillAgent(content::RenderFrame* render_frame, PasswordAutofillAgent* password_autofill_agent, PasswordGenerationAgent* password_generation_agent, - service_manager::BinderRegistry* registry) + blink::AssociatedInterfaceRegistry* registry) : content::RenderFrameObserver(render_frame), form_cache_(render_frame->GetWebFrame()), password_autofill_agent_(password_autofill_agent), @@ -158,7 +159,7 @@ AutofillAgent::~AutofillAgent() { RemoveFormObserver(this); } -void AutofillAgent::BindRequest(mojom::AutofillAgentRequest request) { +void AutofillAgent::BindRequest(mojom::AutofillAgentAssociatedRequest request) { binding_.Bind(std::move(request)); } @@ -417,18 +418,22 @@ void AutofillAgent::DoAcceptDataListSuggestion( void AutofillAgent::TriggerRefillIfNeeded(const FormData& form) { if (!base::FeatureList::IsEnabled(features::kAutofillDynamicForms)) return; + + ReplaceElementIfNowInvalid(form); + FormFieldData field; FormData updated_form; if (form_util::FindFormAndFieldForFormControlElement(element_, &updated_form, &field) && - !form.DynamicallySameFormAs(updated_form)) { + (!element_.IsAutofilled() || !form.DynamicallySameFormAs(updated_form))) { base::TimeTicks forms_seen_timestamp = base::TimeTicks::Now(); WebLocalFrame* frame = render_frame()->GetWebFrame(); std::vector<FormData> forms; forms.push_back(updated_form); // Always communicate to browser process for topmost frame. - if (!forms.empty() || !frame->Parent()) + if (!forms.empty() || !frame->Parent()) { GetAutofillDriver()->FormsSeen(forms, forms_seen_timestamp); + } } } @@ -1029,11 +1034,62 @@ void AutofillAgent::OnFormNoLongerSubmittable() { submitted_forms_.clear(); } +bool AutofillAgent::FindTheUniqueNewVersionOfOldElement( + WebVector<WebFormControlElement>& elements, + bool& element_found, + const WebString& original_element_section, + const WebFormControlElement& original_element) { + for (const WebFormControlElement& current_element : elements) { + if (current_element.IsFocusable() && + original_element.NameForAutofill() == + current_element.NameForAutofill()) { + if (!element_found) { + element_ = current_element; + element_found = true; + } else if (current_element.AutofillSection() == + element_.AutofillSection() || + (current_element.AutofillSection() != + original_element_section && + element_.AutofillSection() != original_element_section)) { + // If there are two elements that share the same name with the element_, + // and the section can't tell them apart, we can't decide between the + // two. + element_ = original_element; + return false; + } else if (current_element.AutofillSection() == + original_element_section) { + // If the current element has the right section, update the element_. + element_ = current_element; + } + } + } + return true; +} + void AutofillAgent::ReplaceElementIfNowInvalid(const FormData& original_form) { // If the document is invalid, bail out. if (element_.GetDocument().IsNull()) return; + WebVector<WebFormElement> forms; + WebVector<WebFormControlElement> elements; + + if (original_form.name.empty()) { + // If the form has no name, check all the forms. + bool element_found = false; + element_.GetDocument().Forms(forms); + for (const WebFormElement& form : forms) { + form.GetFormControlElements(elements); + // If finding a unique element is impossible, return. + if (!FindTheUniqueNewVersionOfOldElement( + elements, element_found, element_.AutofillSection(), element_)) + return; + } + // If the element is not found, we should still check for unowned elements. + if (element_found) + return; + } + if (!element_.Form().IsNull()) { // If |element_|'s parent form has no elements, |element_| is now invalid // and should be updated. @@ -1043,29 +1099,32 @@ void AutofillAgent::ReplaceElementIfNowInvalid(const FormData& original_form) { return; } - // Try to find the new version of the form. WebFormElement form_element; - WebVector<WebFormElement> forms; - element_.GetDocument().Forms(forms); - for (const WebFormElement& form : forms) { - if (original_form.name == form.GetName().Utf16() || - original_form.name == form.GetAttribute("id").Utf16()) { - form_element = form; - break; + if (!original_form.name.empty()) { + // Try to find the new version of the form. + element_.GetDocument().Forms(forms); + for (const WebFormElement& form : forms) { + if (original_form.name == form.GetName().Utf16() || + original_form.name == form.GetAttribute("id").Utf16()) { + form_element = form; + break; + } } } - WebVector<WebFormControlElement> elements; if (form_element.IsNull()) { // Could not find the new version of the form, get all the unowned elements. std::vector<WebElement> fieldsets; elements = form_util::GetUnownedAutofillableFormFieldElements( element_.GetDocument().All(), &fieldsets); - } else { - // Get all the elements of the new version of the form. - form_element.GetFormControlElements(elements); + bool element_found = false; + FindTheUniqueNewVersionOfOldElement(elements, element_found, + element_.AutofillSection(), element_); + return; } - + // This is the case for owned fields that belong to the right named form. + // Get all the elements of the new version of the form. + form_element.GetFormControlElements(elements); // Try to find the new version of the last interacted element. for (const WebFormControlElement& element : elements) { if (element_.NameForAutofill() == element.NameForAutofill()) { @@ -1075,9 +1134,9 @@ void AutofillAgent::ReplaceElementIfNowInvalid(const FormData& original_form) { } } -const mojom::AutofillDriverPtr& AutofillAgent::GetAutofillDriver() { +const mojom::AutofillDriverAssociatedPtr& AutofillAgent::GetAutofillDriver() { if (!autofill_driver_) { - render_frame()->GetRemoteInterfaces()->GetInterface( + render_frame()->GetRemoteAssociatedInterfaces()->GetInterface( mojo::MakeRequest(&autofill_driver_)); } diff --git a/chromium/components/autofill/content/renderer/autofill_agent.h b/chromium/components/autofill/content/renderer/autofill_agent.h index ba36f73adfb..8da5c3c5025 100644 --- a/chromium/components/autofill/content/renderer/autofill_agent.h +++ b/chromium/components/autofill/content/renderer/autofill_agent.h @@ -19,8 +19,8 @@ #include "components/autofill/content/renderer/form_cache.h" #include "components/autofill/content/renderer/form_tracker.h" #include "content/public/renderer/render_frame_observer.h" -#include "mojo/public/cpp/bindings/binding.h" -#include "services/service_manager/public/cpp/binder_registry.h" +#include "mojo/public/cpp/bindings/associated_binding.h" +#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h" #include "third_party/blink/public/web/web_autofill_client.h" #include "third_party/blink/public/web/web_form_control_element.h" #include "third_party/blink/public/web/web_form_element.h" @@ -29,6 +29,10 @@ namespace blink { class WebNode; class WebView; +class WebString; +class WebFormControlElement; +template <typename T> +class WebVector; } namespace autofill { @@ -57,12 +61,12 @@ class AutofillAgent : public content::RenderFrameObserver, AutofillAgent(content::RenderFrame* render_frame, PasswordAutofillAgent* password_autofill_manager, PasswordGenerationAgent* password_generation_agent, - service_manager::BinderRegistry* registry); + blink::AssociatedInterfaceRegistry* registry); ~AutofillAgent() override; - void BindRequest(mojom::AutofillAgentRequest request); + void BindRequest(mojom::AutofillAgentAssociatedRequest request); - const mojom::AutofillDriverPtr& GetAutofillDriver(); + const mojom::AutofillDriverAssociatedPtr& GetAutofillDriver(); const mojom::PasswordManagerDriverAssociatedPtr& GetPasswordManagerDriver(); @@ -266,6 +270,15 @@ class AutofillAgent : public content::RenderFrameObserver, // cleared in this method. void OnFormNoLongerSubmittable(); + // For no name forms, and unowned elements, try to see if there is a unique + // element in the updated form that corresponds to the old |element_|. + // Returns false if more than one element matches the |element_|. + bool FindTheUniqueNewVersionOfOldElement( + blink::WebVector<blink::WebFormControlElement>& elements, + bool& element_found, + const blink::WebString& original_element_section, + const blink::WebFormControlElement& original_element); + // Check whether |element_| was removed or replaced dynamically on the page. // If so, looks for the same element in the updated |form| and replaces the // |element_| with it if it's found. @@ -354,9 +367,9 @@ class AutofillAgent : public content::RenderFrameObserver, // Whether or not we delay focus handling until scrolling occurs. bool focus_requires_scroll_ = true; - mojo::Binding<mojom::AutofillAgent> binding_; + mojo::AssociatedBinding<mojom::AutofillAgent> binding_; - mojom::AutofillDriverPtr autofill_driver_; + mojom::AutofillDriverAssociatedPtr autofill_driver_; bool was_last_action_fill_ = false; diff --git a/chromium/components/autofill/content/renderer/field_data_manager.cc b/chromium/components/autofill/content/renderer/field_data_manager.cc new file mode 100644 index 00000000000..46d6e7d35b4 --- /dev/null +++ b/chromium/components/autofill/content/renderer/field_data_manager.cc @@ -0,0 +1,84 @@ +// Copyright 2018 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 "components/autofill/content/renderer/field_data_manager.h" + +#include "base/i18n/case_conversion.h" +#include "base/logging.h" +#include "third_party/blink/public/web/web_form_control_element.h" + +namespace autofill { + +FieldDataManager::FieldDataManager() = default; + +FieldDataManager::~FieldDataManager() = default; + +void FieldDataManager::ClearData() { + field_value_and_properties_map_.clear(); +} + +bool FieldDataManager::HasFieldData(uint32_t id) const { + return field_value_and_properties_map_.find(id) != + field_value_and_properties_map_.end(); +} + +base::string16 FieldDataManager::GetUserTypedValue(uint32_t id) const { + DCHECK(HasFieldData(id)); + return field_value_and_properties_map_.at(id).first.value_or( + base::string16()); +} + +FieldPropertiesMask FieldDataManager::GetFieldPropertiesMask( + uint32_t id) const { + DCHECK(HasFieldData(id)); + return field_value_and_properties_map_.at(id).second; +} + +bool FieldDataManager::FindMachedValue(const base::string16& value) const { + constexpr size_t kMinMatchSize = 3u; + const auto lowercase = base::i18n::ToLower(value); + for (const auto& map_key : field_value_and_properties_map_) { + const base::string16 typed_from_key = + map_key.second.first.value_or(base::string16()); + if (typed_from_key.empty()) + continue; + if (typed_from_key.size() >= kMinMatchSize && + lowercase.find(base::i18n::ToLower(typed_from_key)) != + base::string16::npos) + return true; + } + return false; +} + +void FieldDataManager::UpdateFieldDataMap( + const blink::WebFormControlElement& element, + const base::string16& value, + FieldPropertiesMask mask) { + uint32_t id = element.UniqueRendererFormControlId(); + if (HasFieldData(id)) { + field_value_and_properties_map_.at(id).first = + base::Optional<base::string16>(value); + field_value_and_properties_map_.at(id).second |= mask; + } else { + field_value_and_properties_map_[id] = + std::make_pair(base::Optional<base::string16>(value), mask); + } + // Reset USER_TYPED and AUTOFILLED flags if the value is empty. + if (value.empty()) { + field_value_and_properties_map_.at(id).second &= + ~(FieldPropertiesFlags::USER_TYPED | FieldPropertiesFlags::AUTOFILLED); + } +} + +void FieldDataManager::UpdateFieldDataMapWithNullValue( + const blink::WebFormControlElement& element, + FieldPropertiesMask mask) { + uint32_t id = element.UniqueRendererFormControlId(); + if (HasFieldData(id)) + field_value_and_properties_map_.at(id).second |= mask; + else + field_value_and_properties_map_[id] = std::make_pair(base::nullopt, mask); +} + +} // namespace autofill diff --git a/chromium/components/autofill/content/renderer/field_data_manager.h b/chromium/components/autofill/content/renderer/field_data_manager.h new file mode 100644 index 00000000000..c00f6f69638 --- /dev/null +++ b/chromium/components/autofill/content/renderer/field_data_manager.h @@ -0,0 +1,56 @@ +// Copyright 2018 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. + +#ifndef COMPONENTS_AUTOFILL_CONTENT_RENDERER_FIELD_DATA_MANAGER_H_ +#define COMPONENTS_AUTOFILL_CONTENT_RENDERER_FIELD_DATA_MANAGER_H_ + +#include <map> + +#include "base/optional.h" +#include "base/strings/string16.h" +#include "components/autofill/core/common/form_field_data.h" + +namespace blink { +class WebFormControlElement; +} + +namespace autofill { + +// This class provides the meathods to update and get the field data (the pair +// of user typed value and field properties mask). +class FieldDataManager { + public: + FieldDataManager(); + ~FieldDataManager(); + + void ClearData(); + bool HasFieldData(uint32_t id) const; + + // Updates the field value associated with the key |element| in + // |field_value_and_properties_map_|. + // Flags in |mask| are added with bitwise OR operation. + // If |value| is empty, USER_TYPED and AUTOFILLED should be cleared. + void UpdateFieldDataMap(const blink::WebFormControlElement& element, + const base::string16& value, + FieldPropertiesMask mask); + // Only update FieldPropertiesMask when value is null. + void UpdateFieldDataMapWithNullValue( + const blink::WebFormControlElement& element, + FieldPropertiesMask mask); + + base::string16 GetUserTypedValue(uint32_t id) const; + FieldPropertiesMask GetFieldPropertiesMask(uint32_t id) const; + + // Check if the string |value| is saved in |field_value_and_properties_map_|. + bool FindMachedValue(const base::string16& value) const; + + private: + std::map<uint32_t, + std::pair<base::Optional<base::string16>, FieldPropertiesMask>> + field_value_and_properties_map_; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CONTENT_RENDERER_FIELD_DATA_MANAGER_H_ diff --git a/chromium/components/autofill/content/renderer/field_data_manager_browsertest.cc b/chromium/components/autofill/content/renderer/field_data_manager_browsertest.cc new file mode 100644 index 00000000000..1c40aae9916 --- /dev/null +++ b/chromium/components/autofill/content/renderer/field_data_manager_browsertest.cc @@ -0,0 +1,113 @@ +// Copyright 2018 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 "components/autofill/content/renderer/field_data_manager.h" + +#include "base/strings/utf_string_conversions.h" +#include "content/public/test/render_view_test.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/web/web_document.h" +#include "third_party/blink/public/web/web_element_collection.h" +#include "third_party/blink/public/web/web_form_control_element.h" +#include "third_party/blink/public/web/web_local_frame.h" + +namespace autofill { + +class FieldDataManagerTest : public content::RenderViewTest { + public: + FieldDataManagerTest() {} + ~FieldDataManagerTest() override {} + + protected: + void SetUp() override { + RenderViewTest::SetUp(); + + LoadHTML( + "<input type='text' id='name1' value='first'>" + "<input type='password' id='name2' value=''>"); + blink::WebLocalFrame* web_frame = GetMainFrame(); + blink::WebElementCollection inputs = + web_frame->GetDocument().GetElementsByHTMLTagName("input"); + for (blink::WebElement element = inputs.FirstItem(); !element.IsNull(); + element = inputs.NextItem()) { + control_elements_.push_back(element.To<blink::WebFormControlElement>()); + } + } + + void TearDown() override { + control_elements_.clear(); + RenderViewTest::TearDown(); + } + + std::vector<blink::WebFormControlElement> control_elements_; +}; + +TEST_F(FieldDataManagerTest, UpdateFieldDataMap) { + FieldDataManager field_data_manager; + field_data_manager.UpdateFieldDataMap(control_elements_[0], + control_elements_[0].Value().Utf16(), + FieldPropertiesFlags::USER_TYPED); + const uint32_t id = control_elements_[0].UniqueRendererFormControlId(); + EXPECT_TRUE(field_data_manager.HasFieldData(id)); + EXPECT_EQ(base::UTF8ToUTF16("first"), + field_data_manager.GetUserTypedValue(id)); + EXPECT_EQ(FieldPropertiesFlags::USER_TYPED, + field_data_manager.GetFieldPropertiesMask(id)); + + field_data_manager.UpdateFieldDataMap(control_elements_[0], + base::UTF8ToUTF16("newvalue"), + FieldPropertiesFlags::AUTOFILLED); + EXPECT_EQ(base::UTF8ToUTF16("newvalue"), + field_data_manager.GetUserTypedValue(id)); + FieldPropertiesMask mask = + FieldPropertiesFlags::USER_TYPED | FieldPropertiesFlags::AUTOFILLED; + EXPECT_EQ(mask, field_data_manager.GetFieldPropertiesMask(id)); + + field_data_manager.UpdateFieldDataMap(control_elements_[1], + control_elements_[1].Value().Utf16(), + FieldPropertiesFlags::AUTOFILLED); + EXPECT_EQ(FieldPropertiesFlags::NO_FLAGS, + field_data_manager.GetFieldPropertiesMask( + control_elements_[1].UniqueRendererFormControlId())); + + field_data_manager.ClearData(); + EXPECT_FALSE(field_data_manager.HasFieldData(id)); +} + +TEST_F(FieldDataManagerTest, UpdateFieldDataMapWithNullValue) { + FieldDataManager field_data_manager; + field_data_manager.UpdateFieldDataMapWithNullValue( + control_elements_[0], FieldPropertiesFlags::USER_TYPED); + const uint32_t id = control_elements_[0].UniqueRendererFormControlId(); + EXPECT_TRUE(field_data_manager.HasFieldData(id)); + EXPECT_EQ(base::string16(), field_data_manager.GetUserTypedValue(id)); + EXPECT_EQ(FieldPropertiesFlags::USER_TYPED, + field_data_manager.GetFieldPropertiesMask(id)); + + field_data_manager.UpdateFieldDataMapWithNullValue( + control_elements_[0], FieldPropertiesFlags::AUTOFILLED); + EXPECT_EQ(base::string16(), field_data_manager.GetUserTypedValue(id)); + FieldPropertiesMask mask = + FieldPropertiesFlags::USER_TYPED | FieldPropertiesFlags::AUTOFILLED; + EXPECT_EQ(mask, field_data_manager.GetFieldPropertiesMask(id)); + + field_data_manager.UpdateFieldDataMap(control_elements_[0], + control_elements_[0].Value().Utf16(), + FieldPropertiesFlags::AUTOFILLED); + EXPECT_EQ(base::UTF8ToUTF16("first"), + field_data_manager.GetUserTypedValue(id)); +} + +TEST_F(FieldDataManagerTest, FindMachedValue) { + FieldDataManager field_data_manager; + field_data_manager.UpdateFieldDataMap(control_elements_[0], + control_elements_[0].Value().Utf16(), + FieldPropertiesFlags::USER_TYPED); + EXPECT_TRUE( + field_data_manager.FindMachedValue(base::UTF8ToUTF16("first_element"))); + EXPECT_FALSE( + field_data_manager.FindMachedValue(base::UTF8ToUTF16("second_element"))); +} + +} // namespace autofill diff --git a/chromium/components/autofill/content/renderer/form_autofill_util.cc b/chromium/components/autofill/content/renderer/form_autofill_util.cc index 8f11a5adb45..53c7396590d 100644 --- a/chromium/components/autofill/content/renderer/form_autofill_util.cc +++ b/chromium/components/autofill/content/renderer/form_autofill_util.cc @@ -22,6 +22,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "components/autofill/content/renderer/field_data_manager.h" #include "components/autofill/core/common/autofill_data_validation.h" #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_regexes.h" @@ -876,6 +877,13 @@ void ForEachMatchingFormFieldCommon( base::i18n::ToLower(element->Value().Utf16()))) continue; + // Check if we should autofill/preview/clear a select element or leave it. + if (!force_override && !is_initiating_element && + IsSelectElement(*element) && element->UserHasEditedTheField() && + base::FeatureList::IsEnabled(features::kAutofillPrefilledFields) && + !SanitizedFieldIsEmpty(element->Value().Utf16())) + continue; + if (((filters & FILTER_DISABLED_ELEMENTS) && !element->IsEnabled()) || ((filters & FILTER_READONLY_ELEMENTS) && element->IsReadOnly()) || // See description for FILTER_NON_FOCUSABLE_ELEMENTS. @@ -1010,7 +1018,7 @@ void PreviewFormField(const FormFieldData& data, // [1, kMaxParseableFields]. bool ExtractFieldsFromControlElements( const WebVector<WebFormControlElement>& control_elements, - const FieldValueAndPropertiesMaskMap* field_value_and_properties_map, + const FieldDataManager* field_data_manager, ExtractMask extract_mask, std::vector<std::unique_ptr<FormFieldData>>* form_fields, std::vector<bool>* fields_extracted, @@ -1027,8 +1035,7 @@ bool ExtractFieldsFromControlElements( // Create a new FormFieldData, fill it out and map it to the field's name. auto form_field = std::make_unique<FormFieldData>(); - WebFormControlElementToFormField(control_element, - field_value_and_properties_map, + WebFormControlElementToFormField(control_element, field_data_manager, extract_mask, form_field.get()); (*element_map)[control_element] = form_field.get(); form_fields->push_back(std::move(form_field)); @@ -1115,7 +1122,7 @@ bool FormOrFieldsetsToFormData( const blink::WebFormControlElement* form_control_element, const std::vector<blink::WebElement>& fieldsets, const WebVector<WebFormControlElement>& control_elements, - const FieldValueAndPropertiesMaskMap* field_value_and_properties_map, + const FieldDataManager* field_data_manager, ExtractMask extract_mask, FormData* form, FormFieldData* field) { @@ -1137,9 +1144,9 @@ bool FormOrFieldsetsToFormData( // requirements and thus will be in the resulting |form|. std::vector<bool> fields_extracted(control_elements.size(), false); - if (!ExtractFieldsFromControlElements( - control_elements, field_value_and_properties_map, extract_mask, - &form_fields, &fields_extracted, &element_map)) { + if (!ExtractFieldsFromControlElements(control_elements, field_data_manager, + extract_mask, &form_fields, + &fields_extracted, &element_map)) { return false; } @@ -1220,7 +1227,7 @@ bool UnownedFormElementsAndFieldSetsToFormData( const std::vector<blink::WebFormControlElement>& control_elements, const blink::WebFormControlElement* element, const blink::WebDocument& document, - const FieldValueAndPropertiesMaskMap* field_value_and_properties_map, + const FieldDataManager* field_data_manager, ExtractMask extract_mask, FormData* form, FormFieldData* field) { @@ -1234,9 +1241,9 @@ bool UnownedFormElementsAndFieldSetsToFormData( form->is_form_tag = false; - return FormOrFieldsetsToFormData( - nullptr, element, fieldsets, control_elements, - field_value_and_properties_map, extract_mask, form, field); + return FormOrFieldsetsToFormData(nullptr, element, fieldsets, + control_elements, field_data_manager, + extract_mask, form, field); } // Check if a script modified username is suitable for Password Manager to @@ -1244,7 +1251,7 @@ bool UnownedFormElementsAndFieldSetsToFormData( bool ScriptModifiedUsernameAcceptable( const base::string16& value, const base::string16& typed_value, - const FieldValueAndPropertiesMaskMap& field_value_and_properties_map) { + const FieldDataManager* field_data_manager) { // The minimal size of a field value that will be substring-matched. constexpr size_t kMinMatchSize = 3u; const auto lowercase = base::i18n::ToLower(value); @@ -1262,18 +1269,7 @@ bool ScriptModifiedUsernameAcceptable( // If the page-generated value comes from user typed or autofilled values in // other fields, that's also likely OK. - for (const auto& map_key : field_value_and_properties_map) { - const base::string16* typed_from_key = map_key.second.first.get(); - if (!typed_from_key) - continue; - if (typed_from_key->size() >= kMinMatchSize && - lowercase.find(base::i18n::ToLower(*typed_from_key)) != - base::string16::npos) { - return true; - } - } - - return false; + return field_data_manager->FindMachedValue(value); } } // namespace @@ -1470,7 +1466,7 @@ std::vector<WebFormControlElement> ExtractAutofillableElementsInForm( void WebFormControlElementToFormField( const WebFormControlElement& element, - const FieldValueAndPropertiesMaskMap* field_value_and_properties_map, + const FieldDataManager* field_data_manager, ExtractMask extract_mask, FormFieldData* field) { DCHECK(field); @@ -1505,12 +1501,10 @@ void WebFormControlElementToFormField( if (element.HasAttribute(kClass)) field->css_classes = element.GetAttribute(kClass).Utf16(); - if (field_value_and_properties_map) { - FieldValueAndPropertiesMaskMap::const_iterator it = - field_value_and_properties_map->find( - element.UniqueRendererFormControlId()); - if (it != field_value_and_properties_map->end()) - field->properties_mask = it->second.second; + if (field_data_manager && + field_data_manager->HasFieldData(element.UniqueRendererFormControlId())) { + field->properties_mask = field_data_manager->GetFieldPropertiesMask( + element.UniqueRendererFormControlId()); } if (!IsAutofillableElement(element)) @@ -1528,7 +1522,6 @@ void WebFormControlElementToFormField( field->text_direction = GetTextDirectionForElement(element); field->is_enabled = element.IsEnabled(); field->is_readonly = element.IsReadOnly(); - field->is_default = element.GetAttribute("value") == element.Value(); } if (IsAutofillableInputElement(input_element)) { @@ -1576,24 +1569,22 @@ void WebFormControlElementToFormField( field->value = value; // If the field was autofilled or the user typed into it, check the value - // stored in |field_value_and_properties_map| against the value property of - // the DOM element. If they differ, then the scripts on the website modified - // the value afterwards. Store the original value as the |typed_value|, unless + // stored in |field_data_manager| against the value property of the DOM + // element. If they differ, then the scripts on the website modified the + // value afterwards. Store the original value as the |typed_value|, unless // this is one of recognised situations when the site-modified value is more // useful for filling. - if (field_value_and_properties_map && + if (field_data_manager && field->properties_mask & (FieldPropertiesFlags::USER_TYPED | FieldPropertiesFlags::AUTOFILLED)) { - const base::string16 typed_value = - *field_value_and_properties_map - ->at(element.UniqueRendererFormControlId()) - .first; + const base::string16 typed_value = field_data_manager->GetUserTypedValue( + element.UniqueRendererFormControlId()); // The typed value is preserved for all passwords. It is also preserved for // potential usernames, as long as the |value| is not deemed acceptable. if (field->form_control_type == "password" || !ScriptModifiedUsernameAcceptable(value, typed_value, - *field_value_and_properties_map)) { + field_data_manager)) { field->typed_value = typed_value; } } @@ -1602,7 +1593,7 @@ void WebFormControlElementToFormField( bool WebFormElementToFormData( const blink::WebFormElement& form_element, const blink::WebFormControlElement& form_control_element, - const FieldValueAndPropertiesMaskMap* field_value_and_properties_map, + const FieldDataManager* field_data_manager, ExtractMask extract_mask, FormData* form, FormFieldData* field) { @@ -1631,7 +1622,7 @@ bool WebFormElementToFormData( std::vector<blink::WebElement> dummy_fieldset; return FormOrFieldsetsToFormData( &form_element, &form_control_element, dummy_fieldset, control_elements, - field_value_and_properties_map, extract_mask, form, field); + field_data_manager, extract_mask, form, field); } std::vector<WebFormControlElement> GetUnownedFormFieldElements( @@ -1765,13 +1756,13 @@ bool UnownedPasswordFormElementsAndFieldSetsToFormData( const std::vector<blink::WebFormControlElement>& control_elements, const blink::WebFormControlElement* element, const blink::WebDocument& document, - const FieldValueAndPropertiesMaskMap* field_value_and_properties_map, + const FieldDataManager* field_data_manager, ExtractMask extract_mask, FormData* form, FormFieldData* field) { return UnownedFormElementsAndFieldSetsToFormData( - fieldsets, control_elements, element, document, - field_value_and_properties_map, extract_mask, form, field); + fieldsets, control_elements, element, document, field_data_manager, + extract_mask, form, field); } diff --git a/chromium/components/autofill/content/renderer/form_autofill_util.h b/chromium/components/autofill/content/renderer/form_autofill_util.h index ab69b3fbfca..429005bcb98 100644 --- a/chromium/components/autofill/content/renderer/form_autofill_util.h +++ b/chromium/components/autofill/content/renderer/form_autofill_util.h @@ -12,7 +12,6 @@ #include "base/macros.h" #include "base/strings/string16.h" -#include "components/autofill/content/renderer/password_form_conversion_utils.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/password_form_field_prediction_map.h" #include "third_party/blink/public/platform/web_vector.h" @@ -22,6 +21,8 @@ class GURL; namespace blink { +enum class WebAutofillState; + class WebDocument; class WebElement; class WebFormControlElement; @@ -36,6 +37,8 @@ namespace autofill { struct FormData; struct FormFieldData; +class FieldDataManager; + namespace form_util { // A bit field mask to extract data from WebFormControlElement. @@ -137,11 +140,11 @@ std::vector<blink::WebFormControlElement> ExtractAutofillableElementsInForm( // Fills out a FormField object from a given WebFormControlElement. // |extract_mask|: See the enum ExtractMask above for details. Field properties -// will be copied from |field_value_and_properties_map|, if the argument is not -// null and has entry for |element| (see properties in FieldPropertiesFlags). +// will be copied from |field_data_manager|, if the argument is not null and +// has entry for |element| (see properties in FieldPropertiesFlags). void WebFormControlElementToFormField( const blink::WebFormControlElement& element, - const FieldValueAndPropertiesMaskMap* field_value_and_properties_map, + const FieldDataManager* field_data_manager, ExtractMask extract_mask, FormFieldData* field); @@ -150,12 +153,12 @@ void WebFormControlElementToFormField( // corresponding to the |form_control_element|. |extract_mask| controls what // data is extracted. Returns true if |form| is filled out. Also returns false // if there are no fields or too many fields in the |form|. Field properties -// will be copied from |field_value_and_properties_map|, if the argument is not -// null and has entry for |element| (see properties in FieldPropertiesFlags). +// will be copied from |field_data_manager|, if the argument is not null and +// has entry for |element| (see properties in FieldPropertiesFlags). bool WebFormElementToFormData( const blink::WebFormElement& form_element, const blink::WebFormControlElement& form_control_element, - const FieldValueAndPropertiesMaskMap* field_value_and_properties_map, + const FieldDataManager* field_data_manager, ExtractMask extract_mask, FormData* form, FormFieldData* field); @@ -192,14 +195,14 @@ bool UnownedCheckoutFormElementsAndFieldSetsToFormData( // Same as above, but without the requirement that the elements only be // related to checkout. Field properties of |control_elements| will be copied -// from |field_value_and_properties_map|, if the argument is not null and has -// corresponding entries (see properties in FieldPropertiesFlags). +// from |field_data_manager|, if the argument is not null and has corresponding +// entries (see properties in FieldPropertiesFlags). bool UnownedPasswordFormElementsAndFieldSetsToFormData( const std::vector<blink::WebElement>& fieldsets, const std::vector<blink::WebFormControlElement>& control_elements, const blink::WebFormControlElement* element, const blink::WebDocument& document, - const FieldValueAndPropertiesMaskMap* field_value_and_properties_map, + const FieldDataManager* field_data_manager, ExtractMask extract_mask, FormData* form, FormFieldData* field); diff --git a/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc b/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc index ac1f4085c65..29879265288 100644 --- a/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc +++ b/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc @@ -344,55 +344,6 @@ TEST_F(FormAutofillUtilsTest, IsReadonly) { } } -TEST_F(FormAutofillUtilsTest, IsDefault) { - LoadHTML( - "<input type='text' id='name1' value='123'>" - "<input type='password' id='name2'>" - "<input type='password' id='name3'>" - "<input type='text' id='name4' value='321'>"); - - const std::vector<blink::WebElement> dummy_fieldsets; - - WebLocalFrame* web_frame = GetMainFrame(); - ASSERT_TRUE(web_frame); - - web_frame->GetDocument() - .GetElementById("name1") - .To<blink::WebInputElement>() - .SetAutofillValue("abc"); - web_frame->GetDocument() - .GetElementById("name3") - .To<blink::WebInputElement>() - .SetAutofillValue("abc"); - - std::vector<blink::WebFormControlElement> control_elements; - blink::WebElementCollection inputs = - web_frame->GetDocument().GetElementsByHTMLTagName("input"); - for (blink::WebElement element = inputs.FirstItem(); !element.IsNull(); - element = inputs.NextItem()) { - control_elements.push_back(element.To<blink::WebFormControlElement>()); - } - - autofill::FormData target; - EXPECT_TRUE( - autofill::form_util::UnownedPasswordFormElementsAndFieldSetsToFormData( - dummy_fieldsets, control_elements, nullptr, web_frame->GetDocument(), - nullptr, autofill::form_util::EXTRACT_NONE, &target, nullptr)); - const struct { - const char* const name; - bool is_default; - } kExpectedFields[] = { - {"name1", false}, {"name2", true}, {"name3", false}, {"name4", true}, - }; - const size_t number_of_cases = arraysize(kExpectedFields); - ASSERT_EQ(number_of_cases, target.fields.size()); - for (size_t i = 0; i < number_of_cases; ++i) { - EXPECT_EQ(base::UTF8ToUTF16(kExpectedFields[i].name), - target.fields[i].name); - EXPECT_EQ(kExpectedFields[i].is_default, target.fields[i].is_default); - } -} - TEST_F(FormAutofillUtilsTest, IsFocusable) { LoadHTML( "<input type='text' id='name1' value='123'>" diff --git a/chromium/components/autofill/content/renderer/form_classifier.cc b/chromium/components/autofill/content/renderer/form_classifier.cc deleted file mode 100644 index 7ab47ad4f6c..00000000000 --- a/chromium/components/autofill/content/renderer/form_classifier.cc +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright 2016 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 "components/autofill/content/renderer/form_classifier.h" - -#include <algorithm> - -#include "base/macros.h" -#include "base/strings/string16.h" -#include "base/strings/string_util.h" -#include "components/autofill/content/renderer/form_autofill_util.h" -#include "third_party/blink/public/platform/web_string.h" -#include "third_party/blink/public/platform/web_vector.h" -#include "third_party/blink/public/web/web_form_control_element.h" -#include "third_party/blink/public/web/web_input_element.h" - -using autofill::form_util::WebFormControlElementToFormField; -using blink::WebFormControlElement; -using blink::WebInputElement; -using blink::WebString; -using blink::WebVector; - -namespace autofill { - -namespace { - -// The words that frequently appear in attribute values of signin forms. -const char* const kSigninTextFeatures[] = {"signin", "login", "logon", "auth"}; -constexpr size_t kNumberOfSigninFeatures = arraysize(kSigninTextFeatures); - -// The words that frequently appear in attribute values of signup forms. -const char* const kSignupTextFeatures[] = {"signup", "regist", "creat"}; -constexpr size_t kNumberOfSignupFeatures = arraysize(kSignupTextFeatures); - -// The words that frequently appear in attribute values of captcha elements. -const char* const kCaptchaFeatures[] = {"captcha", "security", "code"}; -constexpr size_t kNumberOfCaptchaFeatures = arraysize(kCaptchaFeatures); - -// Minimal number of input fields to classify form as signup or change password -// form. If at least one of the listed thresholds is reached or exceeded, the -// form is classified as a form where password generation should be available. -constexpr size_t MINIMAL_NUMBER_OF_TEXT_FIELDS = 2; -constexpr size_t MINIMAL_NUMBER_OF_PASSWORD_FIELDS = 2; -constexpr size_t MINIMAL_NUMBER_OF_CHECKBOX_FIELDS = 3; -constexpr size_t MINIMAL_NUMBER_OF_OTHER_FIELDS = 2; - -// Removes some characters from attribute value. -void ClearAttributeValue(std::string* value) { - value->erase(std::remove_if(value->begin(), value->end(), - [](char x) { return x == '-' || x == '_'; }), - value->end()); -} - -// Find |features| in |element|'s attribute values. Returns true if at least one -// text feature was found. -bool FindTextFeaturesForClass(const blink::WebElement& element, - const char* const features[], - size_t number_of_features) { - DCHECK(features); - - for (unsigned i = 0; i < element.AttributeCount(); ++i) { - std::string filtered_value = - base::ToLowerASCII(element.AttributeValue(i).Utf8()); - ClearAttributeValue(&filtered_value); - - if (filtered_value.empty()) - continue; - for (size_t j = 0; j < number_of_features; ++j) { - if (filtered_value.find(features[j]) != std::string::npos) - return true; - } - } - return false; -} - -// Returns true if at least one captcha feature was found in |element|'s -// attribute values. -bool IsCaptchaInput(const blink::WebInputElement& element) { - return FindTextFeaturesForClass(element, kCaptchaFeatures, - kNumberOfCaptchaFeatures); -} - -// Finds <img>'s inside |form| and checks if <img>'s attributes contains captcha -// text features. Returns true, if at least one occurrence was found. -bool FindCaptchaInImgElements(const blink::WebElement& form, - bool ingnore_invisible) { - CR_DEFINE_STATIC_LOCAL(WebString, kImageTag, ("img")); - - blink::WebElementCollection img_elements = - form.GetElementsByHTMLTagName(kImageTag); - for (blink::WebElement element = img_elements.FirstItem(); !element.IsNull(); - element = img_elements.NextItem()) { - if (ingnore_invisible && !form_util::IsWebElementVisible(element)) - continue; - if (FindTextFeaturesForClass(element, kCaptchaFeatures, - kNumberOfCaptchaFeatures)) { - return true; - } - } - return false; -} - -// Finds signin and signup features in |element|'s attribute values. Sets to -// true |found_signin_text_features| or |found_signup_text_features| if -// appropriate features were found. -void FindTextFeaturesInElement(const blink::WebElement& element, - bool* found_signin_text_features, - bool* found_signup_text_features) { - DCHECK(found_signin_text_features); - DCHECK(found_signup_text_features); - - if (!*found_signin_text_features) { - *found_signin_text_features = FindTextFeaturesForClass( - element, kSigninTextFeatures, kNumberOfSigninFeatures); - } - if (!*found_signup_text_features) { - *found_signup_text_features = FindTextFeaturesForClass( - element, kSignupTextFeatures, kNumberOfSignupFeatures); - } -} - -// Returns true if |element| has type "button" or "image". -bool IsButtonOrImageElement(const WebFormControlElement& element) { - CR_DEFINE_STATIC_LOCAL(WebString, kButton, ("button")); - CR_DEFINE_STATIC_LOCAL(WebString, kImage, ("image")); - - return element.FormControlTypeForAutofill() == kButton || - element.FormControlTypeForAutofill() == kImage; -} - -// Returns true if |element| has type "submit". -bool IsSubmitElement(const WebFormControlElement& element) { - CR_DEFINE_STATIC_LOCAL(WebString, kSubmit, ("submit")); - - return element.FormControlTypeForAutofill() == kSubmit; -} - -// Returns true if |element| has type "hidden"; -bool IsHiddenElement(const WebFormControlElement& element) { - CR_DEFINE_STATIC_LOCAL(WebString, kHidden, ("hidden")); - - return element.FormControlTypeForAutofill() == kHidden; -} - -// Returns true if |element| has type "select-multiple" or "select-one". -bool IsSelectElement(const WebFormControlElement& element) { - CR_DEFINE_STATIC_LOCAL(WebString, kSelectOne, ("select-one")); - CR_DEFINE_STATIC_LOCAL(WebString, kSelectMultiple, ("select-multiple")); - - return element.FormControlTypeForAutofill() == kSelectOne || - element.FormControlTypeForAutofill() == kSelectMultiple; -} - -// Return true if |form| contains at least one visible password element. -bool FormContainsVisiblePasswordFields(const blink::WebFormElement& form) { - WebVector<WebFormControlElement> control_elements; - form.GetFormControlElements(control_elements); - for (auto& control_element : control_elements) { - const WebInputElement* input_element = ToWebInputElement(&control_element); - if (!input_element) - continue; - if (input_element->IsPasswordFieldForAutofill() && - form_util::IsWebElementVisible(*input_element)) { - return true; - } - } - return false; -} - -} // namespace - -bool ClassifyFormAndFindGenerationField(const blink::WebFormElement& form, - base::string16* generation_field) { - DCHECK(generation_field); - - if (form.IsNull()) - return false; - - bool ignore_invisible_elements = FormContainsVisiblePasswordFields(form); - - bool found_signin_text_features = false; - bool found_signup_text_features = false; - size_t number_of_text_input_fields = 0; - size_t number_of_password_input_fields = 0; - size_t number_of_checkbox_input_fields = 0; - size_t number_of_other_input_fields = 0; - bool found_captcha = - FindCaptchaInImgElements(form, ignore_invisible_elements); - - FindTextFeaturesInElement(form, &found_signin_text_features, - &found_signup_text_features); - - std::vector<WebInputElement> passwords; - WebVector<WebFormControlElement> control_elements; - form.GetFormControlElements(control_elements); - - for (const WebFormControlElement& control_element : control_elements) { - if (IsHiddenElement(control_element)) - continue; - if (ignore_invisible_elements) { - if (!form_util::IsWebElementVisible(control_element)) - continue; - } - - // If type="button" or "image", skip them, because it might be a link - // to another form. - if (IsButtonOrImageElement(control_element)) - continue; - - FindTextFeaturesInElement(control_element, &found_signin_text_features, - &found_signup_text_features); - - // Since <select> is not WebInputElement, but WebSelectElement, process - // them as a special case. - if (IsSelectElement(control_element)) { - number_of_other_input_fields++; - } else { - const WebInputElement* input_element = - ToWebInputElement(&control_element); - if (!input_element) - continue; - - if (input_element->IsTextField()) { - if (input_element->IsPasswordFieldForAutofill()) { - ++number_of_password_input_fields; - passwords.push_back(*input_element); - } else { - ++number_of_text_input_fields; - found_captcha = found_captcha || IsCaptchaInput(*input_element); - } - } else { // Non-text fields. - if (input_element->IsCheckbox()) - ++number_of_checkbox_input_fields; - else if (!IsSubmitElement(*input_element)) - ++number_of_other_input_fields; - } - } - } - - if (number_of_password_input_fields == 0 || - number_of_password_input_fields > 3) - return false; - - if ((number_of_text_input_fields - found_captcha >= - MINIMAL_NUMBER_OF_TEXT_FIELDS || - number_of_password_input_fields >= MINIMAL_NUMBER_OF_PASSWORD_FIELDS || - number_of_checkbox_input_fields >= MINIMAL_NUMBER_OF_CHECKBOX_FIELDS || - number_of_other_input_fields >= MINIMAL_NUMBER_OF_OTHER_FIELDS) || - (found_signup_text_features && !found_signin_text_features)) { - WebInputElement password_creation_field; - - // TODO(crbug.com/618309): Improve local classifier to distinguish password - // creation and password usage fields on the change password forms. - if (passwords.size() == 3) - password_creation_field = passwords[1]; - else - password_creation_field = passwords[0]; - - *generation_field = password_creation_field.NameForAutofill().Utf16(); - return true; - } - return false; -} -} diff --git a/chromium/components/autofill/content/renderer/form_classifier.h b/chromium/components/autofill/content/renderer/form_classifier.h deleted file mode 100644 index 9de893adb86..00000000000 --- a/chromium/components/autofill/content/renderer/form_classifier.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2016 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. - -#ifndef COMPONENTS_AUTOFILL_CONTENT_RENDERER_FORM_CLASSIFIER_H_ -#define COMPONENTS_AUTOFILL_CONTENT_RENDERER_FORM_CLASSIFIER_H_ - -#include "third_party/blink/public/web/web_form_element.h" - -namespace autofill { - -// Checks if |form| is eligible for password generation. If yes, sets the name -// of the generation field to |generation_field| and returns true. Otherwise, -// returns false (w/o any changes of |generation_field|). -bool ClassifyFormAndFindGenerationField(const blink::WebFormElement& form, - base::string16* generation_field); -} - -#endif // COMPONENTS_AUTOFILL_CONTENT_RENDERER_FORM_CLASSIFIER_H_ diff --git a/chromium/components/autofill/content/renderer/form_tracker.h b/chromium/components/autofill/content/renderer/form_tracker.h index 8ae1d54dbf3..19a0a41555d 100644 --- a/chromium/components/autofill/content/renderer/form_tracker.h +++ b/chromium/components/autofill/content/renderer/form_tracker.h @@ -112,7 +112,7 @@ class FormTracker : public content::RenderFrameObserver { void ResetLastInteractedElements(); - base::ObserverList<Observer> observers_; + base::ObserverList<Observer>::Unchecked observers_; bool ignore_control_changes_ = false; bool user_gesture_required_ = true; blink::WebFormElement last_interacted_form_; diff --git a/chromium/components/autofill/content/renderer/html_based_username_detector.cc b/chromium/components/autofill/content/renderer/html_based_username_detector.cc index 350bfc6e824..c681e5c2c29 100644 --- a/chromium/components/autofill/content/renderer/html_based_username_detector.cc +++ b/chromium/components/autofill/content/renderer/html_based_username_detector.cc @@ -10,6 +10,7 @@ #include "base/containers/flat_set.h" #include "base/i18n/case_conversion.h" #include "base/macros.h" +#include "base/stl_util.h" #include "base/strings/string_split.h" #include "base/strings/utf_string_conversions.h" #include "components/autofill/content/renderer/form_autofill_util.h" @@ -209,14 +210,10 @@ void RemoveFieldsWithNegativeWords( kNegativeLatin, kNegativeLatinSize, kNegativeNonLatin, kNegativeNonLatinSize}; - possible_usernames_data->erase( - std::remove_if(possible_usernames_data->begin(), - possible_usernames_data->end(), - [](const UsernameFieldData& possible_username) { - return ContainsWordFromCategory(possible_username, - kNegativeCategory); - }), - possible_usernames_data->end()); + base::EraseIf( + *possible_usernames_data, [](const UsernameFieldData& possible_username) { + return ContainsWordFromCategory(possible_username, kNegativeCategory); + }); } // Check if any word from the given category (|category|) appears in fields from @@ -240,12 +237,9 @@ void FindWordsFromCategoryInForm( } } - if (fields_found > 0 && fields_found <= 2) { - if (std::find(username_predictions->begin(), username_predictions->end(), - chosen_field) == username_predictions->end()) { + if (fields_found > 0 && fields_found <= 2) + if (!base::ContainsValue(*username_predictions, chosen_field)) username_predictions->push_back(chosen_field); - } - } } // Find username elements if there is no cached result for the given form and diff --git a/chromium/components/autofill/content/renderer/page_passwords_analyser.cc b/chromium/components/autofill/content/renderer/page_passwords_analyser.cc index c94d0c35b35..1bcc3d84849 100644 --- a/chromium/components/autofill/content/renderer/page_passwords_analyser.cc +++ b/chromium/components/autofill/content/renderer/page_passwords_analyser.cc @@ -197,9 +197,8 @@ std::vector<FormInputCollection> ExtractFormsForAnalysis( // to be username or password fields. if (input.TagName() == "INPUT" && (!input.HasAttribute("type") || - std::find(std::begin(kTypeAttributes), std::end(kTypeAttributes), - input.GetAttribute("type").Utf8()) != - std::end(kTypeAttributes))) { + base::ContainsValue(kTypeAttributes, + input.GetAttribute("type").Utf8()))) { form_input_collections.back().AddInput(input); inputs_with_forms.insert(input); } diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.cc b/chromium/components/autofill/content/renderer/password_autofill_agent.cc index 900a507d742..cfe77748b73 100644 --- a/chromium/components/autofill/content/renderer/password_autofill_agent.cc +++ b/chromium/components/autofill/content/renderer/password_autofill_agent.cc @@ -56,10 +56,19 @@ #include "ui/events/keycodes/keyboard_codes.h" #include "url/gurl.h" +using blink::ToWebInputElement; using blink::WebAutofillState; using blink::WebDocument; -using blink::WebInputElement; +using blink::WebElement; +using blink::WebElementCollection; +using blink::WebFormElement; using blink::WebFormControlElement; +using blink::WebFrame; +using blink::WebInputElement; +using blink::WebLocalFrame; +using blink::WebString; +using blink::WebVector; +using blink::WebView; namespace autofill { namespace { @@ -70,8 +79,13 @@ const size_t kMaximumTextSizeForAutocomplete = 1000; const char kDummyUsernameField[] = "anonymous_username"; const char kDummyPasswordField[] = "anonymous_password"; +// Names of HTML attributes to show form and field signatures for debugging. +const char kDebugAttributeForFormSignature[] = "form_signature"; +const char kDebugAttributeForFieldSignature[] = "field_signature"; +const char kDebugAttributeForParserAnnotations[] = "pm_parser_annotation"; + // Maps element names to the actual elements to simplify form filling. -typedef std::map<base::string16, blink::WebInputElement> FormInputElementMap; +typedef std::map<base::string16, WebInputElement> FormInputElementMap; // Use the shorter name when referencing SavePasswordProgressLogger::StringID // values to spare line breaks. The code provides enough context for that @@ -166,13 +180,13 @@ bool IsFieldPasswordField(const FormFieldData& field) { // either |autocomplete='current-password'| or |autocomplete='new-password'| // attribute. bool HasPasswordWithAutocompleteAttribute( - const std::vector<blink::WebFormControlElement>& control_elements) { - for (const blink::WebFormControlElement& control_element : control_elements) { + const std::vector<WebFormControlElement>& control_elements) { + for (const WebFormControlElement& control_element : control_elements) { if (!control_element.HasHTMLTagName("input")) continue; - const blink::WebInputElement input_element = - control_element.ToConst<blink::WebInputElement>(); + const WebInputElement input_element = + control_element.ToConst<WebInputElement>(); const AutocompleteFlag flag = AutocompleteFlagForElement(input_element); if (input_element.IsPasswordFieldForAutofill() && (flag == AutocompleteFlag::CURRENT_PASSWORD || @@ -195,7 +209,7 @@ base::string16 FieldName(const FormFieldData& field, : field.name; } -bool IsUnownedPasswordFormVisible(const blink::WebInputElement& input_element) { +bool IsUnownedPasswordFormVisible(const WebInputElement& input_element) { return !input_element.IsNull() && form_util::IsWebElementVisible(input_element); } @@ -205,7 +219,7 @@ bool IsUnownedPasswordFormVisible(const blink::WebInputElement& input_element) { // |true|. Otherwise clears the references from each |HTMLInputElement| from // |result| and returns |false|. bool FindFormInputElement( - const std::vector<blink::WebFormControlElement>& control_elements, + const std::vector<WebFormControlElement>& control_elements, const FormFieldData& field, bool ambiguous_or_empty_names, FormInputElementMap* result) { @@ -218,7 +232,7 @@ bool FindFormInputElement( does_password_field_has_ambigous_or_empty_name && HasPasswordWithAutocompleteAttribute(control_elements); base::string16 field_name = FieldName(field, ambiguous_or_empty_names); - for (const blink::WebFormControlElement& control_element : control_elements) { + for (const WebFormControlElement& control_element : control_elements) { if (!ambiguous_or_empty_names && control_element.NameForAutofill().Utf16() != field_name) { continue; @@ -229,8 +243,8 @@ bool FindFormInputElement( // Only fill saved passwords into password fields and usernames into text // fields. - const blink::WebInputElement input_element = - control_element.ToConst<blink::WebInputElement>(); + const WebInputElement input_element = + control_element.ToConst<WebInputElement>(); if (!input_element.IsTextField() || input_element.IsPasswordFieldForAutofill() != is_password_field) continue; @@ -280,7 +294,7 @@ bool FindFormInputElement( // Helper to search through |control_elements| for the specified input elements // in |data|, and add results to |result|. bool FindFormInputElements( - const std::vector<blink::WebFormControlElement>& control_elements, + const std::vector<WebFormControlElement>& control_elements, const PasswordFormFillData& data, bool ambiguous_or_empty_names, FormInputElementMap* result) { @@ -298,23 +312,23 @@ void FindFormElements(content::RenderFrame* render_frame, FormElementsList* results) { DCHECK(results); - blink::WebDocument doc = render_frame->GetWebFrame()->GetDocument(); + WebDocument doc = render_frame->GetWebFrame()->GetDocument(); if (GetSignOnRealm(data.origin) != GetSignOnRealm(form_util::GetCanonicalOriginForDocument(doc))) return; - blink::WebVector<blink::WebFormElement> forms; + WebVector<WebFormElement> forms; doc.Forms(forms); for (size_t i = 0; i < forms.size(); ++i) { - blink::WebFormElement fe = forms[i]; + WebFormElement fe = forms[i]; // Action URL must match. if (data.action != form_util::GetCanonicalActionForForm(fe)) continue; - std::vector<blink::WebFormControlElement> control_elements = + std::vector<WebFormControlElement> control_elements = form_util::ExtractAutofillableElementsInForm(fe); FormInputElementMap cur_map; if (FindFormInputElements(control_elements, data, ambiguous_or_empty_names, @@ -326,7 +340,7 @@ void FindFormElements(content::RenderFrame* render_frame, if (data.action != data.origin) return; - std::vector<blink::WebFormControlElement> control_elements = + std::vector<WebFormControlElement> control_elements = form_util::GetUnownedAutofillableFormFieldElements(doc.All(), nullptr); FormInputElementMap unowned_elements_map; if (FindFormInputElements(control_elements, data, ambiguous_or_empty_names, @@ -334,7 +348,7 @@ void FindFormElements(content::RenderFrame* render_frame, results->push_back(unowned_elements_map); } -bool IsElementEditable(const blink::WebInputElement& element) { +bool IsElementEditable(const WebInputElement& element) { return element.IsEnabled() && !element.IsReadOnly(); } @@ -348,7 +362,7 @@ bool DoUsernamesMatch(const base::string16& potential_suggestion, } // Returns whether the given |element| is editable. -bool IsElementAutocompletable(const blink::WebInputElement& element) { +bool IsElementAutocompletable(const WebInputElement& element) { return IsElementEditable(element); } @@ -358,7 +372,7 @@ bool IsElementAutocompletable(const blink::WebInputElement& element) { // |username_element| is user-defined (i.e., non-empty and non-autofilled), then // this function returns false. This is a precaution, to not override the field // if it has been classified as username by accident. -bool IsUsernameAmendable(const blink::WebInputElement& username_element, +bool IsUsernameAmendable(const WebInputElement& username_element, bool is_password_field_selected) { return !username_element.IsNull() && IsElementAutocompletable(username_element) && @@ -369,7 +383,7 @@ bool IsUsernameAmendable(const blink::WebInputElement& username_element, // Log a message including the name, method and action of |form|. void LogHTMLForm(SavePasswordProgressLogger* logger, SavePasswordProgressLogger::StringID message_id, - const blink::WebFormElement& form) { + const WebFormElement& form) { logger->LogHTMLForm(message_id, form.GetName().Utf8(), GURL(form.Action().Utf8())); } @@ -400,38 +414,6 @@ bool CanShowSuggestion(const PasswordFormFillData& fill_data, return false; } -// Updates the value (i.e. the pair of elements's value |value| and field -// properties |added_flags|) associated with the key |element| in -// |field_value_and_properties_map|. -// Flags in |added_flags| are added with bitwise OR operation. -// If |value| is null, the value is neither updated nor added. -// If |*value| is empty, USER_TYPED and AUTOFILLED should be cleared. -void UpdateFieldValueAndPropertiesMaskMap( - const blink::WebFormControlElement& element, - const base::string16* value, - FieldPropertiesMask added_flags, - FieldValueAndPropertiesMaskMap* field_value_and_properties_map) { - FieldValueAndPropertiesMaskMap::iterator it = - field_value_and_properties_map->find( - element.UniqueRendererFormControlId()); - if (it != field_value_and_properties_map->end()) { - if (value) - it->second.first.reset(new base::string16(*value)); - it->second.second |= added_flags; - } else { - (*field_value_and_properties_map)[element.UniqueRendererFormControlId()] = - std::make_pair( - value ? std::make_unique<base::string16>(*value) : nullptr, - added_flags); - } - // Reset USER_TYPED and AUTOFILLED flags if the value is empty. - if (value && value->empty()) { - (*field_value_and_properties_map)[element.UniqueRendererFormControlId()] - .second &= - ~(FieldPropertiesFlags::USER_TYPED | FieldPropertiesFlags::AUTOFILLED); - } -} - // This function attempts to find the matching credentials for the // |current_username| by scanning |fill_data|. The result is written in // |username| and |password| parameters. @@ -509,73 +491,95 @@ bool IsPublicSuffixDomainMatch(const std::string& url1, } // Helper function that calculates form signature for |password_form| and -// returns it as blink::WebString. -blink::WebString GetFormSignatureAsWebString( - const PasswordForm& password_form) { - return blink::WebString::FromUTF8( +// returns it as WebString. +WebString GetFormSignatureAsWebString(const PasswordForm& password_form) { + return WebString::FromUTF8( base::NumberToString(CalculateFormSignature(password_form.form_data))); } +// Add parser annotations saved in |password_form| to |element|. +void AddParserAnnotations(PasswordForm* password_form, + blink::WebFormControlElement* element) { + base::string16 element_name = element->NameForAutofill().Utf16(); + std::string attribute_value; + if (password_form->username_element == element_name) { + attribute_value = "username_element"; + } else if (password_form->password_element == element_name) { + attribute_value = "password_element"; + } else if (password_form->new_password_element == element_name) { + attribute_value = "new_password_element"; + } else if (password_form->confirmation_password_element == element_name) { + attribute_value = "confirmation_password_element"; + } + element->SetAttribute( + blink::WebString::FromASCII(kDebugAttributeForParserAnnotations), + attribute_value.empty() ? blink::WebString() + : blink::WebString::FromASCII(attribute_value)); +} + // Annotate |fields| with field signatures and form signature as HTML // attributes. void AnnotateFieldsWithSignatures( std::vector<blink::WebFormControlElement>* fields, - const blink::WebString& form_signature) { + const blink::WebString& form_signature, + PasswordForm* password_form) { for (blink::WebFormControlElement& control_element : *fields) { FieldSignature field_signature = CalculateFieldSignatureByNameAndType( control_element.NameForAutofill().Utf16(), control_element.FormControlTypeForAutofill().Utf8()); control_element.SetAttribute( - blink::WebString::FromASCII(kDebugAttributeForFieldSignature), - blink::WebString::FromUTF8(base::NumberToString(field_signature))); + WebString::FromASCII(kDebugAttributeForFieldSignature), + WebString::FromUTF8(base::NumberToString(field_signature))); control_element.SetAttribute( blink::WebString::FromASCII(kDebugAttributeForFormSignature), form_signature); + if (password_form) + AddParserAnnotations(password_form, &control_element); } } // Annotate |forms| and all fields in the |frame| with form and field signatures // as HTML attributes. -void AnnotateFormsAndFieldsWithSignatures( - blink::WebLocalFrame* frame, - blink::WebVector<blink::WebFormElement>* forms) { - for (blink::WebFormElement& form : *forms) { +void AnnotateFormsAndFieldsWithSignatures(WebLocalFrame* frame, + WebVector<WebFormElement>* forms) { + for (WebFormElement& form : *forms) { std::unique_ptr<PasswordForm> password_form( CreatePasswordFormFromWebForm(form, nullptr, nullptr, nullptr)); - blink::WebString form_signature; + WebString form_signature; if (password_form) { form_signature = GetFormSignatureAsWebString(*password_form); - form.SetAttribute( - blink::WebString::FromASCII(kDebugAttributeForFormSignature), - form_signature); + form.SetAttribute(WebString::FromASCII(kDebugAttributeForFormSignature), + form_signature); } - std::vector<blink::WebFormControlElement> form_fields = + std::vector<WebFormControlElement> form_fields = form_util::ExtractAutofillableElementsInForm(form); - AnnotateFieldsWithSignatures(&form_fields, form_signature); + AnnotateFieldsWithSignatures(&form_fields, form_signature, + password_form ? password_form.get() : nullptr); } - std::vector<blink::WebFormControlElement> unowned_elements = + std::vector<WebFormControlElement> unowned_elements = form_util::GetUnownedAutofillableFormFieldElements( frame->GetDocument().All(), nullptr); std::unique_ptr<PasswordForm> password_form( CreatePasswordFormFromUnownedInputElements(*frame, nullptr, nullptr, nullptr)); - blink::WebString form_signature; + WebString form_signature; if (password_form) form_signature = GetFormSignatureAsWebString(*password_form); - AnnotateFieldsWithSignatures(&unowned_elements, form_signature); + AnnotateFieldsWithSignatures(&unowned_elements, form_signature, + password_form ? password_form.get() : nullptr); } // Returns true iff there is a password field in |frame|. -bool HasPasswordField(const blink::WebLocalFrame& frame) { - CR_DEFINE_STATIC_LOCAL(blink::WebString, kPassword, ("password")); +bool HasPasswordField(const WebLocalFrame& frame) { + CR_DEFINE_STATIC_LOCAL(WebString, kPassword, ("password")); - const blink::WebElementCollection elements = frame.GetDocument().All(); - for (blink::WebElement element = elements.FirstItem(); !element.IsNull(); + const WebElementCollection elements = frame.GetDocument().All(); + for (WebElement element = elements.FirstItem(); !element.IsNull(); element = elements.NextItem()) { if (element.IsFormControlElement()) { - const blink::WebFormControlElement& control = - element.To<blink::WebFormControlElement>(); + const WebFormControlElement& control = + element.To<WebFormControlElement>(); if (control.FormControlTypeForAutofill() == kPassword) return true; } @@ -586,28 +590,28 @@ bool HasPasswordField(const blink::WebLocalFrame& frame) { // Returns the closest visible autocompletable non-password text element // preceding the |password_element| either in a form, if it belongs to one, or // in the |frame|. -blink::WebInputElement FindUsernameElementPrecedingPasswordElement( - blink::WebLocalFrame* frame, - const blink::WebInputElement& password_element) { +WebInputElement FindUsernameElementPrecedingPasswordElement( + WebLocalFrame* frame, + const WebInputElement& password_element) { DCHECK(!password_element.IsNull()); - std::vector<blink::WebFormControlElement> elements; + std::vector<WebFormControlElement> elements; if (password_element.Form().IsNull()) { elements = form_util::GetUnownedAutofillableFormFieldElements( frame->GetDocument().All(), nullptr); } else { - blink::WebVector<blink::WebFormControlElement> web_control_elements; + WebVector<WebFormControlElement> web_control_elements; password_element.Form().GetFormControlElements(web_control_elements); elements.assign(web_control_elements.begin(), web_control_elements.end()); } auto iter = std::find(elements.begin(), elements.end(), password_element); if (iter == elements.end()) - return blink::WebInputElement(); + return WebInputElement(); for (auto begin = elements.begin(); iter != begin;) { --iter; - const blink::WebInputElement* input = blink::ToWebInputElement(&*iter); + const WebInputElement* input = ToWebInputElement(&*iter); if (input && input->IsTextField() && !input->IsPasswordFieldForAutofill() && IsElementAutocompletable(*input) && form_util::IsWebElementVisible(*input)) { @@ -615,7 +619,7 @@ blink::WebInputElement FindUsernameElementPrecedingPasswordElement( } } - return blink::WebInputElement(); + return WebInputElement(); } PasswordForm::SubmissionIndicatorEvent ToSubmissionIndicatorEvent( @@ -637,7 +641,7 @@ PasswordForm::SubmissionIndicatorEvent ToSubmissionIndicatorEvent( WebInputElement ConvertToWebInput(const WebFormControlElement& element) { if (element.IsNull()) return WebInputElement(); - const WebInputElement* input = blink::ToWebInputElement(&element); + const WebInputElement* input = ToWebInputElement(&element); return input ? *input : WebInputElement(); } @@ -646,12 +650,9 @@ WebInputElement ConvertToWebInput(const WebFormControlElement& element) { //////////////////////////////////////////////////////////////////////////////// // PasswordAutofillAgent, public: -const char kDebugAttributeForFormSignature[] = "form_signature"; -const char kDebugAttributeForFieldSignature[] = "field_signature"; - PasswordAutofillAgent::PasswordAutofillAgent( content::RenderFrame* render_frame, - service_manager::BinderRegistry* registry) + blink::AssociatedInterfaceRegistry* registry) : content::RenderFrameObserver(render_frame), last_supplied_password_info_iter_(web_input_to_password_info_.end()), logging_state_active_(false), @@ -659,6 +660,7 @@ PasswordAutofillAgent::PasswordAutofillAgent( password_autofill_state_(WebAutofillState::kNotFilled), sent_request_to_store_(false), checked_safe_browsing_reputation_(false), + focus_state_notifier_(this), binding_(this) { registry->AddInterface( base::Bind(&PasswordAutofillAgent::BindRequest, base::Unretained(this))); @@ -671,7 +673,7 @@ PasswordAutofillAgent::~PasswordAutofillAgent() { } void PasswordAutofillAgent::BindRequest( - mojom::PasswordAutofillAgentRequest request) { + mojom::PasswordAutofillAgentAssociatedRequest request) { binding_.Bind(std::move(request)); } @@ -688,6 +690,26 @@ void PasswordAutofillAgent::SetPasswordGenerationAgent( password_generation_agent_ = generation_agent; } +PasswordAutofillAgent::FocusStateNotifier::FocusStateNotifier( + PasswordAutofillAgent* agent) + : was_fillable_(false), was_password_field_(false), agent_(agent) {} + +PasswordAutofillAgent::FocusStateNotifier::~FocusStateNotifier() = default; + +void PasswordAutofillAgent::FocusStateNotifier::FocusedInputChanged( + bool is_fillable, + bool is_password_field) { + // Forward the request, if the field is valid or the request is different. + if (!is_fillable && !was_fillable_ && !is_password_field && + !was_password_field_) { + return; // A previous request already reported this exact state. + } + was_fillable_ = is_fillable; + was_password_field_ = is_password_field; + agent_->GetPasswordManagerDriver()->FocusedInputChanged(is_fillable, + is_password_field); +} + PasswordAutofillAgent::PasswordValueGatekeeper::PasswordValueGatekeeper() : was_user_gesture_seen_(false) { } @@ -696,7 +718,7 @@ PasswordAutofillAgent::PasswordValueGatekeeper::~PasswordValueGatekeeper() { } void PasswordAutofillAgent::PasswordValueGatekeeper::RegisterElement( - blink::WebInputElement* element) { + WebInputElement* element) { if (was_user_gesture_seen_) ShowValue(element); else @@ -709,7 +731,7 @@ void PasswordAutofillAgent::PasswordValueGatekeeper::OnUserGesture() { was_user_gesture_seen_ = true; - for (blink::WebInputElement& element : elements_) + for (WebInputElement& element : elements_) ShowValue(&element); elements_.clear(); @@ -721,7 +743,7 @@ void PasswordAutofillAgent::PasswordValueGatekeeper::Reset() { } void PasswordAutofillAgent::PasswordValueGatekeeper::ShowValue( - blink::WebInputElement* element) { + WebInputElement* element) { if (!element->IsNull() && !element->SuggestedValue().IsEmpty()) { element->SetAutofillValue(element->SuggestedValue()); element->SetAutofillState(WebAutofillState::kAutofilled); @@ -729,9 +751,9 @@ void PasswordAutofillAgent::PasswordValueGatekeeper::ShowValue( } bool PasswordAutofillAgent::TextDidChangeInTextField( - const blink::WebInputElement& element) { + const WebInputElement& element) { // TODO(vabr): Get a mutable argument instead. http://crbug.com/397083 - blink::WebInputElement mutable_element = element; // We need a non-const. + WebInputElement mutable_element = element; // We need a non-const. mutable_element.SetAutofillState(WebAutofillState::kNotFilled); WebInputToPasswordInfoMap::iterator iter = @@ -745,15 +767,14 @@ bool PasswordAutofillAgent::TextDidChangeInTextField( } void PasswordAutofillAgent::UpdateStateForTextChange( - const blink::WebInputElement& element) { + const WebInputElement& element) { // TODO(vabr): Get a mutable argument instead. http://crbug.com/397083 - blink::WebInputElement mutable_element = element; // We need a non-const. + WebInputElement mutable_element = element; // We need a non-const. if (element.IsTextField()) { const base::string16 element_value = element.Value().Utf16(); - UpdateFieldValueAndPropertiesMaskMap(element, &element_value, - FieldPropertiesFlags::USER_TYPED, - &field_value_and_properties_map_); + field_data_manager_.UpdateFieldDataMap(element, element_value, + FieldPropertiesFlags::USER_TYPED); } ProvisionallySavePassword(element.Form(), element, RESTRICTION_NONE); @@ -773,16 +794,16 @@ void PasswordAutofillAgent::UpdateStateForTextChange( } bool PasswordAutofillAgent::FillSuggestion( - const blink::WebFormControlElement& control_element, + const WebFormControlElement& control_element, const base::string16& username, const base::string16& password) { // The element in context of the suggestion popup. - const blink::WebInputElement* element = ToWebInputElement(&control_element); + const WebInputElement* element = ToWebInputElement(&control_element); if (!element) return false; - blink::WebInputElement username_element; - blink::WebInputElement password_element; + WebInputElement username_element; + WebInputElement password_element; PasswordInfo* password_info = nullptr; if (!FindPasswordInfoForElement(*element, &username_element, @@ -810,7 +831,7 @@ bool PasswordAutofillAgent::FillSuggestion( FillPasswordFieldAndSave(&password_element, password); - blink::WebInputElement mutable_filled_element = *element; + WebInputElement mutable_filled_element = *element; mutable_filled_element.SetSelectionRange(element->Value().length(), element->Value().length()); @@ -837,19 +858,18 @@ void PasswordAutofillAgent::FillIntoFocusedField( std::move(callback).Run(autofill::FillingStatus::SUCCESS); } -void PasswordAutofillAgent::FillField(blink::WebInputElement* input, +void PasswordAutofillAgent::FillField(WebInputElement* input, const base::string16& credential) { DCHECK(input); DCHECK(!input->IsNull()); - input->SetAutofillValue(blink::WebString::FromUTF16(credential)); + input->SetAutofillValue(WebString::FromUTF16(credential)); input->SetAutofillState(WebAutofillState::kAutofilled); - UpdateFieldValueAndPropertiesMaskMap( - *input, &credential, FieldPropertiesFlags::AUTOFILLED_ON_USER_TRIGGER, - &field_value_and_properties_map_); + field_data_manager_.UpdateFieldDataMap( + *input, credential, FieldPropertiesFlags::AUTOFILLED_ON_USER_TRIGGER); } void PasswordAutofillAgent::FillPasswordFieldAndSave( - blink::WebInputElement* password_input, + WebInputElement* password_input, const base::string16& credential) { DCHECK(password_input); DCHECK(password_input->IsPasswordFieldForAutofill()); @@ -859,16 +879,16 @@ void PasswordAutofillAgent::FillPasswordFieldAndSave( } bool PasswordAutofillAgent::PreviewSuggestion( - const blink::WebFormControlElement& control_element, - const blink::WebString& username, - const blink::WebString& password) { + const WebFormControlElement& control_element, + const WebString& username, + const WebString& password) { // The element in context of the suggestion popup. - const blink::WebInputElement* element = ToWebInputElement(&control_element); + const WebInputElement* element = ToWebInputElement(&control_element); if (!element) return false; - blink::WebInputElement username_element; - blink::WebInputElement password_element; + WebInputElement username_element; + WebInputElement password_element; PasswordInfo* password_info; if (!FindPasswordInfoForElement(*element, &username_element, @@ -896,13 +916,13 @@ bool PasswordAutofillAgent::PreviewSuggestion( } bool PasswordAutofillAgent::DidClearAutofillSelection( - const blink::WebFormControlElement& control_element) { - const blink::WebInputElement* element = ToWebInputElement(&control_element); + const WebFormControlElement& control_element) { + const WebInputElement* element = ToWebInputElement(&control_element); if (!element) return false; - blink::WebInputElement username_element; - blink::WebInputElement password_element; + WebInputElement username_element; + WebInputElement password_element; PasswordInfo* password_info; if (!FindPasswordInfoForElement(*element, &username_element, @@ -915,9 +935,9 @@ bool PasswordAutofillAgent::DidClearAutofillSelection( } bool PasswordAutofillAgent::FindPasswordInfoForElement( - const blink::WebInputElement& element, - blink::WebInputElement* username_element, - blink::WebInputElement* password_element, + const WebInputElement& element, + WebInputElement* username_element, + WebInputElement* password_element, PasswordInfo** password_info) { DCHECK(username_element && password_element && password_info); username_element->Reset(); @@ -972,7 +992,7 @@ bool PasswordAutofillAgent::FindPasswordInfoForElement( } bool PasswordAutofillAgent::IsUsernameOrPasswordField( - const blink::WebInputElement& element) { + const WebInputElement& element) { // Note: A site may use a Password field to collect a CVV or a Credit Card // number, but showing a slightly misleading warning here is better than // showing no warning at all. @@ -1000,18 +1020,17 @@ bool PasswordAutofillAgent::IsUsernameOrPasswordField( return (password_form->username_element == element.NameForAutofill().Utf16()); } -bool PasswordAutofillAgent::ShowSuggestions( - const blink::WebInputElement& element, - bool show_all, - bool generation_popup_showing) { - blink::WebInputElement username_element; - blink::WebInputElement password_element; +bool PasswordAutofillAgent::ShowSuggestions(const WebInputElement& element, + bool show_all, + bool generation_popup_showing) { + WebInputElement username_element; + WebInputElement password_element; PasswordInfo* password_info; if (!FindPasswordInfoForElement(element, &username_element, &password_element, &password_info)) { if (IsUsernameOrPasswordField(element)) { - blink::WebLocalFrame* frame = render_frame()->GetWebFrame(); + WebLocalFrame* frame = render_frame()->GetWebFrame(); GURL frame_url = GURL(frame->GetDocument().Url()); #if defined(SAFE_BROWSING_DB_LOCAL) if (!checked_safe_browsing_reputation_) { @@ -1071,8 +1090,10 @@ bool PasswordAutofillAgent::ShowSuggestions( bool PasswordAutofillAgent::FrameCanAccessPasswordManager() { // about:blank or about:srcdoc frames should not be allowed to use password // manager. See https://crbug.com/756587. - blink::WebLocalFrame* frame = render_frame()->GetWebFrame(); - if (frame->GetDocument().Url().ProtocolIs(url::kAboutScheme)) + WebLocalFrame* frame = render_frame()->GetWebFrame(); + blink::WebURL url = frame->GetDocument().Url(); + if (url.ProtocolIs(url::kAboutScheme) || url.ProtocolIs(url::kBlobScheme) || + url.ProtocolIs(url::kFileSystemScheme)) return false; return frame->GetSecurityOrigin().CanAccessPasswordManager(); } @@ -1090,7 +1111,7 @@ void PasswordAutofillAgent::FireSubmissionIfFormDisappear( // Prompt to save only if the form is now gone, either invisible or // removed from the DOM. - blink::WebLocalFrame* frame = render_frame()->GetWebFrame(); + WebLocalFrame* frame = render_frame()->GetWebFrame(); const auto& password_form = provisionally_saved_form_.password_form(); // TODO(crbug.com/720347): This method could be called often and checking form // visibility could be expesive. Add performance metrics for this. @@ -1124,7 +1145,7 @@ void PasswordAutofillAgent::SendPasswordForms(bool only_visible) { logger->LogBoolean(Logger::STRING_ONLY_VISIBLE, only_visible); } - blink::WebLocalFrame* frame = render_frame()->GetWebFrame(); + WebLocalFrame* frame = render_frame()->GetWebFrame(); // Make sure that this security origin is allowed to use password manager. blink::WebSecurityOrigin origin = frame->GetDocument().GetSecurityOrigin(); @@ -1146,7 +1167,7 @@ void PasswordAutofillAgent::SendPasswordForms(bool only_visible) { return; } - blink::WebVector<blink::WebFormElement> forms; + WebVector<WebFormElement> forms; frame->GetDocument().Forms(forms); if (IsShowAutofillSignaturesEnabled()) @@ -1155,7 +1176,7 @@ void PasswordAutofillAgent::SendPasswordForms(bool only_visible) { logger->LogNumber(Logger::STRING_NUMBER_OF_ALL_FORMS, forms.size()); std::vector<PasswordForm> password_forms; - for (const blink::WebFormElement& form : forms) { + for (const WebFormElement& form : forms) { if (only_visible) { bool is_form_visible = form_util::AreFormContentsVisible(form); if (logger) { @@ -1184,7 +1205,7 @@ void PasswordAutofillAgent::SendPasswordForms(bool only_visible) { // password submission. bool add_unowned_inputs = true; if (only_visible) { - std::vector<blink::WebFormControlElement> control_elements = + std::vector<WebFormControlElement> control_elements = form_util::GetUnownedAutofillableFormFieldElements( frame->GetDocument().All(), nullptr); add_unowned_inputs = @@ -1210,7 +1231,7 @@ void PasswordAutofillAgent::SendPasswordForms(bool only_visible) { // Send the PasswordFormsRendered message regardless of whether // |password_forms| is empty. The empty |password_forms| are a possible // signal to the browser that a pending login attempt succeeded. - blink::WebFrame* main_frame = render_frame()->GetWebFrame()->Top(); + WebFrame* main_frame = render_frame()->GetWebFrame()->Top(); bool did_stop_loading = !main_frame || !main_frame->IsLoading(); GetPasswordManagerDriver()->PasswordFormsRendered(password_forms, did_stop_loading); @@ -1282,8 +1303,7 @@ void PasswordAutofillAgent::OnFrameDetached() { FrameClosing(); } -void PasswordAutofillAgent::OnWillSubmitForm( - const blink::WebFormElement& form) { +void PasswordAutofillAgent::OnWillSubmitForm(const WebFormElement& form) { std::unique_ptr<RendererSavePasswordProgressLogger> logger; if (logging_state_active_) { logger.reset(new RendererSavePasswordProgressLogger( @@ -1346,16 +1366,16 @@ void PasswordAutofillAgent::FocusedNodeChanged(const blink::WebNode& node) { focused_input_element_.Reset(); if (node.IsNull() || // |node| is null <==> focus outside of frame. - !node.IsElementNode()) { // Not a valid blink::WebElement. - GetPasswordManagerDriver()->FocusedInputChanged( + !node.IsElementNode()) { // Not a valid WebElement. + focus_state_notifier_.FocusedInputChanged( /*is_fillable=*/false, /*is_password_field=*/false); return; } - blink::WebElement web_element = node.ToConst<blink::WebElement>(); + WebElement web_element = node.ToConst<WebElement>(); const WebInputElement* input = ToWebInputElement(&web_element); if (!input) { - GetPasswordManagerDriver()->FocusedInputChanged( + focus_state_notifier_.FocusedInputChanged( /*is_fillable=*/false, /*is_password_field=*/false); return; // If the node isn't an element, don't even try to convert. } @@ -1365,7 +1385,7 @@ void PasswordAutofillAgent::FocusedNodeChanged(const blink::WebNode& node) { focused_input_element_ = *input; is_password = focused_input_element_.IsPasswordFieldForAutofill(); } - GetPasswordManagerDriver()->FocusedInputChanged(is_fillable, is_password); + focus_state_notifier_.FocusedInputChanged(is_fillable, is_password); } void PasswordAutofillAgent::OnDestruct() { @@ -1382,7 +1402,7 @@ void PasswordAutofillAgent::DidStartProvisionalLoad( logger->LogMessage(Logger::STRING_DID_START_PROVISIONAL_LOAD_METHOD); } - blink::WebLocalFrame* navigated_frame = render_frame()->GetWebFrame(); + WebLocalFrame* navigated_frame = render_frame()->GetWebFrame(); if (navigated_frame->Parent()) { if (logger) logger->LogMessage(Logger::STRING_FRAME_NOT_MAIN_FRAME); @@ -1443,7 +1463,7 @@ void PasswordAutofillAgent::FillUsingRendererIDs( StoreDataForFillOnAccountSelect(key, form_data, username_element, password_element); FillFormOnPasswordReceived(form_data, username_element, password_element, - &field_value_and_properties_map_, logger.get()); + &field_data_manager_, logger.get()); } // mojom::PasswordAutofillAgent: @@ -1455,7 +1475,7 @@ void PasswordAutofillAgent::FillPasswordForm( return; } - std::vector<blink::WebInputElement> elements; + std::vector<WebInputElement> elements; std::unique_ptr<RendererSavePasswordProgressLogger> logger; if (logging_state_active_) { logger.reset(new RendererSavePasswordProgressLogger( @@ -1470,17 +1490,15 @@ void PasswordAutofillAgent::FillPasswordForm( return; for (auto element : elements) { - blink::WebInputElement username_element = - !element.IsPasswordFieldForAutofill() ? element - : password_to_username_[element]; - blink::WebInputElement password_element = + WebInputElement username_element = !element.IsPasswordFieldForAutofill() + ? element + : password_to_username_[element]; + WebInputElement password_element = element.IsPasswordFieldForAutofill() ? element : web_input_to_password_info_[element].password_field; - FillFormOnPasswordReceived( - form_data, username_element, password_element, - &field_value_and_properties_map_, - logger.get()); + FillFormOnPasswordReceived(form_data, username_element, password_element, + &field_data_manager_, logger.get()); } } @@ -1488,7 +1506,7 @@ void PasswordAutofillAgent::GetFillableElementFromFormData( int key, const PasswordFormFillData& form_data, RendererSavePasswordProgressLogger* logger, - std::vector<blink::WebInputElement>* elements) { + std::vector<WebInputElement>* elements) { DCHECK(elements); bool ambiguous_or_empty_names = DoesFormContainAmbiguousOrEmptyNames(form_data); @@ -1522,8 +1540,8 @@ void PasswordAutofillAgent::GetFillableElementFromFormData( } // Attach autocomplete listener to enable selecting alternate logins. - blink::WebInputElement username_element; - blink::WebInputElement password_element; + WebInputElement username_element; + WebInputElement password_element; // Check whether the password form has a username input field. if (!username_field_name.empty()) { @@ -1544,7 +1562,7 @@ void PasswordAutofillAgent::GetFillableElementFromFormData( password_element = it->second; } - blink::WebInputElement main_element = + WebInputElement main_element = username_element.IsNull() ? password_element : username_element; if (elements) elements->push_back(main_element); @@ -1558,21 +1576,20 @@ void PasswordAutofillAgent::GetFillableElementFromFormData( void PasswordAutofillAgent::FocusedNodeHasChanged(const blink::WebNode& node) { if (node.IsNull() || !node.IsElementNode()) return; - const blink::WebElement web_element = node.ToConst<blink::WebElement>(); + const WebElement web_element = node.ToConst<WebElement>(); if (!web_element.IsFormControlElement()) return; - const blink::WebFormControlElement control_element = - web_element.ToConst<blink::WebFormControlElement>(); - UpdateFieldValueAndPropertiesMaskMap(control_element, nullptr, - FieldPropertiesFlags::HAD_FOCUS, - &field_value_and_properties_map_); + const WebFormControlElement control_element = + web_element.ToConst<WebFormControlElement>(); + field_data_manager_.UpdateFieldDataMapWithNullValue( + control_element, FieldPropertiesFlags::HAD_FOCUS); } std::unique_ptr<PasswordForm> PasswordAutofillAgent::GetPasswordFormFromWebForm( - const blink::WebFormElement& web_form) { - return CreatePasswordFormFromWebForm( - web_form, &field_value_and_properties_map_, &form_predictions_, - &username_detector_cache_); + const WebFormElement& web_form) { + return CreatePasswordFormFromWebForm(web_form, &field_data_manager_, + &form_predictions_, + &username_detector_cache_); } std::unique_ptr<PasswordForm> @@ -1584,11 +1601,11 @@ PasswordAutofillAgent::GetPasswordFormFromUnownedInputElements() { content::RenderFrame* frame = render_frame(); if (!frame) return nullptr; - blink::WebLocalFrame* web_frame = frame->GetWebFrame(); + WebLocalFrame* web_frame = frame->GetWebFrame(); if (!web_frame) return nullptr; return CreatePasswordFormFromUnownedInputElements( - *web_frame, &field_value_and_properties_map_, &form_predictions_, + *web_frame, &field_data_manager_, &form_predictions_, &username_detector_cache_); } @@ -1606,10 +1623,10 @@ void PasswordAutofillAgent::FindFocusedPasswordForm( FindFocusedPasswordFormCallback callback) { std::unique_ptr<PasswordForm> password_form; - blink::WebElement element = + WebElement element = render_frame()->GetWebFrame()->GetDocument().FocusedElement(); if (!element.IsNull() && element.HasHTMLTagName("input")) { - blink::WebInputElement input = element.To<blink::WebInputElement>(); + WebInputElement input = element.To<WebInputElement>(); if (input.IsPasswordFieldForAutofill()) { if (!input.Form().IsNull()) { password_form = GetPasswordFormFromWebForm(input.Form()); @@ -1639,15 +1656,15 @@ void PasswordAutofillAgent::FindFocusedPasswordForm( bool PasswordAutofillAgent::ShowSuggestionPopup( const PasswordInfo& password_info, - const blink::WebInputElement& user_input, + const WebInputElement& user_input, bool show_all, bool show_on_password_field) { DCHECK(!user_input.IsNull()); - blink::WebFrame* frame = user_input.GetDocument().GetFrame(); + WebFrame* frame = user_input.GetDocument().GetFrame(); if (!frame) return false; - blink::WebView* webview = frame->View(); + WebView* webview = frame->View(); if (!webview) return false; @@ -1683,7 +1700,7 @@ void PasswordAutofillAgent::FrameClosing() { password_to_username_.clear(); last_supplied_password_info_iter_ = web_input_to_password_info_.end(); provisionally_saved_form_.Reset(); - field_value_and_properties_map_.clear(); + field_data_manager_.ClearData(); username_autofill_state_ = WebAutofillState::kNotFilled; password_autofill_state_ = WebAutofillState::kNotFilled; sent_request_to_store_ = false; @@ -1696,23 +1713,22 @@ void PasswordAutofillAgent::FrameClosing() { #endif } -void PasswordAutofillAgent::ClearPreview( - blink::WebInputElement* username, - blink::WebInputElement* password) { +void PasswordAutofillAgent::ClearPreview(WebInputElement* username, + WebInputElement* password) { if (!username->IsNull() && !username->SuggestedValue().IsEmpty()) { - username->SetSuggestedValue(blink::WebString()); + username->SetSuggestedValue(WebString()); username->SetAutofillState(username_autofill_state_); username->SetSelectionRange(username_query_prefix_.length(), username->Value().length()); } if (!password->SuggestedValue().IsEmpty()) { - password->SetSuggestedValue(blink::WebString()); + password->SetSuggestedValue(WebString()); password->SetAutofillState(password_autofill_state_); } } void PasswordAutofillAgent::ProvisionallySavePassword( - const blink::WebFormElement& form, - const blink::WebInputElement& element, + const WebFormElement& form, + const WebInputElement& element, ProvisionallySaveRestriction restriction) { DCHECK(!form.IsNull() || !element.IsNull()); @@ -1744,12 +1760,12 @@ void PasswordAutofillAgent::ProvisionallySavePassword( } bool PasswordAutofillAgent::FillUserNameAndPassword( - blink::WebInputElement* username_element, - blink::WebInputElement* password_element, + WebInputElement* username_element, + WebInputElement* password_element, const PasswordFormFillData& fill_data, bool exact_username_match, bool username_may_use_prefilled_placeholder, - FieldValueAndPropertiesMaskMap* field_value_and_properties_map, + FieldDataManager* field_data_manager, RendererSavePasswordProgressLogger* logger) { if (logger) logger->LogMessage(Logger::STRING_FILL_USERNAME_AND_PASSWORD_METHOD); @@ -1816,8 +1832,7 @@ bool PasswordAutofillAgent::FillUserNameAndPassword( IsElementAutocompletable(*username_element)) { if (!username.empty() && (username_element->Value().IsEmpty() || prefilled_placeholder_username)) { - username_element->SetSuggestedValue( - blink::WebString::FromUTF16(username)); + username_element->SetSuggestedValue(WebString::FromUTF16(username)); gatekeeper_.RegisterElement(username_element); if (prefilled_placeholder_username) { LogPrefilledUsernameFillOutcome( @@ -1825,11 +1840,9 @@ bool PasswordAutofillAgent::FillUserNameAndPassword( kPrefilledPlaceholderUsernameOverridden); } } - - UpdateFieldValueAndPropertiesMaskMap( - *username_element, &username, - FieldPropertiesFlags::AUTOFILLED_ON_PAGELOAD, - field_value_and_properties_map); + field_data_manager->UpdateFieldDataMap( + *username_element, username, + FieldPropertiesFlags::AUTOFILLED_ON_PAGELOAD); username_element->SetAutofillState(WebAutofillState::kAutofilled); if (logger) logger->LogElementName(Logger::STRING_USERNAME_FILLED, *username_element); @@ -1839,11 +1852,10 @@ bool PasswordAutofillAgent::FillUserNameAndPassword( // sure that we do not fill in the DOM with a password until we believe the // user is intentionally interacting with the page. if (password_element->Value().Utf16() != password) - password_element->SetSuggestedValue(blink::WebString::FromUTF16(password)); - UpdateFieldValueAndPropertiesMaskMap( - *password_element, &password, - FieldPropertiesFlags::AUTOFILLED_ON_PAGELOAD, - field_value_and_properties_map); + password_element->SetSuggestedValue(WebString::FromUTF16(password)); + field_data_manager->UpdateFieldDataMap( + *password_element, password, + FieldPropertiesFlags::AUTOFILLED_ON_PAGELOAD); ProvisionallySavePassword(password_element->Form(), *password_element, RESTRICTION_NONE); gatekeeper_.RegisterElement(password_element); @@ -1865,15 +1877,14 @@ void PasswordAutofillAgent::LogPrefilledUsernameFillOutcome( bool PasswordAutofillAgent::FillFormOnPasswordReceived( const PasswordFormFillData& fill_data, - blink::WebInputElement username_element, - blink::WebInputElement password_element, - FieldValueAndPropertiesMaskMap* field_value_and_properties_map, + WebInputElement username_element, + WebInputElement password_element, + FieldDataManager* field_data_manager, RendererSavePasswordProgressLogger* logger) { // Do not fill if the password field is in a chain of iframes not having // identical origin. - blink::WebFrame* cur_frame = password_element.GetDocument().GetFrame(); - blink::WebString bottom_frame_origin = - cur_frame->GetSecurityOrigin().ToString(); + WebFrame* cur_frame = password_element.GetDocument().GetFrame(); + WebString bottom_frame_origin = cur_frame->GetSecurityOrigin().ToString(); DCHECK(cur_frame); @@ -1895,19 +1906,19 @@ bool PasswordAutofillAgent::FillFormOnPasswordReceived( // match for read-only username fields. return FillUserNameAndPassword( &username_element, &password_element, fill_data, exact_username_match, - fill_data.username_may_use_prefilled_placeholder, - field_value_and_properties_map, logger); + fill_data.username_may_use_prefilled_placeholder, field_data_manager, + logger); } void PasswordAutofillAgent::OnProvisionallySaveForm( - const blink::WebFormElement& form, - const blink::WebFormControlElement& element, + const WebFormElement& form, + const WebFormControlElement& element, ElementChangeSource source) { // PasswordAutofillAgent isn't interested in SELECT control change. if (source == ElementChangeSource::SELECT_CHANGED) return; - blink::WebInputElement input_element; + WebInputElement input_element; if (!element.IsNull() && element.HasHTMLTagName("input")) input_element = *ToWebInputElement(&element); @@ -1936,7 +1947,7 @@ void PasswordAutofillAgent::OnProvisionallySaveForm( RESTRICTION_NON_EMPTY_PASSWORD); } -void PasswordAutofillAgent::OnFormSubmitted(const blink::WebFormElement& form) { +void PasswordAutofillAgent::OnFormSubmitted(const WebFormElement& form) { OnWillSubmitForm(form); } diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.h b/chromium/components/autofill/content/renderer/password_autofill_agent.h index a284a03bb42..e25ca05d87d 100644 --- a/chromium/components/autofill/content/renderer/password_autofill_agent.h +++ b/chromium/components/autofill/content/renderer/password_autofill_agent.h @@ -7,6 +7,7 @@ #include <map> #include <memory> +#include <utility> #include <vector> #include "base/macros.h" @@ -15,9 +16,9 @@ #include "components/autofill/content/common/autofill_agent.mojom.h" #include "components/autofill/content/common/autofill_driver.mojom.h" #include "components/autofill/content/renderer/autofill_agent.h" +#include "components/autofill/content/renderer/field_data_manager.h" #include "components/autofill/content/renderer/form_tracker.h" #include "components/autofill/content/renderer/html_based_username_detector.h" -#include "components/autofill/content/renderer/password_form_conversion_utils.h" #include "components/autofill/content/renderer/provisionally_saved_password_form.h" #include "components/autofill/core/common/form_data_predictions.h" #include "components/autofill/core/common/password_form.h" @@ -26,7 +27,7 @@ #include "content/public/renderer/render_frame_observer.h" #include "content/public/renderer/render_view_observer.h" #include "mojo/public/cpp/bindings/binding.h" -#include "services/service_manager/public/cpp/binder_registry.h" +#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h" #include "third_party/blink/public/web/web_input_element.h" #if !defined(OS_ANDROID) && !defined(OS_IOS) @@ -63,6 +64,7 @@ enum class PrefilledUsernameFillOutcome { extern const char kDebugAttributeForFormSignature[]; extern const char kDebugAttributeForFieldSignature[]; +class FieldDataManager; class RendererSavePasswordProgressLogger; class PasswordGenerationAgent; @@ -72,10 +74,10 @@ class PasswordAutofillAgent : public content::RenderFrameObserver, public mojom::PasswordAutofillAgent { public: PasswordAutofillAgent(content::RenderFrame* render_frame, - service_manager::BinderRegistry* registry); + blink::AssociatedInterfaceRegistry* registry); ~PasswordAutofillAgent() override; - void BindRequest(mojom::PasswordAutofillAgentRequest request); + void BindRequest(mojom::PasswordAutofillAgentAssociatedRequest request); void SetAutofillAgent(AutofillAgent* autofill_agent); @@ -210,6 +212,25 @@ class PasswordAutofillAgent : public content::RenderFrameObserver, using PasswordToLoginMap = std::map<blink::WebInputElement, blink::WebInputElement>; + // This class ensures that the driver will only receive relevant signals by + // caching the parameters of the last message sent to the driver. + class FocusStateNotifier { + public: + // Creates a new notifier that uses the agent which owns it to access the + // real driver implementation. + explicit FocusStateNotifier(PasswordAutofillAgent* agent); + ~FocusStateNotifier(); + + void FocusedInputChanged(bool is_fillable, bool is_password_field); + + private: + bool was_fillable_; + bool was_password_field_; + PasswordAutofillAgent* agent_; + + DISALLOW_COPY_AND_ASSIGN(FocusStateNotifier); + }; + // This class keeps track of autofilled password input elements and makes sure // the autofilled password value is not accessible to JavaScript code until // the user interacts with the page. @@ -307,18 +328,17 @@ class PasswordAutofillAgent : public content::RenderFrameObserver, // This function attempts to fill |username_element| and |password_element| // with values from |fill_data|. The |username_element| and |password_element| // will only have the suggestedValue set. If a match is found, return true and - // |field_value_and_properties_map| will be modified with the autofilled - // credentials and |FieldPropertiesFlags::AUTOFILLED| flag. + // |field_data_manager| will be modified with the autofilled credentials and + // |FieldPropertiesFlags::AUTOFILLED| flag. // If |username_may_use_prefilled_placeholder| then this function may // overwrite the value of username field. - bool FillUserNameAndPassword( - blink::WebInputElement* username_element, - blink::WebInputElement* password_element, - const PasswordFormFillData& fill_data, - bool exact_username_match, - bool username_may_use_prefilled_placeholder, - FieldValueAndPropertiesMaskMap* field_value_and_properties_map, - RendererSavePasswordProgressLogger* logger); + bool FillUserNameAndPassword(blink::WebInputElement* username_element, + blink::WebInputElement* password_element, + const PasswordFormFillData& fill_data, + bool exact_username_match, + bool username_may_use_prefilled_placeholder, + FieldDataManager* field_data_manager, + RendererSavePasswordProgressLogger* logger); // Logs whether a username value that was prefilled by the website was // overridden when trying to fill with an existing credential. This logs @@ -331,12 +351,11 @@ class PasswordAutofillAgent : public content::RenderFrameObserver, // attempts to fill the password matching the already filled username, if // such a password exists. The |password_element| will have the // |suggestedValue| set. Returns true if the password is filled. - bool FillFormOnPasswordReceived( - const PasswordFormFillData& fill_data, - blink::WebInputElement username_element, - blink::WebInputElement password_element, - FieldValueAndPropertiesMaskMap* field_value_and_properties_map, - RendererSavePasswordProgressLogger* logger); + bool FillFormOnPasswordReceived(const PasswordFormFillData& fill_data, + blink::WebInputElement username_element, + blink::WebInputElement password_element, + FieldDataManager* field_data_manager, + RendererSavePasswordProgressLogger* logger); // Helper function called when form submission is successful. void FireSubmissionIfFormDisappear( @@ -388,7 +407,7 @@ class PasswordAutofillAgent : public content::RenderFrameObserver, // changes them. // 2) Field properties mask, i.e. whether the field was autofilled, modified // by user, etc. (see FieldPropertiesMask). - FieldValueAndPropertiesMaskMap field_value_and_properties_map_; + FieldDataManager field_data_manager_; PasswordValueGatekeeper gatekeeper_; @@ -423,6 +442,10 @@ class PasswordAutofillAgent : public content::RenderFrameObserver, // username predictions. UsernameDetectorCache username_detector_cache_; + // This notifier is used to avoid sending redundant messages to the password + // manager driver mojo interface. + FocusStateNotifier focus_state_notifier_; + base::WeakPtr<AutofillAgent> autofill_agent_; PasswordGenerationAgent* password_generation_agent_; // Weak reference. @@ -433,7 +456,7 @@ class PasswordAutofillAgent : public content::RenderFrameObserver, mojom::PasswordManagerDriverAssociatedPtr password_manager_driver_; - mojo::Binding<mojom::PasswordAutofillAgent> binding_; + mojo::AssociatedBinding<mojom::PasswordAutofillAgent> binding_; bool prefilled_username_metrics_logged_ = false; DISALLOW_COPY_AND_ASSIGN(PasswordAutofillAgent); diff --git a/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc b/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc index 68e02e38c21..36ddc614ccb 100644 --- a/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc +++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc @@ -799,7 +799,6 @@ bool GetPasswordForm( password_form->new_password_element = FieldName(new_password, "anonymous_new_password"); password_form->new_password_value = new_password->value; - password_form->new_password_value_is_default = new_password->is_default; if (autocomplete_cache.RetrieveFor(new_password) == AutocompleteFlag::NEW_PASSWORD) { password_form->new_password_marked_by_site = true; @@ -917,7 +916,7 @@ bool IsGaiaWithSkipSavePasswordForm(const blink::WebFormElement& form) { std::unique_ptr<PasswordForm> CreatePasswordFormFromWebForm( const WebFormElement& web_form, - const FieldValueAndPropertiesMaskMap* field_value_and_properties_map, + const FieldDataManager* field_data_manager, const FormsPredictionsMap* form_predictions, UsernameDetectorCache* username_detector_cache) { if (web_form.IsNull()) @@ -936,10 +935,10 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromWebForm( if (control_elements.empty()) return nullptr; - if (!WebFormElementToFormData( - web_form, blink::WebFormControlElement(), - field_value_and_properties_map, form_util::EXTRACT_VALUE, - &password_form->form_data, nullptr /* FormFieldData */)) { + if (!WebFormElementToFormData(web_form, blink::WebFormControlElement(), + field_data_manager, form_util::EXTRACT_VALUE, + &password_form->form_data, + nullptr /* FormFieldData */)) { return nullptr; } @@ -954,7 +953,7 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromWebForm( std::unique_ptr<PasswordForm> CreatePasswordFormFromUnownedInputElements( const WebLocalFrame& frame, - const FieldValueAndPropertiesMaskMap* field_value_and_properties_map, + const FieldDataManager* field_data_manager, const FormsPredictionsMap* form_predictions, UsernameDetectorCache* username_detector_cache) { std::vector<blink::WebElement> fieldsets; @@ -967,7 +966,7 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromUnownedInputElements( auto password_form = std::make_unique<PasswordForm>(); if (!UnownedPasswordFormElementsAndFieldSetsToFormData( fieldsets, control_elements, nullptr, frame.GetDocument(), - field_value_and_properties_map, form_util::EXTRACT_VALUE, + field_data_manager, form_util::EXTRACT_VALUE, &password_form->form_data, nullptr /* FormFieldData */)) { return nullptr; } diff --git a/chromium/components/autofill/content/renderer/password_form_conversion_utils.h b/chromium/components/autofill/content/renderer/password_form_conversion_utils.h index 50b49e45a86..390db0b8c40 100644 --- a/chromium/components/autofill/content/renderer/password_form_conversion_utils.h +++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils.h @@ -32,6 +32,8 @@ namespace autofill { struct PasswordForm; +class FieldDataManager; + enum UsernameDetectionMethod { NO_USERNAME_DETECTED, BASE_HEURISTIC, @@ -64,26 +66,19 @@ bool IsGaiaReauthenticationForm(const blink::WebFormElement& form); // Tests whether the given form is a GAIA form with a skip password argument. bool IsGaiaWithSkipSavePasswordForm(const blink::WebFormElement& form); -// TODO(https://crbug.com/849291): Create separate class for keeping information -// from FieldValueAndPropertiesMaskMap. -using FieldValueAndPropertiesMaskMap = - std::map<uint32_t, - std::pair<std::unique_ptr<base::string16>, FieldPropertiesMask>>; - // Create a PasswordForm from DOM form. Webkit doesn't allow storing // custom metadata to DOM nodes, so we have to do this every time an event // happens with a given form and compare against previously Create'd forms // to identify..which sucks. -// If an element of |form| has an entry in |nonscript_modified_values|, the -// associated string is used instead of the element's value to create -// the PasswordForm. +// If an element of |form| has an entry in |field_data_manager|, the associated +// string is used instead of the element's value to create the PasswordForm. // |form_predictions| is Autofill server response, if present it's used for // overwriting default username element selection. // |username_detector_cache| is used by the built-in HTML based username // detector to cache results. Can be null. std::unique_ptr<PasswordForm> CreatePasswordFormFromWebForm( const blink::WebFormElement& form, - const FieldValueAndPropertiesMaskMap* nonscript_modified_values, + const FieldDataManager* field_data_manager, const FormsPredictionsMap* form_predictions, UsernameDetectorCache* username_detector_cache); @@ -91,7 +86,7 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromWebForm( // enclosed in <form> element. std::unique_ptr<PasswordForm> CreatePasswordFormFromUnownedInputElements( const blink::WebLocalFrame& frame, - const FieldValueAndPropertiesMaskMap* nonscript_modified_values, + const FieldDataManager* field_data_manager, const FormsPredictionsMap* form_predictions, UsernameDetectorCache* username_detector_cache); diff --git a/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc b/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc index 732fb63e59c..c8d18963ccf 100644 --- a/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc +++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc @@ -13,6 +13,7 @@ #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "build/build_config.h" +#include "components/autofill/content/renderer/field_data_manager.h" #include "components/autofill/content/renderer/form_autofill_util.h" #include "components/autofill/content/renderer/password_form_conversion_utils.h" #include "components/autofill/core/browser/form_structure.h" @@ -214,21 +215,20 @@ class MAYBE_PasswordFormConversionUtilsTest : public content::RenderViewTest { WebVector<WebFormControlElement> control_elements; form.GetFormControlElements(control_elements); - FieldValueAndPropertiesMaskMap user_input; + FieldDataManager field_data_manager; for (size_t i = 0; i < control_elements.size(); ++i) { WebInputElement* input_element = ToWebInputElement(&control_elements[i]); if (input_element->HasAttribute("set-activated-submit")) input_element->SetActivatedSubmit(true); if (with_user_input) { - const base::string16 element_value = input_element->Value().Utf16(); - user_input[control_elements[i].UniqueRendererFormControlId()] = - std::make_pair(std::make_unique<base::string16>(element_value), - FieldPropertiesFlags::USER_TYPED); + field_data_manager.UpdateFieldDataMap(control_elements[i], + input_element->Value().Utf16(), + FieldPropertiesFlags::USER_TYPED); } } return CreatePasswordFormFromWebForm( - form, with_user_input ? &user_input : nullptr, predictions, + form, with_user_input ? &field_data_manager : nullptr, predictions, &username_detector_cache_); } @@ -741,18 +741,16 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, // A user typed only into "id" and "password" fields. So, the prediction for // "email" field should be ignored despite it is more reliable than prediction // for "id" field. - FieldValueAndPropertiesMaskMap user_input; - user_input[control_elements[2].UniqueRendererFormControlId()] = - std::make_pair( // id - std::make_unique<base::string16>(control_elements[2].Value().Utf16()), - FieldPropertiesFlags::USER_TYPED); - user_input[control_elements[3].UniqueRendererFormControlId()] = - std::make_pair( // password - std::make_unique<base::string16>(control_elements[3].Value().Utf16()), - FieldPropertiesFlags::USER_TYPED); + FieldDataManager field_data_manager; + field_data_manager.UpdateFieldDataMap( + control_elements[2], control_elements[2].Value().Utf16(), + FieldPropertiesFlags::USER_TYPED); // id + field_data_manager.UpdateFieldDataMap( + control_elements[3], control_elements[3].Value().Utf16(), + FieldPropertiesFlags::USER_TYPED); // password std::unique_ptr<PasswordForm> password_form = CreatePasswordFormFromWebForm( - form, &user_input, nullptr, &username_detector_cache); + form, &field_data_manager, nullptr, &username_detector_cache); ASSERT_TRUE(password_form); EXPECT_EQ(base::UTF8ToUTF16("id"), password_form->username_element); @@ -1579,23 +1577,21 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, UserInput) { WebFormElement form; LoadWebFormFromHTML(html, &form, nullptr); - FieldValueAndPropertiesMaskMap user_input; + FieldDataManager field_data_manager; WebVector<WebFormControlElement> control_elements; form.GetFormControlElements(control_elements); ASSERT_EQ("nonvisible_text", control_elements[0].NameForAutofill().Utf8()); - user_input[control_elements[0].UniqueRendererFormControlId()] = - std::make_pair( - std::make_unique<base::string16>(control_elements[0].Value().Utf16()), - FieldPropertiesFlags::USER_TYPED); + field_data_manager.UpdateFieldDataMap(control_elements[0], + control_elements[0].Value().Utf16(), + FieldPropertiesFlags::USER_TYPED); ASSERT_EQ("nonvisible_password", control_elements[2].NameForAutofill().Utf8()); - user_input[control_elements[2].UniqueRendererFormControlId()] = - std::make_pair( - std::make_unique<base::string16>(control_elements[2].Value().Utf16()), - FieldPropertiesFlags::USER_TYPED); + field_data_manager.UpdateFieldDataMap(control_elements[2], + control_elements[2].Value().Utf16(), + FieldPropertiesFlags::USER_TYPED); - std::unique_ptr<PasswordForm> password_form = - CreatePasswordFormFromWebForm(form, &user_input, nullptr, nullptr); + std::unique_ptr<PasswordForm> password_form = CreatePasswordFormFromWebForm( + form, &field_data_manager, nullptr, nullptr); ASSERT_TRUE(password_form); EXPECT_FALSE(password_form->only_for_fallback_saving); @@ -1638,24 +1634,22 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, WebFormElement form; LoadWebFormFromHTML(html, &form, nullptr); - FieldValueAndPropertiesMaskMap user_input; + FieldDataManager field_data_manager; WebVector<WebFormControlElement> control_elements; form.GetFormControlElements(control_elements); ASSERT_EQ("password_with_user_input1", control_elements[9].NameForAutofill().Utf8()); - user_input[control_elements[9].UniqueRendererFormControlId()] = - std::make_pair( - std::make_unique<base::string16>(control_elements[9].Value().Utf16()), - FieldPropertiesFlags::USER_TYPED); + field_data_manager.UpdateFieldDataMap(control_elements[9], + control_elements[9].Value().Utf16(), + FieldPropertiesFlags::USER_TYPED); ASSERT_EQ("password_with_user_input2", control_elements[10].NameForAutofill().Utf8()); - user_input[control_elements[10].UniqueRendererFormControlId()] = - std::make_pair(std::make_unique<base::string16>( - control_elements[10].Value().Utf16()), - FieldPropertiesFlags::USER_TYPED); + field_data_manager.UpdateFieldDataMap(control_elements[10], + control_elements[10].Value().Utf16(), + FieldPropertiesFlags::USER_TYPED); - std::unique_ptr<PasswordForm> password_form = - CreatePasswordFormFromWebForm(form, &user_input, nullptr, nullptr); + std::unique_ptr<PasswordForm> password_form = CreatePasswordFormFromWebForm( + form, &field_data_manager, nullptr, nullptr); ASSERT_TRUE(password_form); EXPECT_FALSE(password_form->only_for_fallback_saving); @@ -1698,24 +1692,22 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, WebFormElement form; LoadWebFormFromHTML(html, &form, nullptr); - FieldValueAndPropertiesMaskMap user_input; + FieldDataManager field_data_manager; WebVector<WebFormControlElement> control_elements; form.GetFormControlElements(control_elements); ASSERT_EQ("password_with_user_input1", control_elements[7].NameForAutofill().Utf8()); - user_input[control_elements[7].UniqueRendererFormControlId()] = - std::make_pair( - std::make_unique<base::string16>(control_elements[7].Value().Utf16()), - FieldPropertiesFlags::USER_TYPED); + field_data_manager.UpdateFieldDataMap(control_elements[7], + control_elements[7].Value().Utf16(), + FieldPropertiesFlags::USER_TYPED); ASSERT_EQ("password_with_user_input2", control_elements[9].NameForAutofill().Utf8()); - user_input[control_elements[9].UniqueRendererFormControlId()] = - std::make_pair( - std::make_unique<base::string16>(control_elements[9].Value().Utf16()), - FieldPropertiesFlags::USER_TYPED); + field_data_manager.UpdateFieldDataMap(control_elements[9], + control_elements[9].Value().Utf16(), + FieldPropertiesFlags::USER_TYPED); - std::unique_ptr<PasswordForm> password_form = - CreatePasswordFormFromWebForm(form, &user_input, nullptr, nullptr); + std::unique_ptr<PasswordForm> password_form = CreatePasswordFormFromWebForm( + form, &field_data_manager, nullptr, nullptr); ASSERT_TRUE(password_form); EXPECT_FALSE(password_form->only_for_fallback_saving); @@ -1863,22 +1855,19 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, LoadWebFormFromHTML(html, &form, nullptr); WebVector<WebFormControlElement> control_elements; form.GetFormControlElements(control_elements); - FieldValueAndPropertiesMaskMap user_input; + FieldDataManager field_data_manager; FieldPropertiesMask mask = FieldPropertiesFlags::AUTOFILLED; if (autofilled_value_was_modified_by_user) mask |= FieldPropertiesFlags::USER_TYPED; - user_input[control_elements[1].UniqueRendererFormControlId()] = - std::make_pair(std::make_unique<base::string16>( - base::ASCIIToUTF16("autofilled_value")), - mask); - user_input[control_elements[2].UniqueRendererFormControlId()] = - std::make_pair( - std::make_unique<base::string16>(base::ASCIIToUTF16("user_value")), - FieldPropertiesFlags::USER_TYPED); - - std::unique_ptr<PasswordForm> password_form( - CreatePasswordFormFromWebForm(form, &user_input, nullptr, nullptr)); + field_data_manager.UpdateFieldDataMap( + control_elements[1], base::ASCIIToUTF16("autofilled_value"), mask); + field_data_manager.UpdateFieldDataMap(control_elements[2], + base::ASCIIToUTF16("user_value"), + FieldPropertiesFlags::USER_TYPED); + + std::unique_ptr<PasswordForm> password_form(CreatePasswordFormFromWebForm( + form, &field_data_manager, nullptr, nullptr)); ASSERT_TRUE(password_form); EXPECT_TRUE(password_form->form_has_autofilled_value); } @@ -2053,15 +2042,13 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, LoadWebFormFromHTML(html, &form, nullptr); WebVector<WebFormControlElement> control_elements; form.GetFormControlElements(control_elements); - FieldValueAndPropertiesMaskMap user_input; - WebInputElement* input_element = ToWebInputElement(&control_elements[3]); - const base::string16 element_value = input_element->Value().Utf16(); - user_input[control_elements[3].UniqueRendererFormControlId()] = - std::make_pair(std::make_unique<base::string16>(element_value), - FieldPropertiesFlags::USER_TYPED); + FieldDataManager field_data_manager; + field_data_manager.UpdateFieldDataMap(control_elements[3], + control_elements[3].Value().Utf16(), + FieldPropertiesFlags::USER_TYPED); std::unique_ptr<PasswordForm> password_form = CreatePasswordFormFromWebForm( - form, &user_input, &predictions, &username_detector_cache_); + form, &field_data_manager, &predictions, &username_detector_cache_); ASSERT_TRUE(password_form); EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("JohnSmith"), password_form->username_value); @@ -2470,34 +2457,31 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, TypedValuePreserved) { WebFormElement form; LoadWebFormFromHTML(html, &form, nullptr); - FieldValueAndPropertiesMaskMap user_input; + FieldDataManager field_data_manager; WebVector<WebFormControlElement> control_elements; form.GetFormControlElements(control_elements); ASSERT_EQ(3u, control_elements.size()); ASSERT_EQ("fine", control_elements[0].NameForAutofill().Utf8()); control_elements[0].SetAutofillValue("same_value"); - user_input[control_elements[0].UniqueRendererFormControlId()] = - std::make_pair( - std::make_unique<base::string16>(control_elements[0].Value().Utf16()), - FieldPropertiesFlags::USER_TYPED); + field_data_manager.UpdateFieldDataMap(control_elements[0], + control_elements[0].Value().Utf16(), + FieldPropertiesFlags::USER_TYPED); ASSERT_EQ("mangled", control_elements[1].NameForAutofill().Utf8()); control_elements[1].SetAutofillValue("mangled_value"); - user_input[control_elements[1].UniqueRendererFormControlId()] = - std::make_pair( - std::make_unique<base::string16>(base::UTF8ToUTF16("original_value")), - FieldPropertiesFlags::USER_TYPED); + field_data_manager.UpdateFieldDataMap(control_elements[1], + base::UTF8ToUTF16("original_value"), + FieldPropertiesFlags::USER_TYPED); ASSERT_EQ("completed_for_user", control_elements[2].NameForAutofill().Utf8()); control_elements[2].SetAutofillValue("email@gmail.com"); - user_input[control_elements[2].UniqueRendererFormControlId()] = - std::make_pair( - std::make_unique<base::string16>(base::UTF8ToUTF16("email")), - FieldPropertiesFlags::USER_TYPED); + field_data_manager.UpdateFieldDataMap(control_elements[2], + base::UTF8ToUTF16("email"), + FieldPropertiesFlags::USER_TYPED); - std::unique_ptr<PasswordForm> password_form = - CreatePasswordFormFromWebForm(form, &user_input, nullptr, nullptr); + std::unique_ptr<PasswordForm> password_form = CreatePasswordFormFromWebForm( + form, &field_data_manager, nullptr, nullptr); ASSERT_TRUE(password_form); diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.cc b/chromium/components/autofill/content/renderer/password_generation_agent.cc index 19467682855..60d1b15c55b 100644 --- a/chromium/components/autofill/content/renderer/password_generation_agent.cc +++ b/chromium/components/autofill/content/renderer/password_generation_agent.cc @@ -13,8 +13,8 @@ #include "base/stl_util.h" #include "base/threading/thread_task_runner_handle.h" #include "components/autofill/content/renderer/form_autofill_util.h" -#include "components/autofill/content/renderer/form_classifier.h" #include "components/autofill/content/renderer/password_autofill_agent.h" +#include "components/autofill/content/renderer/password_form_conversion_utils.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/password_form.h" @@ -35,6 +35,10 @@ #include "ui/gfx/geometry/rect.h" using blink::WebAutofillState; +using blink::WebInputElement; +using blink::WebFormControlElement; +using blink::WebFormElement; +using blink::WebLocalFrame; namespace autofill { @@ -46,31 +50,30 @@ using Logger = autofill::SavePasswordProgressLogger; // Returns pairs of |PasswordForm| and corresponding |WebFormElement| for all // <form>s in the frame and for unowned <input>s. The method doesn't filter out // invalid |PasswordForm|s. -std::vector<std::pair<std::unique_ptr<PasswordForm>, blink::WebFormElement>> +std::vector<std::pair<std::unique_ptr<PasswordForm>, WebFormElement>> GetAllPasswordFormsInFrame(PasswordAutofillAgent* password_agent, - blink::WebLocalFrame* web_frame) { - blink::WebVector<blink::WebFormElement> web_forms; + WebLocalFrame* web_frame) { + blink::WebVector<WebFormElement> web_forms; web_frame->GetDocument().Forms(web_forms); - std::vector<std::pair<std::unique_ptr<PasswordForm>, blink::WebFormElement>> + std::vector<std::pair<std::unique_ptr<PasswordForm>, WebFormElement>> all_forms; - for (const blink::WebFormElement& web_form : web_forms) { + for (const WebFormElement& web_form : web_forms) { all_forms.emplace_back(std::make_pair( password_agent->GetPasswordFormFromWebForm(web_form), web_form)); } all_forms.emplace_back( std::make_pair(password_agent->GetPasswordFormFromUnownedInputElements(), - blink::WebFormElement())); + WebFormElement())); return all_forms; } // Returns true if we think that this form is for account creation. Password // field(s) of the form are pushed back to |passwords|. bool GetAccountCreationPasswordFields( - const std::vector<blink::WebFormControlElement>& control_elements, - std::vector<blink::WebInputElement>* passwords) { + const std::vector<WebFormControlElement>& control_elements, + std::vector<WebInputElement>* passwords) { for (const auto& control_element : control_elements) { - const blink::WebInputElement* input_element = - ToWebInputElement(&control_element); + const WebInputElement* input_element = ToWebInputElement(&control_element); if (input_element && input_element->IsTextField() && input_element->IsPasswordFieldForAutofill()) { passwords->push_back(*input_element); @@ -97,11 +100,11 @@ const PasswordFormGenerationData* FindFormGenerationData( // Returns a vector of up to 2 password fields with autocomplete attribute set // to "new-password". These will be filled with the generated password. -std::vector<blink::WebInputElement> FindNewPasswordElementsMarkedBySite( - const std::vector<blink::WebInputElement>& all_password_elements) { - std::vector<blink::WebInputElement> passwords; +std::vector<WebInputElement> FindNewPasswordElementsMarkedBySite( + const std::vector<WebInputElement>& all_password_elements) { + std::vector<WebInputElement> passwords; - auto is_new_password_field = [](const blink::WebInputElement& element) { + auto is_new_password_field = [](const WebInputElement& element) { return AutocompleteFlagForElement(element) == AutocompleteFlag::NEW_PASSWORD; }; @@ -123,14 +126,14 @@ std::vector<blink::WebInputElement> FindNewPasswordElementsMarkedBySite( // Returns a vector of up to 2 password fields into which Chrome should fill the // generated password. It assumes that |field_signature| describes the field // where Chrome shows the password generation prompt. -std::vector<blink::WebInputElement> FindPasswordElementsForGeneration( - const std::vector<blink::WebInputElement>& all_password_elements, +std::vector<WebInputElement> FindPasswordElementsForGeneration( + const std::vector<WebInputElement>& all_password_elements, const PasswordFormGenerationData& generation_data) { auto generation_field_iter = all_password_elements.end(); auto confirmation_field_iter = all_password_elements.end(); for (auto iter = all_password_elements.begin(); iter != all_password_elements.end(); ++iter) { - const blink::WebInputElement& input = *iter; + const WebInputElement& input = *iter; FieldSignature signature = CalculateFieldSignatureByNameAndType( input.NameForAutofill().Utf16(), input.FormControlTypeForAutofill().Utf8()); @@ -142,7 +145,7 @@ std::vector<blink::WebInputElement> FindPasswordElementsForGeneration( } } - std::vector<blink::WebInputElement> passwords; + std::vector<WebInputElement> passwords; if (generation_field_iter != all_password_elements.end()) { passwords.push_back(*generation_field_iter); @@ -155,9 +158,9 @@ std::vector<blink::WebInputElement> FindPasswordElementsForGeneration( } void CopyElementValueToOtherInputElements( - const blink::WebInputElement* element, - std::vector<blink::WebInputElement>* elements) { - for (blink::WebInputElement& it : *elements) { + const WebInputElement* element, + std::vector<WebInputElement>* elements) { + for (WebInputElement& it : *elements) { if (*element != it) { it.SetAutofillValue(element->Value()); } @@ -168,7 +171,7 @@ void CopyElementValueToOtherInputElements( PasswordGenerationAgent::AccountCreationFormData::AccountCreationFormData( linked_ptr<PasswordForm> password_form, - std::vector<blink::WebInputElement> passwords) + std::vector<WebInputElement> passwords) : form(password_form), password_elements(std::move(passwords)) {} PasswordGenerationAgent::AccountCreationFormData::AccountCreationFormData( @@ -179,7 +182,7 @@ PasswordGenerationAgent::AccountCreationFormData::~AccountCreationFormData() {} PasswordGenerationAgent::PasswordGenerationAgent( content::RenderFrame* render_frame, PasswordAutofillAgent* password_agent, - service_manager::BinderRegistry* registry) + blink::AssociatedInterfaceRegistry* registry) : content::RenderFrameObserver(render_frame), password_is_generated_(false), is_manually_triggered_(false), @@ -187,21 +190,20 @@ PasswordGenerationAgent::PasswordGenerationAgent( generation_popup_shown_(false), editing_popup_shown_(false), enabled_(password_generation::IsPasswordGenerationEnabled()), - form_classifier_enabled_(false), mark_generation_element_( base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kShowAutofillSignatures)), password_agent_(password_agent), binding_(this) { LogBoolean(Logger::STRING_GENERATION_RENDERER_ENABLED, enabled_); - registry->AddInterface(base::Bind(&PasswordGenerationAgent::BindRequest, - base::Unretained(this))); + registry->AddInterface(base::BindRepeating( + &PasswordGenerationAgent::BindRequest, base::Unretained(this))); password_agent_->SetPasswordGenerationAgent(this); } PasswordGenerationAgent::~PasswordGenerationAgent() {} void PasswordGenerationAgent::BindRequest( - mojom::PasswordGenerationAgentRequest request) { + mojom::PasswordGenerationAgentAssociatedRequest request) { binding_.Bind(std::move(request)); } @@ -209,6 +211,7 @@ void PasswordGenerationAgent::DidCommitProvisionalLoad( bool /*is_new_navigation*/, bool is_same_document_navigation) { if (is_same_document_navigation) return; + password_is_generated_ = false; generation_element_.Reset(); last_focused_password_element_.Reset(); } @@ -280,26 +283,11 @@ void PasswordGenerationAgent::OnDynamicFormsSeen() { } void PasswordGenerationAgent::OnFieldAutofilled( - const blink::WebInputElement& password_element) { + const WebInputElement& password_element) { if (password_is_generated_ && generation_element_ == password_element) PasswordNoLongerGenerated(); } -void PasswordGenerationAgent::AllowToRunFormClassifier() { - form_classifier_enabled_ = true; -} - -void PasswordGenerationAgent::RunFormClassifierAndSaveVote( - const blink::WebFormElement& web_form, - const PasswordForm& form) { - DCHECK(form_classifier_enabled_); - - base::string16 generation_field; - ClassifyFormAndFindGenerationField(web_form, &generation_field); - GetPasswordManagerDriver()->SaveGenerationFieldDetectedByClassifier( - form, generation_field); -} - void PasswordGenerationAgent::FindPossibleGenerationForm() { if (!enabled_ || !render_frame()) return; @@ -313,8 +301,8 @@ void PasswordGenerationAgent::FindPossibleGenerationForm() { if (generation_form_data_) return; - blink::WebLocalFrame* web_frame = render_frame()->GetWebFrame(); - std::vector<std::pair<std::unique_ptr<PasswordForm>, blink::WebFormElement>> + WebLocalFrame* web_frame = render_frame()->GetWebFrame(); + std::vector<std::pair<std::unique_ptr<PasswordForm>, WebFormElement>> all_password_forms = GetAllPasswordFormsInFrame(password_agent_, web_frame); for (auto& form : all_password_forms) { @@ -332,16 +320,14 @@ void PasswordGenerationAgent::FindPossibleGenerationForm() { if (realm == GaiaUrls::GetInstance()->gaia_login_form_realm()) continue; - std::vector<blink::WebInputElement> passwords; - const blink::WebFormElement& web_form = form.second; + std::vector<WebInputElement> passwords; + const WebFormElement& web_form = form.second; if (GetAccountCreationPasswordFields( web_form.IsNull() ? form_util::GetUnownedFormFieldElements( web_frame->GetDocument().All(), nullptr) : form_util::ExtractAutofillableElementsInForm(web_form), &passwords)) { - if (form_classifier_enabled_ && !web_form.IsNull()) - RunFormClassifierAndSaveVote(web_form, *password_form); possible_account_creation_forms_.emplace_back( make_linked_ptr(form.first.release()), std::move(passwords)); } @@ -473,7 +459,7 @@ void PasswordGenerationAgent::DetermineGenerationElement() { PasswordForm* possible_password_form = possible_form_data.form.get(); const PasswordFormGenerationData* generation_data = nullptr; - std::vector<blink::WebInputElement> password_elements; + std::vector<WebInputElement> password_elements; if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kLocalHeuristicsOnlyForPasswordGeneration)) { password_elements = possible_form_data.password_elements; @@ -529,14 +515,14 @@ bool PasswordGenerationAgent::SetUpUserTriggeredGeneration() { if (last_focused_password_element_.IsNull() || !render_frame()) return false; - blink::WebFormElement form = last_focused_password_element_.Form(); + WebFormElement form = last_focused_password_element_.Form(); std::unique_ptr<PasswordForm> password_form; - std::vector<blink::WebFormControlElement> control_elements; + std::vector<WebFormControlElement> control_elements; if (!form.IsNull()) { password_form = password_agent_->GetPasswordFormFromWebForm(form); control_elements = form_util::ExtractAutofillableElementsInForm(form); } else { - const blink::WebLocalFrame& frame = *render_frame()->GetWebFrame(); + const WebLocalFrame& frame = *render_frame()->GetWebFrame(); blink::WebDocument doc = frame.GetDocument(); if (doc.IsNull()) return false; @@ -549,7 +535,7 @@ bool PasswordGenerationAgent::SetUpUserTriggeredGeneration() { return false; generation_element_ = last_focused_password_element_; - std::vector<blink::WebInputElement> password_elements; + std::vector<WebInputElement> password_elements; GetAccountCreationPasswordFields(control_elements, &password_elements); password_elements = FindPasswordElementsForGeneration( password_elements, @@ -581,7 +567,7 @@ bool PasswordGenerationAgent::FocusedNodeHasChanged( return false; } - const blink::WebInputElement* element = ToWebInputElement(&web_element); + const WebInputElement* element = ToWebInputElement(&web_element); if (element && element->IsPasswordFieldForAutofill()) last_focused_password_element_ = *element; if (!element || *element != generation_element_) { @@ -614,10 +600,15 @@ bool PasswordGenerationAgent::FocusedNodeHasChanged( } bool PasswordGenerationAgent::TextDidChangeInTextField( - const blink::WebInputElement& element) { + const WebInputElement& element) { if (element != generation_element_) { // Presave the username if it has been changed. - if (password_is_generated_ && + // TODO(crbug.com/879713): investigate why the following DCHECKs can be + // triggered. + DCHECK(!element.IsNull()); + DCHECK(!password_is_generated_ || !generation_element_.IsNull()); + if (password_is_generated_ && !element.IsNull() && + !generation_element_.IsNull() && (element.Form() == generation_element_.Form())) { std::unique_ptr<PasswordForm> presaved_form( CreatePasswordFormToPresave()); @@ -710,14 +701,12 @@ void PasswordGenerationAgent::PasswordNoLongerGenerated() { password_is_generated_ = false; password_edited_ = false; generation_element_.SetShouldRevealPassword(false); - for (blink::WebInputElement& password : - generation_form_data_->password_elements) + for (WebInputElement& password : generation_form_data_->password_elements) password.SetAutofillState(WebAutofillState::kNotFilled); password_generation::LogPasswordGenerationEvent( password_generation::PASSWORD_DELETED); // Clear all other password fields. - for (blink::WebInputElement& element : - generation_form_data_->password_elements) { + for (WebInputElement& element : generation_form_data_->password_elements) { if (generation_element_ != element) element.SetAutofillValue(blink::WebString()); } diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.h b/chromium/components/autofill/content/renderer/password_generation_agent.h index f19f17bc18b..a5f0a8b2594 100644 --- a/chromium/components/autofill/content/renderer/password_generation_agent.h +++ b/chromium/components/autofill/content/renderer/password_generation_agent.h @@ -18,8 +18,8 @@ #include "components/autofill/content/common/autofill_driver.mojom.h" #include "components/autofill/content/renderer/renderer_save_password_progress_logger.h" #include "content/public/renderer/render_frame_observer.h" -#include "mojo/public/cpp/bindings/binding.h" -#include "services/service_manager/public/cpp/binder_registry.h" +#include "mojo/public/cpp/bindings/associated_binding.h" +#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h" #include "third_party/blink/public/web/web_input_element.h" #include "url/gurl.h" @@ -46,10 +46,10 @@ class PasswordGenerationAgent : public content::RenderFrameObserver, PasswordGenerationAgent(content::RenderFrame* render_frame, PasswordAutofillAgent* password_agent, - service_manager::BinderRegistry* registry); + blink::AssociatedInterfaceRegistry* registry); ~PasswordGenerationAgent() override; - void BindRequest(mojom::PasswordGenerationAgentRequest request); + void BindRequest(mojom::PasswordGenerationAgentAssociatedRequest request); // mojom::PasswordGenerationAgent: void FormNotBlacklisted(const PasswordForm& form) override; @@ -60,9 +60,6 @@ class PasswordGenerationAgent : public content::RenderFrameObserver, // generation popup at this field. void UserTriggeredGeneratePassword() override; - // Enables the form classifier. - void AllowToRunFormClassifier() override; - // Returns true if the field being changed is one where a generated password // is being offered. Updates the state of the popup if necessary. bool TextDidChangeInTextField(const blink::WebInputElement& element); @@ -221,9 +218,6 @@ class PasswordGenerationAgent : public content::RenderFrameObserver, // If this feature is enabled. Controlled by Finch. bool enabled_; - // If the form classifier should run. - bool form_classifier_enabled_; - // True iff the generation element should be marked with special HTML // attribute (only for experimental purposes). bool mark_generation_element_; @@ -234,7 +228,7 @@ class PasswordGenerationAgent : public content::RenderFrameObserver, mojom::PasswordManagerClientAssociatedPtr password_manager_client_; - mojo::Binding<mojom::PasswordGenerationAgent> binding_; + mojo::AssociatedBinding<mojom::PasswordGenerationAgent> binding_; DISALLOW_COPY_AND_ASSIGN(PasswordGenerationAgent); }; diff --git a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc index c9c75857070..f79fac872bc 100644 --- a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc +++ b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc @@ -71,10 +71,6 @@ class FakeContentPasswordManagerDriver : public mojom::PasswordManagerDriver { void UserModifiedPasswordField() override {} - void SaveGenerationFieldDetectedByClassifier( - const autofill::PasswordForm& password_form, - const base::string16& generation_field) override {} - void CheckSafeBrowsingReputation(const GURL& form_action, const GURL& frame_url) override {} diff --git a/chromium/components/autofill/content/renderer/test_password_autofill_agent.cc b/chromium/components/autofill/content/renderer/test_password_autofill_agent.cc index 560bbbc410d..6778b3febf6 100644 --- a/chromium/components/autofill/content/renderer/test_password_autofill_agent.cc +++ b/chromium/components/autofill/content/renderer/test_password_autofill_agent.cc @@ -8,7 +8,7 @@ namespace autofill { TestPasswordAutofillAgent::TestPasswordAutofillAgent( content::RenderFrame* render_frame, - service_manager::BinderRegistry* registry) + blink::AssociatedInterfaceRegistry* registry) : PasswordAutofillAgent(render_frame, registry) {} TestPasswordAutofillAgent::~TestPasswordAutofillAgent() {} diff --git a/chromium/components/autofill/content/renderer/test_password_autofill_agent.h b/chromium/components/autofill/content/renderer/test_password_autofill_agent.h index 2f4add17b86..12c16dd14ba 100644 --- a/chromium/components/autofill/content/renderer/test_password_autofill_agent.h +++ b/chromium/components/autofill/content/renderer/test_password_autofill_agent.h @@ -12,7 +12,7 @@ namespace autofill { class TestPasswordAutofillAgent : public PasswordAutofillAgent { public: TestPasswordAutofillAgent(content::RenderFrame* render_frame, - service_manager::BinderRegistry* registry); + blink::AssociatedInterfaceRegistry* registry); ~TestPasswordAutofillAgent() override; private: diff --git a/chromium/components/autofill/content/renderer/test_password_generation_agent.cc b/chromium/components/autofill/content/renderer/test_password_generation_agent.cc index 4076003b313..14b5017adb8 100644 --- a/chromium/components/autofill/content/renderer/test_password_generation_agent.cc +++ b/chromium/components/autofill/content/renderer/test_password_generation_agent.cc @@ -9,7 +9,7 @@ namespace autofill { TestPasswordGenerationAgent::TestPasswordGenerationAgent( content::RenderFrame* render_frame, PasswordAutofillAgent* password_agent, - service_manager::BinderRegistry* registry) + blink::AssociatedInterfaceRegistry* registry) : PasswordGenerationAgent(render_frame, password_agent, registry) { // Always enable when testing. set_enabled(true); diff --git a/chromium/components/autofill/content/renderer/test_password_generation_agent.h b/chromium/components/autofill/content/renderer/test_password_generation_agent.h index f752803b7cc..5ae0e0c6d7a 100644 --- a/chromium/components/autofill/content/renderer/test_password_generation_agent.h +++ b/chromium/components/autofill/content/renderer/test_password_generation_agent.h @@ -9,7 +9,7 @@ #include "base/macros.h" #include "components/autofill/content/renderer/password_generation_agent.h" -#include "services/service_manager/public/cpp/binder_registry.h" +#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h" namespace autofill { @@ -17,7 +17,7 @@ class TestPasswordGenerationAgent : public PasswordGenerationAgent { public: TestPasswordGenerationAgent(content::RenderFrame* render_frame, PasswordAutofillAgent* password_agent, - service_manager::BinderRegistry* registry); + blink::AssociatedInterfaceRegistry* registry); ~TestPasswordGenerationAgent() override; // PasswordGenreationAgent implementation: diff --git a/chromium/components/autofill/core/browser/BUILD.gn b/chromium/components/autofill/core/browser/BUILD.gn index 24528a81894..ccb84650b18 100644 --- a/chromium/components/autofill/core/browser/BUILD.gn +++ b/chromium/components/autofill/core/browser/BUILD.gn @@ -3,10 +3,12 @@ # found in the LICENSE file. import("//build/config/chrome_build.gni") +import("//build/config/jumbo.gni") import("//testing/libfuzzer/fuzzer_test.gni") -static_library("browser") { +jumbo_static_library("browser") { sources = [ + "account_info_getter.h", "address.cc", "address.h", "address_combobox_model.cc", @@ -115,8 +117,6 @@ static_library("browser") { "local_card_migration_manager.h", "name_field.cc", "name_field.h", - "password_generator.cc", - "password_generator.h", "password_requirements_spec_fetcher.h", "password_requirements_spec_fetcher_impl.cc", "password_requirements_spec_fetcher_impl.h", @@ -126,9 +126,12 @@ static_library("browser") { "payments/full_card_request.h", "payments/payments_client.cc", "payments/payments_client.h", + "payments/payments_customer_data.h", "payments/payments_request.h", "payments/payments_service_url.cc", "payments/payments_service_url.h", + "payments/payments_util.cc", + "payments/payments_util.h", "personal_data_manager.cc", "personal_data_manager.h", "personal_data_manager_observer.h", @@ -176,13 +179,19 @@ static_library("browser") { "webdata/autofill_profile_sync_difference_tracker.h", "webdata/autofill_profile_syncable_service.cc", "webdata/autofill_profile_syncable_service.h", + "webdata/autofill_sync_bridge_util.cc", + "webdata/autofill_sync_bridge_util.h", "webdata/autofill_table.cc", "webdata/autofill_table.h", "webdata/autofill_table_encryptor.h", "webdata/autofill_table_encryptor_factory.cc", "webdata/autofill_table_encryptor_factory.h", + "webdata/autofill_wallet_metadata_sync_bridge.cc", + "webdata/autofill_wallet_metadata_sync_bridge.h", "webdata/autofill_wallet_metadata_syncable_service.cc", "webdata/autofill_wallet_metadata_syncable_service.h", + "webdata/autofill_wallet_sync_bridge.cc", + "webdata/autofill_wallet_sync_bridge.h", "webdata/autofill_wallet_syncable_service.cc", "webdata/autofill_wallet_syncable_service.h", "webdata/autofill_webdata.h", @@ -194,8 +203,6 @@ static_library("browser") { "webdata/autofill_webdata_service_observer.h", "webdata/system_encryptor.cc", "webdata/system_encryptor.h", - "webdata/web_data_model_type_controller.cc", - "webdata/web_data_model_type_controller.h", ] if (is_ios) { @@ -220,6 +227,7 @@ static_library("browser") { if (!is_android) { sources += [ "ui/local_card_migration_bubble_controller.h", + "ui/local_card_migration_dialog_controller.h", "ui/save_card_bubble_controller.h", ] } @@ -246,6 +254,7 @@ static_library("browser") { "//third_party/libaddressinput", ] deps = [ + ":password_generator", ":password_generator_fips181", "//base", "//base:i18n", @@ -290,7 +299,7 @@ static_library("browser") { configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] } -static_library("test_support") { +jumbo_static_library("test_support") { testonly = true sources = [ "autofill_test_utils.cc", @@ -331,6 +340,8 @@ static_library("test_support") { "test_region_data_loader.h", "test_sync_service.cc", "test_sync_service.h", + "webdata/autofill_sync_bridge_test_util.cc", + "webdata/autofill_sync_bridge_test_util.h", ] public_deps = [ @@ -362,6 +373,19 @@ static_library("test_support") { ] } +static_library("password_generator") { + sources = [ + "password_generator.cc", + "password_generator.h", + ] + public_deps = [ + "//components/autofill/core/browser/proto", + ] + deps = [ + "//base", + ] +} + static_library("password_generator_fips181") { sources = [ "password_generator_fips181.cc", @@ -445,6 +469,7 @@ source_set("unit_tests") { "payments/full_card_request_unittest.cc", "payments/payments_client_unittest.cc", "payments/payments_service_url_unittest.cc", + "payments/payments_util_unittest.cc", "personal_data_manager_unittest.cc", "phone_field_unittest.cc", "phone_number_i18n_unittest.cc", @@ -459,8 +484,11 @@ source_set("unit_tests") { "webdata/autofill_profile_sync_bridge_unittest.cc", "webdata/autofill_profile_sync_difference_tracker_unittest.cc", "webdata/autofill_profile_syncable_service_unittest.cc", + "webdata/autofill_sync_bridge_util_unittest.cc", "webdata/autofill_table_unittest.cc", + "webdata/autofill_wallet_metadata_sync_bridge_unittest.cc", "webdata/autofill_wallet_metadata_syncable_service_unittest.cc", + "webdata/autofill_wallet_sync_bridge_unittest.cc", "webdata/autofill_wallet_syncable_service_unittest.cc", "webdata/web_data_service_unittest.cc", ] @@ -479,6 +507,7 @@ source_set("unit_tests") { deps = [ ":browser", + ":password_generator", ":password_generator_fips181", ":test_support", ":unit_tests_bundle_data", @@ -543,3 +572,29 @@ fuzzer_test("password_generator_fips181_fuzzer") { ":password_generator_fips181", ] } + +if (use_libfuzzer) { + fuzzer_test("form_structure_process_query_response_fuzzer") { + sources = [ + "form_structure_process_query_response_fuzzer.cc", + ] + deps = [ + ":browser", + "//base:base", + "//components/autofill/core/browser/proto", + "//components/autofill/core/common", + "//third_party/libprotobuf-mutator", + ] + } + + fuzzer_test("password_generator_proto_fuzzer") { + sources = [ + "password_generator_proto_fuzzer.cc", + ] + deps = [ + ":password_generator", + "//components/autofill/core/browser/proto", + "//third_party/libprotobuf-mutator", + ] + } +} diff --git a/chromium/components/autofill/core/browser/DEPS b/chromium/components/autofill/core/browser/DEPS index 5bef9b837fa..f3199c0270c 100644 --- a/chromium/components/autofill/core/browser/DEPS +++ b/chromium/components/autofill/core/browser/DEPS @@ -6,12 +6,7 @@ include_rules = [ "+components/metrics", "+components/policy", "+components/security_state", - - # Autofill depends on //services/identity/public/cpp for its core Google - # identity dependencies, but depends on this isolated file for recording - # some browser-specific signin metrics. - "+components/signin/core/browser/signin_metrics.h", - + "+components/signin/core/browser", "+components/sync", "+components/variations", "+components/version_info", diff --git a/chromium/components/autofill/core/browser/account_info_getter.h b/chromium/components/autofill/core/browser/account_info_getter.h new file mode 100644 index 00000000000..7d71b5fae99 --- /dev/null +++ b/chromium/components/autofill/core/browser/account_info_getter.h @@ -0,0 +1,33 @@ +// Copyright 2018 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_ACCOUNT_INFO_GETTER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_ACCOUNT_INFO_GETTER_H_ + +#include <string> + +#include "components/signin/core/browser/account_info.h" + +namespace autofill { + +// Interface to get account information in Autofill. +class AccountInfoGetter { + public: + // Returns the account info that should be used when communicating with the + // Payments server. The AccountInfo could be empty if there is no account to + // be used by the Payments server. + virtual AccountInfo GetAccountInfoForPaymentsServer() const = 0; + + // Returns true - When user is both signed-in and enabled sync. + // Returns false - When user is not signed-in or does not have sync the + // feature enabled. + virtual bool IsSyncFeatureEnabled() const = 0; + + protected: + virtual ~AccountInfoGetter() {} +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_ACCOUNT_INFO_GETTER_H_ diff --git a/chromium/components/autofill/core/browser/address_combobox_model.h b/chromium/components/autofill/core/browser/address_combobox_model.h index f8b09f44977..a6556e41bbe 100644 --- a/chromium/components/autofill/core/browser/address_combobox_model.h +++ b/chromium/components/autofill/core/browser/address_combobox_model.h @@ -72,7 +72,7 @@ class AddressComboboxModel : public ui::ComboboxModel { std::string default_selected_guid_; // To be called when the data for the given country code was loaded. - base::ObserverList<ui::ComboboxModelObserver> observers_; + base::ObserverList<ui::ComboboxModelObserver>::Unchecked observers_; DISALLOW_COPY_AND_ASSIGN(AddressComboboxModel); }; diff --git a/chromium/components/autofill/core/browser/address_normalizer_impl.cc b/chromium/components/autofill/core/browser/address_normalizer_impl.cc index e4239056532..ca78af9d58a 100644 --- a/chromium/components/autofill/core/browser/address_normalizer_impl.cc +++ b/chromium/components/autofill/core/browser/address_normalizer_impl.cc @@ -14,7 +14,7 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/strings/utf_string_conversions.h" -#include "base/task_scheduler/post_task.h" +#include "base/task/post_task.h" #include "base/threading/sequenced_task_runner_handle.h" #include "base/time/time.h" #include "components/autofill/core/browser/address_i18n.h" @@ -158,7 +158,7 @@ AddressNormalizerImpl::AddressNormalizerImpl(std::unique_ptr<Source> source, // of |storage| accesses an ObserverList that lives on the current sequence. // https://crbug.com/829122 base::PostTaskWithTraitsAndReplyWithResult( - FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND}, + FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, base::BindOnce( &CreateAddressValidator, std::move(source), DeleteOnTaskRunnerStorageUniquePtr( diff --git a/chromium/components/autofill/core/browser/autocomplete_history_manager.cc b/chromium/components/autofill/core/browser/autocomplete_history_manager.cc index d54741f0e61..fb8c47af30f 100644 --- a/chromium/components/autofill/core/browser/autocomplete_history_manager.cc +++ b/chromium/components/autofill/core/browser/autocomplete_history_manager.cc @@ -14,7 +14,6 @@ #include "components/autofill/core/browser/autofill_external_delegate.h" #include "components/autofill/core/browser/suggestion.h" #include "components/autofill/core/browser/validation.h" -#include "components/autofill/core/common/autofill_pref_names.h" #include "components/autofill/core/common/form_data.h" #include "components/prefs/pref_service.h" diff --git a/chromium/components/autofill/core/browser/autofill_address_policy_handler.cc b/chromium/components/autofill/core/browser/autofill_address_policy_handler.cc index 5e930c8dee7..5afc719388c 100644 --- a/chromium/components/autofill/core/browser/autofill_address_policy_handler.cc +++ b/chromium/components/autofill/core/browser/autofill_address_policy_handler.cc @@ -5,7 +5,7 @@ #include "components/autofill/core/browser/autofill_address_policy_handler.h" #include "base/values.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/policy/core/common/policy_map.h" #include "components/policy/policy_constants.h" #include "components/prefs/pref_value_map.h" @@ -26,10 +26,6 @@ void AutofillAddressPolicyHandler::ApplyPolicySettings( if (value && value->GetAsBoolean(&autofill_profile_enabled) && !autofill_profile_enabled) { prefs->SetBoolean(autofill::prefs::kAutofillProfileEnabled, false); - } else { - // Temporary fix for M69. If there is no policy explicitly disabling this - // pref, it should be set to true. - prefs->SetBoolean(autofill::prefs::kAutofillProfileEnabled, true); } } diff --git a/chromium/components/autofill/core/browser/autofill_address_policy_handler_unittest.cc b/chromium/components/autofill/core/browser/autofill_address_policy_handler_unittest.cc index dd299921092..1ea9d60740d 100644 --- a/chromium/components/autofill/core/browser/autofill_address_policy_handler_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_address_policy_handler_unittest.cc @@ -7,7 +7,7 @@ #include <memory> #include "base/values.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/policy/core/common/policy_map.h" #include "components/policy/core/common/policy_types.h" #include "components/policy/policy_constants.h" @@ -24,15 +24,8 @@ TEST_F(AutofillAddressPolicyHandlerTest, Default) { PrefValueMap prefs; AutofillAddressPolicyHandler handler; handler.ApplyPolicySettings(policy, &prefs); - - // Temporary fix for M69. The pref is enabled by default unless it's disabled - // by policy. - const base::Value* value = nullptr; - ASSERT_TRUE(prefs.GetValue(autofill::prefs::kAutofillProfileEnabled, &value)); - EXPECT_TRUE(value); - bool autofill_profile_enabled = false; - ASSERT_TRUE(value->GetAsBoolean(&autofill_profile_enabled)); - EXPECT_TRUE(autofill_profile_enabled); + EXPECT_FALSE( + prefs.GetValue(autofill::prefs::kAutofillProfileEnabled, nullptr)); } TEST_F(AutofillAddressPolicyHandlerTest, Enabled) { @@ -45,14 +38,9 @@ TEST_F(AutofillAddressPolicyHandlerTest, Enabled) { AutofillAddressPolicyHandler handler; handler.ApplyPolicySettings(policy, &prefs); - // Temporary fix for M69. The pref is enabled by default unless it's disabled - // by policy. - const base::Value* value = nullptr; - ASSERT_TRUE(prefs.GetValue(autofill::prefs::kAutofillProfileEnabled, &value)); - EXPECT_TRUE(value); - bool autofill_profile_enabled = false; - ASSERT_TRUE(value->GetAsBoolean(&autofill_profile_enabled)); - EXPECT_TRUE(autofill_profile_enabled); + // Enabling Autofill for profiles should not set the prefs. + EXPECT_FALSE( + prefs.GetValue(autofill::prefs::kAutofillProfileEnabled, nullptr)); } TEST_F(AutofillAddressPolicyHandlerTest, Disabled) { diff --git a/chromium/components/autofill/core/browser/autofill_address_util.cc b/chromium/components/autofill/core/browser/autofill_address_util.cc index 49cd7dd25e7..d16f649137d 100644 --- a/chromium/components/autofill/core/browser/autofill_address_util.cc +++ b/chromium/components/autofill/core/browser/autofill_address_util.cc @@ -77,16 +77,16 @@ void GetAddressComponents(const std::string& country_code, std::string* components_language_code) { DCHECK(address_components); - i18n::addressinput::Localization localization; + ::i18n::addressinput::Localization localization; localization.SetGetter(l10n_util::GetStringUTF8); std::string not_used; std::vector<AddressUiComponent> components = - i18n::addressinput::BuildComponents( + ::i18n::addressinput::BuildComponents( country_code, localization, ui_language_code, components_language_code ? components_language_code : ¬_used); if (components.empty()) { static const char kDefaultCountryCode[] = "US"; - components = i18n::addressinput::BuildComponents( + components = ::i18n::addressinput::BuildComponents( kDefaultCountryCode, localization, ui_language_code, components_language_code ? components_language_code : ¬_used); } @@ -107,31 +107,31 @@ void GetAddressComponents(const std::string& country_code, component->SetString(kFieldNameKey, components[i].name); switch (components[i].field) { - case i18n::addressinput::COUNTRY: + case ::i18n::addressinput::COUNTRY: component->SetString(kFieldTypeKey, kCountryField); break; - case i18n::addressinput::ADMIN_AREA: + case ::i18n::addressinput::ADMIN_AREA: component->SetString(kFieldTypeKey, kStateField); break; - case i18n::addressinput::LOCALITY: + case ::i18n::addressinput::LOCALITY: component->SetString(kFieldTypeKey, kCityField); break; - case i18n::addressinput::DEPENDENT_LOCALITY: + case ::i18n::addressinput::DEPENDENT_LOCALITY: component->SetString(kFieldTypeKey, kDependentLocalityField); break; - case i18n::addressinput::SORTING_CODE: + case ::i18n::addressinput::SORTING_CODE: component->SetString(kFieldTypeKey, kSortingCodeField); break; - case i18n::addressinput::POSTAL_CODE: + case ::i18n::addressinput::POSTAL_CODE: component->SetString(kFieldTypeKey, kPostalCodeField); break; - case i18n::addressinput::STREET_ADDRESS: + case ::i18n::addressinput::STREET_ADDRESS: component->SetString(kFieldTypeKey, kAddressLineField); break; - case i18n::addressinput::ORGANIZATION: + case ::i18n::addressinput::ORGANIZATION: component->SetString(kFieldTypeKey, kCompanyNameField); break; - case i18n::addressinput::RECIPIENT: + case ::i18n::addressinput::RECIPIENT: component->SetString(kFieldTypeKey, kFullNameField); break; } diff --git a/chromium/components/autofill/core/browser/autofill_assistant.cc b/chromium/components/autofill/core/browser/autofill_assistant.cc index b9f5e194572..8c630de5ff8 100644 --- a/chromium/components/autofill/core/browser/autofill_assistant.cc +++ b/chromium/components/autofill/core/browser/autofill_assistant.cc @@ -6,11 +6,11 @@ #include "base/containers/adapters.h" #include "base/strings/string16.h" -#include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/common/autofill_constants.h" +#include "components/autofill/core/common/autofill_features.h" namespace autofill { @@ -25,19 +25,20 @@ void AutofillAssistant::Reset() { credit_card_form_data_.reset(); } -bool AutofillAssistant::CanShowCreditCardAssist( - const std::vector<std::unique_ptr<FormStructure>>& form_structures) { +bool AutofillAssistant::CanShowCreditCardAssist() { + const auto& form_structures = autofill_manager_->form_structures(); if (form_structures.empty() || credit_card_form_data_ != nullptr || - !IsAutofillCreditCardAssistEnabled() || + !features::IsAutofillCreditCardAssistEnabled() || // Context of the page is not secure or target URL is valid but not // secure. !(autofill_manager_->client()->IsContextSecure() && - (!form_structures.front()->target_url().is_valid() || - !form_structures.front()->target_url().SchemeIs("http")))) { + (!form_structures.begin()->second->target_url().is_valid() || + !form_structures.begin()->second->target_url().SchemeIs("http")))) { return false; } - for (auto& cur_form : base::Reversed(form_structures)) { + for (const auto& kv : form_structures) { + auto& cur_form = kv.second; if (cur_form->IsCompleteCreditCardForm()) { credit_card_form_data_ = std::make_unique<FormData>(cur_form->ToFormData()); diff --git a/chromium/components/autofill/core/browser/autofill_assistant.h b/chromium/components/autofill/core/browser/autofill_assistant.h index 79f097f82b3..ecd60f91914 100644 --- a/chromium/components/autofill/core/browser/autofill_assistant.h +++ b/chromium/components/autofill/core/browser/autofill_assistant.h @@ -17,7 +17,6 @@ namespace autofill { class AutofillManager; class CreditCard; -class FormStructure; // This class encompasses the triggering rules and the logic for the autofill // assisted filling mechanisms. @@ -30,9 +29,9 @@ class AutofillAssistant : public payments::FullCardRequest::ResultDelegate { void Reset(); // Returns whether a credit card assist can be shown. Will go through the - // forms in |form_structures| and extract the credit card form. - bool CanShowCreditCardAssist( - const std::vector<std::unique_ptr<FormStructure>>& form_structures); + // forms in autofill_manager_.form_structures() and extract the credit card + // form. + bool CanShowCreditCardAssist(); // Will show an assist infobar for the previously extracted form proposing to // autofill it. Should only be called if CanShowCreditCardAssist() returned diff --git a/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc b/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc index 342c81ed767..e22a2c240ab 100644 --- a/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc @@ -13,7 +13,6 @@ #include "base/strings/utf_string_conversions.h" #include "base/test/scoped_feature_list.h" #include "components/autofill/core/browser/autofill_driver.h" -#include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/credit_card.h" @@ -22,6 +21,7 @@ #include "components/autofill/core/browser/test_autofill_driver.h" #include "components/autofill/core/browser/test_personal_data_manager.h" #include "components/autofill/core/common/autofill_constants.h" +#include "components/autofill/core/common/autofill_features.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -47,6 +47,8 @@ class MockAutofillManager : public AutofillManager { const CreditCard& credit_card, const base::string16& cvc)); + using AutofillManager::mutable_form_structures; + private: DISALLOW_COPY_AND_ASSIGN(MockAutofillManager); }; @@ -64,7 +66,8 @@ class AutofillAssistantTest : public testing::Test { autofill_assistant_(&autofill_manager_) {} void EnableAutofillCreditCardAssist() { - scoped_feature_list_.InitAndEnableFeature(kAutofillCreditCardAssist); + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillCreditCardAssist); } // Returns a valid credit card form. @@ -104,8 +107,7 @@ class AutofillAssistantTest : public testing::Test { std::unique_ptr<FormStructure> CreateValidCreditCardForm() { std::unique_ptr<FormStructure> form_structure; form_structure.reset(new FormStructure(CreateValidCreditCardFormData())); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); return form_structure; } @@ -127,23 +129,25 @@ MATCHER_P(CreditCardMatches, guid, "") { TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOff) { std::unique_ptr<FormStructure> form_structure = CreateValidCreditCardForm(); - std::vector<std::unique_ptr<FormStructure>> form_structures; - form_structures.push_back(std::move(form_structure)); - EXPECT_FALSE(autofill_assistant_.CanShowCreditCardAssist(form_structures)); + auto& form_structures = *autofill_manager_.mutable_form_structures(); + auto signature = form_structure->form_signature(); + form_structures[signature] = std::move(form_structure); + EXPECT_FALSE(autofill_assistant_.CanShowCreditCardAssist()); } // Tests that with the feature enabled and proper input, // CanShowCreditCardAssist() behaves as expected. TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn) { EnableAutofillCreditCardAssist(); - std::unique_ptr<FormStructure> form_structure = CreateValidCreditCardForm(); - std::vector<std::unique_ptr<FormStructure>> form_structures; - EXPECT_FALSE(autofill_assistant_.CanShowCreditCardAssist(form_structures)); + EXPECT_FALSE(autofill_assistant_.CanShowCreditCardAssist()); // With valid input, the function extracts the credit card form properly. - form_structures.push_back(std::move(form_structure)); - EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist(form_structures)); + std::unique_ptr<FormStructure> form_structure = CreateValidCreditCardForm(); + auto& form_structures = *autofill_manager_.mutable_form_structures(); + auto signature = form_structure->form_signature(); + form_structures[signature] = std::move(form_structure); + EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist()); } // Tests that with the feature enabled and proper input, @@ -153,13 +157,13 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_Secure) { // Can be shown if the context is secure. FormData form = CreateValidCreditCardFormData(); - std::unique_ptr<FormStructure> form_structure(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + auto form_structure = std::make_unique<FormStructure>(form); + form_structure->DetermineHeuristicTypes(); - std::vector<std::unique_ptr<FormStructure>> form_structures; - form_structures.push_back(std::move(form_structure)); - EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist(form_structures)); + auto& form_structures = *autofill_manager_.mutable_form_structures(); + auto signature = form_structure->form_signature(); + form_structures[signature] = std::move(form_structure); + EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist()); } // Tests that with the feature enabled and proper input, @@ -171,13 +175,13 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_NotSecure) { FormData form = CreateValidCreditCardFormData(); form.origin = GURL("http://myform.com"); form.action = GURL("http://myform.com/submit"); - std::unique_ptr<FormStructure> form_structure(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + auto form_structure = std::make_unique<FormStructure>(form); + form_structure->DetermineHeuristicTypes(); - std::vector<std::unique_ptr<FormStructure>> form_structures; - form_structures.push_back(std::move(form_structure)); - EXPECT_FALSE(autofill_assistant_.CanShowCreditCardAssist(form_structures)); + auto& form_structures = *autofill_manager_.mutable_form_structures(); + auto signature = form_structure->form_signature(); + form_structures[signature] = std::move(form_structure); + EXPECT_FALSE(autofill_assistant_.CanShowCreditCardAssist()); } TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_Javascript) { @@ -187,13 +191,13 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_Javascript) { // function (which is a valid url). FormData form = CreateValidCreditCardFormData(); form.action = GURL("javascript:alert('hello');"); - std::unique_ptr<FormStructure> form_structure(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + auto form_structure = std::make_unique<FormStructure>(form); + form_structure->DetermineHeuristicTypes(); - std::vector<std::unique_ptr<FormStructure>> form_structures; - form_structures.push_back(std::move(form_structure)); - EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist(form_structures)); + auto& form_structures = *autofill_manager_.mutable_form_structures(); + auto signature = form_structure->form_signature(); + form_structures[signature] = std::move(form_structure); + EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist()); } TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_WeirdJs) { @@ -203,13 +207,13 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_WeirdJs) { // function that may or may not be valid. FormData form = CreateValidCreditCardFormData(); form.action = GURL("javascript:myFunc"); - std::unique_ptr<FormStructure> form_structure(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + auto form_structure = std::make_unique<FormStructure>(form); + form_structure->DetermineHeuristicTypes(); - std::vector<std::unique_ptr<FormStructure>> form_structures; - form_structures.push_back(std::move(form_structure)); - EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist(form_structures)); + auto& form_structures = *autofill_manager_.mutable_form_structures(); + auto signature = form_structure->form_signature(); + form_structures[signature] = std::move(form_structure); + EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist()); } TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_EmptyAction) { @@ -218,13 +222,13 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_EmptyAction) { // Can be shown if the context is secure and the form action is empty. FormData form = CreateValidCreditCardFormData(); form.action = GURL(); - std::unique_ptr<FormStructure> form_structure(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + auto form_structure = std::make_unique<FormStructure>(form); + form_structure->DetermineHeuristicTypes(); - std::vector<std::unique_ptr<FormStructure>> form_structures; - form_structures.push_back(std::move(form_structure)); - EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist(form_structures)); + auto& form_structures = *autofill_manager_.mutable_form_structures(); + auto signature = form_structure->form_signature(); + form_structures[signature] = std::move(form_structure); + EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist()); } TEST_F(AutofillAssistantTest, ShowAssistForCreditCard_ValidCard_CancelCvc) { @@ -232,9 +236,10 @@ TEST_F(AutofillAssistantTest, ShowAssistForCreditCard_ValidCard_CancelCvc) { std::unique_ptr<FormStructure> form_structure = CreateValidCreditCardForm(); // Will extract the credit card form data. - std::vector<std::unique_ptr<FormStructure>> form_structures; - form_structures.push_back(std::move(form_structure)); - EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist(form_structures)); + auto& form_structures = *autofill_manager_.mutable_form_structures(); + auto signature = form_structure->form_signature(); + form_structures[signature] = std::move(form_structure); + EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist()); // Create a valid card for the assist. CreditCard card; @@ -255,9 +260,10 @@ TEST_F(AutofillAssistantTest, ShowAssistForCreditCard_ValidCard_SubmitCvc) { std::unique_ptr<FormStructure> form_structure = CreateValidCreditCardForm(); // Will extract the credit card form data. - std::vector<std::unique_ptr<FormStructure>> form_structures; - form_structures.push_back(std::move(form_structure)); - EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist(form_structures)); + auto& form_structures = *autofill_manager_.mutable_form_structures(); + auto signature = form_structure->form_signature(); + form_structures[signature] = std::move(form_structure); + EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist()); // Create a valid card for the assist. CreditCard card; diff --git a/chromium/components/autofill/core/browser/autofill_client.h b/chromium/components/autofill/core/browser/autofill_client.h index d49be23802a..6880d1b07b8 100644 --- a/chromium/components/autofill/core/browser/autofill_client.h +++ b/chromium/components/autofill/core/browser/autofill_client.h @@ -51,6 +51,7 @@ class AutofillWebDataService; class CardUnmaskDelegate; class CreditCard; class FormStructure; +class MigratableCreditCard; class PersonalDataManager; struct Suggestion; @@ -123,8 +124,9 @@ class AutofillClient : public RiskDataLoader { // context if possible, SECURITY_LEVEL_COUNT otherwise. virtual security_state::SecurityLevel GetSecurityLevelForUmaHistograms() = 0; - // Causes the Autofill settings UI to be shown. - virtual void ShowAutofillSettings() = 0; + // Causes the Autofill settings UI to be shown. If |show_credit_card_settings| + // is true, will show the credit card specific subpage. + virtual void ShowAutofillSettings(bool show_credit_card_settings) = 0; // Runs |callback| if the |profile| should be imported as personal data. virtual void ConfirmSaveAutofillProfile(const AutofillProfile& profile, @@ -137,8 +139,18 @@ class AutofillClient : public RiskDataLoader { base::WeakPtr<CardUnmaskDelegate> delegate) = 0; virtual void OnUnmaskVerificationResult(PaymentsRpcResult result) = 0; - // Runs |closure| if the user accepts the migration process. - virtual void ShowLocalCardMigrationPrompt(base::OnceClosure closure) = 0; + // Runs |closure| if the user accepts the card migration offer. This causes + // the card migration dialog to be shown. + virtual void ShowLocalCardMigrationDialog( + base::OnceClosure show_migration_dialog_closure) = 0; + + // Shows a dialog with the given |legal_message|. Runs |closure| if + // the user would like the selected |migratable_credit_cards| to be + // uploaded to cloud. + virtual void ConfirmMigrateLocalCardToCloud( + std::unique_ptr<base::DictionaryValue> legal_message, + std::vector<MigratableCreditCard>& migratable_credit_cards, + base::OnceClosure start_migrating_cards_closure) = 0; // Runs |callback| if the |card| should be imported as personal data. // |metric_logger| can be used to log user actions. diff --git a/chromium/components/autofill/core/browser/autofill_credit_card_policy_handler.cc b/chromium/components/autofill/core/browser/autofill_credit_card_policy_handler.cc index 06b9deec8e9..9a8b1f4606a 100644 --- a/chromium/components/autofill/core/browser/autofill_credit_card_policy_handler.cc +++ b/chromium/components/autofill/core/browser/autofill_credit_card_policy_handler.cc @@ -5,7 +5,7 @@ #include "components/autofill/core/browser/autofill_credit_card_policy_handler.h" #include "base/values.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/policy/core/common/policy_map.h" #include "components/policy/policy_constants.h" #include "components/prefs/pref_value_map.h" @@ -26,10 +26,6 @@ void AutofillCreditCardPolicyHandler::ApplyPolicySettings( if (value && value->GetAsBoolean(&autofill_credit_card_enabled) && !autofill_credit_card_enabled) { prefs->SetBoolean(autofill::prefs::kAutofillCreditCardEnabled, false); - } else { - // Temporary fix for M69. If there is no policy explicitly disabling this - // pref, it should be set to true. - prefs->SetBoolean(autofill::prefs::kAutofillCreditCardEnabled, true); } } diff --git a/chromium/components/autofill/core/browser/autofill_credit_card_policy_handler_unittest.cc b/chromium/components/autofill/core/browser/autofill_credit_card_policy_handler_unittest.cc index 4f548ca1b14..a6bd1013a26 100644 --- a/chromium/components/autofill/core/browser/autofill_credit_card_policy_handler_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_credit_card_policy_handler_unittest.cc @@ -7,7 +7,7 @@ #include <memory> #include "base/values.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/policy/core/common/policy_map.h" #include "components/policy/core/common/policy_types.h" #include "components/policy/policy_constants.h" @@ -24,16 +24,8 @@ TEST_F(AutofillCreditCardPolicyHandlerTest, Default) { PrefValueMap prefs; AutofillCreditCardPolicyHandler handler; handler.ApplyPolicySettings(policy, &prefs); - - // Temporary fix for M69. The pref is enabled by default unless it's disabled - // by policy. - const base::Value* value = nullptr; - ASSERT_TRUE( - prefs.GetValue(autofill::prefs::kAutofillCreditCardEnabled, &value)); - EXPECT_TRUE(value); - bool autofill_credit_card_enabled = false; - ASSERT_TRUE(value->GetAsBoolean(&autofill_credit_card_enabled)); - EXPECT_TRUE(autofill_credit_card_enabled); + EXPECT_FALSE( + prefs.GetValue(autofill::prefs::kAutofillCreditCardEnabled, nullptr)); } TEST_F(AutofillCreditCardPolicyHandlerTest, Enabled) { @@ -46,15 +38,9 @@ TEST_F(AutofillCreditCardPolicyHandlerTest, Enabled) { AutofillCreditCardPolicyHandler handler; handler.ApplyPolicySettings(policy, &prefs); - // Temporary fix for M69. The pref is enabled by default unless it's disabled - // by policy. - const base::Value* value = nullptr; - ASSERT_TRUE( - prefs.GetValue(autofill::prefs::kAutofillCreditCardEnabled, &value)); - EXPECT_TRUE(value); - bool autofill_credit_card_enabled = false; - ASSERT_TRUE(value->GetAsBoolean(&autofill_credit_card_enabled)); - EXPECT_TRUE(autofill_credit_card_enabled); + // Enabling Autofill for credit cards should not set the prefs. + EXPECT_FALSE( + prefs.GetValue(autofill::prefs::kAutofillCreditCardEnabled, nullptr)); } TEST_F(AutofillCreditCardPolicyHandlerTest, Disabled) { @@ -72,10 +58,10 @@ TEST_F(AutofillCreditCardPolicyHandlerTest, Disabled) { EXPECT_TRUE( prefs.GetValue(autofill::prefs::kAutofillCreditCardEnabled, &value)); ASSERT_TRUE(value); - bool autofill_credit_card_enabled = true; - bool result = value->GetAsBoolean(&autofill_credit_card_enabled); + bool autofill_credt_card_enabled = true; + bool result = value->GetAsBoolean(&autofill_credt_card_enabled); ASSERT_TRUE(result); - EXPECT_FALSE(autofill_credit_card_enabled); + EXPECT_FALSE(autofill_credt_card_enabled); } } // namespace autofill
\ No newline at end of file diff --git a/chromium/components/autofill/core/browser/autofill_data_util.cc b/chromium/components/autofill/core/browser/autofill_data_util.cc index 7f2b78b89e0..9bb74de20be 100644 --- a/chromium/components/autofill/core/browser/autofill_data_util.cc +++ b/chromium/components/autofill/core/browser/autofill_data_util.cc @@ -16,6 +16,7 @@ #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/grit/components_scaled_resources.h" #include "components/strings/grit/components_strings.h" #include "third_party/icu/source/common/unicode/uscript.h" @@ -240,6 +241,21 @@ bool SplitCJKName(const std::vector<base::StringPiece16>& name_tokens, } // namespace +std::string TruncateUTF8(const std::string& data) { + std::string trimmed_value; + base::TruncateUTF8ToByteSize(data, AutofillTable::kMaxDataLength, + &trimmed_value); + return trimmed_value; +} + +bool IsCreditCardExpirationType(ServerFieldType type) { + return type == CREDIT_CARD_EXP_MONTH || + type == CREDIT_CARD_EXP_2_DIGIT_YEAR || + type == CREDIT_CARD_EXP_4_DIGIT_YEAR || + type == CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR || + type == CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR; +} + bool IsCJKName(base::StringPiece16 name) { // The name is considered to be a CJK name if it is only CJK characters, // spaces, and "middle dot" separators, with at least one CJK character, and diff --git a/chromium/components/autofill/core/browser/autofill_data_util.h b/chromium/components/autofill/core/browser/autofill_data_util.h index 863b99d54ec..ee3ede76fc8 100644 --- a/chromium/components/autofill/core/browser/autofill_data_util.h +++ b/chromium/components/autofill/core/browser/autofill_data_util.h @@ -9,6 +9,7 @@ #include "base/strings/string16.h" #include "base/strings/string_piece_forward.h" +#include "components/autofill/core/browser/field_types.h" namespace autofill { @@ -22,6 +23,12 @@ struct NameParts { base::string16 family; }; +// Truncates a string to the nearest UTF-8 character that will leave +// the string less than or equal to the specified byte size. +std::string TruncateUTF8(const std::string& data); + +bool IsCreditCardExpirationType(ServerFieldType type); + // Used to map Chrome card issuer networks to Payment Request API basic card // payment spec issuer networks and icons. // https://w3c.github.io/webpayments-methods-card/#method-id diff --git a/chromium/components/autofill/core/browser/autofill_download_manager.cc b/chromium/components/autofill/core/browser/autofill_download_manager.cc index 6c2fa15f626..1903d2e6ea2 100644 --- a/chromium/components/autofill/core/browser/autofill_download_manager.cc +++ b/chromium/components/autofill/core/browser/autofill_download_manager.cc @@ -12,6 +12,8 @@ #include "base/command_line.h" #include "base/location.h" #include "base/logging.h" +#include "base/metrics/field_trial_params.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/numerics/safe_conversions.h" #include "base/rand_util.h" @@ -24,7 +26,6 @@ #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/proto/server.pb.h" #include "components/autofill/core/common/autofill_features.h" -#include "components/autofill/core/common/autofill_pref_names.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/data_use_measurement/core/data_use_user_data.h" #include "components/variations/net/variations_http_headers.h" @@ -42,7 +43,7 @@ namespace autofill { namespace { const size_t kMaxQueryGetSize = 1400; // 1.25KB -const size_t kMaxFormCacheSize = 16; +const size_t kAutofillDownloadManagerMaxFormCacheSize = 16; const size_t kMaxFieldsPerQueryRequest = 100; const net::BackoffEntry::Policy kAutofillBackoffPolicy = { @@ -76,6 +77,9 @@ const char kDefaultAutofillServerURL[] = // Returns the base URL for the autofill server. GURL GetAutofillServerURL() { + // If a valid autofill server URL is specified on the command line, then the + // AutofillDownlaodManager will use it, and assume that server communication + // is enabled. const base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess(); if (command_line.HasSwitch(switches::kAutofillServerURL)) { @@ -83,63 +87,100 @@ GURL GetAutofillServerURL() { if (url.is_valid()) return url; - LOG(ERROR) << "Invalid URL given for --" << switches::kAutofillServerURL - << ". Using default value."; + LOG(ERROR) << "Invalid URL value for --" << switches::kAutofillServerURL + << ": " + << command_line.GetSwitchValueASCII( + switches::kAutofillServerURL); } - GURL default_url(kDefaultAutofillServerURL); - DCHECK(default_url.is_valid()); - return default_url; + // If communication is disabled, leave the autofill server URL unset. + if (!base::FeatureList::IsEnabled(features::kAutofillServerCommunication)) + return GURL(); + + // Server communication is enabled. If there's an autofill server url param + // use it, otherwise use the default. + const std::string autofill_server_url_str = + base::FeatureParam<std::string>(&features::kAutofillServerCommunication, + switches::kAutofillServerURL, + kDefaultAutofillServerURL) + .Get(); + + GURL autofill_server_url(autofill_server_url_str); + + if (!autofill_server_url.is_valid()) { + LOG(ERROR) << "Invalid URL param for " + << features::kAutofillServerCommunication.name << "/" + << switches::kAutofillServerURL << ": " + << autofill_server_url_str; + return GURL(); + } + + return autofill_server_url; } -// Helper to log the HTTP |response_code| received for |request_type| to UMA. -void LogHttpResponseCode(AutofillDownloadManager::RequestType request_type, - int response_code) { - const char* name = nullptr; +// Helper to log the HTTP |response_code| and other data received for +// |request_type| to UMA. +void LogHttpResponseData(AutofillDownloadManager::RequestType request_type, + int response_code, + int net_error, + base::TimeDelta request_duration) { + int response_or_error_code = + (net_error == net::OK || net_error == net::ERR_FAILED) ? response_code + : net_error; switch (request_type) { case AutofillDownloadManager::REQUEST_QUERY: - name = "Autofill.Query.HttpResponseCode"; + base::UmaHistogramSparse("Autofill.Query.HttpResponseOrErrorCode", + response_or_error_code); + UMA_HISTOGRAM_TIMES("Autofill.Query.RequestDuration", request_duration); break; case AutofillDownloadManager::REQUEST_UPLOAD: - name = "Autofill.Upload.HttpResponseCode"; + base::UmaHistogramSparse("Autofill.Upload.HttpResponseOrErrorCode", + response_or_error_code); + UMA_HISTOGRAM_TIMES("Autofill.Upload.RequestDuration", request_duration); break; default: NOTREACHED(); - name = "Autofill.Unknown.HttpResponseCode"; + base::UmaHistogramSparse("Autofill.Unknown.HttpResponseOrErrorCode", + response_or_error_code); + UMA_HISTOGRAM_TIMES("Autofill.Unknown.RequestDuration", request_duration); } - - if (response_code < 100 || response_code > 599) - response_code = 0; - - // An expanded version of UMA_HISTOGRAM_ENUMERATION that supports using - // a different name with each invocation. - base::HistogramBase* histogram = base::LinearHistogram::FactoryGet( - name, 1, 599, 600, base::HistogramBase::kUmaTargetedHistogramFlag); - histogram->Add(response_code); } // Helper to log, to UMA, the |num_bytes| sent for a failing instance of // |request_type|. void LogFailingPayloadSize(AutofillDownloadManager::RequestType request_type, size_t num_bytes) { - const char* name = nullptr; switch (request_type) { case AutofillDownloadManager::REQUEST_QUERY: - name = "Autofill.Query.FailingPayloadSize"; + UMA_HISTOGRAM_COUNTS_100000("Autofill.Query.FailingPayloadSize", + num_bytes); break; case AutofillDownloadManager::REQUEST_UPLOAD: - name = "Autofill.Upload.FailingPayloadSize"; + UMA_HISTOGRAM_COUNTS_100000("Autofill.Upload.FailingPayloadSize", + num_bytes); break; default: NOTREACHED(); - name = "Autofill.Unknown.FailingPayloadSize"; + UMA_HISTOGRAM_COUNTS_100000("Autofill.Unknown.FailingPayloadSize", + num_bytes); } +} - // An expanded version of UMA_HISTOGRAM_COUNTS_100000 that supports using - // a different name with each invocation. - base::HistogramBase* histogram = base::Histogram::FactoryGet( - name, 1, 100000, 50, base::HistogramBase::kUmaTargetedHistogramFlag); - histogram->Add(num_bytes); +// Helper to log, to UMA, the |delay| caused by exponential backoff. +void LogExponentialBackoffDelay( + AutofillDownloadManager::RequestType request_type, + base::TimeDelta delay) { + switch (request_type) { + case AutofillDownloadManager::REQUEST_QUERY: + UMA_HISTOGRAM_MEDIUM_TIMES("Autofill.Query.BackoffDelay", delay); + break; + case AutofillDownloadManager::REQUEST_UPLOAD: + UMA_HISTOGRAM_MEDIUM_TIMES("Autofill.Upload.BackoffDelay", delay); + break; + default: + NOTREACHED(); + UMA_HISTOGRAM_MEDIUM_TIMES("Autofill.Unknown.BackoffDelay", delay); + } } net::NetworkTrafficAnnotationTag GetNetworkTrafficAnnotation( @@ -259,8 +300,11 @@ std::ostream& operator<<(std::ostream& out, for (const auto& field : upload.field()) { out << "\n Field" - << "\n signature: " << field.signature() - << "\n autofill_type: " << field.autofill_type(); + << "\n signature: " << field.signature() << "\n autofill_type: [" + << field.autofill_type(0); + for (int i = 1; i < field.autofill_type_size(); ++i) + out << ", " << field.autofill_type(i); + out << "]"; if (!field.name().empty()) out << "\n name: " << field.name(); if (!field.autocomplete().empty()) @@ -286,7 +330,7 @@ AutofillDownloadManager::AutofillDownloadManager(AutofillDriver* driver, : driver_(driver), observer_(observer), autofill_server_url_(GetAutofillServerURL()), - max_form_cache_size_(kMaxFormCacheSize), + max_form_cache_size_(kAutofillDownloadManagerMaxFormCacheSize), loader_backoff_(&kAutofillBackoffPolicy), weak_factory_(this) { DCHECK(observer_); @@ -296,6 +340,9 @@ AutofillDownloadManager::~AutofillDownloadManager() = default; bool AutofillDownloadManager::StartQueryRequest( const std::vector<FormStructure*>& forms) { + if (!IsEnabled()) + return false; + // Do not send the request if it contains more fields than the server can // accept. if (CountActiveFieldsInForms(forms) > kMaxFieldsPerQueryRequest) @@ -337,6 +384,9 @@ bool AutofillDownloadManager::StartUploadRequest( const ServerFieldTypeSet& available_field_types, const std::string& login_form_signature, bool observed_submission) { + if (!IsEnabled()) + return false; + AutofillUploadContents upload; if (!form.EncodeUploadRequest(available_field_types, form_was_autofilled, login_form_signature, observed_submission, @@ -429,7 +479,7 @@ bool AutofillDownloadManager::StartRequest(FormRequestData request_data) { url_loader_factory.get(), base::BindOnce(&AutofillDownloadManager::OnSimpleLoaderComplete, base::Unretained(this), std::move(--url_loaders_.end()), - std::move(request_data))); + std::move(request_data), base::TimeTicks::Now())); return true; } @@ -488,13 +538,16 @@ std::string AutofillDownloadManager::GetCombinedSignature( void AutofillDownloadManager::OnSimpleLoaderComplete( std::list<std::unique_ptr<network::SimpleURLLoader>>::iterator it, FormRequestData request_data, + base::TimeTicks request_start, std::unique_ptr<std::string> response_body) { // Move the loader out of the active loaders list. std::unique_ptr<network::SimpleURLLoader> simple_loader = std::move(*it); url_loaders_.erase(it); CHECK(request_data.form_signatures.size()); - int response_code = -1; + // net:ERR_FAILED is not an HTTP response code, but if none is available, the + // UMA logging can accept this as a generic fallback as well. + int response_code = net::ERR_FAILED; if (simple_loader->ResponseInfo() && simple_loader->ResponseInfo()->headers) { response_code = simple_loader->ResponseInfo()->headers->response_code(); } @@ -502,7 +555,9 @@ void AutofillDownloadManager::OnSimpleLoaderComplete( const bool success = !!response_body; loader_backoff_.InformOfRequest(success); - LogHttpResponseCode(request_data.request_type, response_code); + LogHttpResponseData(request_data.request_type, response_code, + simple_loader->NetError(), + base::TimeTicks::Now() - request_start); if (!success) { DVLOG(1) << "AutofillDownloadManager: " @@ -519,6 +574,9 @@ void AutofillDownloadManager::OnSimpleLoaderComplete( if (response_code >= 400 && response_code <= 499) return; + base::TimeDelta backoff = loader_backoff_.GetTimeUntilRelease(); + LogExponentialBackoffDelay(request_data.request_type, backoff); + // Reschedule with the appropriate delay, ignoring return value because // payload is already well formed. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( @@ -526,7 +584,7 @@ void AutofillDownloadManager::OnSimpleLoaderComplete( base::BindOnce( base::IgnoreResult(&AutofillDownloadManager::StartRequest), weak_factory_.GetWeakPtr(), std::move(request_data)), - loader_backoff_.GetTimeUntilRelease()); + backoff); return; } diff --git a/chromium/components/autofill/core/browser/autofill_download_manager.h b/chromium/components/autofill/core/browser/autofill_download_manager.h index 675bb0dde30..c1b7b97b837 100644 --- a/chromium/components/autofill/core/browser/autofill_download_manager.h +++ b/chromium/components/autofill/core/browser/autofill_download_manager.h @@ -88,6 +88,9 @@ class AutofillDownloadManager { const std::string& login_form_signature, bool observed_submission); + // Returns true if the autofill server communication is enabled. + bool IsEnabled() const { return autofill_server_url_.is_valid(); } + private: friend class AutofillDownloadManagerTest; FRIEND_TEST_ALL_PREFIXES(AutofillDownloadManagerTest, QueryAndUploadTest); @@ -132,6 +135,7 @@ class AutofillDownloadManager { void OnSimpleLoaderComplete( std::list<std::unique_ptr<network::SimpleURLLoader>>::iterator it, FormRequestData request_data, + base::TimeTicks request_start, std::unique_ptr<std::string> response_body); // The AutofillDriver that this instance will use. Must not be null, and must @@ -144,7 +148,7 @@ class AutofillDownloadManager { // The autofill server URL root: scheme://host[:port]/path excluding the // final path component for the request and the query params. - GURL autofill_server_url_; + const GURL autofill_server_url_; // Loaders used for the processing the requests. Invalidated after completion. std::list<std::unique_ptr<network::SimpleURLLoader>> url_loaders_; diff --git a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc index af9142ea5ac..f0e8e5ed501 100644 --- a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc @@ -18,7 +18,7 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" -#include "base/task_scheduler/post_task.h" +#include "base/task/post_task.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_command_line.h" #include "base/test/scoped_feature_list.h" @@ -281,15 +281,15 @@ TEST_F(AutofillDownloadManagerTest, QueryAndUploadTest) { auto* request = GetPendingRequest(1); test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList( request, responses[1]); - histogram.ExpectBucketCount("Autofill.Upload.HttpResponseCode", net::HTTP_OK, - 1); + histogram.ExpectBucketCount("Autofill.Upload.HttpResponseOrErrorCode", + net::HTTP_OK, 1); // Request 2: Unsuccessful upload. request = GetPendingRequest(2); test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList( request, network::CreateResourceResponseHead(net::HTTP_NOT_FOUND), responses[2], network::URLLoaderCompletionStatus(net::OK)); - histogram.ExpectBucketCount("Autofill.Upload.HttpResponseCode", + histogram.ExpectBucketCount("Autofill.Upload.HttpResponseOrErrorCode", net::HTTP_NOT_FOUND, 1); // Request 0: Successful query. @@ -298,8 +298,8 @@ TEST_F(AutofillDownloadManagerTest, QueryAndUploadTest) { request, responses[0]); EXPECT_EQ(3U, responses_.size()); histogram.ExpectBucketCount("Autofill.Query.WasInCache", CACHE_MISS, 1); - histogram.ExpectBucketCount("Autofill.Query.HttpResponseCode", net::HTTP_OK, - 1); + histogram.ExpectBucketCount("Autofill.Query.HttpResponseOrErrorCode", + net::HTTP_OK, 1); // Check Request 1. EXPECT_EQ(AutofillDownloadManagerTest::UPLOAD_SUCCESSFULL, @@ -346,7 +346,7 @@ TEST_F(AutofillDownloadManagerTest, QueryAndUploadTest) { request, network::CreateResourceResponseHead(net::HTTP_INTERNAL_SERVER_ERROR), responses[0], network::URLLoaderCompletionStatus(net::OK)); - histogram.ExpectBucketCount("Autofill.Query.HttpResponseCode", + histogram.ExpectBucketCount("Autofill.Query.HttpResponseOrErrorCode", net::HTTP_INTERNAL_SERVER_ERROR, 1); // Check Request 4. @@ -465,7 +465,7 @@ TEST_F(AutofillDownloadManagerTest, BackoffLogic_Query) { // There should not be an additional retry. ASSERT_EQ(test_url_loader_factory_.NumPending(), 0); - histogram.ExpectBucketCount("Autofill.Query.HttpResponseCode", + histogram.ExpectBucketCount("Autofill.Query.HttpResponseOrErrorCode", net::HTTP_REQUEST_ENTITY_TOO_LARGE, 1); auto buckets = histogram.GetAllSamples("Autofill.Query.FailingPayloadSize"); ASSERT_EQ(1U, buckets.size()); @@ -550,7 +550,7 @@ TEST_F(AutofillDownloadManagerTest, BackoffLogic_Upload) { network::CreateResourceResponseHead(net::HTTP_REQUEST_ENTITY_TOO_LARGE), "", network::URLLoaderCompletionStatus(net::OK)); ASSERT_EQ(test_url_loader_factory_.NumPending(), 0); - histogram.ExpectBucketCount("Autofill.Upload.HttpResponseCode", + histogram.ExpectBucketCount("Autofill.Upload.HttpResponseOrErrorCode", net::HTTP_REQUEST_ENTITY_TOO_LARGE, 1); auto buckets = histogram.GetAllSamples("Autofill.Upload.FailingPayloadSize"); ASSERT_EQ(1U, buckets.size()); @@ -750,27 +750,60 @@ TEST_F(AutofillDownloadManagerTest, CacheQueryTest) { namespace { -class AutofillQueryTest : public AutofillDownloadManager::Observer, - public testing::Test { +enum ServerCommuncationMode { + DISABLED, + FINCHED_URL, + COMMAND_LINE_URL, + DEFAULT_URL +}; + +class AutofillServerCommunicationTest + : public AutofillDownloadManager::Observer, + public testing::TestWithParam<ServerCommuncationMode> { protected: void SetUp() override { - scoped_feature_list_.InitAndEnableFeature( + testing::TestWithParam<ServerCommuncationMode>::SetUp(); + + scoped_feature_list_1_.InitAndEnableFeature( features::kAutofillCacheQueryResponses); // Setup the server. - server_.RegisterRequestHandler(base::BindRepeating( - &AutofillQueryTest::RequestHandler, base::Unretained(this))); + server_.RegisterRequestHandler( + base::BindRepeating(&AutofillServerCommunicationTest::RequestHandler, + base::Unretained(this))); ASSERT_TRUE(server_.Start()); - scoped_command_line_.GetProcessCommandLine()->AppendSwitchASCII( - switches::kAutofillServerURL, - server_.base_url().Resolve("/tbproxy/af/").spec().c_str()); + GURL autofill_server_url(server_.base_url().Resolve("/tbproxy/af/")); + ASSERT_TRUE(autofill_server_url.is_valid()); // Intialize the autofill driver. shared_url_loader_factory_ = base::MakeRefCounted<network::TestSharedURLLoaderFactory>(); driver_ = std::make_unique<TestAutofillDriver>(); driver_->SetSharedURLLoaderFactory(shared_url_loader_factory_); + + // Configure the autofill server communications channel. + switch (GetParam()) { + case DISABLED: + scoped_feature_list_2_.InitAndDisableFeature( + features::kAutofillServerCommunication); + break; + case FINCHED_URL: + scoped_feature_list_2_.InitAndEnableFeatureWithParameters( + features::kAutofillServerCommunication, + {{switches::kAutofillServerURL, autofill_server_url.spec()}}); + break; + case COMMAND_LINE_URL: + scoped_command_line_.GetProcessCommandLine()->AppendSwitchASCII( + switches::kAutofillServerURL, autofill_server_url.spec()); + FALLTHROUGH; + case DEFAULT_URL: + scoped_feature_list_2_.InitAndEnableFeature( + features::kAutofillServerCommunication); + break; + default: + ASSERT_TRUE(false); + } } void TearDown() override { @@ -786,45 +819,78 @@ class AutofillQueryTest : public AutofillDownloadManager::Observer, run_loop_->QuitWhenIdle(); } + void OnUploadedPossibleFieldTypes() override { + ASSERT_TRUE(run_loop_); + run_loop_->QuitWhenIdle(); + } + std::unique_ptr<HttpResponse> RequestHandler(const HttpRequest& request) { GURL absolute_url = server_.GetURL(request.relative_url); ++call_count_; - if (absolute_url.path() != "/tbproxy/af/query") - return nullptr; + if (absolute_url.path() == "/tbproxy/af/query") { + AutofillQueryResponseContents proto; + proto.add_field()->set_overall_type_prediction(NAME_FIRST); + + auto response = std::make_unique<BasicHttpResponse>(); + response->set_code(net::HTTP_OK); + response->set_content(proto.SerializeAsString()); + response->set_content_type("text/proto"); + response->AddCustomHeader( + "Cache-Control", + base::StringPrintf("max-age=%" PRId64, + base::TimeDelta::FromMilliseconds( + cache_expiration_in_milliseconds_) + .InSeconds())); + return response; + } + + if (absolute_url.path() == "/tbproxy/af/upload") { + auto response = std::make_unique<BasicHttpResponse>(); + response->set_code(net::HTTP_OK); + return response; + } - AutofillQueryResponseContents proto; - proto.add_field()->set_overall_type_prediction(NAME_FIRST); - - auto response = std::make_unique<BasicHttpResponse>(); - response->set_code(net::HTTP_OK); - response->set_content(proto.SerializeAsString()); - response->set_content_type("text/proto"); - response->AddCustomHeader( - "Cache-Control", - base::StringPrintf( - "max-age=%" PRId64, - base::TimeDelta::FromMilliseconds(cache_expiration_in_milliseconds_) - .InSeconds())); - return response; + return nullptr; } - void SendQueryRequest( + bool SendQueryRequest( const std::vector<std::unique_ptr<FormStructure>>& form_structures) { - ASSERT_TRUE(run_loop_ == nullptr); + EXPECT_EQ(run_loop_, nullptr); run_loop_ = std::make_unique<base::RunLoop>(); AutofillDownloadManager download_manager(driver_.get(), this); - ASSERT_TRUE(download_manager.StartQueryRequest( - ToRawPointerVector(form_structures))); - run_loop_->Run(); + bool succeeded = + download_manager.StartQueryRequest(ToRawPointerVector(form_structures)); + if (succeeded) + run_loop_->Run(); run_loop_.reset(); + return succeeded; + } + + bool SendUploadRequest(const FormStructure& form, + bool form_was_autofilled, + const ServerFieldTypeSet& available_field_types, + const std::string& login_form_signature, + bool observed_submission) { + EXPECT_EQ(run_loop_, nullptr); + run_loop_ = std::make_unique<base::RunLoop>(); + + AutofillDownloadManager download_manager(driver_.get(), this); + bool succeeded = download_manager.StartUploadRequest( + form, form_was_autofilled, available_field_types, login_form_signature, + observed_submission); + if (succeeded) + run_loop_->Run(); + run_loop_.reset(); + return succeeded; } base::test::ScopedTaskEnvironment scoped_task_environment_{ base::test::ScopedTaskEnvironment::MainThreadType::IO}; base::test::ScopedCommandLine scoped_command_line_; - base::test::ScopedFeatureList scoped_feature_list_; + base::test::ScopedFeatureList scoped_feature_list_1_; + base::test::ScopedFeatureList scoped_feature_list_2_; EmbeddedTestServer server_; int cache_expiration_in_milliseconds_ = 100000; std::unique_ptr<base::RunLoop> run_loop_; @@ -835,7 +901,61 @@ class AutofillQueryTest : public AutofillDownloadManager::Observer, } // namespace -TEST_F(AutofillQueryTest, CacheableResponse) { +TEST_P(AutofillServerCommunicationTest, IsEnabled) { + AutofillDownloadManager download_manager(driver_.get(), this); + EXPECT_EQ(download_manager.IsEnabled(), GetParam() != DISABLED); +} + +TEST_P(AutofillServerCommunicationTest, Query) { + FormData form; + FormFieldData field; + + field.label = ASCIIToUTF16("First Name:"); + field.name = ASCIIToUTF16("firstname"); + field.form_control_type = "text"; + form.fields.push_back(field); + + std::vector<std::unique_ptr<FormStructure>> form_structures; + form_structures.push_back(std::make_unique<FormStructure>(form)); + + EXPECT_EQ(GetParam() != DISABLED, SendQueryRequest(form_structures)); +} + +TEST_P(AutofillServerCommunicationTest, Upload) { + FormData form; + FormFieldData field; + + field.label = ASCIIToUTF16("First Name:"); + field.name = ASCIIToUTF16("firstname"); + field.form_control_type = "text"; + form.fields.push_back(field); + + field.label = ASCIIToUTF16("Last Name:"); + field.name = ASCIIToUTF16("lastname"); + field.form_control_type = "text"; + form.fields.push_back(field); + + field.label = ASCIIToUTF16("Email:"); + field.name = ASCIIToUTF16("email"); + field.form_control_type = "text"; + form.fields.push_back(field); + + AutofillDownloadManager download_manager(driver_.get(), this); + EXPECT_EQ(GetParam() != DISABLED, + SendUploadRequest(FormStructure(form), true, {}, "", true)); +} + +// Note that we omit DEFAULT_URL from the test params. We don't actually want +// the tests to hit the production server. +INSTANTIATE_TEST_CASE_P(All, + AutofillServerCommunicationTest, + ::testing::Values(DISABLED, + FINCHED_URL, + COMMAND_LINE_URL)); + +using AutofillQueryTest = AutofillServerCommunicationTest; + +TEST_P(AutofillQueryTest, CacheableResponse) { FormFieldData field; field.label = ASCIIToUTF16("First Name:"); field.name = ASCIIToUTF16("firstname"); @@ -852,7 +972,7 @@ TEST_F(AutofillQueryTest, CacheableResponse) { SCOPED_TRACE("First Query"); base::HistogramTester histogram; call_count_ = 0; - ASSERT_NO_FATAL_FAILURE(SendQueryRequest(form_structures)); + ASSERT_TRUE(SendQueryRequest(form_structures)); EXPECT_EQ(1u, call_count_); histogram.ExpectBucketCount("Autofill.ServerQueryResponse", AutofillMetrics::QUERY_SENT, 1); @@ -866,7 +986,7 @@ TEST_F(AutofillQueryTest, CacheableResponse) { SCOPED_TRACE("Second Query"); base::HistogramTester histogram; call_count_ = 0; - ASSERT_NO_FATAL_FAILURE(SendQueryRequest(form_structures)); + ASSERT_TRUE(SendQueryRequest(form_structures)); EXPECT_EQ(0u, call_count_); histogram.ExpectBucketCount("Autofill.ServerQueryResponse", AutofillMetrics::QUERY_SENT, 1); @@ -875,7 +995,7 @@ TEST_F(AutofillQueryTest, CacheableResponse) { } } -TEST_F(AutofillQueryTest, ExpiredCacheInResponse) { +TEST_P(AutofillQueryTest, ExpiredCacheInResponse) { FormFieldData field; field.label = ASCIIToUTF16("First Name:"); field.name = ASCIIToUTF16("firstname"); @@ -895,7 +1015,7 @@ TEST_F(AutofillQueryTest, ExpiredCacheInResponse) { SCOPED_TRACE("First Query"); base::HistogramTester histogram; call_count_ = 0; - ASSERT_NO_FATAL_FAILURE(SendQueryRequest(form_structures)); + ASSERT_TRUE(SendQueryRequest(form_structures)); EXPECT_EQ(1u, call_count_); histogram.ExpectBucketCount("Autofill.ServerQueryResponse", AutofillMetrics::QUERY_SENT, 1); @@ -916,7 +1036,7 @@ TEST_F(AutofillQueryTest, ExpiredCacheInResponse) { SCOPED_TRACE("Second Query"); base::HistogramTester histogram; call_count_ = 0; - ASSERT_NO_FATAL_FAILURE(SendQueryRequest(form_structures)); + ASSERT_TRUE(SendQueryRequest(form_structures)); EXPECT_EQ(1u, call_count_); histogram.ExpectBucketCount("Autofill.ServerQueryResponse", AutofillMetrics::QUERY_SENT, 1); @@ -925,4 +1045,11 @@ TEST_F(AutofillQueryTest, ExpiredCacheInResponse) { } } +// Note that we omit DEFAULT_URL from the test params. We don't actually want +// the tests to hit the production server. We also excluded DISABLED, since +// these tests exercise "enabled" functionality. +INSTANTIATE_TEST_CASE_P(All, + AutofillQueryTest, + ::testing::Values(FINCHED_URL, COMMAND_LINE_URL)); + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_experiments.cc b/chromium/components/autofill/core/browser/autofill_experiments.cc index 35548d3eea4..22d8d06286b 100644 --- a/chromium/components/autofill/core/browser/autofill_experiments.cc +++ b/chromium/components/autofill/core/browser/autofill_experiments.cc @@ -6,6 +6,7 @@ #include "base/command_line.h" #include "base/feature_list.h" +#include "base/metrics/field_trial_params.h" #include "base/strings/string16.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" @@ -13,7 +14,7 @@ #include "build/build_config.h" #include "components/autofill/core/browser/suggestion.h" #include "components/autofill/core/common/autofill_features.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/prefs/pref_service.h" #include "components/strings/grit/components_strings.h" @@ -26,112 +27,41 @@ namespace autofill { -const base::Feature kAutofillAlwaysFillAddresses{ - "AlwaysFillAddresses", base::FEATURE_ENABLED_BY_DEFAULT}; -const base::Feature kAutofillCreateDataForTest{ - "AutofillCreateDataForTest", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kAutofillCreditCardAssist{ - "AutofillCreditCardAssist", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kAutofillScanCardholderName{ - "AutofillScanCardholderName", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kAutofillCreditCardAblationExperiment{ - "AutofillCreditCardAblationExperiment", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kAutofillCreditCardLocalCardMigration{ - "AutofillCreditCardLocalCardMigration", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kAutofillDeleteDisusedAddresses{ - "AutofillDeleteDisusedAddresses", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kAutofillDeleteDisusedCreditCards{ - "AutofillDeleteDisusedCreditCards", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kAutofillExpandedPopupViews{ - "AutofillExpandedPopupViews", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kAutofillPreferServerNamePredictions{ - "AutofillPreferServerNamePredictions", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kAutofillRationalizeFieldTypePredictions{ - "AutofillRationalizeFieldTypePredictions", - base::FEATURE_ENABLED_BY_DEFAULT}; -const base::Feature kAutofillSaveCardDialogUnlabeledExpirationDate{ - "AutofillSaveCardDialogUnlabeledExpirationDate", - base::FEATURE_ENABLED_BY_DEFAULT}; -const base::Feature kAutofillSuggestInvalidProfileData{ - "AutofillSuggestInvalidProfileData", base::FEATURE_ENABLED_BY_DEFAULT}; -const base::Feature kAutofillSuppressDisusedAddresses{ - "AutofillSuppressDisusedAddresses", base::FEATURE_ENABLED_BY_DEFAULT}; -const base::Feature kAutofillSuppressDisusedCreditCards{ - "AutofillSuppressDisusedCreditCards", base::FEATURE_ENABLED_BY_DEFAULT}; -const base::Feature kAutofillUpstream{"AutofillUpstream", - base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kAutofillUpstreamAllowAllEmailDomains{ - "AutofillUpstreamAllowAllEmailDomains", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kAutofillUpstreamAlwaysRequestCardholderName{ - "AutofillUpstreamAlwaysRequestCardholderName", - base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kAutofillUpstreamBlankCardholderNameField{ - "AutofillUpstreamBlankCardholderNameField", - base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kAutofillUpstreamEditableCardholderName{ - "AutofillUpstreamEditableCardholderName", - base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kAutofillUpstreamSendPanFirstSix{ - "AutofillUpstreamSendPanFirstSix", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kAutofillUpstreamUpdatePromptExplanation{ - "AutofillUpstreamUpdatePromptExplanation", - base::FEATURE_ENABLED_BY_DEFAULT}; -const base::Feature kAutofillVoteUsingInvalidProfileData{ - "AutofillVoteUsingInvalidProfileData", base::FEATURE_ENABLED_BY_DEFAULT}; - -const char kCreditCardSigninPromoImpressionLimitParamKey[] = "impression_limit"; - -#if defined(OS_MACOSX) -const base::Feature kMacViewsAutofillPopup{"MacViewsAutofillPopup", - base::FEATURE_ENABLED_BY_DEFAULT}; -#endif // defined(OS_MACOSX) - -bool IsAutofillEnabled(const PrefService* pref_service) { - return pref_service->GetBoolean(prefs::kAutofillEnabled); -} - -bool IsInAutofillSuggestionsDisabledExperiment() { - std::string group_name = - base::FieldTrialList::FindFullName("AutofillEnabled"); - return group_name == "Disabled"; -} - -bool IsAutofillCreditCardAssistEnabled() { -#if !defined(OS_ANDROID) && !defined(OS_IOS) - return false; -#else - return base::FeatureList::IsEnabled(kAutofillCreditCardAssist); -#endif -} - -bool IsAutofillCreditCardLocalCardMigrationExperimentEnabled() { - return base::FeatureList::IsEnabled(kAutofillCreditCardLocalCardMigration); -} - -bool OfferStoreUnmaskedCards() { -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) - // The checkbox can be forced on with a flag, but by default we don't store - // on Linux due to lack of system keychain integration. See crbug.com/162735 - return base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableOfferStoreUnmaskedWalletCards); -#else - // Query the field trial before checking command line flags to ensure UMA - // reports the correct group. - std::string group_name = - base::FieldTrialList::FindFullName("OfferStoreUnmaskedWalletCards"); - - // The checkbox can be forced on or off with flags. - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableOfferStoreUnmaskedWalletCards)) - return true; - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableOfferStoreUnmaskedWalletCards)) - return false; - - // Otherwise use the field trial to show the checkbox or not. - return group_name != "Disabled"; -#endif +#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) +namespace { +// Returns the font weight corresponding to the value of param +// kAutofillForcedFontWeightParameterName, or kDefault if the param is not +// valid. +ForcedFontWeight GetFontWeightFromParam() { + std::string param = base::GetFieldTrialParamValueByFeature( + kAutofillPrimaryInfoStyleExperiment, + kAutofillForcedFontWeightParameterName); + + if (param == kAutofillForcedFontWeightParameterMedium) + return ForcedFontWeight::kMedium; + if (param == kAutofillForcedFontWeightParameterBold) + return ForcedFontWeight::kBold; + + return ForcedFontWeight::kDefault; } +} // namespace +#endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) + +#if !defined(OS_ANDROID) +const base::Feature kAutofillDropdownLayoutExperiment{ + "AutofillDropdownLayout", base::FEATURE_DISABLED_BY_DEFAULT}; +const char kAutofillDropdownLayoutParameterName[] = "variant"; +const char kAutofillDropdownLayoutParameterLeadingIcon[] = "leading-icon"; +const char kAutofillDropdownLayoutParameterTrailingIcon[] = "trailing-icon"; +#endif // !defined(OS_ANDROID) + +#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) +const base::Feature kAutofillPrimaryInfoStyleExperiment{ + "AutofillPrimaryInfoStyleExperiment", base::FEATURE_DISABLED_BY_DEFAULT}; +const char kAutofillForcedFontWeightParameterName[] = "font_weight"; +const char kAutofillForcedFontWeightParameterMedium[] = "medium"; +const char kAutofillForcedFontWeightParameterBold[] = "bold"; +#endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) bool IsCreditCardUploadEnabled(const PrefService* pref_service, const syncer::SyncService* sync_service, @@ -159,70 +89,129 @@ bool IsCreditCardUploadEnabled(const PrefService* pref_service, return false; // Check Payments integration user setting. - if (!pref_service->GetBoolean(prefs::kAutofillWalletImportEnabled)) + if (!prefs::IsPaymentsIntegrationEnabled(pref_service)) return false; // Check that the user is logged into a supported domain. if (user_email.empty()) return false; + std::string domain = gaia::ExtractDomainName(user_email); // If the "allow all email domains" flag is off, restrict credit card upload // only to Google Accounts with @googlemail, @gmail, @google, or @chromium // domains. - if (!base::FeatureList::IsEnabled(kAutofillUpstreamAllowAllEmailDomains) && + if (!base::FeatureList::IsEnabled( + features::kAutofillUpstreamAllowAllEmailDomains) && !(domain == "googlemail.com" || domain == "gmail.com" || domain == "google.com" || domain == "chromium.org")) { return false; } - return base::FeatureList::IsEnabled(kAutofillUpstream); + return base::FeatureList::IsEnabled(features::kAutofillUpstream); } -bool IsAutofillUpstreamAlwaysRequestCardholderNameExperimentEnabled() { - return base::FeatureList::IsEnabled( - kAutofillUpstreamAlwaysRequestCardholderName); +bool IsInAutofillSuggestionsDisabledExperiment() { + std::string group_name = + base::FieldTrialList::FindFullName("AutofillEnabled"); + return group_name == "Disabled"; } -bool IsAutofillUpstreamBlankCardholderNameFieldExperimentEnabled() { - return base::FeatureList::IsEnabled( - kAutofillUpstreamBlankCardholderNameField); +bool IsAutofillCreditCardAssistEnabled() { +#if !defined(OS_ANDROID) && !defined(OS_IOS) + return false; +#else + return base::FeatureList::IsEnabled(features::kAutofillCreditCardAssist); +#endif } -bool IsAutofillUpstreamEditableCardholderNameExperimentEnabled() { - return base::FeatureList::IsEnabled(kAutofillUpstreamEditableCardholderName); +features::LocalCardMigrationExperimentalFlag +GetLocalCardMigrationExperimentalFlag() { + if (!base::FeatureList::IsEnabled( + features::kAutofillCreditCardLocalCardMigration)) + return features::LocalCardMigrationExperimentalFlag::kMigrationDisabled; + + std::string param = base::GetFieldTrialParamValueByFeature( + features::kAutofillCreditCardLocalCardMigration, + features::kAutofillCreditCardLocalCardMigrationParameterName); + + if (param == + features:: + kAutofillCreditCardLocalCardMigrationParameterWithoutSettingsPage) { + return features::LocalCardMigrationExperimentalFlag:: + kMigrationWithoutSettingsPage; + } + return features::LocalCardMigrationExperimentalFlag:: + kMigrationIncludeSettingsPage; } -bool IsAutofillUpstreamSendPanFirstSixExperimentEnabled() { - return base::FeatureList::IsEnabled(kAutofillUpstreamSendPanFirstSix); +bool IsAutofillNoLocalSaveOnUploadSuccessExperimentEnabled() { + return base::FeatureList::IsEnabled( + features::kAutofillNoLocalSaveOnUploadSuccess); } -bool IsAutofillUpstreamUpdatePromptExplanationExperimentEnabled() { - return base::FeatureList::IsEnabled(kAutofillUpstreamUpdatePromptExplanation); -} +bool OfferStoreUnmaskedCards() { +#if defined(OS_LINUX) && !defined(OS_CHROMEOS) + // The checkbox can be forced on with a flag, but by default we don't store + // on Linux due to lack of system keychain integration. See crbug.com/162735 + return base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableOfferStoreUnmaskedWalletCards); +#else + // Query the field trial before checking command line flags to ensure UMA + // reports the correct group. + std::string group_name = + base::FieldTrialList::FindFullName("OfferStoreUnmaskedWalletCards"); -#if defined(OS_MACOSX) -bool IsMacViewsAutofillPopupExperimentEnabled() { -#if BUILDFLAG(MAC_VIEWS_BROWSER) - if (!::features::IsViewsBrowserCocoa()) + // The checkbox can be forced on or off with flags. + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableOfferStoreUnmaskedWalletCards)) return true; + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableOfferStoreUnmaskedWalletCards)) + return false; + + // Otherwise use the field trial to show the checkbox or not. + return group_name != "Disabled"; #endif +} - return base::FeatureList::IsEnabled(kMacViewsAutofillPopup); +bool ShouldUseActiveSignedInAccount() { + // If butter is enabled or the feature to get the Payment Identity from Sync + // is enabled, the account of the active signed-in user should be used. + return base::FeatureList::IsEnabled( + features::kAutofillEnableAccountWalletStorage) || + base::FeatureList::IsEnabled( + features::kAutofillGetPaymentsIdentityFromSync); } -#endif // defined(OS_MACOSX) -bool ShouldUseNativeViews() { -#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) - return base::FeatureList::IsEnabled(kAutofillExpandedPopupViews) || - base::FeatureList::IsEnabled(::features::kExperimentalUi); -#else - return false; -#endif +#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) +ForcedFontWeight GetForcedFontWeight() { + if (!base::FeatureList::IsEnabled(kAutofillPrimaryInfoStyleExperiment)) + return ForcedFontWeight::kDefault; + + // Only read the feature param's value the first time it's needed. + static ForcedFontWeight font_weight_from_param = GetFontWeightFromParam(); + return font_weight_from_param; } +#endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) -bool IsAutofillSaveCardDialogUnlabeledExpirationDateEnabled() { - return base::FeatureList::IsEnabled( - kAutofillSaveCardDialogUnlabeledExpirationDate); +#if !defined(OS_ANDROID) +ForcedPopupLayoutState GetForcedPopupLayoutState() { + if (!base::FeatureList::IsEnabled(kAutofillDropdownLayoutExperiment)) + return ForcedPopupLayoutState::kDefault; + + std::string param = base::GetFieldTrialParamValueByFeature( + kAutofillDropdownLayoutExperiment, kAutofillDropdownLayoutParameterName); + + if (param == kAutofillDropdownLayoutParameterLeadingIcon) { + return ForcedPopupLayoutState::kLeadingIcon; + } else if (param == kAutofillDropdownLayoutParameterTrailingIcon) { + return ForcedPopupLayoutState::kTrailingIcon; + } + + // Unknown parameter value. + NOTREACHED(); + return ForcedPopupLayoutState::kDefault; } +#endif // !defined(OS_ANDROID) } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_experiments.h b/chromium/components/autofill/core/browser/autofill_experiments.h index 7264f45c5fe..7cada16372b 100644 --- a/chromium/components/autofill/core/browser/autofill_experiments.h +++ b/chromium/components/autofill/core/browser/autofill_experiments.h @@ -22,40 +22,27 @@ class SyncService; namespace autofill { -extern const base::Feature kAutofillAlwaysFillAddresses; -extern const base::Feature kAutofillCreateDataForTest; -extern const base::Feature kAutofillCreditCardAssist; -extern const base::Feature kAutofillScanCardholderName; -extern const base::Feature kAutofillCreditCardAblationExperiment; -extern const base::Feature kAutofillCreditCardLocalCardMigration; -extern const base::Feature kAutofillDeleteDisusedAddresses; -extern const base::Feature kAutofillDeleteDisusedCreditCards; -extern const base::Feature kAutofillExpandedPopupViews; -extern const base::Feature kAutofillPreferServerNamePredictions; -extern const base::Feature kAutofillRationalizeFieldTypePredictions; -extern const base::Feature kAutofillSaveCardDialogUnlabeledExpirationDate; -extern const base::Feature kAutofillSuggestInvalidProfileData; -extern const base::Feature kAutofillSuppressDisusedAddresses; -extern const base::Feature kAutofillSuppressDisusedCreditCards; -extern const base::Feature kAutofillUpstream; -extern const base::Feature kAutofillUpstreamAllowAllEmailDomains; -extern const base::Feature kAutofillUpstreamAlwaysRequestCardholderName; -extern const base::Feature kAutofillUpstreamBlankCardholderNameField; -extern const base::Feature kAutofillUpstreamEditableCardholderName; -extern const base::Feature kAutofillUpstreamSendPanFirstSix; -extern const base::Feature kAutofillUpstreamUpdatePromptExplanation; -extern const base::Feature kAutofillVoteUsingInvalidProfileData; -extern const char kCreditCardSigninPromoImpressionLimitParamKey[]; -extern const char kAutofillCreditCardLastUsedDateShowExpirationDateKey[]; -extern const char kAutofillUpstreamMaxMinutesSinceAutofillProfileUseKey[]; - -#if defined(OS_MACOSX) -extern const base::Feature kMacViewsAutofillPopup; -#endif // defined(OS_MACOSX) - -// Returns true if autofill should be enabled. See also -// IsInAutofillSuggestionsDisabledExperiment below. -bool IsAutofillEnabled(const PrefService* pref_service); +// Parameterized Features (grouped with parameter name and options) +#if !defined(OS_ANDROID) +extern const base::Feature kAutofillDropdownLayoutExperiment; +extern const char kAutofillDropdownLayoutParameterName[]; +extern const char kAutofillDropdownLayoutParameterLeadingIcon[]; +extern const char kAutofillDropdownLayoutParameterTrailingIcon[]; +#endif // !defined(OS_ANDROID) + +#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) +extern const base::Feature kAutofillPrimaryInfoStyleExperiment; +extern const char kAutofillForcedFontWeightParameterName[]; +extern const char kAutofillForcedFontWeightParameterMedium[]; +extern const char kAutofillForcedFontWeightParameterBold[]; +#endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) + +// Returns true if uploading credit cards to Wallet servers is enabled. This +// requires the appropriate flags and user settings to be true and the user to +// be a member of a supported domain. +bool IsCreditCardUploadEnabled(const PrefService* pref_service, + const syncer::SyncService* sync_service, + const std::string& user_email); // Returns true if autofill suggestions are disabled via experiment. The // disabled experiment isn't the same as disabling autofill completely since we @@ -66,65 +53,44 @@ bool IsInAutofillSuggestionsDisabledExperiment(); // Returns whether the Autofill credit card assist infobar should be shown. bool IsAutofillCreditCardAssistEnabled(); +// Returns whether locally saving card when credit card upload succeeds should +// be disabled. +bool IsAutofillNoLocalSaveOnUploadSuccessExperimentEnabled(); + // Returns true if the user should be offered to locally store unmasked cards. // This controls whether the option is presented at all rather than the default // response of the option. bool OfferStoreUnmaskedCards(); -// Returns true if uploading credit cards to Wallet servers is enabled. This -// requires the appropriate flags and user settings to be true and the user to -// be a member of a supported domain. -bool IsCreditCardUploadEnabled(const PrefService* pref_service, - const syncer::SyncService* sync_service, - const std::string& user_email); - -// Returns whether Autofill credit card local card migration experiment is -// enabled. -bool IsAutofillCreditCardLocalCardMigrationExperimentEnabled(); - -// For testing purposes; not to be launched. When enabled, Chrome Upstream -// always requests that the user enters/confirms cardholder name in the -// offer-to-save dialog, regardless of if it was present or if the user is a -// Google Payments customer. Note that this will override the detected -// cardholder name, if one was found. -bool IsAutofillUpstreamAlwaysRequestCardholderNameExperimentEnabled(); - -// For experimental purposes; not to be made available in chrome://flags. When -// enabled and Chrome Upstream requests the cardholder name in the offer-to-save -// dialog, the field will be blank instead of being prefilled with the name from -// the user's Google Account. -bool IsAutofillUpstreamBlankCardholderNameFieldExperimentEnabled(); - -// Returns whether the experiment is enabled where Chrome Upstream can request -// the user to enter/confirm cardholder name in the offer-to-save bubble if it -// was not detected or was conflicting during the checkout flow and the user is -// NOT a Google Payments customer. -bool IsAutofillUpstreamEditableCardholderNameExperimentEnabled(); - -// Returns whether the experiment is enabled where Chrome Upstream sends the -// first six digits of the card PAN to Google Payments to help determine whether -// card upload is possible. -bool IsAutofillUpstreamSendPanFirstSixExperimentEnabled(); - -// Returns whether the experiment is enbaled where upstream sends updated -// prompt explanation which changes 'save this card' to 'save your card and -// billing address.' -bool IsAutofillUpstreamUpdatePromptExplanationExperimentEnabled(); - -#if defined(OS_MACOSX) -// Returns true if whether the views autofill popup feature is enabled or the -// we're using the views browser. -bool IsMacViewsAutofillPopupExperimentEnabled(); -#endif // defined(OS_MACOSX) - -// Returns true if the native Views implementation of the Desktop dropdown -// should be used. This will also be true if the kExperimentalUi flag is true, -// which forces a bunch of forthcoming UI changes on. -bool ShouldUseNativeViews(); - -// Returns true if expiration dates on the save card dialog should be -// unlabeled, i.e. not preceded by "Exp." -bool IsAutofillSaveCardDialogUnlabeledExpirationDateEnabled(); +// Returns whether the account of the active signed-in user should be used. +bool ShouldUseActiveSignedInAccount(); + +#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) +enum class ForcedFontWeight { + kDefault, // No change to the font weight. + kMedium, + kBold, +}; + +// Returns the font weight to be used for primary information on the Autofill +// dropdown for Addresses and Credit Cards. Returns kDefault if feature +// kAutofillPrimaryInfoStyleExperiment is disabled or if the corresponding +// feature param is invalid. +ForcedFontWeight GetForcedFontWeight(); +#endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) + +#if !defined(OS_ANDROID) +enum class ForcedPopupLayoutState { + kDefault, // No popup layout forced by experiment. + kLeadingIcon, // Experiment forces leading (left in LTR) icon layout. + kTrailingIcon, // Experiment forces trailing (right in LTR) icon layout. +}; +// Returns kDefault if no experimental behavior is enabled for +// kAutofillDropdownLayoutExperiment; returns kLeftIcon or kRightIcon +// if the experiment param matches kAutofillDropdownLayoutParameterLeadingIcon +// or kAutofillDropdownLayoutParameterTrailingIcon, respectively. +ForcedPopupLayoutState GetForcedPopupLayoutState(); +#endif // !defined(OS_ANDROID) } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc b/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc index 7c8b01dcfd1..724db579a5c 100644 --- a/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc @@ -6,7 +6,8 @@ #include "base/test/scoped_feature_list.h" #include "components/autofill/core/browser/test_sync_service.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/testing_pref_service.h" #include "testing/gtest/include/gtest/gtest.h" @@ -38,68 +39,68 @@ class AutofillExperimentsTest : public testing::Test { }; TEST_F(AutofillExperimentsTest, DenyUpload_FeatureEnabled) { - scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream); + scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); EXPECT_TRUE(IsCreditCardUploadEnabled()); } TEST_F(AutofillExperimentsTest, DenyUpload_FeatureDisabled) { - scoped_feature_list_.InitAndDisableFeature(kAutofillUpstream); + scoped_feature_list_.InitAndDisableFeature(features::kAutofillUpstream); EXPECT_FALSE(IsCreditCardUploadEnabled()); } TEST_F(AutofillExperimentsTest, DenyUpload_SyncServiceCannotStart) { - scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream); + scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); sync_service_.SetDisableReasons( syncer::SyncService::DISABLE_REASON_USER_CHOICE); EXPECT_FALSE(IsCreditCardUploadEnabled()); } TEST_F(AutofillExperimentsTest, DenyUpload_AuthError) { - scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream); + scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); sync_service_.SetInAuthError(true); EXPECT_FALSE(IsCreditCardUploadEnabled()); } TEST_F(AutofillExperimentsTest, DenyUpload_SyncServiceDoesNotHaveAutofillProfilePreferredDataType) { - scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream); + scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); sync_service_.SetDataTypes(syncer::ModelTypeSet()); EXPECT_FALSE(IsCreditCardUploadEnabled()); } TEST_F(AutofillExperimentsTest, DenyUpload_SyncCycleNotComplete) { - scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream); + scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); sync_service_.SetSyncCycleComplete(false); EXPECT_FALSE(IsCreditCardUploadEnabled()); } TEST_F(AutofillExperimentsTest, DenyUpload_SyncConfigurationNotDone) { - scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream); + scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); sync_service_.SetConfigurationDone(false); EXPECT_FALSE(IsCreditCardUploadEnabled()); } TEST_F(AutofillExperimentsTest, DenyUpload_SyncServiceUsingSecondaryPassphrase) { - scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream); + scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); sync_service_.SetIsUsingSecondaryPassphrase(true); EXPECT_FALSE(IsCreditCardUploadEnabled()); } TEST_F(AutofillExperimentsTest, DenyUpload_AutofillWalletImportEnabledPrefIsDisabled) { - scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream); - pref_service_.SetBoolean(prefs::kAutofillWalletImportEnabled, false); + scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); + prefs::SetPaymentsIntegrationEnabled(&pref_service_, false); EXPECT_FALSE(IsCreditCardUploadEnabled()); } TEST_F(AutofillExperimentsTest, DenyUpload_EmptyUserEmail) { - scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream); + scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); EXPECT_FALSE(IsCreditCardUploadEnabled("")); } TEST_F(AutofillExperimentsTest, AllowUpload_UserEmailWithGoogleDomain) { - scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream); + scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); EXPECT_TRUE(IsCreditCardUploadEnabled("john.smith@gmail.com")); EXPECT_TRUE(IsCreditCardUploadEnabled("googler@google.com")); EXPECT_TRUE(IsCreditCardUploadEnabled("old.school@googlemail.com")); @@ -107,7 +108,7 @@ TEST_F(AutofillExperimentsTest, AllowUpload_UserEmailWithGoogleDomain) { } TEST_F(AutofillExperimentsTest, DenyUpload_UserEmailWithNonGoogleDomain) { - scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream); + scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); EXPECT_FALSE(IsCreditCardUploadEnabled("cool.user@hotmail.com")); EXPECT_FALSE(IsCreditCardUploadEnabled("john.smith@johnsmith.com")); EXPECT_FALSE(IsCreditCardUploadEnabled("fake.googler@google.net")); @@ -117,7 +118,9 @@ TEST_F(AutofillExperimentsTest, DenyUpload_UserEmailWithNonGoogleDomain) { TEST_F(AutofillExperimentsTest, AllowUpload_UserEmailWithNonGoogleDomainIfExperimentEnabled) { scoped_feature_list_.InitWithFeatures( - {kAutofillUpstream, kAutofillUpstreamAllowAllEmailDomains}, {}); + {features::kAutofillUpstream, + features::kAutofillUpstreamAllowAllEmailDomains}, + {}); EXPECT_TRUE(IsCreditCardUploadEnabled("cool.user@hotmail.com")); EXPECT_TRUE(IsCreditCardUploadEnabled("john.smith@johnsmith.com")); EXPECT_TRUE(IsCreditCardUploadEnabled("fake.googler@google.net")); diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate.cc b/chromium/components/autofill/core/browser/autofill_external_delegate.cc index aca02c8f337..33184ca396f 100644 --- a/chromium/components/autofill/core/browser/autofill_external_delegate.cc +++ b/chromium/components/autofill/core/browser/autofill_external_delegate.cc @@ -12,13 +12,13 @@ #include "base/command_line.h" #include "base/feature_list.h" #include "base/i18n/case_conversion.h" +#include "base/logging.h" #include "base/stl_util.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "components/autofill/core/browser/autocomplete_history_manager.h" #include "components/autofill/core/browser/autofill_driver.h" -#include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/popup_item_ids.h" @@ -92,7 +92,7 @@ void AutofillExternalDelegate::OnSuggestionsReturned( // go between the values and menu items. Skip this when using the Native Views // implementation, which has its own logic for distinguishing footer rows. // TODO(crbug.com/831603): Remove this when the relevant feature is on 100%. - if (!suggestions.empty() && !autofill::ShouldUseNativeViews()) { + if (!suggestions.empty() && !features::ShouldUseNativeViews()) { suggestions.push_back(Suggestion()); suggestions.back().frontend_id = POPUP_ITEM_ID_SEPARATOR; } @@ -223,7 +223,7 @@ void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value, int position) { if (identifier == POPUP_ITEM_ID_AUTOFILL_OPTIONS) { // User selected 'Autofill Options'. - manager_->ShowAutofillSettings(); + manager_->ShowAutofillSettings(popup_type_ == PopupType::kCreditCards); } else if (identifier == POPUP_ITEM_ID_CLEAR_FORM) { // User selected 'Clear form'. driver_->RendererShouldClearFilledSection(); @@ -404,14 +404,10 @@ void AutofillExternalDelegate::InsertDataListValues( // the list of datalist values. std::set<base::string16> data_list_set(data_list_values_.begin(), data_list_values_.end()); - suggestions->erase( - std::remove_if( - suggestions->begin(), suggestions->end(), - [&data_list_set](const Suggestion& suggestion) { - return suggestion.frontend_id == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY && - base::ContainsKey(data_list_set, suggestion.value); - }), - suggestions->end()); + base::EraseIf(*suggestions, [&data_list_set](const Suggestion& suggestion) { + return suggestion.frontend_id == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY && + base::ContainsKey(data_list_set, suggestion.value); + }); #if !defined(OS_ANDROID) // Insert the separator between the datalist and Autofill/Autocomplete values @@ -434,14 +430,21 @@ void AutofillExternalDelegate::InsertDataListValues( base::string16 AutofillExternalDelegate::GetSettingsSuggestionValue() const { - if (GetPopupType() == PopupType::kAddresses) - return l10n_util::GetStringUTF16(IDS_AUTOFILL_MANAGE_ADDRESSES); + switch (GetPopupType()) { + case PopupType::kAddresses: + return l10n_util::GetStringUTF16(IDS_AUTOFILL_MANAGE_ADDRESSES); - if (GetPopupType() == PopupType::kCreditCards) - return l10n_util::GetStringUTF16(IDS_AUTOFILL_MANAGE_PAYMENT_METHODS); + case PopupType::kCreditCards: + return l10n_util::GetStringUTF16(IDS_AUTOFILL_MANAGE_PAYMENT_METHODS); - DCHECK_EQ(GetPopupType(), PopupType::kPersonalInformation); - return l10n_util::GetStringUTF16(IDS_AUTOFILL_MANAGE); + case PopupType::kPersonalInformation: + case PopupType::kUnspecified: + return l10n_util::GetStringUTF16(IDS_AUTOFILL_MANAGE); + + case PopupType::kPasswords: + NOTREACHED(); + return base::string16(); + } } } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc index e35f340546a..69706bcf006 100644 --- a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc @@ -869,10 +869,10 @@ TEST_F(AutofillExternalDelegateUnitTest, IncludeFooterSeparatorForOldUIOnly) { if (enabled) { scoped_feature_list.InitAndEnableFeature( - autofill::kAutofillExpandedPopupViews); + features::kAutofillExpandedPopupViews); } else { scoped_feature_list.InitAndDisableFeature( - autofill::kAutofillExpandedPopupViews); + features::kAutofillExpandedPopupViews); } IssueOnQuery(kQueryId); diff --git a/chromium/components/autofill/core/browser/autofill_field.cc b/chromium/components/autofill/core/browser/autofill_field.cc index 0d427d70b72..53c47a7ee10 100644 --- a/chromium/components/autofill/core/browser/autofill_field.cc +++ b/chromium/components/autofill/core/browser/autofill_field.cc @@ -10,9 +10,9 @@ #include "base/feature_list.h" #include "base/strings/string_number_conversions.h" -#include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/proto/server.pb.h" +#include "components/autofill/core/common/autofill_features.h" namespace autofill { @@ -28,7 +28,6 @@ AutofillField::AutofillField() only_fill_when_focused_(false), generation_type_(AutofillUploadContents::Field::NO_GENERATION), generated_password_changed_(false), - form_classifier_outcome_(AutofillUploadContents::Field::NO_OUTCOME), vote_type_(AutofillUploadContents::Field::NO_INFORMATION) {} AutofillField::AutofillField(const FormFieldData& field, @@ -47,7 +46,6 @@ AutofillField::AutofillField(const FormFieldData& field, parseable_name_(field.name), generation_type_(AutofillUploadContents::Field::NO_GENERATION), generated_password_changed_(false), - form_classifier_outcome_(AutofillUploadContents::Field::NO_OUTCOME), vote_type_(AutofillUploadContents::Field::NO_INFORMATION) {} AutofillField::~AutofillField() {} @@ -116,7 +114,8 @@ AutofillType AutofillField::ComputedType() const { // it might be better to fix this server-side. // See http://crbug.com/429236 for background. bool believe_server; - if (base::FeatureList::IsEnabled(kAutofillPreferServerNamePredictions)) { + if (base::FeatureList::IsEnabled( + features::kAutofillPreferServerNamePredictions)) { believe_server = true; } else { believe_server = !(server_type_ == NAME_FULL && diff --git a/chromium/components/autofill/core/browser/autofill_field.h b/chromium/components/autofill/core/browser/autofill_field.h index 7b616def23c..50a98cfa48c 100644 --- a/chromium/components/autofill/core/browser/autofill_field.h +++ b/chromium/components/autofill/core/browser/autofill_field.h @@ -133,15 +133,6 @@ class AutofillField : public FormFieldData { return generated_password_changed_; } - void set_form_classifier_outcome( - AutofillUploadContents::Field::FormClassifierOutcome outcome) { - form_classifier_outcome_ = outcome; - } - AutofillUploadContents::Field::FormClassifierOutcome form_classifier_outcome() - const { - return form_classifier_outcome_; - } - void set_vote_type(AutofillUploadContents::Field::VoteType type) { vote_type_ = type; } @@ -220,9 +211,6 @@ class AutofillField : public FormFieldData { // Whether the generated password was changed by user. bool generated_password_changed_; - // The outcome of HTML parsing based form classifier. - AutofillUploadContents::Field::FormClassifierOutcome form_classifier_outcome_; - // The vote type, if the autofill type is USERNAME or any password vote. // Otherwise, the field is ignored. |vote_type_| provides context as to what // triggered the vote. diff --git a/chromium/components/autofill/core/browser/autofill_handler.cc b/chromium/components/autofill/core/browser/autofill_handler.cc index 04c50fa0d53..865ecd43122 100644 --- a/chromium/components/autofill/core/browser/autofill_handler.cc +++ b/chromium/components/autofill/core/browser/autofill_handler.cc @@ -16,7 +16,33 @@ namespace { // Set a conservative upper bound on the number of forms we are willing to // cache, simply to prevent unbounded memory consumption. -const size_t kMaxFormCacheSize = 100; +const size_t kAutofillHandlerMaxFormCacheSize = 100; + +// Returns the AutofillField* corresponding to |field| in |form| or nullptr, +// if not found. +AutofillField* FindAutofillFillField(const FormStructure& form, + const FormFieldData& field) { + for (const auto& cur_field : form) { + if (cur_field->SameFieldAs(field)) { + return cur_field.get(); + } + } + return nullptr; +} + +// Returns true if |live_form| does not match |cached_form|. +bool CachedFormNeedsUpdate(const FormData& live_form, + const FormStructure& cached_form) { + if (live_form.fields.size() != cached_form.field_count()) + return true; + + for (size_t i = 0; i < cached_form.field_count(); ++i) { + if (!cached_form.field(i)->SameFieldAs(live_form.fields[i])) + return true; + } + + return false; +} } // namespace @@ -24,7 +50,7 @@ using base::TimeTicks; AutofillHandler::AutofillHandler(AutofillDriver* driver) : driver_(driver) {} -AutofillHandler::~AutofillHandler() {} +AutofillHandler::~AutofillHandler() = default; void AutofillHandler::OnFormSubmitted(const FormData& form, bool known_success, @@ -47,21 +73,38 @@ void AutofillHandler::OnFormsSeen(const std::vector<FormData>& forms, if (forms.empty()) return; - std::vector<FormStructure*> form_structures; + // Parse each of the forms. Because parsing a given FormData may invalidate + // and replace a form parsed before it (invalidating any pointers we might + // hold) we track the newly created form signatures instead of remembering + // the pointer values. + std::set<FormSignature> new_form_signatures; for (const FormData& form : forms) { const auto parse_form_start_time = TimeTicks::Now(); FormStructure* form_structure = nullptr; if (!ParseForm(form, /*cached_form=*/nullptr, &form_structure)) continue; DCHECK(form_structure); - if (form_structure == nullptr) - continue; - form_structures.push_back(form_structure); + new_form_signatures.insert(form_structure->form_signature()); AutofillMetrics::LogParseFormTiming(TimeTicks::Now() - parse_form_start_time); } - if (!form_structures.empty()) - OnFormsParsed(form_structures, timestamp); + + if (new_form_signatures.empty()) + return; + + // Populate the set of newly created form structures and call the + // OnFormsParsed handler. + std::vector<FormStructure*> new_form_structures; + new_form_structures.reserve(new_form_signatures.size()); + for (auto signature : new_form_signatures) { + FormStructure* form_structure = nullptr; + if (FindCachedForm(signature, &form_structure) && form_structure) { + new_form_structures.push_back(form_structure); + } else { + NOTREACHED(); + } + } + OnFormsParsed(new_form_structures, timestamp); } void AutofillHandler::OnTextFieldDidChange(const FormData& form, @@ -136,47 +179,84 @@ void AutofillHandler::SendFormDataToRenderer( driver_->SendFormDataToRenderer(query_id, action, data); } +bool AutofillHandler::GetCachedFormAndField(const FormData& form, + const FormFieldData& field, + FormStructure** form_structure, + AutofillField** autofill_field) { + // Maybe find an existing FormStructure that corresponds to |form|. + FormStructure* cached_form = nullptr; + if (FindCachedForm(form, &cached_form)) { + DCHECK(cached_form); + if (!CachedFormNeedsUpdate(form, *cached_form)) { + // There is no data to return if there are no auto-fillable fields. + if (!cached_form->autofill_count()) + return false; + + // Return the cached form and matching field, if any. + *form_structure = cached_form; + *autofill_field = FindAutofillFillField(**form_structure, field); + return *autofill_field != nullptr; + } + } + + // The form is new or updated, parse it and discard |cached_form|. + // i.e., |cached_form| is no longer valid after this call. + if (!ParseForm(form, std::move(cached_form), form_structure)) + return false; + + // Annotate the updated form with its predicted types. + driver()->SendAutofillTypePredictionsToRenderer({*form_structure}); + + // There is no data to return if there are no auto-fillable fields. + if (!(*form_structure)->autofill_count()) + return false; + + // Find the AutofillField that corresponds to |field|. + *autofill_field = FindAutofillFillField(**form_structure, field); + return *autofill_field != nullptr; +} + +bool AutofillHandler::FindCachedForm(FormSignature form_signature, + FormStructure** form_structure) const { + auto it = form_structures_.find(form_signature); + if (it != form_structures_.end()) { + *form_structure = it->second.get(); + return true; + } + return false; +} + bool AutofillHandler::FindCachedForm(const FormData& form, FormStructure** form_structure) const { // Find the FormStructure that corresponds to |form|. - // Scan backward through the cached |form_structures_|, as updated versions of - // forms are added to the back of the list, whereas original versions of these - // forms might appear toward the beginning of the list. The communication - // protocol with the crowdsourcing server does not permit us to discard the - // original versions of the forms. - *form_structure = nullptr; - const auto& form_signature = autofill::CalculateFormSignature(form); - for (auto& cur_form : base::Reversed(form_structures_)) { - if (cur_form->form_signature() == form_signature || *cur_form == form) { - *form_structure = cur_form.get(); - - // The same form might be cached with multiple field counts: in some - // cases, non-autofillable fields are filtered out, whereas in other cases - // they are not. To avoid thrashing the cache, keep scanning until we - // find a cached version with the same number of fields, if there is one. - if (cur_form->field_count() == form.fields.size()) - break; + if (FindCachedForm(autofill::CalculateFormSignature(form), form_structure)) + return true; + + // The form might have been modified by JavaScript which resulted in a change + // of form signature. Compare it to all the forms in the cache to look for a + // match. + for (const auto& it : form_structures_) { + if (*it.second == form) { + *form_structure = it.second.get(); + return true; } } - if (!(*form_structure)) - return false; - - return true; + *form_structure = nullptr; + return false; } bool AutofillHandler::ParseForm(const FormData& form, const FormStructure* cached_form, FormStructure** parsed_form_structure) { DCHECK(parsed_form_structure); - if (form_structures_.size() >= kMaxFormCacheSize) + if (form_structures_.size() >= kAutofillHandlerMaxFormCacheSize) return false; auto form_structure = std::make_unique<FormStructure>(form); form_structure->ParseFieldTypesFromAutocompleteAttributes(); - if (!form_structure->ShouldBeParsed()) { + if (!form_structure->ShouldBeParsed()) return false; - } if (cached_form) { // We need to keep the server data if available. We need to use them while @@ -186,12 +266,20 @@ bool AutofillHandler::ParseForm(const FormData& form, /*only_server_and_autofill_state=*/true); } + form_structure->DetermineHeuristicTypes(); + + // Hold the parsed_form_structure we intend to return. We can use this to + // reference the form_signature when transferring ownership below. + *parsed_form_structure = form_structure.get(); + // Ownership is transferred to |form_structures_| which maintains it until - // the manager is Reset() or destroyed. It is safe to use references below - // as long as receivers don't take ownership. - form_structure->set_form_parsed_timestamp(TimeTicks::Now()); - form_structures_.push_back(std::move(form_structure)); - *parsed_form_structure = form_structures_.back().get(); + // the form is parsed again or the AutofillHandler is destroyed. + // + // Note that this insert/update takes ownership of the new form structure + // and also destroys the previously cached form structure. + form_structures_[(*parsed_form_structure)->form_signature()] = + std::move(form_structure); + return true; } diff --git a/chromium/components/autofill/core/browser/autofill_handler.h b/chromium/components/autofill/core/browser/autofill_handler.h index 74e76a5fa77..f228eaff880 100644 --- a/chromium/components/autofill/core/browser/autofill_handler.h +++ b/chromium/components/autofill/core/browser/autofill_handler.h @@ -5,14 +5,16 @@ #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_HANDLER_H_ #define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_HANDLER_H_ +#include <map> +#include <memory> #include <string> -#include <vector> #include "base/compiler_specific.h" #include "base/time/time.h" #include "build/build_config.h" #include "components/autofill/core/browser/autofill_driver.h" #include "components/autofill/core/common/form_data.h" +#include "components/autofill/core/common/signatures_util.h" #include "components/autofill/core/common/submission_source.h" namespace gfx { @@ -21,6 +23,7 @@ class RectF; namespace autofill { +class AutofillField; struct FormData; struct FormFieldData; class FormStructure; @@ -34,6 +37,9 @@ class AutofillHandler { DISABLE_AUTOFILL_DOWNLOAD_MANAGER, }; + using FormStructureMap = + std::map<FormSignature, std::unique_ptr<FormStructure>>; + virtual ~AutofillHandler(); // Invoked when the value of textfield is changed. @@ -109,13 +115,20 @@ class AutofillHandler { AutofillDriver::RendererFormDataAction action, const FormData& data); + // Fills |form_structure| and |autofill_field| with the cached elements + // corresponding to |form| and |field|. This might have the side-effect of + // updating the cache. Returns false if the |form| is not autofillable, or if + // it is not already present in the cache and the cache is full. + bool GetCachedFormAndField(const FormData& form, + const FormFieldData& field, + FormStructure** form_structure, + AutofillField** autofill_field) WARN_UNUSED_RESULT; + // Returns the number of forms this Autofill handler is aware of. size_t NumFormsDetected() const { return form_structures_.size(); } // Returns the present form structures seen by Autofill handler. - const std::vector<std::unique_ptr<FormStructure>>& form_structures() { - return form_structures_; - } + const FormStructureMap& form_structures() const { return form_structures_; } protected: AutofillHandler(AutofillDriver* driver); @@ -158,17 +171,19 @@ class AutofillHandler { virtual void OnFormsParsed(const std::vector<FormStructure*>& form_structures, const base::TimeTicks timestamp) = 0; - AutofillDriver* driver() { return driver_; } + // Fills |form_structure| with a pointer to the cached form structure + // corresponding to |form_signature|. Returns false if no cached form + // structure is found with a matching signature. + bool FindCachedForm(FormSignature form_signature, + FormStructure** form_structure) const WARN_UNUSED_RESULT; - // Fills |form_structure| cached element corresponding to |form|. - // Returns false if the cached element was not found. + // Fills |form_structure| with a pointer to the cached form structure + // corresponding to |form|. This will do a direct match of the form's + // signature as well as fuzzy match of the forms structure if no directly + // matching form signature is found. Returns false if no match is found. bool FindCachedForm(const FormData& form, FormStructure** form_structure) const WARN_UNUSED_RESULT; - std::vector<std::unique_ptr<FormStructure>>* mutable_form_structures() { - return &form_structures_; - } - // Parses the |form| with the server data retrieved from the |cached_form| // (if any), and writes it to the |parse_form_structure|. Adds the // |parse_form_structure| to the |form_structures_|. Returns true if the form @@ -177,13 +192,17 @@ class AutofillHandler { const FormStructure* cached_form, FormStructure** parsed_form_structure); - private: - // Our copy of the form data. - std::vector<std::unique_ptr<FormStructure>> form_structures_; + AutofillDriver* driver() { return driver_; } + + FormStructureMap* mutable_form_structures() { return &form_structures_; } + private: // Provides driver-level context to the shared code of the component. Must // outlive this object. - AutofillDriver* driver_; + AutofillDriver* const driver_; + + // Our copy of the form data. + FormStructureMap form_structures_; DISALLOW_COPY_AND_ASSIGN(AutofillHandler); }; diff --git a/chromium/components/autofill/core/browser/autofill_handler_proxy.cc b/chromium/components/autofill/core/browser/autofill_handler_proxy.cc index 1f6cc73f3ac..7ed1e4e63eb 100644 --- a/chromium/components/autofill/core/browser/autofill_handler_proxy.cc +++ b/chromium/components/autofill/core/browser/autofill_handler_proxy.cc @@ -65,8 +65,9 @@ void AutofillHandlerProxy::OnSelectControlDidChangeImpl( bool AutofillHandlerProxy::ShouldParseForms(const std::vector<FormData>& forms, const base::TimeTicks timestamp) { provider_->OnFormsSeen(this, forms, timestamp); - // Don't use form_structure. - return false; + // Need to parse the |forms| to FormStructure, so heuristic_type can be + // retrieved later. + return true; } void AutofillHandlerProxy::OnFormsParsed( diff --git a/chromium/components/autofill/core/browser/autofill_manager.cc b/chromium/components/autofill/core/browser/autofill_manager.cc index 34026869008..a83084e922b 100644 --- a/chromium/components/autofill/core/browser/autofill_manager.cc +++ b/chromium/components/autofill/core/browser/autofill_manager.cc @@ -32,13 +32,13 @@ #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" -#include "base/task_scheduler/post_task.h" +#include "base/task/post_task.h" #include "base/threading/thread_restrictions.h" #include "build/build_config.h" #include "components/autofill/core/browser/autocomplete_history_manager.h" #include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/autofill_data_model.h" -#include "components/autofill/core/browser/autofill_experiments.h" +#include "components/autofill/core/browser/autofill_data_util.h" #include "components/autofill/core/browser/autofill_external_delegate.h" #include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/autofill_manager_test_delegate.h" @@ -59,7 +59,7 @@ #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_data_validation.h" #include "components/autofill/core/common/autofill_features.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/autofill_util.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_data_predictions.h" @@ -151,12 +151,17 @@ void SelectRightNameType(const ServerFieldTypeSet& old_types, } } -bool IsCreditCardExpirationType(ServerFieldType type) { - return type == CREDIT_CARD_EXP_MONTH || - type == CREDIT_CARD_EXP_2_DIGIT_YEAR || - type == CREDIT_CARD_EXP_4_DIGIT_YEAR || - type == CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR || - type == CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR; +void LogDeveloperEngagementUkm(ukm::UkmRecorder* ukm_recorder, + ukm::SourceId source_id, + FormStructure* form_structure) { + if (form_structure->developer_engagement_metrics()) { + AutofillMetrics::LogDeveloperEngagementUkm( + ukm_recorder, source_id, form_structure->main_frame_origin().GetURL(), + form_structure->IsCompleteCreditCardForm(), + form_structure->GetFormTypes(), + form_structure->developer_engagement_metrics(), + form_structure->form_signature()); + } } } // namespace @@ -178,41 +183,6 @@ AutofillManager::AutofillManager( AutofillManager::~AutofillManager() {} -// static -void AutofillManager::RegisterProfilePrefs( - user_prefs::PrefRegistrySyncable* registry) { - registry->RegisterDoublePref( - prefs::kAutofillBillingCustomerNumber, 0.0, - user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); - // This pref is not synced because it's for a signin promo, which by - // definition will not be synced. - registry->RegisterIntegerPref( - prefs::kAutofillCreditCardSigninPromoImpressionCount, 0); - registry->RegisterBooleanPref( - prefs::kAutofillEnabled, true, - user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); - registry->RegisterBooleanPref( - prefs::kAutofillProfileEnabled, true, - user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); - registry->RegisterIntegerPref( - prefs::kAutofillLastVersionDeduped, 0, - user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); - registry->RegisterIntegerPref( - prefs::kAutofillLastVersionDisusedAddressesDeleted, 0, - user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); - // These choices are made on a per-device basis, so they're not syncable. - registry->RegisterBooleanPref(prefs::kAutofillWalletImportEnabled, true); - registry->RegisterBooleanPref( - prefs::kAutofillWalletImportStorageCheckboxState, true); - registry->RegisterIntegerPref( - prefs::kAutofillAcceptSaveCreditCardPromptState, - prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_NONE); - registry->RegisterIntegerPref( - prefs::kAutofillLastVersionDisusedCreditCardsDeleted, 0); - registry->RegisterBooleanPref(prefs::kAutofillCreditCardEnabled, true); - registry->RegisterBooleanPref(prefs::kAutofillOrphanRowsRemoved, false); -} - void AutofillManager::SetExternalDelegate(AutofillExternalDelegate* delegate) { // TODO(jrg): consider passing delegate into the ctor. That won't // work if the delegate has a pointer to the AutofillManager, but @@ -221,8 +191,8 @@ void AutofillManager::SetExternalDelegate(AutofillExternalDelegate* delegate) { autocomplete_history_manager_->SetExternalDelegate(delegate); } -void AutofillManager::ShowAutofillSettings() { - client_->ShowAutofillSettings(); +void AutofillManager::ShowAutofillSettings(bool show_credit_card_settings) { + client_->ShowAutofillSettings(show_credit_card_settings); } bool AutofillManager::ShouldShowScanCreditCard(const FormData& form, @@ -241,7 +211,7 @@ bool AutofillManager::ShouldShowScanCreditCard(const FormData& form, bool is_scannable_name_on_card_field = autofill_field->Type().GetStorableType() == CREDIT_CARD_NAME_FULL && - base::FeatureList::IsEnabled(kAutofillScanCardholderName); + base::FeatureList::IsEnabled(features::kAutofillScanCardholderName); if (!is_card_number_field && !is_scannable_name_on_card_field) return false; @@ -426,7 +396,7 @@ bool AutofillManager::MaybeStartVoteUploadProcess( FormStructure* raw_form = form_structure.get(); TimeTicks loaded_timestamp = forms_loaded_timestamps_[raw_form->ToFormData()]; base::PostTaskWithTraitsAndReply( - FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND}, + FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, base::BindOnce(&AutofillManager::DeterminePossibleFieldTypesForUpload, copied_profiles, copied_credit_cards, app_locale_, raw_form), @@ -566,7 +536,7 @@ void AutofillManager::OnQueryFormFieldAutofillImpl( if (suggestions.empty() && !ShouldShowCreditCardSigninPromo(form, field) && field.should_autocomplete && !(context.focused_field && - (IsCreditCardExpirationType( + (autofill::data_util::IsCreditCardExpirationType( context.focused_field->Type().GetStorableType()) || context.focused_field->Type().html_type() == HTML_TYPE_UNRECOGNIZED || context.focused_field->Type().GetStorableType() == @@ -949,29 +919,29 @@ void AutofillManager::SelectFieldOptionsDidChange(const FormData& form) { FormStructure* cached_form = nullptr; ignore_result(FindCachedForm(form, &cached_form)); - if (!ParseFormInternal(form, cached_form, &form_structure)) + if (!ParseForm(form, cached_form, &form_structure)) return; if (ShouldTriggerRefill(*form_structure)) - TriggerRefill(form, form_structure); + TriggerRefill(form); } void AutofillManager::OnLoadedServerPredictions( std::string response, const std::vector<std::string>& form_signatures) { - // We obtain the current valid FormStructures represented by - // |form_signatures|. We invert both lists because most recent forms are at - // the end of the list (and reverse the resulting pointer vector). + // Get the current valid FormStructures represented by |form_signatures|. std::vector<FormStructure*> queried_forms; - for (const std::string& signature : base::Reversed(form_signatures)) { - for (auto& cur_form : base::Reversed(form_structures())) { - if (cur_form->FormSignatureAsStr() == signature) { - queried_forms.push_back(cur_form.get()); - break; - } + queried_forms.reserve(form_signatures.size()); + for (const std::string& signature : form_signatures) { + // The |signature| is the direct string representation of the FormSignature. + // Convert it to a uint64_t to do the lookup. + FormSignature form_signature; + FormStructure* form_structure; + if (base::StringToUint64(signature, &form_signature) && + FindCachedForm(form_signature, &form_structure)) { + queried_forms.push_back(form_structure); } } - std::reverse(queried_forms.begin(), queried_forms.end()); // If there are no current forms corresponding to the queried signatures, drop // the query response. @@ -1041,17 +1011,17 @@ void AutofillManager::OnDidEndTextFieldEditing() { } bool AutofillManager::IsAutofillEnabled() const { - return ::autofill::IsAutofillEnabled(client_->GetPrefs()) && + return ::autofill::prefs::IsAutofillEnabled(client_->GetPrefs()) && client_->IsAutofillSupported(); } bool AutofillManager::IsProfileAutofillEnabled() const { - return client_->GetPrefs()->GetBoolean(prefs::kAutofillProfileEnabled) && + return ::autofill::prefs::IsProfileAutofillEnabled(client_->GetPrefs()) && client_->IsAutofillSupported(); } bool AutofillManager::IsCreditCardAutofillEnabled() const { - return client_->GetPrefs()->GetBoolean(prefs::kAutofillCreditCardEnabled) && + return ::autofill::prefs::IsCreditCardAutofillEnabled(client_->GetPrefs()) && client_->IsAutofillSupported(); } @@ -1151,10 +1121,7 @@ AutofillManager::AutofillManager( driver->GetURLLoaderFactory(), client->GetPrefs(), client->GetIdentityManager(), - /*unmask_delegate=*/this, - // save_delegate starts out as nullptr and is set up by the - // CreditCardSaveManager owned by form_data_importer_. - /*save_delegate=*/nullptr, + client->GetPersonalDataManager(), driver->IsIncognito())), app_locale_(app_locale), personal_data_(personal_data), @@ -1278,7 +1245,8 @@ void AutofillManager::FillOrPreviewDataModelForm( FormData result = form; - if (base::FeatureList::IsEnabled(kAutofillRationalizeFieldTypePredictions)) { + if (base::FeatureList::IsEnabled( + features::kAutofillRationalizeFieldTypePredictions)) { form_structure->RationalizePhoneNumbersInSection(autofill_field->section); } @@ -1345,7 +1313,8 @@ void AutofillManager::FillOrPreviewDataModelForm( } // Don't fill expired cards expiration date. - if (IsCreditCardExpirationType(cached_field->Type().GetStorableType()) && + if (data_util::IsCreditCardExpirationType( + cached_field->Type().GetStorableType()) && static_cast<const CreditCard*>(&data_model) ->IsExpired(AutofillClock::Now())) { continue; @@ -1391,59 +1360,21 @@ void AutofillManager::FillOrPreviewDataModelForm( std::unique_ptr<FormStructure> AutofillManager::ValidateSubmittedForm( const FormData& form) { - std::unique_ptr<FormStructure> submitted_form( - std::make_unique<FormStructure>(form)); - if (!ShouldUploadForm(*submitted_form)) - return std::unique_ptr<FormStructure>(); - // Ignore forms not present in our cache. These are typically forms with // wonky JavaScript that also makes them not auto-fillable. FormStructure* cached_submitted_form; - if (!FindCachedForm(form, &cached_submitted_form)) - return std::unique_ptr<FormStructure>(); + if (!FindCachedForm(form, &cached_submitted_form) || + !ShouldUploadForm(*cached_submitted_form)) { + return nullptr; + } + auto submitted_form = std::make_unique<FormStructure>(form); submitted_form->RetrieveFromCache(*cached_submitted_form, /*apply_is_autofilled=*/false, /*only_server_and_autofill_state=*/false); return submitted_form; } -bool AutofillManager::GetCachedFormAndField(const FormData& form, - const FormFieldData& field, - FormStructure** form_structure, - AutofillField** autofill_field) { - // Find the FormStructure that corresponds to |form|. - // If we do not have this form in our cache but it is parseable, we'll add it - // in the call to |UpdateCachedForm()|. - if (!FindCachedForm(form, form_structure) && - !FormStructure(form).ShouldBeParsed()) { - return false; - } - - // Update the cached form to reflect any dynamic changes to the form data, if - // necessary. - if (!UpdateCachedForm(form, *form_structure, form_structure)) - return false; - - // No data to return if there are no auto-fillable fields. - if (!(*form_structure)->autofill_count()) - return false; - - // Find the AutofillField that corresponds to |field|. - *autofill_field = nullptr; - for (const auto& current : **form_structure) { - if (current->SameFieldAs(field)) { - *autofill_field = current.get(); - break; - } - } - - // Even though we always update the cache, the field might not exist if the - // website disables autocomplete while the user is interacting with the form. - // See http://crbug.com/160476 - return *autofill_field != nullptr; -} - AutofillField* AutofillManager::GetAutofillField(const FormData& form, const FormFieldData& field) { if (!personal_data_) @@ -1472,29 +1403,6 @@ bool AutofillManager::FormHasAddressField(const FormData& form) { return false; } -bool AutofillManager::UpdateCachedForm(const FormData& live_form, - const FormStructure* cached_form, - FormStructure** updated_form) { - bool needs_update = - (!cached_form || live_form.fields.size() != cached_form->field_count()); - for (size_t i = 0; !needs_update && i < cached_form->field_count(); ++i) - needs_update = !cached_form->field(i)->SameFieldAs(live_form.fields[i]); - - if (!needs_update) - return true; - - // Note: We _must not_ remove the original version of the cached form from - // the list of |form_structures_|. Otherwise, we break parsing of the - // crowdsourcing server's response to our query. - if (!ParseFormInternal(live_form, cached_form, updated_form)) - return false; - - // Annotate the updated form with its predicted types. - driver()->SendAutofillTypePredictionsToRenderer({*updated_form}); - - return true; -} - std::vector<Suggestion> AutofillManager::GetProfileSuggestions( const FormStructure& form, const FormFieldData& field, @@ -1574,8 +1482,10 @@ void AutofillManager::OnFormsParsed( std::vector<FormStructure*> queryable_forms; std::set<FormType> form_types; for (FormStructure* form_structure : form_structures) { - form_structure->DetermineHeuristicTypes(client_->GetUkmRecorder(), - client_->GetUkmSourceId()); + // TODO(crbug.com/869482): avoid logging developer engagement multiple + // times for a given form if it or other forms on the page are dynamic. + LogDeveloperEngagementUkm(client_->GetUkmRecorder(), + client_->GetUkmSourceId(), form_structure); forms_loaded_timestamps_[form_structure->ToFormData()] = timestamp; std::set<FormType> current_form_types = form_structure->GetFormTypes(); form_types.insert(current_form_types.begin(), current_form_types.end()); @@ -1600,13 +1510,13 @@ void AutofillManager::OnFormsParsed( if (filling_context->on_refill_timer.IsRunning()) filling_context->on_refill_timer.AbandonAndStop(); - // Can TriggerRefill get FormData from FormStructure? + // Start a new timer to trigger refill. filling_context->on_refill_timer.Start( FROM_HERE, base::TimeDelta::FromMilliseconds(kWaitTimeForDynamicFormsMs), base::BindRepeating(&AutofillManager::TriggerRefill, weak_ptr_factory_.GetWeakPtr(), - form_structure->ToFormData(), form_structure)); + form_structure->ToFormData())); } } @@ -1628,8 +1538,7 @@ void AutofillManager::OnFormsParsed( // prompt for credit card assisted filling. Upon accepting the infobar, the // form will automatically be filled with the user's information through this // class' FillCreditCardForm(). - if (autofill_assistant_.CanShowCreditCardAssist( - AutofillHandler::form_structures())) { + if (autofill_assistant_.CanShowCreditCardAssist()) { const std::vector<CreditCard*> cards = personal_data_->GetCreditCardsToSuggest( client_->AreServerCardsSupported()); @@ -1652,18 +1561,6 @@ void AutofillManager::OnFormsParsed( } } -bool AutofillManager::ParseFormInternal(const FormData& form, - const FormStructure* cached_form, - FormStructure** parsed_form_structure) { - if (ParseForm(form, cached_form, parsed_form_structure)) { - (*parsed_form_structure) - ->DetermineHeuristicTypes(client_->GetUkmRecorder(), - client_->GetUkmSourceId()); - return true; - } - return false; -} - int AutofillManager::BackendIDToInt(const std::string& backend_id) const { if (!base::IsValidGUID(backend_id)) return 0; @@ -1955,8 +1852,13 @@ bool AutofillManager::ShouldTriggerRefill(const FormStructure& form_structure) { delta.InMilliseconds() < kLimitBeforeRefillMs; } -void AutofillManager::TriggerRefill(const FormData& form, - FormStructure* form_structure) { +void AutofillManager::TriggerRefill(const FormData& form) { + FormStructure* form_structure = nullptr; + if (!FindCachedForm(form, &form_structure)) + return; + + DCHECK(form_structure); + address_form_event_logger_->OnDidRefill(); auto itr = @@ -1964,7 +1866,12 @@ void AutofillManager::TriggerRefill(const FormData& form, DCHECK(itr != filling_contexts_map_.end()); FillingContext* filling_context = itr->second.get(); - DCHECK(!filling_context->attempted_refill); + // The refill attempt can happen from different paths, some of which happen + // after waiting for a while. Therefore, although this condition has been + // checked prior to calling TriggerRefill, it may not hold, when we get here. + if (filling_context->attempted_refill) + return; + filling_context->attempted_refill = true; // Try to find the field from which the original field originated. @@ -2037,7 +1944,8 @@ void AutofillManager::GetAvailableSuggestions( &context->is_all_server_suggestions); // Logic for disabling/ablating credit card autofill. - if (base::FeatureList::IsEnabled(kAutofillCreditCardAblationExperiment) && + if (base::FeatureList::IsEnabled( + features::kAutofillCreditCardAblationExperiment) && !suggestions->empty()) { context->suppress_reason = SuppressReason::kCreditCardsAblation; suggestions->clear(); @@ -2047,7 +1955,7 @@ void AutofillManager::GetAvailableSuggestions( // On desktop, don't return non credit card related suggestions for forms or // fields that have the "autocomplete" attribute set to off, only if the // feature to always fill addresses is off. - if (!base::FeatureList::IsEnabled(kAutofillAlwaysFillAddresses) && + if (!base::FeatureList::IsEnabled(features::kAutofillAlwaysFillAddresses) && IsDesktopPlatform() && !field.should_autocomplete) { context->suppress_reason = SuppressReason::kAutocompleteOff; return; diff --git a/chromium/components/autofill/core/browser/autofill_manager.h b/chromium/components/autofill/core/browser/autofill_manager.h index eda55e319c2..2b7feeb4dc9 100644 --- a/chromium/components/autofill/core/browser/autofill_manager.h +++ b/chromium/components/autofill/core/browser/autofill_manager.h @@ -35,6 +35,7 @@ #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/popup_types.h" #include "components/autofill/core/common/form_data.h" +#include "components/autofill/core/common/signatures_util.h" #if defined(OS_ANDROID) || defined(OS_IOS) #include "components/autofill/core/browser/autofill_assistant.h" @@ -44,10 +45,6 @@ namespace gfx { class RectF; } -namespace user_prefs { -class PrefRegistrySyncable; -} - namespace autofill { class AutofillDataModel; @@ -71,13 +68,9 @@ extern const int kCreditCardSigninPromoImpressionLimit; // forms. One per frame; owned by the AutofillDriver. class AutofillManager : public AutofillHandler, public AutofillDownloadManager::Observer, - public payments::PaymentsClientUnmaskDelegate, public payments::FullCardRequest::ResultDelegate, public payments::FullCardRequest::UIDelegate { public: - // Registers our Enable/Disable Autofill pref. - static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); - AutofillManager(AutofillDriver* driver, AutofillClient* client, const std::string& app_locale, @@ -87,7 +80,7 @@ class AutofillManager : public AutofillHandler, // Sets an external delegate. void SetExternalDelegate(AutofillExternalDelegate* delegate); - void ShowAutofillSettings(); + void ShowAutofillSettings(bool show_credit_card_settings); // Whether the |field| should show an entry to scan a credit card. virtual bool ShouldShowScanCreditCard(const FormData& form, @@ -141,6 +134,8 @@ class AutofillManager : public AutofillHandler, return download_manager_.get(); } + FormDataImporter* form_data_importer() { return form_data_importer_.get(); } + payments::FullCardRequest* GetOrCreateFullCardRequest(); payments::FullCardRequest* CreateFullCardRequest( @@ -336,18 +331,14 @@ class AutofillManager : public AutofillHandler, SuppressReason suppress_reason = SuppressReason::kNotSuppressed; }; - bool ParseFormInternal(const FormData& form, - const FormStructure* cached_form, - FormStructure** parsed_form_structure); - // AutofillDownloadManager::Observer: void OnLoadedServerPredictions( std::string response, const std::vector<std::string>& form_signatures) override; - - // payments::PaymentsClientUnmaskDelegate: + // Returns the real PAN retrieved from Payments. |real_pan| will be empty on + // failure. void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result, - const std::string& real_pan) override; + const std::string& real_pan); // payments::FullCardRequest::ResultDelegate: void OnFullCardRequestSucceeded( @@ -414,15 +405,6 @@ class AutofillManager : public AutofillHandler, // or personal data. std::unique_ptr<FormStructure> ValidateSubmittedForm(const FormData& form); - // Fills |form_structure| and |autofill_field| with the cached elements - // corresponding to |form| and |field|. This might have the side-effect of - // updating the cache. Returns false if the |form| is not autofillable, or if - // it is not already present in the cache and the cache is full. - bool GetCachedFormAndField(const FormData& form, - const FormFieldData& field, - FormStructure** form_structure, - AutofillField** autofill_field) WARN_UNUSED_RESULT; - // Returns the field corresponding to |form| and |field| that can be // autofilled. Returns NULL if the field cannot be autofilled. AutofillField* GetAutofillField(const FormData& form, @@ -433,14 +415,6 @@ class AutofillManager : public AutofillHandler, // |FieldTypeGroup|. bool FormHasAddressField(const FormData& form) WARN_UNUSED_RESULT; - // Re-parses |live_form| and adds the result to |form_structures_|. - // |cached_form| should be a pointer to the existing version of the form, or - // NULL if no cached version exists. The updated form is then written into - // |updated_form|. Returns false if the cache could not be updated. - bool UpdateCachedForm(const FormData& live_form, - const FormStructure* cached_form, - FormStructure** updated_form) WARN_UNUSED_RESULT; - // Returns a list of values from the stored profiles that match |type| and the // value of |field| and returns the labels of the matching profiles. |labels| // is filled with the Profile label. @@ -519,7 +493,7 @@ class AutofillManager : public AutofillHandler, // Attempts to refill the form that was changed dynamically. Should only be // called if ShouldTriggerRefill returns true. - void TriggerRefill(const FormData& form, FormStructure* form_structure); + void TriggerRefill(const FormData& form); // Replaces the contents of |suggestions| with available suggestions for // |field|. |context| will contain additional information about the @@ -634,6 +608,7 @@ class AutofillManager : public AutofillHandler, friend class FormStructureBrowserTest; friend class GetMatchingTypesTest; friend class SaveCardBubbleViewsBrowserTestBase; + friend class SaveCardInfobarEGTestHelper; FRIEND_TEST_ALL_PREFIXES(ProfileMatchingTypesTest, DeterminePossibleFieldTypesForUpload); FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, diff --git a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc index 4db3f8b3dfe..18dbb5af79f 100644 --- a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc @@ -29,7 +29,6 @@ #include "build/build_config.h" #include "components/autofill/core/browser/autocomplete_history_manager.h" #include "components/autofill/core/browser/autofill_download_manager.h" -#include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/credit_card.h" @@ -48,7 +47,7 @@ #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_features.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/autofill/core/common/autofill_util.h" #include "components/autofill/core/common/form_data.h" @@ -512,7 +511,7 @@ class AutofillManagerTest : public testing::Test { void DisableCreditCardAutofill() { scoped_feature_list_.InitAndEnableFeature( - kAutofillCreditCardAblationExperiment); + features::kAutofillCreditCardAblationExperiment); } // Wrappers around the TestAutofillExternalDelegate::GetSuggestions call that @@ -745,7 +744,8 @@ TEST_F(AutofillManagerTest, GetProfileSuggestions_UnrecognizedAttribute) { TEST_F(AutofillManagerTest, GetProfileSuggestions_MinFieldsEnforced_NoAutocomplete) { base::test::ScopedFeatureList features; - features.InitAndEnableFeature(kAutofillEnforceMinRequiredFieldsForHeuristics); + features.InitAndEnableFeature( + features::kAutofillEnforceMinRequiredFieldsForHeuristics); // Set up our form data. FormData form; form.name = ASCIIToUTF16("MyForm"); @@ -777,7 +777,8 @@ TEST_F(AutofillManagerTest, TEST_F(AutofillManagerTest, GetProfileSuggestions_MinFieldsEnforced_WithOneAutocomplete) { base::test::ScopedFeatureList features; - features.InitAndEnableFeature(kAutofillEnforceMinRequiredFieldsForHeuristics); + features.InitAndEnableFeature( + features::kAutofillEnforceMinRequiredFieldsForHeuristics); // Set up our form data. FormData form; form.name = ASCIIToUTF16("MyForm"); @@ -883,7 +884,8 @@ TEST_F(AutofillManagerTest, TEST_F(AutofillManagerTest, GetProfileSuggestions_SmallFormWithTwoAutocomplete) { base::test::ScopedFeatureList features; - features.InitAndEnableFeature(kAutofillEnforceMinRequiredFieldsForHeuristics); + features.InitAndEnableFeature( + features::kAutofillEnforceMinRequiredFieldsForHeuristics); // Set up our form data. FormData form; form.name = ASCIIToUTF16("MyForm"); @@ -2082,7 +2084,7 @@ TEST_F(AutofillManagerTest, FillAddressForm_UnrecognizedAttribute) { // is disabled. TEST_F(AutofillManagerTest, FillAddressForm_AutocompleteOffRespected) { base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature(kAutofillAlwaysFillAddresses); + feature_list.InitAndDisableFeature(features::kAutofillAlwaysFillAddresses); FormData address_form; address_form.name = ASCIIToUTF16("MyForm"); @@ -2935,7 +2937,7 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_ComponentizedNumbers) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormsSeen(forms); int page_id = 1; @@ -2963,7 +2965,7 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_ComponentizedNumbers) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormsSeen(forms_copy); int page_id = 1; @@ -3022,7 +3024,7 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_WholeNumbers) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormsSeen(forms); int page_id = 1; @@ -3046,7 +3048,7 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_WholeNumbers) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormsSeen(forms_copy); int page_id = 1; @@ -3115,7 +3117,7 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_FillPartsOnceOnly) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormsSeen(forms); int page_id = 1; @@ -3144,7 +3146,7 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_FillPartsOnceOnly) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormsSeen(forms_copy); int page_id = 1; @@ -3213,7 +3215,7 @@ TEST_F(AutofillManagerTest, { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormsSeen(forms); int page_id = 1; @@ -3238,7 +3240,7 @@ TEST_F(AutofillManagerTest, { base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormsSeen(forms_copy); int page_id = 1; @@ -3299,7 +3301,7 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_BestEfforFilling) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormsSeen(forms); int page_id = 1; @@ -3324,7 +3326,7 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_BestEfforFilling) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormsSeen(forms); int page_id = 1; @@ -3381,7 +3383,7 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_FocusOnSecondPhoneNumber) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormsSeen(forms); int page_id = 1; @@ -3408,7 +3410,7 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_FocusOnSecondPhoneNumber) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormsSeen(forms); int page_id = 1; @@ -3468,7 +3470,7 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_HiddenFieldShouldNotCount) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormsSeen(forms); int page_id = 1; @@ -3492,7 +3494,7 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_HiddenFieldShouldNotCount) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormsSeen(forms); int page_id = 1; @@ -3632,7 +3634,7 @@ TEST_F(AutofillManagerTest, { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormsSeen(forms); int page_id = 1; @@ -3684,7 +3686,7 @@ TEST_F(AutofillManagerTest, { base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormsSeen(forms); int page_id = 1; @@ -4128,8 +4130,7 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions) { // Simulate having seen this form on page load. // |form_structure| will be owned by |autofill_manager_|. TestFormStructure* form_structure = new TestFormStructure(form); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); autofill_manager_->AddSeenFormStructure(base::WrapUnique(form_structure)); // Similarly, a second form. @@ -4149,8 +4150,7 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions) { form2.fields.push_back(field); TestFormStructure* form_structure2 = new TestFormStructure(form2); - form_structure2->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure2->DetermineHeuristicTypes(); autofill_manager_->AddSeenFormStructure(base::WrapUnique(form_structure2)); AutofillQueryResponseContents response; @@ -4202,8 +4202,7 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions_ResetManager) { // Simulate having seen this form on page load. // |form_structure| will be owned by |autofill_manager_|. TestFormStructure* form_structure = new TestFormStructure(form); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); autofill_manager_->AddSeenFormStructure(base::WrapUnique(form_structure)); AutofillQueryResponseContents response; @@ -4256,8 +4255,7 @@ TEST_F(AutofillManagerTest, DetermineHeuristicsWithOverallPrediction) { // Simulate having seen this form on page load. // |form_structure| will be owned by |autofill_manager_|. TestFormStructure* form_structure = new TestFormStructure(form); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); autofill_manager_->AddSeenFormStructure(base::WrapUnique(form_structure)); AutofillQueryResponseContents response; @@ -4324,8 +4322,7 @@ TEST_F(AutofillManagerTest, FormSubmittedServerTypes) { // Simulate having seen this form on page load. // |form_structure| will be owned by |autofill_manager_|. TestFormStructure* form_structure = new TestFormStructure(form); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); // Clear the heuristic types, and instead set the appropriate server types. std::vector<ServerFieldType> heuristic_types, server_types; @@ -4584,9 +4581,9 @@ TEST_P(ProfileMatchingTypesTest, DeterminePossibleFieldTypesForUpload) { // Enable/Disable ignoring invalid profile data for the scope of this test. base::test::ScopedFeatureList sfl; if (vote_using_invalid_profile_data) { - sfl.InitAndEnableFeature(kAutofillVoteUsingInvalidProfileData); + sfl.InitAndEnableFeature(features::kAutofillVoteUsingInvalidProfileData); } else { - sfl.InitAndDisableFeature(kAutofillVoteUsingInvalidProfileData); + sfl.InitAndDisableFeature(features::kAutofillVoteUsingInvalidProfileData); } // Set up the test profiles. @@ -5713,14 +5710,16 @@ TEST_F(AutofillManagerTest, ShouldUploadForm) { // With min required fields enabled. { base::test::ScopedFeatureList features; - features.InitAndEnableFeature(kAutofillEnforceMinRequiredFieldsForUpload); + features.InitAndEnableFeature( + features::kAutofillEnforceMinRequiredFieldsForUpload); EXPECT_FALSE(autofill_manager_->ShouldUploadForm(FormStructure(form))); } // With min required fields disabled. { base::test::ScopedFeatureList features; - features.InitAndDisableFeature(kAutofillEnforceMinRequiredFieldsForUpload); + features.InitAndDisableFeature( + features::kAutofillEnforceMinRequiredFieldsForUpload); EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form))); } @@ -5731,14 +5730,16 @@ TEST_F(AutofillManagerTest, ShouldUploadForm) { // With min required fields enabled. { base::test::ScopedFeatureList features; - features.InitAndEnableFeature(kAutofillEnforceMinRequiredFieldsForUpload); + features.InitAndEnableFeature( + features::kAutofillEnforceMinRequiredFieldsForUpload); EXPECT_FALSE(autofill_manager_->ShouldUploadForm(FormStructure(form))); } // With min required fields disabled. { base::test::ScopedFeatureList features; - features.InitAndDisableFeature(kAutofillEnforceMinRequiredFieldsForUpload); + features.InitAndDisableFeature( + features::kAutofillEnforceMinRequiredFieldsForUpload); EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form))); } @@ -5748,14 +5749,16 @@ TEST_F(AutofillManagerTest, ShouldUploadForm) { // With min required fields enabled. { base::test::ScopedFeatureList features; - features.InitAndEnableFeature(kAutofillEnforceMinRequiredFieldsForUpload); + features.InitAndEnableFeature( + features::kAutofillEnforceMinRequiredFieldsForUpload); EXPECT_FALSE(autofill_manager_->ShouldUploadForm(FormStructure(form))); } // With min required fields disabled. { base::test::ScopedFeatureList features; - features.InitAndDisableFeature(kAutofillEnforceMinRequiredFieldsForUpload); + features.InitAndDisableFeature( + features::kAutofillEnforceMinRequiredFieldsForUpload); EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form))); } @@ -5786,22 +5789,19 @@ TEST_F(AutofillManagerTest, ShouldUploadForm) { // With min required fields enabled. { base::test::ScopedFeatureList features; - features.InitAndEnableFeature(kAutofillEnforceMinRequiredFieldsForUpload); + features.InitAndEnableFeature( + features::kAutofillEnforceMinRequiredFieldsForUpload); EXPECT_FALSE(autofill_manager_->ShouldUploadForm(FormStructure(form))); } // With min required fields disabled. { base::test::ScopedFeatureList features; - features.InitAndDisableFeature(kAutofillEnforceMinRequiredFieldsForUpload); + features.InitAndDisableFeature( + features::kAutofillEnforceMinRequiredFieldsForUpload); EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form))); } - // Has two fields which are password fields. - test::CreateTestFormField("New Password", "new_pw", "", "password", &field); - form.fields.push_back(field); - EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form))); - // Autofill disabled. autofill_manager_->SetAutofillEnabled(false); EXPECT_FALSE(autofill_manager_->ShouldUploadForm(FormStructure(form))); @@ -5847,7 +5847,7 @@ TEST_F(AutofillManagerTest, TEST_F(AutofillManagerTest, DisplaySuggestions_AutocompleteOffRespected_AddressField) { base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature(kAutofillAlwaysFillAddresses); + feature_list.InitAndDisableFeature(features::kAutofillAlwaysFillAddresses); // Set up an address form. FormData mixed_form; @@ -5964,8 +5964,7 @@ TEST_F(AutofillManagerTest, DisplaySuggestionsForUpdatedServerTypedForm) { form.fields.push_back(field); auto form_structure = std::make_unique<TestFormStructure>(form); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); // Make sure the form can not be autofilled now. ASSERT_EQ(0u, form_structure->autofill_count()); for (size_t idx = 0; idx < form_structure->field_count(); ++idx) { @@ -6041,6 +6040,8 @@ TEST_F(AutofillManagerTest, FormWithLongOptionValuesIsAcceptable) { // Test that a sign-in form submission sends an upload with types matching the // fields. +// TODO(https://crbug.com/889472): Remove this test together with sending +// sign-in vote. TEST_F(AutofillManagerTest, SignInFormSubmission_Upload) { // Set up our form data (it's already filled out with user data). FormData form; @@ -6074,21 +6075,15 @@ TEST_F(AutofillManagerTest, SignInFormSubmission_Upload) { std::unique_ptr<FormStructure> form_structure(new FormStructure(form)); form_structure->set_is_signin_upload(true); - form_structure->set_form_parsed_timestamp(base::TimeTicks::Now()); form_structure->field(1)->set_possible_types({autofill::PASSWORD}); std::string signature = form_structure->FormSignatureAsStr(); - ServerFieldTypeSet uploaded_available_types; EXPECT_CALL(*download_manager_, StartUploadRequest(_, false, _, std::string(), true)) - .WillOnce(DoAll(SaveArg<2>(&uploaded_available_types), Return(true))); + .Times(0); autofill_manager_->MaybeStartVoteUploadProcess(std::move(form_structure), base::TimeTicks::Now(), true); - - EXPECT_EQ(signature, autofill_manager_->GetSubmittedFormSignature()); - EXPECT_NE(uploaded_available_types.end(), - uploaded_available_types.find(autofill::PASSWORD)); } // Test that with small form upload enabled but heuristics and query disabled @@ -6251,7 +6246,8 @@ TEST_P(OnFocusOnFormFieldTest, AddressSuggestions) { TEST_P(OnFocusOnFormFieldTest, AddressSuggestions_AutocompleteOffNotRespected) { base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature(kAutofillAlwaysFillAddresses); + scoped_feature_list.InitAndEnableFeature( + features::kAutofillAlwaysFillAddresses); FormData form; form.name = ASCIIToUTF16("MyForm"); @@ -6278,7 +6274,8 @@ TEST_P(OnFocusOnFormFieldTest, AddressSuggestions_AutocompleteOffRespected) { return; base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature(kAutofillAlwaysFillAddresses); + scoped_feature_list.InitAndDisableFeature( + features::kAutofillAlwaysFillAddresses); FormData form; form.name = ASCIIToUTF16("MyForm"); @@ -6331,7 +6328,7 @@ TEST_P(OnFocusOnFormFieldTest, CreditCardSuggestions_NonSecureContext) { TEST_P(OnFocusOnFormFieldTest, CreditCardSuggestions_Ablation) { base::test::ScopedFeatureList scoped_feature_list; scoped_feature_list.InitAndEnableFeature( - kAutofillCreditCardAblationExperiment); + features::kAutofillCreditCardAblationExperiment); // Set up our form data. FormData form; diff --git a/chromium/components/autofill/core/browser/autofill_merge_unittest.cc b/chromium/components/autofill/core/browser/autofill_merge_unittest.cc index 0695357a5fb..cbbc5c17a70 100644 --- a/chromium/components/autofill/core/browser/autofill_merge_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_merge_unittest.cc @@ -15,7 +15,6 @@ #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" -#include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/country_names.h" diff --git a/chromium/components/autofill/core/browser/autofill_metrics.cc b/chromium/components/autofill/core/browser/autofill_metrics.cc index 7295ceb2f42..68666bec133 100644 --- a/chromium/components/autofill/core/browser/autofill_metrics.cc +++ b/chromium/components/autofill/core/browser/autofill_metrics.cc @@ -15,12 +15,12 @@ #include "base/strings/strcat.h" #include "base/strings/string_piece.h" #include "base/time/time.h" -#include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/common/autofill_clock.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/form_data.h" #include "services/metrics/public/cpp/ukm_builders.h" @@ -702,6 +702,11 @@ void AutofillMetrics::LogSaveCardCardholderNameWasEdited(bool edited) { } // static +void AutofillMetrics::LogPaymentsCustomerDataBillingIdIsValid(bool valid) { + UMA_HISTOGRAM_BOOLEAN("Autofill.PaymentsCustomerDataBillingIdIsValid", valid); +} + +// static void AutofillMetrics::LogCardUploadDecisionMetrics( int upload_decision_metrics) { DCHECK(upload_decision_metrics); @@ -790,6 +795,17 @@ void AutofillMetrics::LogSaveCardPromptMetricBySecurityLevel( } // static +void AutofillMetrics::LogManageCardsPromptMetric(ManageCardsPromptMetric metric, + bool is_upload_save) { + DCHECK_LT(metric, NUM_MANAGE_CARDS_PROMPT_METRICS); + std::string destination = is_upload_save ? ".Upload" : ".Local"; + std::string metric_with_destination = + "Autofill.ManageCardsPrompt" + destination; + base::UmaHistogramEnumeration(metric_with_destination, metric, + NUM_MANAGE_CARDS_PROMPT_METRICS); +} + +// static void AutofillMetrics::LogScanCreditCardPromptMetric( ScanCreditCardPromptMetric metric) { DCHECK_LT(metric, NUM_SCAN_CREDIT_CARD_PROMPT_METRICS); @@ -832,6 +848,31 @@ void AutofillMetrics::LogLocalCardMigrationBubbleUserInteractionMetric( } // static +void AutofillMetrics::LogLocalCardMigrationPromptMetric( + LocalCardMigrationOrigin local_card_migration_origin, + LocalCardMigrationPromptMetric metric) { + DCHECK_LT(metric, NUM_LOCAL_CARD_MIGRATION_PROMPT_METRICS); + std::string histogram_name = "Autofill.LocalCardMigrationOrigin."; + // Switch to different sub-histogram depending on local card migration origin. + switch (local_card_migration_origin) { + case LocalCardMigrationOrigin::UseOfLocalCard: + histogram_name += "UseOfLocalCard"; + break; + case LocalCardMigrationOrigin::UseOfServerCard: + histogram_name += "UseOfServerCard"; + break; + case LocalCardMigrationOrigin::SettingsPage: + histogram_name += "SettingsPage"; + break; + default: + NOTREACHED(); + return; + } + base::UmaHistogramEnumeration(histogram_name, metric, + NUM_LOCAL_CARD_MIGRATION_PROMPT_METRICS); +} + +// static void AutofillMetrics::LogSaveCardWithFirstAndLastNameOffered(bool is_local) { std::string histogram_name = "Autofill.SaveCardWithFirstAndLastNameOffered."; histogram_name += is_local ? "Local" : "Server"; diff --git a/chromium/components/autofill/core/browser/autofill_metrics.h b/chromium/components/autofill/core/browser/autofill_metrics.h index 192a7f1219f..f556888ee54 100644 --- a/chromium/components/autofill/core/browser/autofill_metrics.h +++ b/chromium/components/autofill/core/browser/autofill_metrics.h @@ -18,7 +18,6 @@ #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/form_types.h" -#include "components/autofill/core/common/autofill_pref_names.h" #include "components/autofill/core/common/form_field_data.h" #include "components/autofill/core/common/signatures_util.h" #include "components/security_state/core/security_state.h" @@ -243,6 +242,20 @@ class AutofillMetrics { NUM_SAVE_CARD_PROMPT_METRICS, }; + // Metrics to measure user interaction with the Manage Cards view + // shown when user clicks on the save card icon after accepting + // to save a card. + enum ManageCardsPromptMetric { + // The manage cards promo was shown. + MANAGE_CARDS_SHOWN, + // The user clicked on [Done]. + MANAGE_CARDS_DONE, + // The user clicked on [Manage cards]. + MANAGE_CARDS_MANAGE_CARDS, + + NUM_MANAGE_CARDS_PROMPT_METRICS + }; + // Metrics measuring how well we predict field types. These metric values are // logged for each field in a submitted form for: // - the heuristic prediction @@ -423,6 +436,30 @@ class AutofillMetrics { NUM_LOCAL_CARD_MIGRATION_BUBBLE_USER_INTERACTION_METRICS, }; + // These metrics are logged for each local card migration origin. These are + // used to derive the conversion rate for each triggering source. + enum LocalCardMigrationPromptMetric { + // The intermediate bubble is shown to the user. + INTERMEDIATE_BUBBLE_SHOWN = 0, + // The intermediate bubble is accepted by the user. + INTERMEDIATE_BUBBLE_ACCEPTED = 1, + // The main dialog is shown to the user. + MAIN_DIALOG_SHOWN = 2, + // The main dialog is accepted by the user. + MAIN_DIALOG_ACCEPTED = 3, + NUM_LOCAL_CARD_MIGRATION_PROMPT_METRICS, + }; + + // Local card migration origin denotes from where the migration is triggered. + enum LocalCardMigrationOrigin { + // Trigger when user submitted a form using local card. + UseOfLocalCard, + // Trigger when user submitted a form using server card. + UseOfServerCard, + // Trigger from settings page. + SettingsPage, + }; + // Each of these metrics is logged only for potentially autofillable forms, // i.e. forms with at least three fields, etc. // These are used to derive certain "user happiness" metrics. For example, we @@ -812,6 +849,10 @@ class AutofillMetrics { // from its prefilled value or not. static void LogSaveCardCardholderNameWasEdited(bool edited); + // Logs whether the PaymentsCustomerData's billing ID was valid at the time of + // use. + static void LogPaymentsCustomerDataBillingIdIsValid(bool valid); + // |upload_decision_metrics| is a bitmask of |CardUploadDecisionMetric|. static void LogCardUploadDecisionMetrics(int upload_decision_metrics); static void LogCreditCardInfoBarMetric( @@ -830,6 +871,8 @@ class AutofillMetrics { SaveCardPromptMetric metric, bool is_uploading, security_state::SecurityLevel security_level); + static void LogManageCardsPromptMetric(ManageCardsPromptMetric metric, + bool is_uploading); static void LogScanCreditCardPromptMetric(ScanCreditCardPromptMetric metric); static void LogLocalCardMigrationBubbleOfferMetric( LocalCardMigrationBubbleOfferMetric metric, @@ -837,6 +880,9 @@ class AutofillMetrics { static void LogLocalCardMigrationBubbleUserInteractionMetric( LocalCardMigrationBubbleUserInteractionMetric metric, bool is_reshow); + static void LogLocalCardMigrationPromptMetric( + LocalCardMigrationOrigin local_card_migration_origin, + LocalCardMigrationPromptMetric metric); // Should be called when credit card scan is finished. |duration| should be // the time elapsed between launching the credit card scanner and getting back diff --git a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc index 8052cca1a87..a026ce43633 100644 --- a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc @@ -20,7 +20,6 @@ #include "base/test/scoped_feature_list.h" #include "base/test/scoped_task_environment.h" #include "base/time/time.h" -#include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_external_delegate.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/personal_data_manager.h" @@ -38,9 +37,9 @@ #include "components/autofill/core/common/form_field_data.h" #include "components/prefs/pref_service.h" #include "components/ukm/test_ukm_recorder.h" -#include "components/ukm/ukm_source.h" #include "components/webdata/common/web_data_results.h" #include "services/metrics/public/cpp/ukm_builders.h" +#include "services/metrics/public/cpp/ukm_source.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/geometry/rect.h" @@ -1924,10 +1923,11 @@ TEST_F(AutofillMetricsTest, QualityMetrics_BasedOnAutocomplete) { std::unique_ptr<TestFormStructure> form_structure = std::make_unique<TestFormStructure>(form); TestFormStructure* form_structure_ptr = form_structure.get(); - form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); - autofill_manager_->mutable_form_structures()->push_back( - std::move(form_structure)); + form_structure->DetermineHeuristicTypes(); + ASSERT_TRUE(autofill_manager_->mutable_form_structures() + ->emplace(form_structure_ptr->form_signature(), + std::move(form_structure)) + .second); AutofillQueryResponseContents response; // Server response will match with autocomplete. @@ -7401,7 +7401,13 @@ TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric_NoUkmService) { } // Test the ukm recorded when Suggestion is shown. -TEST_F(AutofillMetricsTest, AutofillSuggestionShownTest) { +// Flaky on Win. http://crbug.com/876954 +#if defined(OS_WIN) +#define MAYBE_AutofillSuggestionShownTest DISABLED_AutofillSuggestionShownTest +#else +#define MAYBE_AutofillSuggestionShownTest AutofillSuggestionShownTest +#endif +TEST_F(AutofillMetricsTest, MAYBE_AutofillSuggestionShownTest) { RecreateCreditCards(true /* include_local_credit_card */, false /* include_masked_server_credit_card */, false /* include_full_server_credit_card */); @@ -7505,7 +7511,7 @@ TEST_F(AutofillMetricsTest, DynamicFormMetrics) { AutofillMetrics::FORM_EVENT_DYNAMIC_CHANGE_AFTER_REFILL, 0); // Trigger a refill, the refill metric should be updated. - autofill_manager_->TriggerRefill(form, &form_structure); + autofill_manager_->TriggerRefill(form); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", AutofillMetrics::FORM_EVENT_DID_SEE_DYNAMIC_FORM, 2); diff --git a/chromium/components/autofill/core/browser/autofill_policy_handler.cc b/chromium/components/autofill/core/browser/autofill_policy_handler.cc index 38f9033999c..2f3d7ff7afc 100644 --- a/chromium/components/autofill/core/browser/autofill_policy_handler.cc +++ b/chromium/components/autofill/core/browser/autofill_policy_handler.cc @@ -5,7 +5,7 @@ #include "components/autofill/core/browser/autofill_policy_handler.h" #include "base/values.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/policy/core/common/policy_map.h" #include "components/policy/policy_constants.h" #include "components/prefs/pref_value_map.h" @@ -21,10 +21,26 @@ AutofillPolicyHandler::~AutofillPolicyHandler() {} void AutofillPolicyHandler::ApplyPolicySettings( const policy::PolicyMap& policies, PrefValueMap* prefs) { + const base::Value* autofill_credit_card_policy_value = + policies.GetValue(policy::key::kAutofillCreditCardEnabled); + const base::Value* autofill_address_policy_value = + policies.GetValue(policy::key::kAutofillAddressEnabled); + // Ignore the old policy if either of the new fine-grained policies are set. + if ((autofill_credit_card_policy_value && + autofill_credit_card_policy_value->is_bool()) || + (autofill_address_policy_value && + autofill_address_policy_value->is_bool())) { + return; + } + const base::Value* value = policies.GetValue(policy_name()); - bool auto_fill_enabled; - if (value && value->GetAsBoolean(&auto_fill_enabled) && !auto_fill_enabled) - prefs->SetBoolean(autofill::prefs::kAutofillEnabled, false); + bool autofill_enabled; + if (value && value->GetAsBoolean(&autofill_enabled) && !autofill_enabled) { + prefs->SetBoolean(autofill::prefs::kAutofillEnabledDeprecated, false); + // Disable the fine-grained prefs if the master pref is disabled by policy. + prefs->SetBoolean(autofill::prefs::kAutofillCreditCardEnabled, false); + prefs->SetBoolean(autofill::prefs::kAutofillProfileEnabled, false); + } } } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_policy_handler_unittest.cc b/chromium/components/autofill/core/browser/autofill_policy_handler_unittest.cc index 09ccd18e9a5..a9fb41d8916 100644 --- a/chromium/components/autofill/core/browser/autofill_policy_handler_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_policy_handler_unittest.cc @@ -4,9 +4,9 @@ #include <memory> -#include "components/autofill/core/browser/autofill_policy_handler.h" #include "base/values.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/browser/autofill_policy_handler.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/policy/core/common/policy_map.h" #include "components/policy/core/common/policy_types.h" #include "components/policy/policy_constants.h" @@ -23,7 +23,8 @@ TEST_F(AutofillPolicyHandlerTest, Default) { PrefValueMap prefs; AutofillPolicyHandler handler; handler.ApplyPolicySettings(policy, &prefs); - EXPECT_FALSE(prefs.GetValue(autofill::prefs::kAutofillEnabled, nullptr)); + EXPECT_FALSE( + prefs.GetValue(autofill::prefs::kAutofillEnabledDeprecated, nullptr)); } TEST_F(AutofillPolicyHandlerTest, Enabled) { @@ -35,8 +36,14 @@ TEST_F(AutofillPolicyHandlerTest, Enabled) { AutofillPolicyHandler handler; handler.ApplyPolicySettings(policy, &prefs); - // Enabling Autofill should not set the pref. - EXPECT_FALSE(prefs.GetValue(autofill::prefs::kAutofillEnabled, nullptr)); + // Enabling Autofill should not set the pref. Profile and credit card Autofill + // prefs should also not get set. + EXPECT_FALSE( + prefs.GetValue(autofill::prefs::kAutofillEnabledDeprecated, nullptr)); + EXPECT_FALSE( + prefs.GetValue(autofill::prefs::kAutofillProfileEnabled, nullptr)); + EXPECT_FALSE( + prefs.GetValue(autofill::prefs::kAutofillCreditCardEnabled, nullptr)); } TEST_F(AutofillPolicyHandlerTest, Disabled) { @@ -48,14 +55,73 @@ TEST_F(AutofillPolicyHandlerTest, Disabled) { AutofillPolicyHandler handler; handler.ApplyPolicySettings(policy, &prefs); - // Disabling Autofill should switch the pref to managed. + // Disabling Autofill by policy should set the pref. const base::Value* value = nullptr; - EXPECT_TRUE(prefs.GetValue(autofill::prefs::kAutofillEnabled, &value)); + EXPECT_TRUE( + prefs.GetValue(autofill::prefs::kAutofillEnabledDeprecated, &value)); + ASSERT_TRUE(value); + EXPECT_FALSE(value->GetBool()); + + // Disabling Autofill by policy should set the profile Autofill pref. + value = nullptr; + EXPECT_TRUE(prefs.GetValue(autofill::prefs::kAutofillProfileEnabled, &value)); ASSERT_TRUE(value); - bool autofill_enabled = true; - bool result = value->GetAsBoolean(&autofill_enabled); - ASSERT_TRUE(result); - EXPECT_FALSE(autofill_enabled); + EXPECT_FALSE(value->GetBool()); + + // Disabling Autofill by policy should set the credit card Autofill pref. + value = nullptr; + EXPECT_TRUE( + prefs.GetValue(autofill::prefs::kAutofillCreditCardEnabled, &value)); + ASSERT_TRUE(value); + EXPECT_FALSE(value->GetBool()); +} + +TEST_F(AutofillPolicyHandlerTest, DeprecatedPolicyIgnored_AddressEnabled) { + policy::PolicyMap policy; + policy.Set(policy::key::kAutoFillEnabled, policy::POLICY_LEVEL_MANDATORY, + policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD, + std::make_unique<base::Value>(false), nullptr); + policy.Set(policy::key::kAutofillAddressEnabled, + policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER, + policy::POLICY_SOURCE_CLOUD, std::make_unique<base::Value>(false), + nullptr); + PrefValueMap prefs; + AutofillPolicyHandler handler; + handler.ApplyPolicySettings(policy, &prefs); + + // Settings either of the fine-grained policies should cause the old policy to + // be ignored. The fine-grained policies should not get set by this handler + // either. + EXPECT_FALSE( + prefs.GetValue(autofill::prefs::kAutofillEnabledDeprecated, nullptr)); + EXPECT_FALSE( + prefs.GetValue(autofill::prefs::kAutofillProfileEnabled, nullptr)); + EXPECT_FALSE( + prefs.GetValue(autofill::prefs::kAutofillCreditCardEnabled, nullptr)); +} + +TEST_F(AutofillPolicyHandlerTest, DeprecatedPolicyIgnored_CreditCardEnabled) { + policy::PolicyMap policy; + policy.Set(policy::key::kAutoFillEnabled, policy::POLICY_LEVEL_MANDATORY, + policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD, + std::make_unique<base::Value>(false), nullptr); + policy.Set(policy::key::kAutofillCreditCardEnabled, + policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER, + policy::POLICY_SOURCE_CLOUD, std::make_unique<base::Value>(false), + nullptr); + PrefValueMap prefs; + AutofillPolicyHandler handler; + handler.ApplyPolicySettings(policy, &prefs); + + // Settings either of the fine-grained policies should cause the old policy to + // be ignored. The fine-grained policies should not get set by this handler + // either. + EXPECT_FALSE( + prefs.GetValue(autofill::prefs::kAutofillEnabledDeprecated, nullptr)); + EXPECT_FALSE( + prefs.GetValue(autofill::prefs::kAutofillProfileEnabled, nullptr)); + EXPECT_FALSE( + prefs.GetValue(autofill::prefs::kAutofillCreditCardEnabled, nullptr)); } } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_profile.cc b/chromium/components/autofill/core/browser/autofill_profile.cc index ede6790f6f2..2a003f14016 100644 --- a/chromium/components/autofill/core/browser/autofill_profile.cc +++ b/chromium/components/autofill/core/browser/autofill_profile.cc @@ -25,7 +25,6 @@ #include "components/autofill/core/browser/address.h" #include "components/autofill/core/browser/address_i18n.h" #include "components/autofill/core/browser/autofill_country.h" -#include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/autofill_profile_comparator.h" @@ -37,6 +36,7 @@ #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_constants.h" +#include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_l10n_util.h" #include "components/autofill/core/common/form_field_data.h" #include "components/strings/grit/components_strings.h" @@ -297,8 +297,8 @@ void AutofillProfile::GetMatchingTypes( } for (auto type : matching_types_in_this_profile) { if (GetValidityState(type) == INVALID) { - bool vote_using_invalid_data = - base::FeatureList::IsEnabled(kAutofillVoteUsingInvalidProfileData); + bool vote_using_invalid_data = base::FeatureList::IsEnabled( + features::kAutofillVoteUsingInvalidProfileData); UMA_HISTOGRAM_BOOLEAN("Autofill.InvalidProfileData.UsedForMetrics", vote_using_invalid_data); if (!vote_using_invalid_data) @@ -678,7 +678,7 @@ base::string16 AutofillProfile::ConstructInferredLabel( std::vector<ServerFieldType> remaining_fields; for (size_t i = 0; i < included_fields_size && num_fields_to_use > 0; ++i) { - AddressField address_field; + ::i18n::addressinput::AddressField address_field; if (!i18n::FieldForType(included_fields[i], &address_field) || !::i18n::addressinput::IsFieldUsed(address_field, address_region_code) || diff --git a/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc b/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc index f81dc6f0315..c7af768ddd3 100644 --- a/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc +++ b/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc @@ -7,6 +7,7 @@ #include "base/guid.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_data_util.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/country_names.h" #include "components/autofill/core/browser/field_types.h" @@ -16,19 +17,13 @@ using base::UTF16ToUTF8; using base::UTF8ToUTF16; +using autofill::data_util::TruncateUTF8; using sync_pb::AutofillProfileSpecifics; using syncer::EntityData; namespace autofill { namespace { -std::string TruncateUTF8(const std::string& data) { - std::string trimmed_value; - base::TruncateUTF8ToByteSize(data, AutofillTable::kMaxDataLength, - &trimmed_value); - return trimmed_value; -} - bool IsAutofillProfileSpecificsValid( const AutofillProfileSpecifics& specifics) { return base::IsValidGUID(specifics.guid()); diff --git a/chromium/components/autofill/core/browser/autofill_profile_unittest.cc b/chromium/components/autofill/core/browser/autofill_profile_unittest.cc index 276979c8b10..656ab3f5eb2 100644 --- a/chromium/components/autofill/core/browser/autofill_profile_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_profile_unittest.cc @@ -383,14 +383,13 @@ TEST(AutofillProfileTest, CreateInferredLabelsI18n_JP_Latn) { test::kEmptyOrigin)); test::SetProfileInfo(profiles.back().get(), "Miku", "", "Hatsune", "miku@rei.com", "Rei Inc", "Roppongi Hills Mori Tower", - "6-10-1 Roppongi", "Minato-ku", "Tokyo", "106-6126", + "6-10-1 Roppongi, Minato-ku", "", "Tokyo", "106-6126", "JP", "+81-3-6384-9000"); profiles.back()->set_language_code("ja_Latn"); static const char* kExpectedLabels[] = { "", "Miku Hatsune", "Miku Hatsune, Roppongi Hills Mori Tower", - "Miku Hatsune, Roppongi Hills Mori Tower, 6-10-1 Roppongi", "Miku Hatsune, Roppongi Hills Mori Tower, 6-10-1 Roppongi, Minato-ku", "Miku Hatsune, Roppongi Hills Mori Tower, 6-10-1 Roppongi, Minato-ku, " "Tokyo", @@ -420,24 +419,23 @@ TEST(AutofillProfileTest, CreateInferredLabelsI18n_JP_ja) { profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(), test::kEmptyOrigin)); test::SetProfileInfo(profiles.back().get(), "ミク", "", "初音", - "miku@rei.com", "例", "六本木ヒルズ森タワー", - "六本木 6-10-1", "港区", "東京都", "106-6126", "JP", + "miku@rei.com", "例", "港区六本木ヒルズ森タワー", + "六本木 6-10-1", "", "東京都", "106-6126", "JP", "03-6384-9000"); profiles.back()->set_language_code("ja_JP"); static const char* kExpectedLabels[] = { - "", - "初音ミク", - "六本木ヒルズ森タワー初音ミク", - "六本木ヒルズ森タワー六本木 6-10-1初音ミク", - "港区六本木ヒルズ森タワー六本木 6-10-1初音ミク", - "東京都港区六本木ヒルズ森タワー六本木 6-10-1初音ミク", - "〒106-6126東京都港区六本木ヒルズ森タワー六本木 6-10-1初音ミク", - "〒106-6126東京都港区六本木ヒルズ森タワー六本木 6-10-1例初音ミク", - "〒106-6126東京都港区六本木ヒルズ森タワー六本木 6-10-1例初音ミク, Japan", - "〒106-6126東京都港区六本木ヒルズ森タワー六本木 6-10-1例初音ミク, Japan, " - "miku@rei.com", - "〒106-6126東京都港区六本木ヒルズ森タワー六本木 6-10-1例初音ミク, Japan, " - "miku@rei.com, 03-6384-9000", + "", + "初音ミク", + "港区六本木ヒルズ森タワー初音ミク", + "港区六本木ヒルズ森タワー六本木 6-10-1初音ミク", + "東京都港区六本木ヒルズ森タワー六本木 6-10-1初音ミク", + "〒106-6126東京都港区六本木ヒルズ森タワー六本木 6-10-1初音ミク", + "〒106-6126東京都港区六本木ヒルズ森タワー六本木 6-10-1例初音ミク", + "〒106-6126東京都港区六本木ヒルズ森タワー六本木 6-10-1例初音ミク, Japan", + "〒106-6126東京都港区六本木ヒルズ森タワー六本木 6-10-1例初音ミク, Japan, " + "miku@rei.com", + "〒106-6126東京都港区六本木ヒルズ森タワー六本木 6-10-1例初音ミク, Japan, " + "miku@rei.com, 03-6384-9000", }; std::vector<base::string16> labels; diff --git a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc b/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc index 4f022dd6432..098480bbfd2 100644 --- a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc +++ b/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc @@ -14,7 +14,7 @@ #include "components/autofill/core/browser/legal_message_line.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_features.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/grit/components_scaled_resources.h" #include "components/infobars/core/infobar.h" #include "components/infobars/core/infobar_manager.h" @@ -96,11 +96,18 @@ base::string16 AutofillSaveCardInfoBarDelegateMobile::GetDescriptionText() if (!IsGooglePayBrandingEnabled()) return base::string16(); - return IsAutofillUpstreamUpdatePromptExplanationExperimentEnabled() - ? l10n_util::GetStringUTF16( - IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3) - : l10n_util::GetStringUTF16( - IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V2); + if (OfferStoreUnmaskedCards() && + !IsAutofillNoLocalSaveOnUploadSuccessExperimentEnabled()) { + return l10n_util::GetStringUTF16( + features::IsAutofillUpstreamUpdatePromptExplanationExperimentEnabled() + ? IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3_WITH_DEVICE + : IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V2_WITH_DEVICE); + } else { + return l10n_util::GetStringUTF16( + features::IsAutofillUpstreamUpdatePromptExplanationExperimentEnabled() + ? IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3 + : IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V2); + } } int AutofillSaveCardInfoBarDelegateMobile::GetIconId() const { @@ -110,9 +117,10 @@ int AutofillSaveCardInfoBarDelegateMobile::GetIconId() const { base::string16 AutofillSaveCardInfoBarDelegateMobile::GetMessageText() const { return l10n_util::GetStringUTF16( - IsGooglePayBrandingEnabled() || !upload_ + IsGooglePayBrandingEnabled() ? IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD_V3 - : IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD); + : upload_ ? IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD + : IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL); } infobars::InfoBarDelegate::InfoBarIdentifier diff --git a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h b/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h index 4e0dfcebea0..8295b74984b 100644 --- a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h +++ b/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h @@ -38,6 +38,7 @@ class AutofillSaveCardInfoBarDelegateMobile : public ConfirmInfoBarDelegate { ~AutofillSaveCardInfoBarDelegateMobile() override; + bool upload() const { return upload_; } int issuer_icon_id() const { return issuer_icon_id_; } const base::string16& card_label() const { return card_label_; } const base::string16& card_sub_label() const { return card_sub_label_; } diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.cc b/chromium/components/autofill/core/browser/autofill_test_utils.cc index 0140cc599e2..2b0efc706da 100644 --- a/chromium/components/autofill/core/browser/autofill_test_utils.cc +++ b/chromium/components/autofill/core/browser/autofill_test_utils.cc @@ -13,13 +13,12 @@ #include "base/time/time.h" #include "build/build_config.h" #include "components/autofill/core/browser/autofill_external_delegate.h" -#include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/autofill/core/common/autofill_constants.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_field_data.h" #include "components/os_crypt/os_crypt_mocker.h" @@ -37,6 +36,8 @@ namespace test { namespace { +const int kValidityStateBitfield = 1984; + std::string GetRandomCardNumber() { const size_t length = 16; std::string value; @@ -56,7 +57,7 @@ std::unique_ptr<PrefService> PrefServiceForTesting() { std::unique_ptr<PrefService> PrefServiceForTesting( user_prefs::PrefRegistrySyncable* registry) { - AutofillManager::RegisterProfilePrefs(registry); + prefs::RegisterProfilePrefs(registry); PrefServiceFactory factory; factory.set_user_prefs(base::MakeRefCounted<TestingPrefStore>()); @@ -102,14 +103,16 @@ void CreateTestSelectField(const std::vector<const char*>& values, CreateTestSelectField("", "", "", values, values, values.size(), field); } -void CreateTestAddressFormData(FormData* form) { +void CreateTestAddressFormData(FormData* form, const char* unique_id) { std::vector<ServerFieldTypeSet> types; - CreateTestAddressFormData(form, &types); + CreateTestAddressFormData(form, &types, unique_id); } void CreateTestAddressFormData(FormData* form, - std::vector<ServerFieldTypeSet>* types) { - form->name = ASCIIToUTF16("MyForm"); + std::vector<ServerFieldTypeSet>* types, + const char* unique_id) { + form->name = + ASCIIToUTF16("MyForm") + ASCIIToUTF16(unique_id ? unique_id : ""); form->origin = GURL("http://myform.com/form.html"); form->action = GURL("http://myform.com/submit.html"); form->main_frame_origin = @@ -175,8 +178,10 @@ void CreateTestAddressFormData(FormData* form, types->push_back(type_set); } -void CreateTestPersonalInformationFormData(FormData* form) { - form->name = ASCIIToUTF16("MyForm"); +void CreateTestPersonalInformationFormData(FormData* form, + const char* unique_id) { + form->name = + ASCIIToUTF16("MyForm") + ASCIIToUTF16(unique_id ? unique_id : ""); form->origin = GURL("http://myform.com/form.html"); form->action = GURL("http://myform.com/submit.html"); form->main_frame_origin = @@ -197,8 +202,10 @@ void CreateTestPersonalInformationFormData(FormData* form) { void CreateTestCreditCardFormData(FormData* form, bool is_https, bool use_month_type, - bool split_names) { - form->name = ASCIIToUTF16("MyForm"); + bool split_names, + const char* unique_id) { + form->name = + ASCIIToUTF16("MyForm") + ASCIIToUTF16(unique_id ? unique_id : ""); if (is_https) { form->origin = GURL("https://myform.com/form.html"); form->action = GURL("https://myform.com/submit.html"); @@ -333,6 +340,50 @@ AutofillProfile GetVerifiedProfile2() { return profile; } +AutofillProfile GetServerProfile() { + AutofillProfile profile(AutofillProfile::SERVER_PROFILE, "id1"); + // Note: server profiles don't have email addresses and only have full names. + SetProfileInfo(&profile, "", "", "", "", "Google, Inc.", "123 Fake St.", + "Apt. 42", "Mountain View", "California", "94043", "US", + "1.800.555.1234"); + + profile.SetInfo(NAME_FULL, ASCIIToUTF16("John K. Doe"), "en"); + profile.SetRawInfo(ADDRESS_HOME_SORTING_CODE, ASCIIToUTF16("CEDEX")); + profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY, + ASCIIToUTF16("Santa Clara")); + + profile.set_language_code("en"); + profile.SetValidityFromBitfieldValue(kValidityStateBitfield); + profile.set_use_count(7); + profile.set_use_date(base::Time::FromTimeT(54321)); + + profile.GenerateServerProfileIdentifier(); + + return profile; +} + +AutofillProfile GetServerProfile2() { + AutofillProfile profile(AutofillProfile::SERVER_PROFILE, "id2"); + // Note: server profiles don't have email addresses. + SetProfileInfo(&profile, "", "", "", "", "Main, Inc.", "4323 Wrong St.", + "Apt. 1032", "Sunnyvale", "California", "10011", "US", + "+1 514-123-1234"); + + profile.SetInfo(NAME_FULL, ASCIIToUTF16("Jim S. Bristow"), "en"); + profile.SetRawInfo(ADDRESS_HOME_SORTING_CODE, ASCIIToUTF16("XEDEC")); + profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY, + ASCIIToUTF16("Santa Monica")); + + profile.set_language_code("en"); + profile.SetValidityFromBitfieldValue(kValidityStateBitfield); + profile.set_use_count(14); + profile.set_use_date(base::Time::FromTimeT(98765)); + + profile.GenerateServerProfileIdentifier(); + + return profile; +} + CreditCard GetCreditCard() { CreditCard credit_card(base::GenerateGUID(), kEmptyOrigin); SetCreditCardInfo(&credit_card, "Test User", "4111111111111111" /* Visa */, @@ -364,6 +415,7 @@ CreditCard GetMaskedServerCard() { test::SetCreditCardInfo(&credit_card, "Bonnie Parker", "2109" /* Mastercard */, "12", "2020", "1"); credit_card.SetNetworkForMaskedCard(kMasterCard); + credit_card.set_card_type(CreditCard::CARD_TYPE_CREDIT); return credit_card; } @@ -372,6 +424,7 @@ CreditCard GetMaskedServerCardAmex() { test::SetCreditCardInfo(&credit_card, "Justin Thyme", "8431" /* Amex */, "9", "2020", "1"); credit_card.SetNetworkForMaskedCard(kAmericanExpressCard); + credit_card.set_card_type(CreditCard::CARD_TYPE_PREPAID); return credit_card; } @@ -529,7 +582,7 @@ void FillUploadField(AutofillUploadContents::Field* field, field->set_type(control_type); if (autocomplete) field->set_autocomplete(autocomplete); - field->set_autofill_type(autofill_type); + field->add_autofill_type(autofill_type); } void FillQueryField(AutofillQueryContents::Form::Field* field, diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.h b/chromium/components/autofill/core/browser/autofill_test_utils.h index 38077c09d6c..f9d9ca30f4f 100644 --- a/chromium/components/autofill/core/browser/autofill_test_utils.h +++ b/chromium/components/autofill/core/browser/autofill_test_utils.h @@ -63,22 +63,28 @@ void CreateTestSelectField(const std::vector<const char*>& values, // Populates |form| with data corresponding to a simple address form. // Note that this actually appends fields to the form data, which can be useful // for building up more complex test forms. Another version of the function is -// provided in case the caller wants the vector of expected field |types|. -void CreateTestAddressFormData(FormData* form); +// provided in case the caller wants the vector of expected field |types|. Use +// |unique_id| optionally ensure that each form has its own signature. +void CreateTestAddressFormData(FormData* form, const char* unique_id = nullptr); void CreateTestAddressFormData(FormData* form, - std::vector<ServerFieldTypeSet>* types); + std::vector<ServerFieldTypeSet>* types, + const char* unique_id = nullptr); // Populates |form| with data corresponding to a simple personal information -// form, including name and email, but no address-related fields. -void CreateTestPersonalInformationFormData(FormData* form); +// form, including name and email, but no address-related fields. Use +// |unique_id| to optionally ensure that each form has its own signature. +void CreateTestPersonalInformationFormData(FormData* form, + const char* unique_id = nullptr); // Populates |form| with data corresponding to a simple credit card form. // Note that this actually appends fields to the form data, which can be -// useful for building up more complex test forms. +// useful for building up more complex test forms. Use |unique_id| to optionally +// ensure that each form has its own signature. void CreateTestCreditCardFormData(FormData* form, bool is_https, bool use_month_type, - bool split_names = false); + bool split_names = false, + const char* unique_id = nullptr); // Returns a full profile with valid info according to rules for Canada. AutofillProfile GetFullValidProfileForCanada(); @@ -107,6 +113,12 @@ AutofillProfile GetVerifiedProfile(); // Returns a verified profile full of dummy info, different to the above. AutofillProfile GetVerifiedProfile2(); +// Returns a server profile full of dummy info. +AutofillProfile GetServerProfile(); + +// Returns a server profile full of dummy info, different to the above. +AutofillProfile GetServerProfile2(); + // Returns a credit card full of dummy info. CreditCard GetCreditCard(); diff --git a/chromium/components/autofill/core/browser/autofill_type.cc b/chromium/components/autofill/core/browser/autofill_type.cc index 24447b2d4b1..3f2b48a3509 100644 --- a/chromium/components/autofill/core/browser/autofill_type.cc +++ b/chromium/components/autofill/core/browser/autofill_type.cc @@ -612,6 +612,9 @@ std::string AutofillType::ToString() const { // static std::string AutofillType::ServerFieldTypeToString(ServerFieldType type) { + // You are free to add or remove the String representation of ServerFieldType, + // but don't change any existing values, Android WebView presents them to + // Autofill Service as part of APIs. switch (type) { case NO_SERVER_DATA: return "NO_SERVER_DATA"; diff --git a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.cc b/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.cc index 575c9e43120..c7281467b2d 100644 --- a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.cc +++ b/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.cc @@ -9,7 +9,7 @@ #include "base/bind.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/prefs/pref_service.h" #include "components/sync/driver/sync_client.h" #include "components/sync/driver/sync_service.h" @@ -117,10 +117,9 @@ void AutofillWalletDataTypeController::OnUserPrefChanged() { bool AutofillWalletDataTypeController::IsEnabled() { DCHECK(CalledOnValidThread()); - // Require the user-visible pref to be enabled to sync Wallet data/metadata, - // and also check that Autofill for credit cards is not disabled by policy. - PrefService* ps = sync_client_->GetPrefService(); - return ps->GetBoolean(autofill::prefs::kAutofillWalletImportEnabled); + // Require the user-visible pref to be enabled to sync Wallet data/metadata. + return autofill::prefs::IsPaymentsIntegrationEnabled( + sync_client_->GetPrefService()); } void AutofillWalletDataTypeController::DisableForPolicy() { if (state() != NOT_RUNNING && state() != STOPPING) { diff --git a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller_unittest.cc b/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller_unittest.cc index b6d29b62219..06df1f28eb7 100644 --- a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller_unittest.cc @@ -17,10 +17,11 @@ #include "base/threading/thread.h" #include "base/threading/thread_task_runner_handle.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" #include "components/prefs/testing_pref_service.h" +#include "components/sync/driver/configure_context.h" #include "components/sync/driver/data_type_controller_mock.h" #include "components/sync/driver/fake_generic_change_processor.h" #include "components/sync/driver/fake_sync_client.h" @@ -85,8 +86,6 @@ class AutofillWalletDataTypeControllerTest : public testing::Test, void SetUp() override { prefs_.registry()->RegisterBooleanPref( autofill::prefs::kAutofillWalletImportEnabled, true); - prefs_.registry()->RegisterBooleanPref( - autofill::prefs::kAutofillCreditCardEnabled, true); web_data_service_ = base::MakeRefCounted<FakeWebDataService>( base::ThreadTaskRunnerHandle::Get(), @@ -124,6 +123,7 @@ class AutofillWalletDataTypeControllerTest : public testing::Test, void Start() { autofill_wallet_dtc_->LoadModels( + syncer::ConfigureContext(), base::Bind(&AutofillWalletDataTypeControllerTest::OnLoadFinished, base::Unretained(this))); base::RunLoop().RunUntilIdle(); @@ -178,8 +178,7 @@ TEST_F(AutofillWalletDataTypeControllerTest, DatatypeDisabledWhileRunning) { EXPECT_EQ(syncer::DataTypeController::RUNNING, autofill_wallet_dtc_->state()); EXPECT_FALSE(last_error_.IsSet()); EXPECT_EQ(syncer::AUTOFILL_WALLET_DATA, last_type_); - GetPrefService()->SetBoolean(autofill::prefs::kAutofillWalletImportEnabled, - false); + autofill::prefs::SetPaymentsIntegrationEnabled(GetPrefService(), false); base::RunLoop().RunUntilIdle(); EXPECT_TRUE(last_error_.IsSet()); } @@ -187,8 +186,7 @@ TEST_F(AutofillWalletDataTypeControllerTest, DatatypeDisabledWhileRunning) { TEST_F(AutofillWalletDataTypeControllerTest, DatatypeDisabledAtStartup) { SetStartExpectations(); web_data_service_->LoadDatabase(); - GetPrefService()->SetBoolean(autofill::prefs::kAutofillWalletImportEnabled, - false); + autofill::prefs::SetPaymentsIntegrationEnabled(GetPrefService(), false); EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING, autofill_wallet_dtc_->state()); Start(); diff --git a/chromium/components/autofill/core/browser/contact_info.cc b/chromium/components/autofill/core/browser/contact_info.cc index 105d135c28c..c5e1156704c 100644 --- a/chromium/components/autofill/core/browser/contact_info.cc +++ b/chromium/components/autofill/core/browser/contact_info.cc @@ -14,6 +14,7 @@ #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/autofill_data_util.h" #include "components/autofill/core/browser/autofill_type.h" +#include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_l10n_util.h" namespace autofill { @@ -240,7 +241,8 @@ void CompanyInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const { } base::string16 CompanyInfo::GetRawInfo(ServerFieldType type) const { - if (type == COMPANY_NAME) + if (type == COMPANY_NAME && + base::FeatureList::IsEnabled(features::kAutofillEnableCompanyName)) return company_name_; return base::string16(); diff --git a/chromium/components/autofill/core/browser/contact_info_unittest.cc b/chromium/components/autofill/core/browser/contact_info_unittest.cc index d07dfa041f1..9fbcdb41b63 100644 --- a/chromium/components/autofill/core/browser/contact_info_unittest.cc +++ b/chromium/components/autofill/core/browser/contact_info_unittest.cc @@ -11,8 +11,10 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/common/autofill_features.h" #include "testing/gtest/include/gtest/gtest.h" using base::ASCIIToUTF16; @@ -397,4 +399,30 @@ INSTANTIATE_TEST_CASE_P( NamePartsAreEmptyTestCase{"", "Mitchell", "", "", false}, NamePartsAreEmptyTestCase{"", "", "Morrison", "", false})); +struct CompanyNameEnabledDisabledTest : public testing::TestWithParam<bool> { + CompanyNameEnabledDisabledTest() : feature_state(GetParam()) { + feature_list_.InitWithFeatureState(features::kAutofillEnableCompanyName, + feature_state); + } + + const bool feature_state; + + private: + base::test::ScopedFeatureList feature_list_; +}; + +TEST_P(CompanyNameEnabledDisabledTest, GetInfo) { + SCOPED_TRACE(feature_state ? "Enabled" : "Disabled"); + const char kCompanyName[] = "Google"; + CompanyInfo company; + company.SetInfo(AutofillType(COMPANY_NAME), ASCIIToUTF16(kCompanyName), + "en-US"); + EXPECT_EQ(ASCIIToUTF16(feature_state ? kCompanyName : ""), + company.GetInfo(AutofillType(COMPANY_NAME), "en-US")); +} + +INSTANTIATE_TEST_CASE_P(ContactInfoTest, + CompanyNameEnabledDisabledTest, + testing::Bool()); + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/credit_card.cc b/chromium/components/autofill/core/browser/credit_card.cc index bf5ff7af86e..2b9c802979a 100644 --- a/chromium/components/autofill/core/browser/credit_card.cc +++ b/chromium/components/autofill/core/browser/credit_card.cc @@ -28,12 +28,12 @@ #include "base/time/time.h" #include "build/build_config.h" #include "components/autofill/core/browser/autofill_data_util.h" -#include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_constants.h" +#include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_regexes.h" #include "components/autofill/core/common/form_field_data.h" #include "components/grit/components_scaled_resources.h" @@ -46,8 +46,13 @@ using base::ASCIIToUTF16; namespace autofill { -const base::char16 kMidlineEllipsis[] = {0x2022, 0x2006, 0x2022, 0x2006, 0x2022, - 0x2006, 0x2022, 0x2006, 0}; +// Unicode characters used in card number obfuscation: +// - 0x2022 - Bullet. +// - 0x2006 - SIX-PER-EM SPACE (small space between bullets). +// - 0x2060 - WORD-JOINER (makes obfuscated string undivisible). +const base::char16 kMidlineEllipsis[] = { + 0x2022, 0x2060, 0x2006, 0x2060, 0x2022, 0x2060, 0x2006, 0x2060, 0x2022, + 0x2060, 0x2006, 0x2060, 0x2022, 0x2060, 0x2006, 0x2060, 0}; namespace { @@ -798,7 +803,7 @@ base::string16 CreditCard::AbbreviatedExpirationDateForDisplay() const { return base::string16(); return l10n_util::GetStringFUTF16( - IsAutofillSaveCardDialogUnlabeledExpirationDateEnabled() + features::IsAutofillSaveCardDialogUnlabeledExpirationDateEnabled() ? IDS_AUTOFILL_CREDIT_CARD_EXPIRATION_DATE_ABBR_V2 : IDS_AUTOFILL_CREDIT_CARD_EXPIRATION_DATE_ABBR, month, year); diff --git a/chromium/components/autofill/core/browser/credit_card_save_manager.cc b/chromium/components/autofill/core/browser/credit_card_save_manager.cc index d0aba9954e5..58028662750 100644 --- a/chromium/components/autofill/core/browser/credit_card_save_manager.cc +++ b/chromium/components/autofill/core/browser/credit_card_save_manager.cc @@ -31,12 +31,12 @@ #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/payments/payments_client.h" +#include "components/autofill/core/browser/payments/payments_util.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_util.h" -#include "components/prefs/pref_service.h" #include "services/identity/public/cpp/identity_manager.h" #include "url/gurl.h" @@ -78,11 +78,7 @@ CreditCardSaveManager::CreditCardSaveManager( payments_client_(payments_client), app_locale_(app_locale), personal_data_manager_(personal_data_manager), - weak_ptr_factory_(this) { - if (payments_client_) { - payments_client_->SetSaveDelegate(this); - } -} + weak_ptr_factory_(this) {} CreditCardSaveManager::~CreditCardSaveManager() {} @@ -104,7 +100,6 @@ void CreditCardSaveManager::AttemptToOfferCardUploadSave( // Abort the uploading if |payments_client_| is nullptr. if (!payments_client_) return; - payments_client_->SetSaveDelegate(this); upload_request_ = payments::PaymentsClient::UploadRequestDetails(); upload_request_.card = card; uploading_local_card_ = uploading_local_card; @@ -156,34 +151,59 @@ void CreditCardSaveManager::AttemptToOfferCardUploadSave( } // Add active experiments to the request payload. - if (IsAutofillUpstreamSendPanFirstSixExperimentEnabled()) { + if (features::IsAutofillUpstreamSendPanFirstSixExperimentEnabled()) { upload_request_.active_experiments.push_back( - kAutofillUpstreamSendPanFirstSix.name); + features::kAutofillUpstreamSendPanFirstSix.name); } - if (IsAutofillUpstreamUpdatePromptExplanationExperimentEnabled()) { + if (features::IsAutofillUpstreamUpdatePromptExplanationExperimentEnabled()) { upload_request_.active_experiments.push_back( - kAutofillUpstreamUpdatePromptExplanation.name); + features::kAutofillUpstreamUpdatePromptExplanation.name); } - int detected_values = GetDetectedValues(); + // We store the detected values in the upload request, because the addresses + // are being possibly modified in the next code block, and we want the + // detected values to reflect addresses *before* they are modified. + upload_request_.detected_values = GetDetectedValues(); // If the user must provide cardholder name, log it and set // |should_request_name_from_user_| so the offer-to-save dialog know to ask // for it. should_request_name_from_user_ = false; - if (detected_values & DetectedValue::USER_PROVIDED_NAME) { + if (upload_request_.detected_values & DetectedValue::USER_PROVIDED_NAME) { upload_decision_metrics_ |= AutofillMetrics::USER_REQUESTED_TO_PROVIDE_CARDHOLDER_NAME; should_request_name_from_user_ = true; } + // If the relevant feature is enabled, only send the country of the + // recently-used addresses. We make a copy here to avoid modifying + // |upload_request_.profiles|, which should always have full addresses even + // after this function goes out of scope. + bool send_only_country_in_addresses = base::FeatureList::IsEnabled( + features::kAutofillSendOnlyCountryInGetUploadDetails); + std::vector<AutofillProfile> country_only_profiles; + if (send_only_country_in_addresses) { + for (const AutofillProfile& address : upload_request_.profiles) { + AutofillProfile country_only; + country_only.SetInfo(ADDRESS_HOME_COUNTRY, + address.GetInfo(ADDRESS_HOME_COUNTRY, app_locale_), + app_locale_); + country_only_profiles.emplace_back(std::move(country_only)); + } + } + // All required data is available, start the upload process. if (observer_for_testing_) observer_for_testing_->OnDecideToRequestUploadSave(); payments_client_->GetUploadDetails( - upload_request_.profiles, detected_values, + send_only_country_in_addresses ? country_only_profiles + : upload_request_.profiles, + upload_request_.detected_values, base::UTF16ToASCII(CreditCard::StripSeparators(card.number())) .substr(0, 6), - upload_request_.active_experiments, app_locale_); + upload_request_.active_experiments, app_locale_, + base::BindOnce(&CreditCardSaveManager::OnDidGetUploadDetails, + weak_ptr_factory_.GetWeakPtr()), + payments::kUploadCardBillableServiceNumber); } bool CreditCardSaveManager::IsCreditCardUploadEnabled() { @@ -192,7 +212,7 @@ bool CreditCardSaveManager::IsCreditCardUploadEnabled() { return observer_for_testing_ || ::autofill::IsCreditCardUploadEnabled( client_->GetPrefs(), client_->GetSyncService(), - client_->GetIdentityManager()->GetPrimaryAccountInfo().email); + personal_data_manager_->GetAccountInfoForPaymentsServer().email); } bool CreditCardSaveManager::IsUploadEnabledForNetwork( @@ -221,7 +241,8 @@ void CreditCardSaveManager::OnDidUploadCard( // upload succeeds and we can store unmasked cards on this OS, we will keep a // copy of the card as a full server card on the device. if (result == AutofillClient::SUCCESS && !server_id.empty() && - OfferStoreUnmaskedCards()) { + OfferStoreUnmaskedCards() && + !IsAutofillNoLocalSaveOnUploadSuccessExperimentEnabled()) { upload_request_.card.set_record_type(CreditCard::FULL_SERVER_CARD); upload_request_.card.SetServerStatus(CreditCard::OK); upload_request_.card.set_server_id(server_id); @@ -261,20 +282,20 @@ void CreditCardSaveManager::OnDidGetUploadDetails( } else { // If the upload details request failed and we *know* we have all possible // information (card number, expiration, cvc, name, and address), fall back - // to a local save. It indicates that "Payments doesn't want this card" or - // "Payments doesn't currently support this country", in which case the - // upload details request will consistently fail and if we don't fall back - // to a local save, the user will never be offered *any* kind of credit card - // save. (Note that this could intermittently backfire if there's a network - // breakdown or Payments outage, resulting in sometimes showing upload and - // sometimes offering local save, but such cases should be rare.) - int detected_values = GetDetectedValues(); + // to a local save (for new cards only). It indicates that "Payments doesn't + // want this card" or "Payments doesn't currently support this country", in + // which case the upload details request will consistently fail and if we + // don't fall back to a local save, the user will never be offered *any* + // kind of credit card save. (Note that this could intermittently backfire + // if there's a network breakdown or Payments outage, resulting in sometimes + // showing upload and sometimes offering local save, but such cases should + // be rare.) bool found_name_and_postal_code_and_cvc = - (detected_values & DetectedValue::CARDHOLDER_NAME || - detected_values & DetectedValue::ADDRESS_NAME) && - detected_values & DetectedValue::POSTAL_CODE && - detected_values & DetectedValue::CVC; - if (found_name_and_postal_code_and_cvc) + (upload_request_.detected_values & DetectedValue::CARDHOLDER_NAME || + upload_request_.detected_values & DetectedValue::ADDRESS_NAME) && + upload_request_.detected_values & DetectedValue::POSTAL_CODE && + upload_request_.detected_values & DetectedValue::CVC; + if (found_name_and_postal_code_and_cvc && !uploading_local_card_) OfferCardLocalSave(upload_request_.card); upload_decision_metrics_ |= AutofillMetrics::UPLOAD_NOT_OFFERED_GET_UPLOAD_DETAILS_FAILED; @@ -387,20 +408,6 @@ void CreditCardSaveManager::SetProfilesForCreditCardUpload( if (verified_zip.empty() && !candidate_profiles.empty()) upload_decision_metrics_ |= AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ZIP_CODE; - // If the relevant feature is enabled, only send the country of the - // recently-used addresses. - if (base::FeatureList::IsEnabled( - features::kAutofillSendOnlyCountryInGetUploadDetails)) { - for (size_t i = 0; i < candidate_profiles.size(); i++) { - AutofillProfile country_only; - country_only.SetInfo( - ADDRESS_HOME_COUNTRY, - candidate_profiles[i].GetInfo(ADDRESS_HOME_COUNTRY, app_locale_), - app_locale_); - candidate_profiles[i] = std::move(country_only); - } - } - // Set up |upload_request->profiles|. upload_request->profiles.assign(candidate_profiles.begin(), candidate_profiles.end()); @@ -461,13 +468,14 @@ int CreditCardSaveManager::GetDetectedValues() const { } } - // If the billing_customer_number Priority Preference is non-zero, it means - // the user has a Google Payments account. Include a bit for existence of this - // account (NOT the id itself), as it will help determine if a new Payments - // customer might need to be created when save is accepted. - if (static_cast<int64_t>(payments_client_->GetPrefService()->GetDouble( - prefs::kAutofillBillingCustomerNumber)) != 0) + // If the billing_customer_number is non-zero, it means the user has a Google + // Payments account. Include a bit for existence of this account (NOT the id + // itself), as it will help determine if a new Payments customer might need to + // be created when save is accepted. + if (payments::GetBillingCustomerId(personal_data_manager_, + payments_client_->GetPrefService()) != 0) { detected_values |= DetectedValue::HAS_GOOGLE_PAYMENTS_ACCOUNT; + } // If one of the following is true, signal that cardholder name will be // explicitly requested in the offer-to-save bubble: @@ -478,8 +486,9 @@ int CreditCardSaveManager::GetDetectedValues() const { if ((!(detected_values & DetectedValue::CARDHOLDER_NAME) && !(detected_values & DetectedValue::ADDRESS_NAME) && !(detected_values & DetectedValue::HAS_GOOGLE_PAYMENTS_ACCOUNT) && - IsAutofillUpstreamEditableCardholderNameExperimentEnabled()) || - IsAutofillUpstreamAlwaysRequestCardholderNameExperimentEnabled()) { + features::IsAutofillUpstreamEditableCardholderNameExperimentEnabled()) || + features:: + IsAutofillUpstreamAlwaysRequestCardholderNameExperimentEnabled()) { detected_values |= DetectedValue::USER_PROVIDED_NAME; } @@ -519,15 +528,16 @@ void CreditCardSaveManager::SendUploadCardRequest() { if (observer_for_testing_) observer_for_testing_->OnSentUploadCardRequest(); upload_request_.app_locale = app_locale_; - upload_request_.billing_customer_number = - static_cast<int64_t>(payments_client_->GetPrefService()->GetDouble( - prefs::kAutofillBillingCustomerNumber)); + upload_request_.billing_customer_number = payments::GetBillingCustomerId( + personal_data_manager_, payments_client_->GetPrefService()); AutofillMetrics::LogUploadAcceptedCardOriginMetric( uploading_local_card_ ? AutofillMetrics::USER_ACCEPTED_UPLOAD_OF_LOCAL_CARD : AutofillMetrics::USER_ACCEPTED_UPLOAD_OF_NEW_CARD); - payments_client_->UploadCard(upload_request_); + payments_client_->UploadCard( + upload_request_, base::BindOnce(&CreditCardSaveManager::OnDidUploadCard, + weak_ptr_factory_.GetWeakPtr())); } AutofillMetrics::CardUploadDecisionMetric diff --git a/chromium/components/autofill/core/browser/credit_card_save_manager.h b/chromium/components/autofill/core/browser/credit_card_save_manager.h index 4a32e67e617..dc08f81b3b8 100644 --- a/chromium/components/autofill/core/browser/credit_card_save_manager.h +++ b/chromium/components/autofill/core/browser/credit_card_save_manager.h @@ -24,7 +24,7 @@ namespace autofill { // Manages logic for determining whether upload credit card save to Google // Payments is available as well as actioning both local and upload credit card // save logic. Owned by FormDataImporter. -class CreditCardSaveManager : public payments::PaymentsClientSaveDelegate { +class CreditCardSaveManager { public: // Possible fields and values detected during credit card form submission, to // be sent to Google Payments to better determine if upload credit card save @@ -105,19 +105,24 @@ class CreditCardSaveManager : public payments::PaymentsClientSaveDelegate { void SetAppLocale(std::string app_locale) { app_locale_ = app_locale; } protected: - // payments::PaymentsClientSaveDelegate: - // Exposed for testing. - void OnDidUploadCard(AutofillClient::PaymentsRpcResult result, - const std::string& server_id) override; + // Returns the result of an upload request. If |result| == + // |AutofillClient::SUCCESS|, |server_id| may, optionally, contain the opaque + // identifier for the card on the server. Exposed for testing. + virtual void OnDidUploadCard(AutofillClient::PaymentsRpcResult result, + const std::string& server_id); private: + friend class CreditCardSaveManagerTest; + friend class CreditCardSaveManagerTestObserverBridge; friend class SaveCardBubbleViewsBrowserTestBase; - // payments::PaymentsClientSaveDelegate: + // Returns the legal message retrieved from Payments. On failure or not + // meeting Payments's conditions for upload, |legal_message| will contain + // nullptr. void OnDidGetUploadDetails( AutofillClient::PaymentsRpcResult result, const base::string16& context_token, - std::unique_ptr<base::DictionaryValue> legal_message) override; + std::unique_ptr<base::DictionaryValue> legal_message); // Examines |card| and the stored profiles and if a candidate set of profiles // is found that matches the client-side validation rules, assigns the values diff --git a/chromium/components/autofill/core/browser/credit_card_save_manager_unittest.cc b/chromium/components/autofill/core/browser/credit_card_save_manager_unittest.cc index dd186e27cfb..cdac485ca2c 100644 --- a/chromium/components/autofill/core/browser/credit_card_save_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/credit_card_save_manager_unittest.cc @@ -40,14 +40,15 @@ #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_field_data.h" #include "components/prefs/pref_service.h" #include "components/ukm/test_ukm_recorder.h" -#include "components/ukm/ukm_source.h" #include "net/url_request/url_request_context_getter.h" #include "net/url_request/url_request_test_util.h" #include "services/metrics/public/cpp/ukm_builders.h" +#include "services/metrics/public/cpp/ukm_source.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -112,19 +113,16 @@ class CreditCardSaveManagerTest : public testing::Test { autofill_driver_->SetURLRequestContext(request_context_.get()); payments_client_ = new payments::TestPaymentsClient( autofill_driver_->GetURLLoaderFactory(), autofill_client_.GetPrefs(), - autofill_client_.GetIdentityManager(), - /*unmask_delegate=*/nullptr, - // Will be set by CreditCardSaveManager's ctor - /*save_delegate=*/nullptr); + autofill_client_.GetIdentityManager(), &personal_data_); credit_card_save_manager_ = new TestCreditCardSaveManager(autofill_driver_.get(), &autofill_client_, payments_client_, &personal_data_); + credit_card_save_manager_->SetCreditCardUploadEnabled(true); autofill_manager_.reset(new TestAutofillManager( autofill_driver_.get(), &autofill_client_, &personal_data_, std::unique_ptr<CreditCardSaveManager>(credit_card_save_manager_), payments_client_)); autofill_manager_->SetExpectedObservedSubmission(true); - payments_client_->SetSaveDelegate(credit_card_save_manager_); } void TearDown() override { @@ -140,17 +138,18 @@ class CreditCardSaveManagerTest : public testing::Test { } void EnableAutofillUpstreamSendPanFirstSixExperiment() { - scoped_feature_list_.InitAndEnableFeature(kAutofillUpstreamSendPanFirstSix); + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillUpstreamSendPanFirstSix); } void EnableAutofillUpstreamUpdatePromptExplanationExperiment() { scoped_feature_list_.InitAndEnableFeature( - kAutofillUpstreamUpdatePromptExplanation); + features::kAutofillUpstreamUpdatePromptExplanation); } void DisableAutofillUpstreamUpdatePromptExplanationExperiment() { scoped_feature_list_.InitAndDisableFeature( - kAutofillUpstreamUpdatePromptExplanation); + features::kAutofillUpstreamUpdatePromptExplanation); } void FormsSeen(const std::vector<FormData>& forms) { @@ -162,6 +161,10 @@ class CreditCardSaveManagerTest : public testing::Test { form, false, SubmissionSource::FORM_SUBMISSION, base::TimeTicks::Now()); } + void UserHasAcceptedUpload(const base::string16& cardholder_name) { + credit_card_save_manager_->OnUserDidAcceptUpload(cardholder_name); + } + // Populates |form| with data corresponding to a simple credit card form. // Note that this actually appends fields to the form data, which can be // useful for building up more complex test forms. @@ -347,6 +350,7 @@ class CreditCardSaveManagerTest : public testing::Test { #define MAYBE_ImportFormDataCreditCardHTTPS ImportFormDataCreditCardHTTPS #endif TEST_F(CreditCardSaveManagerTest, MAYBE_ImportFormDataCreditCardHTTPS) { + credit_card_save_manager_->SetCreditCardUploadEnabled(false); TestSaveCreditCards(true); } @@ -358,6 +362,7 @@ TEST_F(CreditCardSaveManagerTest, MAYBE_ImportFormDataCreditCardHTTPS) { #define MAYBE_ImportFormDataCreditCardHTTP ImportFormDataCreditCardHTTP #endif TEST_F(CreditCardSaveManagerTest, MAYBE_ImportFormDataCreditCardHTTP) { + credit_card_save_manager_->SetCreditCardUploadEnabled(false); TestSaveCreditCards(false); } @@ -371,6 +376,8 @@ TEST_F(CreditCardSaveManagerTest, MAYBE_ImportFormDataCreditCardHTTP) { CreditCardSavedWhenAutocompleteOff #endif TEST_F(CreditCardSaveManagerTest, MAYBE_CreditCardSavedWhenAutocompleteOff) { + credit_card_save_manager_->SetCreditCardUploadEnabled(false); + // Set up our form data. FormData form; CreateTestCreditCardFormData(&form, false, false); @@ -409,7 +416,6 @@ TEST_F(CreditCardSaveManagerTest, InvalidCreditCardNumberIsNotSaved) { } TEST_F(CreditCardSaveManagerTest, CreditCardDisabledDoesNotSave) { - personal_data_.ClearProfiles(); autofill_manager_->SetCreditCardEnabled(false); // Create, fill and submit an address form in order to establish a recent @@ -446,9 +452,6 @@ TEST_F(CreditCardSaveManagerTest, CreditCardDisabledDoesNotSave) { TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FullAddresses) { scoped_feature_list_.InitAndDisableFeature( features::kAutofillSendOnlyCountryInGetUploadDetails); - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. @@ -478,9 +481,9 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FullAddresses) { EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded()); - EXPECT_THAT( - payments_client_->active_experiments_in_request(), - UnorderedElementsAre(kAutofillUpstreamUpdatePromptExplanation.name)); + EXPECT_THAT(payments_client_->active_experiments_in_request(), + UnorderedElementsAre( + features::kAutofillUpstreamUpdatePromptExplanation.name)); // Verify that one profile was saved, and it was included in the upload // details request to payments. @@ -504,6 +507,13 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FullAddresses) { // modified the profile. histogram_tester.ExpectTotalCount( "Autofill.DaysSincePreviousUseAtSubmission.Profile", 0); + + // Simulate that the user has accepted the upload from the prompt. + UserHasAcceptedUpload(/*cardholder_name=*/base::ASCIIToUTF16("")); + // We should find that full addresses are included in the UploadCard request. + EXPECT_THAT( + payments_client_->addresses_in_upload_card(), + testing::UnorderedElementsAreArray({*personal_data_.GetProfiles()[0]})); } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_OnlyCountryInAddresses) { @@ -511,9 +521,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_OnlyCountryInAddresses) { // details request will only contain the country. scoped_feature_list_.InitAndEnableFeature( features::kAutofillSendOnlyCountryInGetUploadDetails); - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. @@ -543,9 +550,9 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_OnlyCountryInAddresses) { EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded()); - EXPECT_THAT( - payments_client_->active_experiments_in_request(), - UnorderedElementsAre(kAutofillUpstreamUpdatePromptExplanation.name)); + EXPECT_THAT(payments_client_->active_experiments_in_request(), + UnorderedElementsAre( + features::kAutofillUpstreamUpdatePromptExplanation.name)); // Verify that even though the full address profile was saved, only the // country was included in the upload details request to payments. @@ -573,15 +580,19 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_OnlyCountryInAddresses) { // modified the profile. histogram_tester.ExpectTotalCount( "Autofill.DaysSincePreviousUseAtSubmission.Profile", 0); + + // Simulate that the user has accepted the upload from the prompt. + UserHasAcceptedUpload(/*cardholder_name=*/base::ASCIIToUTF16("")); + // We should find that full addresses are included in the UploadCard request, + // even though only countries were included in GetUploadDetails. + EXPECT_THAT( + payments_client_->addresses_in_upload_card(), + testing::UnorderedElementsAreArray({*personal_data_.GetProfiles()[0]})); } // Tests that a credit card inferred from a form with a credit card first and // last name can be uploaded. TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FirstAndLastName) { - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; @@ -612,9 +623,9 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FirstAndLastName) { EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded()); - EXPECT_THAT( - payments_client_->active_experiments_in_request(), - UnorderedElementsAre(kAutofillUpstreamUpdatePromptExplanation.name)); + EXPECT_THAT(payments_client_->active_experiments_in_request(), + UnorderedElementsAre( + features::kAutofillUpstreamUpdatePromptExplanation.name)); // Server did not send a server_id, expect copy of card is not stored. EXPECT_TRUE(personal_data_.GetCreditCards().empty()); @@ -642,10 +653,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FirstAndLastName) { // last name can be uploaded when the last name comes before first name on the // form. TEST_F(CreditCardSaveManagerTest, UploadCreditCard_LastAndFirstName) { - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; @@ -698,9 +705,9 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_LastAndFirstName) { EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded()); - EXPECT_THAT( - payments_client_->active_experiments_in_request(), - UnorderedElementsAre(kAutofillUpstreamUpdatePromptExplanation.name)); + EXPECT_THAT(payments_client_->active_experiments_in_request(), + UnorderedElementsAre( + features::kAutofillUpstreamUpdatePromptExplanation.name)); // Server did not send a server_id, expect copy of card is not stored. EXPECT_TRUE(personal_data_.GetCreditCards().empty()); @@ -725,9 +732,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_LastAndFirstName) { } TEST_F(CreditCardSaveManagerTest, UploadCreditCardAndSaveCopy) { - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + scoped_feature_list_.InitAndDisableFeature( + features::kAutofillNoLocalSaveOnUploadSuccess); const char* const server_id = "InstrumentData:1234"; payments_client_->SetServerIdForCardUpload(server_id); @@ -775,8 +781,47 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCardAndSaveCopy) { #endif } -TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FeatureNotEnabled) { +TEST_F(CreditCardSaveManagerTest, UploadCreditCard_DisableLocalSave) { + personal_data_.ClearCreditCards(); personal_data_.ClearProfiles(); + + credit_card_save_manager_->SetCreditCardUploadEnabled(true); + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillNoLocalSaveOnUploadSuccess); + + const char* const server_id = "InstrumentData:1234"; + payments_client_->SetServerIdForCardUpload(server_id); + + // Create, fill and submit an address form in order to establish a recent + // profile which can be selected for the upload request. + FormData address_form; + test::CreateTestAddressFormData(&address_form); + FormsSeen(std::vector<FormData>(1, address_form)); + + ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); + FormSubmitted(address_form); + + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + + // Edit the data, and submit. + const char* const card_number = "4111111111111111"; + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16(card_number); + credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + FormSubmitted(credit_card_form); + EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded()); + + // Don't keep a copy of the card on this device. + EXPECT_TRUE(personal_data_.GetCreditCards().empty()); +} + +TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FeatureNotEnabled) { credit_card_save_manager_->SetCreditCardUploadEnabled(false); // Create, fill and submit an address form in order to establish a recent @@ -811,9 +856,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FeatureNotEnabled) { } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcUnavailable) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; @@ -855,9 +897,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcUnavailable) { } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcInvalidLength) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; @@ -896,13 +935,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcInvalidLength) { } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MultipleCvcFields) { - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - - // Remove the profiles that were created in the TestPersonalDataManager - // constructor because they would result in conflicting names that would - // prevent the upload. - personal_data_.ClearProfiles(); - // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; @@ -958,13 +990,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MultipleCvcFields) { } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoCvcFieldOnForm) { - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - - // Remove the profiles that were created in the TestPersonalDataManager - // constructor because they would result in conflicting names that would - // prevent the upload. - personal_data_.ClearProfiles(); - // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; @@ -1018,13 +1043,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoCvcFieldOnForm) { TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoCvcFieldOnForm_InvalidCvcInNonCvcField) { - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - - // Remove the profiles that were created in the TestPersonalDataManager - // constructor because they would result in conflicting names that would - // prevent the upload. - personal_data_.ClearProfiles(); - // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; @@ -1081,13 +1099,6 @@ TEST_F(CreditCardSaveManagerTest, TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoCvcFieldOnForm_CvcInNonCvcField) { - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - - // Remove the profiles that were created in the TestPersonalDataManager - // constructor because they would result in conflicting names that would - // prevent the upload. - personal_data_.ClearProfiles(); - // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; @@ -1146,13 +1157,6 @@ TEST_F(CreditCardSaveManagerTest, TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoCvcFieldOnForm_CvcInAddressField) { - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - - // Remove the profiles that were created in the TestPersonalDataManager - // constructor because they would result in conflicting names that would - // prevent the upload. - personal_data_.ClearProfiles(); - // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; @@ -1208,9 +1212,6 @@ TEST_F(CreditCardSaveManagerTest, } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoProfileAvailable) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Don't fill or submit an address form. // Set up our credit card form data. @@ -1248,9 +1249,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoRecentlyUsedProfile) { TestAutofillClock test_clock; test_clock.SetNow(kArbitraryTime); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create, fill and submit an address form in order to establish a profile. FormData address_form; test::CreateTestAddressFormData(&address_form); @@ -1298,9 +1296,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoRecentlyUsedProfile) { TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcUnavailableAndNoProfileAvailable) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Don't fill or submit an address form. // Set up our credit card form data. @@ -1336,9 +1331,6 @@ TEST_F(CreditCardSaveManagerTest, } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoNameAvailable) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; @@ -1378,9 +1370,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoNameAvailable) { TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoNameAvailableAndNoProfileAvailable) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Don't fill or submit an address form. // Set up our credit card form data. @@ -1416,13 +1405,10 @@ TEST_F(CreditCardSaveManagerTest, } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesConflict) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create, fill and submit two address forms with different zip codes. FormData address_form1, address_form2; - test::CreateTestAddressFormData(&address_form1); - test::CreateTestAddressFormData(&address_form2); + test::CreateTestAddressFormData(&address_form1, "1"); + test::CreateTestAddressFormData(&address_form2, "2"); std::vector<FormData> address_forms; address_forms.push_back(address_form1); @@ -1469,9 +1455,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesConflict) { TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesDoNotDiscardWhitespace) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create two separate profiles with different zip codes. Must directly add // instead of submitting a form, because they're deduped on form submit. AutofillProfile profile1; @@ -1519,9 +1502,6 @@ TEST_F(CreditCardSaveManagerTest, } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesHavePrefixMatch) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create, fill and submit two address forms with different zip codes. FormData address_form1, address_form2; test::CreateTestAddressFormData(&address_form1); @@ -1565,9 +1545,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesHavePrefixMatch) { } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoZipCodeAvailable) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; @@ -1613,9 +1590,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoZipCodeAvailable) { } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormHasMiddleInitial) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create, fill and submit two address forms with different names. FormData address_form1, address_form2; test::CreateTestAddressFormData(&address_form1); @@ -1658,9 +1632,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormHasMiddleInitial) { } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoMiddleInitialInCCForm) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create, fill and submit two address forms with different names. FormData address_form1, address_form2; test::CreateTestAddressFormData(&address_form1); @@ -1701,9 +1672,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoMiddleInitialInCCForm) { TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormHasCardholderMiddleName) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create, fill and submit address form without middle name. FormData address_form; test::CreateTestAddressFormData(&address_form); @@ -1742,9 +1710,6 @@ TEST_F(CreditCardSaveManagerTest, } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormHasAddressMiddleName) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create, fill and submit address form with middle name. FormData address_form; test::CreateTestAddressFormData(&address_form); @@ -1783,9 +1748,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormHasAddressMiddleName) { } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NamesCanMismatch) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create, fill and submit two address forms with different names. FormData address_form1, address_form2; test::CreateTestAddressFormData(&address_form1); @@ -1837,9 +1799,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_IgnoreOldProfiles) { TestAutofillClock test_clock; test_clock.SetNow(kArbitraryTime); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create, fill and submit two address forms with different names. FormData address_form1, address_form2; test::CreateTestAddressFormData(&address_form1); @@ -1886,9 +1845,7 @@ TEST_F( CreditCardSaveManagerTest, UploadCreditCard_RequestCardholderNameIfNameMissingAndNoPaymentsCustomer) { scoped_feature_list_.InitAndEnableFeature( - kAutofillUpstreamEditableCardholderName); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + features::kAutofillUpstreamEditableCardholderName); // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. @@ -1931,9 +1888,7 @@ TEST_F( CreditCardSaveManagerTest, UploadCreditCard_RequestCardholderNameIfNameConflictingAndNoPaymentsCustomer) { scoped_feature_list_.InitAndEnableFeature( - kAutofillUpstreamEditableCardholderName); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + features::kAutofillUpstreamEditableCardholderName); // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. @@ -1976,9 +1931,7 @@ TEST_F( CreditCardSaveManagerTest, UploadCreditCard_DoNotRequestCardholderNameIfNameExistsAndNoPaymentsCustomer) { scoped_feature_list_.InitAndEnableFeature( - kAutofillUpstreamEditableCardholderName); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + features::kAutofillUpstreamEditableCardholderName); // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. @@ -2019,9 +1972,7 @@ TEST_F( CreditCardSaveManagerTest, UploadCreditCard_DoNotRequestCardholderNameIfNameMissingAndPaymentsCustomer) { scoped_feature_list_.InitAndEnableFeature( - kAutofillUpstreamEditableCardholderName); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + features::kAutofillUpstreamEditableCardholderName); // Set the billing_customer_number Priority Preference to designate existence // of a Payments account. @@ -2069,9 +2020,7 @@ TEST_F( CreditCardSaveManagerTest, UploadCreditCard_DoNotRequestCardholderNameIfNameConflictingAndPaymentsCustomer) { scoped_feature_list_.InitAndEnableFeature( - kAutofillUpstreamEditableCardholderName); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + features::kAutofillUpstreamEditableCardholderName); // Set the billing_customer_number Priority Preference to designate existence // of a Payments account. @@ -2119,9 +2068,7 @@ TEST_F( CreditCardSaveManagerTest, UploadCreditCard_DoNotRequestCardholderNameIfNameMissingAndNoPaymentsCustomerExpOff) { scoped_feature_list_.InitAndDisableFeature( - kAutofillUpstreamEditableCardholderName); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + features::kAutofillUpstreamEditableCardholderName); // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. @@ -2164,9 +2111,7 @@ TEST_F( CreditCardSaveManagerTest, UploadCreditCard_DoNotRequestCardholderNameIfNameConflictingAndNoPaymentsCustomerExpOff) { scoped_feature_list_.InitAndDisableFeature( - kAutofillUpstreamEditableCardholderName); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + features::kAutofillUpstreamEditableCardholderName); // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. @@ -2211,9 +2156,7 @@ TEST_F( CreditCardSaveManagerTest, UploadCreditCard_ShouldRequestCardholderName_ResetBetweenConsecutiveSaves) { scoped_feature_list_.InitAndEnableFeature( - kAutofillUpstreamEditableCardholderName); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + features::kAutofillUpstreamEditableCardholderName); // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. @@ -2261,9 +2204,7 @@ TEST_F( TEST_F(CreditCardSaveManagerTest, UploadCreditCard_RequestCardholderNameIfTestingExperimentOn) { scoped_feature_list_.InitAndEnableFeature( - kAutofillUpstreamAlwaysRequestCardholderName); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + features::kAutofillUpstreamAlwaysRequestCardholderName); // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. @@ -2308,9 +2249,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_LogPreviousUseDate) { TestAutofillClock test_clock; test_clock.SetNow(kArbitraryTime); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; @@ -2352,9 +2290,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_LogPreviousUseDate) { } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadDetailsFails) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Anything other than "en-US" will cause GetUploadDetails to return a failure // response. credit_card_save_manager_->SetAppLocale("pt-BR"); @@ -2396,10 +2331,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadDetailsFails) { } TEST_F(CreditCardSaveManagerTest, DuplicateMaskedCreditCard_NoUpload) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - credit_card_save_manager_->SetAppLocale("en-US"); - // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; @@ -2435,10 +2366,28 @@ TEST_F(CreditCardSaveManagerTest, DuplicateMaskedCreditCard_NoUpload) { EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded()); } -TEST_F(CreditCardSaveManagerTest, GetDetectedValues_NothingIfNothingFound) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); +// This class is parametrized to allow running all the inheriting tests with and +// without a specific feature enabled. See INSTANTIATE_TEST_CASE_P. +class CreditCardSaveManagerFeatureParameterizedTest + : public CreditCardSaveManagerTest, + public ::testing::WithParamInterface< + /*enable_send_only_country_in_get_upload_details=*/bool> { + public: + CreditCardSaveManagerFeatureParameterizedTest() {} + ~CreditCardSaveManagerFeatureParameterizedTest() override {} + + void SetUp() override { + CreditCardSaveManagerTest::SetUp(); + scoped_feature_list_.InitWithFeatureState( + features::kAutofillSendOnlyCountryInGetUploadDetails, + /*enable_send_only_country_in_get_upload_details=*/GetParam()); + } + + private: + DISALLOW_COPY_AND_ASSIGN(CreditCardSaveManagerFeatureParameterizedTest); +}; +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, NothingIfNothingFound) { // Set up our credit card form data. FormData credit_card_form; CreateTestCreditCardFormData(&credit_card_form, true, false); @@ -2456,10 +2405,7 @@ TEST_F(CreditCardSaveManagerTest, GetDetectedValues_NothingIfNothingFound) { EXPECT_EQ(payments_client_->detected_values_in_upload_details(), 0); } -TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectCvc) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, DetectCvc) { // Set up our credit card form data. FormData credit_card_form; CreateTestCreditCardFormData(&credit_card_form, true, false); @@ -2478,10 +2424,7 @@ TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectCvc) { CreditCardSaveManager::DetectedValue::CVC); } -TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectCardholderName) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, DetectCardholderName) { // Set up our credit card form data. FormData credit_card_form; CreateTestCreditCardFormData(&credit_card_form, true, false); @@ -2500,10 +2443,7 @@ TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectCardholderName) { CreditCardSaveManager::DetectedValue::CARDHOLDER_NAME); } -TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectAddressName) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, DetectAddressName) { // Set up a new address profile. AutofillProfile profile; profile.set_guid("00000000-0000-0000-0000-000000000200"); @@ -2528,11 +2468,8 @@ TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectAddressName) { CreditCardSaveManager::DetectedValue::ADDRESS_NAME); } -TEST_F(CreditCardSaveManagerTest, - GetDetectedValues_DetectCardholderAndAddressNameIfMatching) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, + DetectCardholderAndAddressNameIfMatching) { // Set up a new address profile. AutofillProfile profile; profile.set_guid("00000000-0000-0000-0000-000000000200"); @@ -2558,11 +2495,8 @@ TEST_F(CreditCardSaveManagerTest, CreditCardSaveManager::DetectedValue::ADDRESS_NAME); } -TEST_F(CreditCardSaveManagerTest, - GetDetectedValues_DetectNoUniqueNameIfNamesConflict) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, + DetectNoUniqueNameIfNamesConflict) { // Set up a new address profile. AutofillProfile profile; profile.set_guid("00000000-0000-0000-0000-000000000200"); @@ -2586,10 +2520,7 @@ TEST_F(CreditCardSaveManagerTest, EXPECT_EQ(payments_client_->detected_values_in_upload_details(), 0); } -TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectPostalCode) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, DetectPostalCode) { // Set up a new address profile. AutofillProfile profile; profile.set_guid("00000000-0000-0000-0000-000000000200"); @@ -2614,11 +2545,8 @@ TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectPostalCode) { CreditCardSaveManager::DetectedValue::POSTAL_CODE); } -TEST_F(CreditCardSaveManagerTest, - GetDetectedValues_DetectNoUniquePostalCodeIfZipsConflict) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, + DetectNoUniquePostalCodeIfZipsConflict) { // Set up two new address profiles with conflicting postal codes. AutofillProfile profile1; profile1.set_guid("00000000-0000-0000-0000-000000000200"); @@ -2646,10 +2574,7 @@ TEST_F(CreditCardSaveManagerTest, EXPECT_EQ(payments_client_->detected_values_in_upload_details(), 0); } -TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectAddressLine) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, DetectAddressLine) { // Set up a new address profile. AutofillProfile profile; profile.set_guid("00000000-0000-0000-0000-000000000200"); @@ -2674,10 +2599,7 @@ TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectAddressLine) { CreditCardSaveManager::DetectedValue::ADDRESS_LINE); } -TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectLocality) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, DetectLocality) { // Set up a new address profile. AutofillProfile profile; profile.set_guid("00000000-0000-0000-0000-000000000200"); @@ -2702,10 +2624,8 @@ TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectLocality) { CreditCardSaveManager::DetectedValue::LOCALITY); } -TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectAdministrativeArea) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, + DetectAdministrativeArea) { // Set up a new address profile. AutofillProfile profile; profile.set_guid("00000000-0000-0000-0000-000000000200"); @@ -2730,10 +2650,7 @@ TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectAdministrativeArea) { CreditCardSaveManager::DetectedValue::ADMINISTRATIVE_AREA); } -TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectCountryCode) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, DetectCountryCode) { // Set up a new address profile. AutofillProfile profile; profile.set_guid("00000000-0000-0000-0000-000000000200"); @@ -2758,11 +2675,8 @@ TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectCountryCode) { CreditCardSaveManager::DetectedValue::COUNTRY_CODE); } -TEST_F(CreditCardSaveManagerTest, - GetDetectedValues_DetectHasGooglePaymentAccount) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, + DetectHasGooglePaymentAccount) { // Set the billing_customer_number Priority Preference to designate existence // of a Payments account. autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, @@ -2786,10 +2700,7 @@ TEST_F(CreditCardSaveManagerTest, CreditCardSaveManager::DetectedValue::HAS_GOOGLE_PAYMENTS_ACCOUNT); } -TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectEverythingAtOnce) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, DetectEverythingAtOnce) { // Set up a new address profile. AutofillProfile profile; profile.set_guid("00000000-0000-0000-0000-000000000200"); @@ -2826,11 +2737,8 @@ TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectEverythingAtOnce) { CreditCardSaveManager::DetectedValue::COUNTRY_CODE); } -TEST_F(CreditCardSaveManagerTest, - GetDetectedValues_DetectSubsetOfPossibleFields) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, + DetectSubsetOfPossibleFields) { // Set up a new address profile, taking out address line and state. AutofillProfile profile; profile.set_guid("00000000-0000-0000-0000-000000000200"); @@ -2864,11 +2772,8 @@ TEST_F(CreditCardSaveManagerTest, // This test checks that ADDRESS_LINE, LOCALITY, ADMINISTRATIVE_AREA, and // COUNTRY_CODE don't care about possible conflicts or consistency and are // populated if even one address profile contains it. -TEST_F(CreditCardSaveManagerTest, - GetDetectedValues_DetectAddressComponentsAcrossProfiles) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, + DetectAddressComponentsAcrossProfiles) { // Set up four new address profiles, each with a different address component. AutofillProfile profile1; profile1.set_guid("00000000-0000-0000-0000-000000000200"); @@ -2909,11 +2814,8 @@ TEST_F(CreditCardSaveManagerTest, CreditCardSaveManager::DetectedValue::COUNTRY_CODE); } -TEST_F(CreditCardSaveManagerTest, +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, UploadCreditCard_LogAdditionalErrorsWithUploadDetailsFailure) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Anything other than "en-US" will cause GetUploadDetails to return a failure // response. credit_card_save_manager_->SetAppLocale("pt-BR"); @@ -2962,12 +2864,9 @@ TEST_F(CreditCardSaveManagerTest, 1 /* expected_num_matching_entries */); } -TEST_F( - CreditCardSaveManagerTest, +TEST_P( + CreditCardSaveManagerFeatureParameterizedTest, UploadCreditCard_ShouldOfferLocalSaveIfEverythingDetectedAndPaymentsDeclines) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Anything other than "en-US" will cause GetUploadDetails to return a failure // response. credit_card_save_manager_->SetAppLocale("pt-BR"); @@ -3005,12 +2904,9 @@ TEST_F( EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded()); } -TEST_F( - CreditCardSaveManagerTest, +TEST_P( + CreditCardSaveManagerFeatureParameterizedTest, UploadCreditCard_ShouldOfferLocalSaveIfEverythingDetectedAndPaymentsDeclines_WithFirstAndLastName) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Anything other than "en-US" will cause GetUploadDetails to return a failure // response. credit_card_save_manager_->SetAppLocale("pt-BR"); @@ -3058,12 +2954,9 @@ TEST_F( "Autofill.SaveCardWithFirstAndLastNameComplete.Server", 0); } -TEST_F( - CreditCardSaveManagerTest, +TEST_P( + CreditCardSaveManagerFeatureParameterizedTest, UploadCreditCard_ShouldNotOfferLocalSaveIfSomethingNotDetectedAndPaymentsDeclines) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Anything other than "en-US" will cause GetUploadDetails to return a failure // response. credit_card_save_manager_->SetAppLocale("pt-BR"); @@ -3098,11 +2991,8 @@ TEST_F( EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded()); } -TEST_F(CreditCardSaveManagerTest, +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, UploadCreditCard_PaymentsDecidesOfferToSaveIfNoCvc) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; @@ -3143,11 +3033,8 @@ TEST_F(CreditCardSaveManagerTest, 1 /* expected_num_matching_entries */); } -TEST_F(CreditCardSaveManagerTest, +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, UploadCreditCard_PaymentsDecidesOfferToSaveIfNoName) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; @@ -3189,11 +3076,8 @@ TEST_F(CreditCardSaveManagerTest, 1 /* expected_num_matching_entries */); } -TEST_F(CreditCardSaveManagerTest, +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, UploadCreditCard_PaymentsDecidesOfferToSaveIfConflictingNames) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; @@ -3234,11 +3118,8 @@ TEST_F(CreditCardSaveManagerTest, 1 /* expected_num_matching_entries */); } -TEST_F(CreditCardSaveManagerTest, +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, UploadCreditCard_PaymentsDecidesOfferToSaveIfNoZip) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Set up a new address profile without a postal code. AutofillProfile profile; profile.set_guid("00000000-0000-0000-0000-000000000200"); @@ -3281,11 +3162,8 @@ TEST_F(CreditCardSaveManagerTest, 1 /* expected_num_matching_entries */); } -TEST_F(CreditCardSaveManagerTest, +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, UploadCreditCard_PaymentsDecidesOfferToSaveIfConflictingZips) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Set up two new address profiles with conflicting postal codes. AutofillProfile profile1; profile1.set_guid("00000000-0000-0000-0000-000000000200"); @@ -3340,11 +3218,8 @@ TEST_F(CreditCardSaveManagerTest, 1 /* expected_num_matching_entries */); } -TEST_F(CreditCardSaveManagerTest, +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, UploadCreditCard_PaymentsDecidesOfferToSaveIfNothingFound) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - // Set up a new address profile without a name or postal code. AutofillProfile profile; profile.set_guid("00000000-0000-0000-0000-000000000200"); @@ -3392,18 +3267,23 @@ TEST_F(CreditCardSaveManagerTest, 1 /* expected_num_matching_entries */); } -TEST_F( - CreditCardSaveManagerTest, - UploadCreditCard_AddUpdatePromptExplanationFlagStateToRequestIfExperimentOn) { - EnableAutofillUpstreamUpdatePromptExplanationExperiment(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, + UploadCreditCard_UploadOfLocalCard) { + // Add a local credit card whose |TypeAndLastFourDigits| matches what we will + // enter below. + CreditCard local_card; + test::SetCreditCardInfo(&local_card, "Flo Master", "4111111111111111", + NextMonth().c_str(), NextYear().c_str(), "1"); + local_card.set_record_type(CreditCard::LOCAL_CARD); + personal_data_.AddCreditCard(local_card); // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; test::CreateTestAddressFormData(&address_form); FormsSeen(std::vector<FormData>(1, address_form)); + ExpectUniqueFillableFormParsedUkm(); + ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); FormSubmitted(address_form); @@ -3411,35 +3291,40 @@ TEST_F( FormData credit_card_form; CreateTestCreditCardFormData(&credit_card_form, true, false); FormsSeen(std::vector<FormData>(1, credit_card_form)); + ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */); // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); - credit_card_form.fields[1].value = ASCIIToUTF16("4444333322221111"); + credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); - // Confirm upload happened and that the enabled UpdatePromptExplanation - // experiment flag state was sent in the request. + base::HistogramTester histogram_tester; + EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded()); - EXPECT_THAT( - payments_client_->active_experiments_in_request(), - UnorderedElementsAre(kAutofillUpstreamUpdatePromptExplanation.name)); -} -TEST_F(CreditCardSaveManagerTest, - UploadCreditCard_DoNotAddAnyFlagStatesToRequestIfExperimentsOff) { - DisableAutofillUpstreamUpdatePromptExplanationExperiment(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + // Verify that metrics noted it was an existing local card for which credit + // card upload was offered and accepted. + histogram_tester.ExpectUniqueSample( + "Autofill.UploadOfferedCardOrigin", + AutofillMetrics::OFFERING_UPLOAD_OF_LOCAL_CARD, 1); + histogram_tester.ExpectUniqueSample( + "Autofill.UploadAcceptedCardOrigin", + AutofillMetrics::USER_ACCEPTED_UPLOAD_OF_LOCAL_CARD, 1); +} +TEST_P(CreditCardSaveManagerFeatureParameterizedTest, + UploadCreditCard_UploadOfNewCard) { // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; test::CreateTestAddressFormData(&address_form); FormsSeen(std::vector<FormData>(1, address_form)); + ExpectUniqueFillableFormParsedUkm(); + ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); FormSubmitted(address_form); @@ -3447,6 +3332,7 @@ TEST_F(CreditCardSaveManagerTest, FormData credit_card_form; CreateTestCreditCardFormData(&credit_card_form, true, false); FormsSeen(std::vector<FormData>(1, credit_card_form)); + ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */); // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); @@ -3455,18 +3341,24 @@ TEST_F(CreditCardSaveManagerTest, credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); - // Confirm that upload happened and that no experiment flag state was sent in - // the request. + base::HistogramTester histogram_tester; + EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded()); - EXPECT_TRUE(payments_client_->active_experiments_in_request().empty()); + + // Verify that metrics noted it was a brand new card for which credit card + // upload was offered and accepted. + histogram_tester.ExpectUniqueSample( + "Autofill.UploadOfferedCardOrigin", + AutofillMetrics::OFFERING_UPLOAD_OF_NEW_CARD, 1); + histogram_tester.ExpectUniqueSample( + "Autofill.UploadAcceptedCardOrigin", + AutofillMetrics::USER_ACCEPTED_UPLOAD_OF_NEW_CARD, 1); } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_AddPanFirstSixToRequest) { EnableAutofillUpstreamSendPanFirstSixExperiment(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. @@ -3496,32 +3388,30 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_AddPanFirstSixToRequest) { EXPECT_EQ(payments_client_->pan_first_six_in_upload_details(), "444433"); // Confirm that the "send pan first six" experiment flag and enabled // UpdatePromptExplanation experiment flag state was sent in the request. - EXPECT_THAT( - payments_client_->active_experiments_in_request(), - UnorderedElementsAre(kAutofillUpstreamSendPanFirstSix.name, - kAutofillUpstreamUpdatePromptExplanation.name)); + EXPECT_THAT(payments_client_->active_experiments_in_request(), + UnorderedElementsAre( + features::kAutofillUpstreamSendPanFirstSix.name, + features::kAutofillUpstreamUpdatePromptExplanation.name)); } -TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadOfLocalCard) { - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); - - // Add a local credit card whose |TypeAndLastFourDigits| matches what we will - // enter below. - CreditCard local_card; - test::SetCreditCardInfo(&local_card, "Flo Master", "4111111111111111", - NextMonth().c_str(), NextYear().c_str(), "1"); - local_card.set_record_type(CreditCard::LOCAL_CARD); - personal_data_.AddCreditCard(local_card); +// Every test will appear with suffix /0 (param false) and /1 (param true), e.g. +// CreditCardSaveManagerFeatureParameterizedTest.NothingIfNothingFound/0: +// Feature disabled +// CreditCardSaveManagerFeatureParameterizedTest.NothingIfNothingFound/1: +// Feature enabled. +INSTANTIATE_TEST_CASE_P(, // Empty instatiation name. + CreditCardSaveManagerFeatureParameterizedTest, + ::testing::Values(false, true)); +TEST_F( + CreditCardSaveManagerTest, + UploadCreditCard_AddUpdatePromptExplanationFlagStateToRequestIfExperimentOn) { + EnableAutofillUpstreamUpdatePromptExplanationExperiment(); // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; test::CreateTestAddressFormData(&address_form); FormsSeen(std::vector<FormData>(1, address_form)); - ExpectUniqueFillableFormParsedUkm(); - ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); FormSubmitted(address_form); @@ -3529,44 +3419,33 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadOfLocalCard) { FormData credit_card_form; CreateTestCreditCardFormData(&credit_card_form, true, false); FormsSeen(std::vector<FormData>(1, credit_card_form)); - ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */); // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); - credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); + credit_card_form.fields[1].value = ASCIIToUTF16("4444333322221111"); credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); - base::HistogramTester histogram_tester; - + // Confirm upload happened and that the enabled UpdatePromptExplanation + // experiment flag state was sent in the request. EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded()); - - // Verify that metrics noted it was an existing local card for which credit - // card upload was offered and accepted. - histogram_tester.ExpectUniqueSample( - "Autofill.UploadOfferedCardOrigin", - AutofillMetrics::OFFERING_UPLOAD_OF_LOCAL_CARD, 1); - histogram_tester.ExpectUniqueSample( - "Autofill.UploadAcceptedCardOrigin", - AutofillMetrics::USER_ACCEPTED_UPLOAD_OF_LOCAL_CARD, 1); + EXPECT_THAT(payments_client_->active_experiments_in_request(), + UnorderedElementsAre( + features::kAutofillUpstreamUpdatePromptExplanation.name)); } -TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadOfNewCard) { - // No cards already on the device. - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); +TEST_F(CreditCardSaveManagerTest, + UploadCreditCard_DoNotAddAnyFlagStatesToRequestIfExperimentsOff) { + DisableAutofillUpstreamUpdatePromptExplanationExperiment(); // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. FormData address_form; test::CreateTestAddressFormData(&address_form); FormsSeen(std::vector<FormData>(1, address_form)); - ExpectUniqueFillableFormParsedUkm(); - ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); FormSubmitted(address_form); @@ -3574,7 +3453,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadOfNewCard) { FormData credit_card_form; CreateTestCreditCardFormData(&credit_card_form, true, false); FormsSeen(std::vector<FormData>(1, credit_card_form)); - ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */); // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); @@ -3583,25 +3461,15 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadOfNewCard) { credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); - base::HistogramTester histogram_tester; - + // Confirm that upload happened and that no experiment flag state was sent in + // the request. EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded()); - - // Verify that metrics noted it was a brand new card for which credit card - // upload was offered and accepted. - histogram_tester.ExpectUniqueSample( - "Autofill.UploadOfferedCardOrigin", - AutofillMetrics::OFFERING_UPLOAD_OF_NEW_CARD, 1); - histogram_tester.ExpectUniqueSample( - "Autofill.UploadAcceptedCardOrigin", - AutofillMetrics::USER_ACCEPTED_UPLOAD_OF_NEW_CARD, 1); + EXPECT_TRUE(payments_client_->active_experiments_in_request().empty()); } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_EloDisallowed) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); scoped_feature_list_.InitAndEnableFeature( features::kAutofillUpstreamDisallowElo); @@ -3632,8 +3500,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_EloDisallowed) { } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_EloAllowed) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); scoped_feature_list_.InitAndDisableFeature( features::kAutofillUpstreamDisallowElo); @@ -3663,8 +3529,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_EloAllowed) { } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_JcbDisallowed) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); scoped_feature_list_.InitAndEnableFeature( features::kAutofillUpstreamDisallowJcb); @@ -3695,8 +3559,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_JcbDisallowed) { } TEST_F(CreditCardSaveManagerTest, UploadCreditCard_JcbAllowed) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); scoped_feature_list_.InitAndDisableFeature( features::kAutofillUpstreamDisallowJcb); @@ -3730,8 +3592,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_JcbAllowed) { // This test ensures that we do not offer local save (again) for the card that // FormDataImporter imported. TEST_F(CreditCardSaveManagerTest, UploadCreditCard_DisallowedLocalCard) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); scoped_feature_list_.InitAndEnableFeature( features::kAutofillUpstreamDisallowElo); diff --git a/chromium/components/autofill/core/browser/field_filler.cc b/chromium/components/autofill/core/browser/field_filler.cc index cb536280e1e..e1e56eb081d 100644 --- a/chromium/components/autofill/core/browser/field_filler.cc +++ b/chromium/components/autofill/core/browser/field_filler.cc @@ -17,7 +17,6 @@ #include "components/autofill/core/browser/autofill_country.h" #include "components/autofill/core/browser/autofill_data_model.h" #include "components/autofill/core/browser/autofill_data_util.h" -#include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_type.h" @@ -26,6 +25,7 @@ #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/phone_number.h" #include "components/autofill/core/browser/state_names.h" +#include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_l10n_util.h" #include "components/autofill/core/common/autofill_util.h" #include "components/strings/grit/components_strings.h" @@ -626,7 +626,7 @@ bool FieldFiller::FillFormField(const AutofillField& field, const AutofillType type = field.Type(); // Don't fill if autocomplete=off is set on |field| on desktop for non credit // card related fields. - if (!base::FeatureList::IsEnabled(kAutofillAlwaysFillAddresses) && + if (!base::FeatureList::IsEnabled(features::kAutofillAlwaysFillAddresses) && !field.should_autocomplete && IsDesktopPlatform() && (type.group() != CREDIT_CARD)) { return false; diff --git a/chromium/components/autofill/core/browser/field_filler_unittest.cc b/chromium/components/autofill/core/browser/field_filler_unittest.cc index 928e2b9f97e..b092bfbff40 100644 --- a/chromium/components/autofill/core/browser/field_filler_unittest.cc +++ b/chromium/components/autofill/core/browser/field_filler_unittest.cc @@ -19,7 +19,6 @@ #include "base/test/scoped_task_environment.h" #include "components/autofill/core/browser/address_normalizer.h" #include "components/autofill/core/browser/address_normalizer_impl.h" -#include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_test_utils.h" @@ -27,6 +26,7 @@ #include "components/autofill/core/browser/country_names.h" #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/libaddressinput/src/cpp/include/libaddressinput/null_storage.h" @@ -335,7 +335,7 @@ TEST_F(AutofillFieldFillerTest, IsFieldFillable) { TEST_F(AutofillFieldFillerTest, FillFormField_AutocompleteOffRespected_AddressField) { base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature(kAutofillAlwaysFillAddresses); + feature_list.InitAndDisableFeature(features::kAutofillAlwaysFillAddresses); AutofillField field; field.should_autocomplete = false; diff --git a/chromium/components/autofill/core/browser/form_data_importer.cc b/chromium/components/autofill/core/browser/form_data_importer.cc index 543e5c7cabd..95c19c44471 100644 --- a/chromium/components/autofill/core/browser/form_data_importer.cc +++ b/chromium/components/autofill/core/browser/form_data_importer.cc @@ -20,7 +20,6 @@ #include "build/build_config.h" #include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/autofill_country.h" -#include "components/autofill/core/browser/autofill_experiments.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" @@ -138,7 +137,8 @@ void FormDataImporter::ImportFormData(const FormStructure& submitted_form, if (local_card_migration_manager_ && local_card_migration_manager_->ShouldOfferLocalCardMigration( imported_credit_card_record_type_)) { - local_card_migration_manager_->AttemptToOfferLocalCardMigration(); + local_card_migration_manager_->AttemptToOfferLocalCardMigration( + /*is_from_settings_page=*/false); return; } diff --git a/chromium/components/autofill/core/browser/form_data_importer.h b/chromium/components/autofill/core/browser/form_data_importer.h index 596fd065c8d..e7bc5b6f71c 100644 --- a/chromium/components/autofill/core/browser/form_data_importer.h +++ b/chromium/components/autofill/core/browser/form_data_importer.h @@ -61,6 +61,10 @@ class FormDataImporter { static bool IsValidLearnableProfile(const AutofillProfile& profile, const std::string& app_locale); + LocalCardMigrationManager* local_card_migration_manager() { + return local_card_migration_manager_.get(); + } + protected: // Exposed for testing. void set_credit_card_save_manager( @@ -142,6 +146,7 @@ class FormDataImporter { friend class FormDataImporterTest; friend class FormDataImporterTestBase; friend class SaveCardBubbleViewsBrowserTestBase; + friend class SaveCardInfobarEGTestHelper; FRIEND_TEST_ALL_PREFIXES(AutofillMergeTest, MergeProfiles); FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, AllowDuplicateMaskedServerCardIfFlagEnabled); diff --git a/chromium/components/autofill/core/browser/form_data_importer_unittest.cc b/chromium/components/autofill/core/browser/form_data_importer_unittest.cc index 3c0c3300f53..556fdb6ac1a 100644 --- a/chromium/components/autofill/core/browser/form_data_importer_unittest.cc +++ b/chromium/components/autofill/core/browser/form_data_importer_unittest.cc @@ -38,6 +38,7 @@ #include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/common/autofill_constants.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/autofill/core/common/autofill_util.h" #include "components/autofill/core/common/form_data.h" @@ -183,8 +184,7 @@ class FormDataImporterTestBase { const char* exp_cc_month, const char* exp_cc_year) { FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card)); ASSERT_TRUE(imported_credit_card); @@ -294,8 +294,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles) { test::CreateTestFormField("Zip:", "zip", "94102", "text", &field); form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure)); WaitForOnPersonalDataChanged(); @@ -332,8 +331,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_BadEmail) { test::CreateTestFormField("Zip:", "zip", "94102", "text", &field); form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); EXPECT_FALSE(ImportAddressProfiles(form_structure)); ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size()); @@ -362,8 +360,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoEmails) { "example@example.com", "text", &field); form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure)); WaitForOnPersonalDataChanged(); @@ -394,8 +391,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoDifferentEmails) { &field); form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); EXPECT_FALSE(ImportAddressProfiles(form_structure)); ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size()); @@ -415,8 +411,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_NotEnoughFilledFields) { "4111 1111 1111 1111", "text", &field); form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); EXPECT_FALSE(ImportAddressProfiles(form_structure)); ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size()); @@ -442,8 +437,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MinimumAddressUSA) { test::CreateTestFormField("Country:", "country", "USA", "text", &field); form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure)); WaitForOnPersonalDataChanged(); @@ -470,8 +464,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MinimumAddressGB) { &field); form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure)); WaitForOnPersonalDataChanged(); @@ -493,8 +486,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MinimumAddressGI) { test::CreateTestFormField("Country:", "country", "Gibraltar", "text", &field); form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure)); WaitForOnPersonalDataChanged(); @@ -534,8 +526,7 @@ TEST_F(FormDataImporterTest, test::CreateTestFormField("Zip:", "zip", "94102", "text", &field); form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure)); WaitForOnPersonalDataChanged(); @@ -574,8 +565,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MultilineAddress) { test::CreateTestFormField("Zip:", "zip", "94102", "text", &field); form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure)); WaitForOnPersonalDataChanged(); @@ -615,8 +605,7 @@ TEST_F(FormDataImporterTest, form1.fields.push_back(field); FormStructure form_structure1(form1); - form_structure1.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure1.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure1)); WaitForOnPersonalDataChanged(); @@ -652,8 +641,7 @@ TEST_F(FormDataImporterTest, form2.fields.push_back(field); FormStructure form_structure2(form2); - form_structure2.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure2.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure2)); WaitForOnPersonalDataChanged(); @@ -710,8 +698,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoValidProfilesSameForm) { form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure)); WaitForOnPersonalDataChanged(); @@ -785,8 +772,7 @@ TEST_F(FormDataImporterTest, // Still able to do the import. FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure)); WaitForOnPersonalDataChanged(); @@ -868,8 +854,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_ThreeValidProfilesSameForm) { form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure)); WaitForOnPersonalDataChanged(); @@ -923,8 +908,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_SameProfileWithConflict) { form1.fields.push_back(field); FormStructure form_structure1(form1); - form_structure1.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure1.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure1)); WaitForOnPersonalDataChanged(); @@ -970,8 +954,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_SameProfileWithConflict) { form2.fields.push_back(field); FormStructure form_structure2(form2); - form_structure2.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure2.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure2)); WaitForOnPersonalDataChanged(); @@ -1008,8 +991,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInOld) { form1.fields.push_back(field); FormStructure form_structure1(form1); - form_structure1.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure1.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure1)); WaitForOnPersonalDataChanged(); @@ -1045,8 +1027,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInOld) { form2.fields.push_back(field); FormStructure form_structure2(form2); - form_structure2.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure2.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure2)); WaitForOnPersonalDataChanged(); @@ -1090,8 +1071,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInNew) { form1.fields.push_back(field); FormStructure form_structure1(form1); - form_structure1.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure1.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure1)); WaitForOnPersonalDataChanged(); @@ -1129,8 +1109,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInNew) { form2.fields.push_back(field); FormStructure form_structure2(form2); - form_structure2.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure2.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure2)); WaitForOnPersonalDataChanged(); @@ -1166,8 +1145,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_InsufficientAddress) { form1.fields.push_back(field); FormStructure form_structure1(form1); - form_structure1.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure1.DetermineHeuristicTypes(); EXPECT_FALSE(ImportAddressProfiles(form_structure1)); // Since no refresh is expected, reload the data from the database to make @@ -1219,8 +1197,7 @@ TEST_F(FormDataImporterTest, form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure)); // Wait for the refresh, which in this case is a no-op. @@ -1240,8 +1217,8 @@ TEST_F(FormDataImporterTest, form.fields[0] = field; FormStructure form_structure2(form); - form_structure2.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure2.DetermineHeuristicTypes(); + EXPECT_TRUE(ImportAddressProfiles(form_structure2)); // Wait for the refresh, which in this case is a no-op. @@ -1281,8 +1258,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_UnrecognizedCountry) { form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); EXPECT_FALSE(ImportAddressProfiles(form_structure)); // Since no refresh is expected, reload the data from the database to make @@ -1321,8 +1297,7 @@ TEST_F(FormDataImporterTest, form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); EXPECT_TRUE(ImportAddressProfiles(form_structure)); WaitForOnPersonalDataChanged(); @@ -1369,8 +1344,7 @@ TEST_F(FormDataImporterTest, form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); EXPECT_FALSE(ImportAddressProfiles(form_structure)); // Since no refresh is expected, reload the data from the database to make @@ -1391,8 +1365,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_Valid) { "2999"); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; base::HistogramTester histogram_tester; EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card)); @@ -1420,8 +1393,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_InvalidCardNumber) { "2999"); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; base::HistogramTester histogram_tester; EXPECT_FALSE(ImportCreditCard(form_structure, false, &imported_credit_card)); @@ -1444,8 +1416,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_InvalidExpiryDate) { "2999"); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; base::HistogramTester histogram_tester; EXPECT_FALSE(ImportCreditCard(form_structure, false, &imported_credit_card)); @@ -1481,8 +1452,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_MonthSelectInvalidText) { form.fields[2].option_contents = contents; FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; base::HistogramTester histogram_tester; EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card)); @@ -1511,8 +1481,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_TwoValidCards) { "2999"); FormStructure form_structure1(form1); - form_structure1.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure1.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card)); ASSERT_TRUE(imported_credit_card); @@ -1533,8 +1502,8 @@ TEST_F(FormDataImporterTest, ImportCreditCard_TwoValidCards) { AddFullCreditCardForm(&form2, "", "5500 0000 0000 0004", "02", "2999"); FormStructure form_structure2(form2); - form_structure2.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure2.DetermineHeuristicTypes(); + std::unique_ptr<CreditCard> imported_credit_card2; EXPECT_TRUE(ImportCreditCard(form_structure2, false, &imported_credit_card2)); ASSERT_TRUE(imported_credit_card2); @@ -1652,8 +1621,7 @@ TEST_F(FormDataImporterTest, // The card should not be offered to be saved locally because the feature flag // is disabled. FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_FALSE(ImportCreditCard(form_structure, false, &imported_credit_card)); ASSERT_FALSE(imported_credit_card); @@ -1682,8 +1650,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_DuplicateServerCards_FullCard) { // The card should not be offered to be saved locally because it only matches // the full server card. FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_FALSE(ImportCreditCard(form_structure, false, &imported_credit_card)); ASSERT_FALSE(imported_credit_card); @@ -1696,8 +1663,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_SameCreditCardWithConflict) { "2998"); FormStructure form_structure1(form1); - form_structure1.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure1.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card)); ASSERT_TRUE(imported_credit_card); @@ -1720,8 +1686,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_SameCreditCardWithConflict) { /* different year */ "2999"); FormStructure form_structure2(form2); - form_structure2.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure2.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card2; EXPECT_TRUE(ImportCreditCard(form_structure2, false, &imported_credit_card2)); EXPECT_FALSE(imported_credit_card2); @@ -1746,8 +1711,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_ShouldReturnLocalCard) { "2998"); FormStructure form_structure1(form1); - form_structure1.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure1.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card)); ASSERT_TRUE(imported_credit_card); @@ -1770,8 +1734,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_ShouldReturnLocalCard) { /* different year */ "2999"); FormStructure form_structure2(form2); - form_structure2.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure2.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card2; EXPECT_TRUE(ImportCreditCard(form_structure2, /* should_return_local_card= */ true, @@ -1799,8 +1762,8 @@ TEST_F(FormDataImporterTest, ImportCreditCard_EmptyCardWithConflict) { "2998"); FormStructure form_structure1(form1); - form_structure1.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure1.DetermineHeuristicTypes(); + std::unique_ptr<CreditCard> imported_credit_card; EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card)); ASSERT_TRUE(imported_credit_card); @@ -1822,8 +1785,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_EmptyCardWithConflict) { "2999"); FormStructure form_structure2(form2); - form_structure2.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure2.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card2; EXPECT_FALSE( ImportCreditCard(form_structure2, false, &imported_credit_card2)); @@ -1850,8 +1812,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_MissingInfoInNew) { "2999"); FormStructure form_structure1(form1); - form_structure1.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure1.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card)); ASSERT_TRUE(imported_credit_card); @@ -1874,8 +1835,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_MissingInfoInNew) { "4111-1111-1111-1111", "01", "2999"); FormStructure form_structure2(form2); - form_structure2.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure2.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card2; EXPECT_TRUE(ImportCreditCard(form_structure2, false, &imported_credit_card2)); EXPECT_FALSE(imported_credit_card2); @@ -1900,8 +1860,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_MissingInfoInNew) { /* no year */ nullptr); FormStructure form_structure3(form3); - form_structure3.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure3.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card3; EXPECT_FALSE( ImportCreditCard(form_structure3, false, &imported_credit_card3)); @@ -1943,8 +1902,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_MissingInfoInOld) { /* different year */ "2999"); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card)); EXPECT_FALSE(imported_credit_card); @@ -1985,8 +1943,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_SameCardWithSeparators) { "2999"); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card)); EXPECT_FALSE(imported_credit_card); @@ -2026,8 +1983,7 @@ TEST_F(FormDataImporterTest, /* different year */ "2999"); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card)); ASSERT_FALSE(imported_credit_card); @@ -2065,8 +2021,7 @@ TEST_F(FormDataImporterTest, "2999"); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, @@ -2086,8 +2041,7 @@ TEST_F(FormDataImporterTest, "2999"); FormStructure form_structure2(form2); - form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure2.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card2; EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure2, /*profile_autofill_enabled=*/true, @@ -2124,8 +2078,7 @@ TEST_F(FormDataImporterTest, test::CreateTestFormField("Zip:", "zip", "94102", "text", &field); form3.fields.push_back(field); FormStructure form_structure3(form3); - form_structure3.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure3.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card3; EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure3, /*profile_autofill_enabled=*/true, @@ -2146,8 +2099,7 @@ TEST_F(FormDataImporterTest, "2999"); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, @@ -2182,8 +2134,7 @@ TEST_F(FormDataImporterTest, "2999"); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, @@ -2218,8 +2169,7 @@ TEST_F(FormDataImporterTest, "2999"); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, @@ -2253,8 +2203,7 @@ TEST_F(FormDataImporterTest, "2999"); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, @@ -2275,8 +2224,7 @@ TEST_F(FormDataImporterTest, "2999"); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, @@ -2298,8 +2246,7 @@ TEST_F(FormDataImporterTest, "1999"); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, @@ -2338,8 +2285,7 @@ TEST_F(FormDataImporterTest, form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, @@ -2384,8 +2330,7 @@ TEST_F(FormDataImporterTest, ImportFormData_OneAddressOneCreditCard) { "2999"); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, @@ -2463,8 +2408,7 @@ TEST_F(FormDataImporterTest, ImportFormData_TwoAddressesOneCreditCard) { "2999"); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; // Still returns true because the credit card import was successful. EXPECT_TRUE(form_data_importer_->ImportFormData( @@ -2519,8 +2463,7 @@ TEST_F(FormDataImporterTest, ImportFormData_AddressesDisabledOneCreditCard) { "2999"); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/false, @@ -2574,8 +2517,7 @@ TEST_F(FormDataImporterTest, ImportFormData_OneAddressCreditCardDisabled) { "2999"); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, @@ -2633,8 +2575,7 @@ TEST_F(FormDataImporterTest, ImportFormData_AddressCreditCardDisabled) { "2999"); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, @@ -2689,8 +2630,7 @@ TEST_F(FormDataImporterTest, DontDuplicateMaskedServerCard) { form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, @@ -2737,8 +2677,7 @@ TEST_F(FormDataImporterTest, DontDuplicateFullServerCard) { form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, @@ -2781,8 +2720,7 @@ TEST_F(FormDataImporterTest, base::HistogramTester histogram_tester; FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, @@ -2829,8 +2767,7 @@ TEST_F(FormDataImporterTest, base::HistogramTester histogram_tester; FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, @@ -2877,8 +2814,7 @@ TEST_F(FormDataImporterTest, base::HistogramTester histogram_tester; FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, @@ -2926,8 +2862,7 @@ TEST_F(FormDataImporterTest, base::HistogramTester histogram_tester; FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, diff --git a/chromium/components/autofill/core/browser/form_field.cc b/chromium/components/autofill/core/browser/form_field.cc index c8d7bf171e3..3328e18c6f9 100644 --- a/chromium/components/autofill/core/browser/form_field.cc +++ b/chromium/components/autofill/core/browser/form_field.cc @@ -70,7 +70,8 @@ FieldCandidatesMap FormField::ParseFormFields( ParseFormFieldsPass(PhoneField::Parse, processed_fields, &field_candidates); // Address pass. - ParseFormFieldsPass(AddressField::Parse, processed_fields, &field_candidates); + ParseFormFieldsPass(autofill::AddressField::Parse, processed_fields, + &field_candidates); // Credit card pass. ParseFormFieldsPass(CreditCardField::Parse, processed_fields, diff --git a/chromium/components/autofill/core/browser/form_structure.cc b/chromium/components/autofill/core/browser/form_structure.cc index f712a2d4983..9760452889a 100644 --- a/chromium/components/autofill/core/browser/form_structure.cc +++ b/chromium/components/autofill/core/browser/form_structure.cc @@ -25,7 +25,7 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" -#include "components/autofill/core/browser/autofill_experiments.h" +#include "components/autofill/core/browser/autofill_data_util.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/field_candidates.h" @@ -44,7 +44,6 @@ #include "components/autofill/core/common/form_field_data_predictions.h" #include "components/autofill/core/common/signatures_util.h" #include "components/security_state/core/security_state.h" -#include "services/metrics/public/cpp/ukm_recorder.h" #include "url/origin.h" namespace autofill { @@ -287,14 +286,6 @@ std::ostream& operator<<( return out; } -bool IsCreditCardExpirationType(ServerFieldType type) { - return type == CREDIT_CARD_EXP_MONTH || - type == CREDIT_CARD_EXP_2_DIGIT_YEAR || - type == CREDIT_CARD_EXP_4_DIGIT_YEAR || - type == CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR || - type == CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR; -} - // Returns true iff all form fields autofill types are in |contained_types|. bool AllTypesCaptured(const FormStructure& form, const ServerFieldTypeSet& contained_types) { @@ -338,6 +329,7 @@ void EncodePasswordAttributesVote( FormStructure::FormStructure(const FormData& form) : form_name_(form.name), + submission_event_(PasswordForm::SubmissionIndicatorEvent::NONE), source_url_(form.origin), target_url_(form.action), main_frame_origin_(form.main_frame_origin), @@ -353,7 +345,9 @@ FormStructure::FormStructure(const FormData& form) is_formless_checkout_(form.is_formless_checkout), all_fields_are_passwords_(!form.fields.empty()), is_signin_upload_(false), - passwords_were_revealed_(false) { + form_parsed_timestamp_(base::TimeTicks::Now()), + passwords_were_revealed_(false), + developer_engagement_metrics_(0) { // Copy the form fields. std::map<base::string16, size_t> unique_names; for (const FormFieldData& field : form.fields) { @@ -381,8 +375,7 @@ FormStructure::FormStructure(const FormData& form) FormStructure::~FormStructure() {} -void FormStructure::DetermineHeuristicTypes(ukm::UkmRecorder* ukm_recorder, - ukm::SourceId source_id) { +void FormStructure::DetermineHeuristicTypes() { const auto determine_heuristic_types_start_time = base::TimeTicks::Now(); // First, try to detect field types based on each field's |autocomplete| @@ -407,31 +400,25 @@ void FormStructure::DetermineHeuristicTypes(ukm::UkmRecorder* ukm_recorder, UpdateAutofillCount(); IdentifySections(has_author_specified_sections_); - int developer_engagement_metrics = 0; + developer_engagement_metrics_ = 0; if (IsAutofillable()) { AutofillMetrics::DeveloperEngagementMetric metric = has_author_specified_types_ ? AutofillMetrics::FILLABLE_FORM_PARSED_WITH_TYPE_HINTS : AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS; - developer_engagement_metrics |= 1 << metric; + developer_engagement_metrics_ |= 1 << metric; AutofillMetrics::LogDeveloperEngagementMetric(metric); } if (has_author_specified_upi_vpa_hint_) { AutofillMetrics::LogDeveloperEngagementMetric( AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT); - developer_engagement_metrics |= + developer_engagement_metrics_ |= 1 << AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT; } - if (developer_engagement_metrics) { - AutofillMetrics::LogDeveloperEngagementUkm( - ukm_recorder, source_id, main_frame_origin().GetURL(), - IsCompleteCreditCardForm(), GetFormTypes(), - developer_engagement_metrics, form_signature()); - } - - if (base::FeatureList::IsEnabled(kAutofillRationalizeFieldTypePredictions)) + if (base::FeatureList::IsEnabled( + features::kAutofillRationalizeFieldTypePredictions)) RationalizeFieldTypePredictions(); AutofillMetrics::LogDetermineHeuristicTypesTiming( @@ -444,7 +431,6 @@ bool FormStructure::EncodeUploadRequest( const std::string& login_form_signature, bool observed_submission, AutofillUploadContents* upload) const { - DCHECK(ShouldBeUploaded()); DCHECK(AllTypesCaptured(*this, available_field_types)); upload->set_submission(observed_submission); @@ -453,6 +439,13 @@ bool FormStructure::EncodeUploadRequest( upload->set_autofill_used(form_was_autofilled); upload->set_data_present(EncodeFieldTypes(available_field_types)); upload->set_passwords_revealed(passwords_were_revealed_); + if (submission_event_ != PasswordForm::SubmissionIndicatorEvent::NONE) { + DCHECK(submission_event_ != PasswordForm::SubmissionIndicatorEvent:: + SUBMISSION_INDICATOR_EVENT_COUNT); + upload->set_submission_event( + static_cast<AutofillUploadContents_SubmissionIndicatorEvent>( + submission_event_)); + } if (password_attributes_vote_) { EncodePasswordAttributesVote(*password_attributes_vote_, password_length_vote_, upload); @@ -523,6 +516,14 @@ void FormStructure::ParseQueryResponse( VLOG(1) << "Autofill query response was successfully parsed:\n" << response; + ProcessQueryResponse(response, forms, form_interactions_ukm_logger); +} + +// static +void FormStructure::ProcessQueryResponse( + const AutofillQueryResponseContents& response, + const std::vector<FormStructure*>& forms, + AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger) { AutofillMetrics::LogServerQueryMetric(AutofillMetrics::QUERY_RESPONSE_PARSED); bool heuristics_detected_fillable_field = false; @@ -582,7 +583,8 @@ void FormStructure::ParseQueryResponse( features::kAutofillRationalizeRepeatedServerPredictions)) form->RationalizeRepeatedFields(form_interactions_ukm_logger); - if (base::FeatureList::IsEnabled(kAutofillRationalizeFieldTypePredictions)) + if (base::FeatureList::IsEnabled( + features::kAutofillRationalizeFieldTypePredictions)) form->RationalizeFieldTypePredictions(); form->IdentifySections(false); @@ -663,7 +665,7 @@ bool FormStructure::IsCompleteCreditCardForm() const { bool found_cc_expiration = false; for (const auto& field : fields_) { ServerFieldType type = field->Type().GetStorableType(); - if (!found_cc_expiration && IsCreditCardExpirationType(type)) { + if (!found_cc_expiration && data_util::IsCreditCardExpirationType(type)) { found_cc_expiration = true; } else if (!found_cc_number && type == CREDIT_CARD_NUMBER) { found_cc_number = true; @@ -723,8 +725,7 @@ bool FormStructure::ShouldBeQueried() const { } bool FormStructure::ShouldBeUploaded() const { - return (has_password_field_ || - active_field_count() >= MinRequiredFieldsForUpload()) && + return active_field_count() >= MinRequiredFieldsForUpload() && ShouldBeParsed(); } @@ -769,7 +770,7 @@ void FormStructure::RetrieveFromCache( UpdateAutofillCount(); // Update form parsed timestamp - set_form_parsed_timestamp(cached_form.form_parsed_timestamp()); + form_parsed_timestamp_ = cached_form.form_parsed_timestamp_; // The form signature should match between query and upload requests to the // server. On many websites, form elements are dynamically added, removed, or @@ -1580,49 +1581,45 @@ void FormStructure::EncodeFormForUpload(AutofillUploadContents* upload) const { if (IsCheckable(field->check_status)) continue; - const ServerFieldTypeSet& types = field->possible_types(); - for (const auto& field_type : types) { - // Add the same field elements as the query and a few more below. - if (ShouldSkipField(*field)) - continue; + // Add the same field elements as the query and a few more below. + if (ShouldSkipField(*field)) + continue; - AutofillUploadContents::Field* added_field = upload->add_field(); - added_field->set_autofill_type(field_type); - if (field->generation_type()) { - added_field->set_generation_type(field->generation_type()); - added_field->set_generated_password_changed( - field->generated_password_changed()); - } + auto* added_field = upload->add_field(); - if (field->form_classifier_outcome()) { - added_field->set_form_classifier_outcome( - field->form_classifier_outcome()); - } + for (const auto& field_type : field->possible_types()) { + added_field->add_autofill_type(field_type); + } - if (field->vote_type()) { - added_field->set_vote_type(field->vote_type()); - } + if (field->generation_type()) { + added_field->set_generation_type(field->generation_type()); + added_field->set_generated_password_changed( + field->generated_password_changed()); + } + + if (field->vote_type()) { + added_field->set_vote_type(field->vote_type()); + } - added_field->set_signature(field->GetFieldSignature()); + added_field->set_signature(field->GetFieldSignature()); - if (field->properties_mask) - added_field->set_properties_mask(field->properties_mask); + if (field->properties_mask) + added_field->set_properties_mask(field->properties_mask); - if (IsAutofillFieldMetadataEnabled()) { - added_field->set_type(field->form_control_type); + if (IsAutofillFieldMetadataEnabled()) { + added_field->set_type(field->form_control_type); - if (!field->name.empty()) - added_field->set_name(base::UTF16ToUTF8(field->name)); + if (!field->name.empty()) + added_field->set_name(base::UTF16ToUTF8(field->name)); - if (!field->id.empty()) - added_field->set_id(base::UTF16ToUTF8(field->id)); + if (!field->id.empty()) + added_field->set_id(base::UTF16ToUTF8(field->id)); - if (!field->autocomplete_attribute.empty()) - added_field->set_autocomplete(field->autocomplete_attribute); + if (!field->autocomplete_attribute.empty()) + added_field->set_autocomplete(field->autocomplete_attribute); - if (!field->css_classes.empty()) - added_field->set_css_classes(base::UTF16ToUTF8(field->css_classes)); - } + if (!field->css_classes.empty()) + added_field->set_css_classes(base::UTF16ToUTF8(field->css_classes)); } } } diff --git a/chromium/components/autofill/core/browser/form_structure.h b/chromium/components/autofill/core/browser/form_structure.h index d41617d668a..2cf3f6e028e 100644 --- a/chromium/components/autofill/core/browser/form_structure.h +++ b/chromium/components/autofill/core/browser/form_structure.h @@ -23,6 +23,7 @@ #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/form_types.h" #include "components/autofill/core/browser/proto/server.pb.h" +#include "components/autofill/core/common/password_form.h" #include "url/gurl.h" #include "url/origin.h" @@ -32,10 +33,6 @@ namespace base { class TimeTicks; } -namespace ukm { -class UkmRecorder; -} - namespace autofill { // Password attributes (whether a password has special symbols, numeric, etc.) @@ -58,10 +55,8 @@ class FormStructure { virtual ~FormStructure(); // Runs several heuristics against the form fields to determine their possible - // types. If |ukm_recorder| and |source_id| is specified, logs UKM for - // the form structure corresponding to the source mapped from the |source_id|. - void DetermineHeuristicTypes(ukm::UkmRecorder* ukm_recorder, - ukm::SourceId source_id); + // types. + void DetermineHeuristicTypes(); // Encodes the proto |upload| request from this FormStructure. // In some cases, a |login_form_signature| is included as part of the upload. @@ -80,12 +75,21 @@ class FormStructure { std::vector<std::string>* encoded_signatures, autofill::AutofillQueryContents* query); - // Parses the field types from the server query response. |forms| must be the - // same as the one passed to EncodeQueryRequest when constructing the query. + // Parses response as AutofillQueryResponseContents proto and calls + // ProcessQueryResponse. static void ParseQueryResponse(std::string response, const std::vector<FormStructure*>& forms, AutofillMetrics::FormInteractionsUkmLogger*); + // Parses the field types from the server query response. |forms| must be the + // same as the one passed to EncodeQueryRequest when constructing the query. + // |form_interactions_ukm_logger| is used to provide logs to UKM and can be + // null in tests. + static void ProcessQueryResponse( + const AutofillQueryResponseContents& response, + const std::vector<FormStructure*>& forms, + AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger); + // Returns predictions using the details from the given |form_structures| and // their fields' predicted types. static std::vector<FormDataPredictions> GetFieldTypePredictions( @@ -128,8 +132,8 @@ class FormStructure { // directly. bool ShouldBeQueried() const; - // Returns true if we should upload votes for this form to the crowd-sourcing - // server. + // Returns true if we should upload Autofill votes for this form to the + // crowd-sourcing server. It is not applied for Password Manager votes. bool ShouldBeUploaded() const; // Sets the field types to be those set for |cached_form|. @@ -228,14 +232,16 @@ class FormStructure { return has_author_specified_upi_vpa_hint_; } + void set_submission_event( + PasswordForm::SubmissionIndicatorEvent submission_event) { + submission_event_ = submission_event; + } + void set_upload_required(UploadRequired required) { upload_required_ = required; } UploadRequired upload_required() const { return upload_required_; } - void set_form_parsed_timestamp(const base::TimeTicks form_parsed_timestamp) { - form_parsed_timestamp_ = form_parsed_timestamp; - } base::TimeTicks form_parsed_timestamp() const { return form_parsed_timestamp_; } @@ -284,6 +290,11 @@ class FormStructure { "|password_attributes_vote_| has no value."; return password_length_vote_; } + + PasswordForm::SubmissionIndicatorEvent get_submission_event_for_testing() + const { + return submission_event_; + } #endif bool operator==(const FormData& form) const; @@ -295,6 +306,8 @@ class FormStructure { // - Name for Autofill of first field base::string16 GetIdentifierForRefill() const; + int developer_engagement_metrics() { return developer_engagement_metrics_; }; + private: friend class AutofillMergeTest; friend class FormStructureTest; @@ -442,6 +455,10 @@ class FormStructure { // The name of the form. base::string16 form_name_; + // The type of the event that was taken as an indication that the form has + // been successfully submitted. + PasswordForm::SubmissionIndicatorEvent submission_event_; + // The source URL. GURL source_url_; @@ -505,7 +522,7 @@ class FormStructure { // the form name, and the form field names in a 64-bit hash. FormSignature form_signature_; - // When a form is parsed on this page. + // The timestamp (not wallclock time) when this form was initially parsed. base::TimeTicks form_parsed_timestamp_; // If phone number rationalization has been performed for a given section. @@ -523,6 +540,11 @@ class FormStructure { // has no value, |password_length_vote_| should be ignored. size_t password_length_vote_; + // Used to record whether developer has used autocomplete markup or + // UPI-VPA hints, This is a bitmask of DeveloperEngagementMetric and set in + // DetermineHeuristicTypes(). + int developer_engagement_metrics_; + DISALLOW_COPY_AND_ASSIGN(FormStructure); }; diff --git a/chromium/components/autofill/core/browser/form_structure_process_query_response_fuzzer.cc b/chromium/components/autofill/core/browser/form_structure_process_query_response_fuzzer.cc new file mode 100644 index 00000000000..b684f2f6ed2 --- /dev/null +++ b/chromium/components/autofill/core/browser/form_structure_process_query_response_fuzzer.cc @@ -0,0 +1,50 @@ +// Copyright 2018 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 <stdlib.h> + +#include <iostream> + +#include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/form_structure.h" +#include "components/autofill/core/common/form_data.h" +#include "components/autofill/core/common/form_field_data.h" +#include "testing/libfuzzer/proto/lpm_interface.h" + +namespace autofill { +namespace { + +using ::base::ASCIIToUTF16; + +void AddField(const std::string& label, + const std::string& name, + const std::string& control_type, + FormData* form_data) { + FormFieldData field; + field.label = ASCIIToUTF16(label); + field.name = ASCIIToUTF16(name); + field.form_control_type = control_type; + + form_data->fields.push_back(field); +} + +// We run ProcessQueryResponse twice with hardcoded forms vectors. Ideally we +// should also generate forms vectors by using fuzzing, but at the moment we use +// simplified approach. There is no specific reason to use those two hardcoded +// forms vectors, so it can be changed if needed. +DEFINE_BINARY_PROTO_FUZZER(const AutofillQueryResponseContents& response) { + std::vector<FormStructure*> forms; + FormStructure::ProcessQueryResponse(response, forms, nullptr); + + FormData form_data; + AddField("username", "username", "text", &form_data); + AddField("password", "password", "password", &form_data); + + FormStructure form(form_data); + forms.push_back(&form); + FormStructure::ProcessQueryResponse(response, forms, nullptr); +} + +} // namespace +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/form_structure_unittest.cc b/chromium/components/autofill/core/browser/form_structure_unittest.cc index ee8a503e718..61c14608319 100644 --- a/chromium/components/autofill/core/browser/form_structure_unittest.cc +++ b/chromium/components/autofill/core/browser/form_structure_unittest.cc @@ -20,6 +20,7 @@ #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_field_data.h" +#include "components/autofill/core/common/password_form.h" #include "components/autofill/core/common/signatures_util.h" #include "components/variations/entropy_provider.h" #include "testing/gtest/include/gtest/gtest.h" @@ -96,8 +97,7 @@ class FormStructureTest : public testing::Test { InitFeature(&feature_list, kAutofillEnforceMinRequiredFieldsForHeuristics, enforce_min_fields); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); return form_structure.IsAutofillable(); } @@ -210,8 +210,7 @@ TEST_F(FormStructureTest, AutofillCount) { // Only text and select fields that are heuristically matched are counted. form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_EQ(3U, form_structure->autofill_count()); // Add a field with should_autocomplete=false. This should not be considered a @@ -223,8 +222,7 @@ TEST_F(FormStructureTest, AutofillCount) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_EQ(4U, form_structure->autofill_count()); } @@ -470,8 +468,7 @@ TEST_F(FormStructureTest, DetermineHeuristicTypes_AutocompleteFalse) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->ShouldBeParsed()); EXPECT_EQ(3U, form_structure->autofill_count()); EXPECT_EQ(NAME_FULL, form_structure->field(0)->Type().GetStorableType()); @@ -525,8 +522,7 @@ TEST_F(FormStructureTest, HeuristicsContactInfo) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); // Expect the correct number of fields. @@ -583,8 +579,7 @@ TEST_F(FormStructureTest, HeuristicsAutocompleteAttribute) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); EXPECT_TRUE(form_structure->has_author_specified_types()); EXPECT_TRUE(form_structure->has_author_specified_upi_vpa_hint()); @@ -630,8 +625,7 @@ TEST_F(FormStructureTest, Heuristics_FormlessNonCheckoutForm) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); // Expect the correct number of fields. @@ -647,8 +641,7 @@ TEST_F(FormStructureTest, Heuristics_FormlessNonCheckoutForm) { form.is_form_tag = false; form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); // Expect the correct number of fields. @@ -689,8 +682,7 @@ TEST_F(FormStructureTest, StripCommonNamePrefix) { form.fields.push_back(field); std::unique_ptr<FormStructure> form_structure(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); // Expect the correct number of fields. @@ -730,8 +722,7 @@ TEST_F(FormStructureTest, StripCommonNamePrefix_SmallPrefix) { form.fields.push_back(field); std::unique_ptr<FormStructure> form_structure(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); // Expect the correct number of fields. @@ -767,8 +758,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_Minimal) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsCompleteCreditCardForm()); } @@ -806,8 +796,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_Full) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsCompleteCreditCardForm()); } @@ -825,8 +814,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_OnlyCCNumber) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_FALSE(form_structure->IsCompleteCreditCardForm()); } @@ -867,8 +855,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_AddressForm) { field.name = base::string16(); form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_FALSE(form_structure->IsCompleteCreditCardForm()); } @@ -898,8 +885,7 @@ TEST_F(FormStructureTest, HeuristicsAutocompleteAttributePhoneTypes) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); // Expect the correct number of fields. @@ -939,8 +925,7 @@ TEST_F(FormStructureTest, form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); EXPECT_TRUE(form_structure->ShouldBeQueried()); EXPECT_TRUE(form_structure->ShouldBeUploaded()); @@ -979,8 +964,7 @@ TEST_F(FormStructureTest, form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); EXPECT_TRUE(form_structure->ShouldBeQueried()); EXPECT_TRUE(form_structure->ShouldBeUploaded()); @@ -1024,8 +1008,7 @@ TEST_F(FormStructureTest, form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); EXPECT_TRUE(form_structure->ShouldBeQueried()); @@ -1069,8 +1052,7 @@ TEST_F(FormStructureTest, // Disabled. {}); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); ASSERT_EQ(2U, form_structure.field_count()); ASSERT_EQ(0U, form_structure.autofill_count()); EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(0)->heuristic_type()); @@ -1083,8 +1065,7 @@ TEST_F(FormStructureTest, // Default configuration. { FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); ASSERT_EQ(2U, form_structure.field_count()); ASSERT_EQ(0U, form_structure.autofill_count()); EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(0)->heuristic_type()); @@ -1100,8 +1081,7 @@ TEST_F(FormStructureTest, feature_list.InitAndDisableFeature( kAutofillEnforceMinRequiredFieldsForHeuristics); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); ASSERT_EQ(2U, form_structure.field_count()); ASSERT_EQ(2U, form_structure.autofill_count()); EXPECT_EQ(NAME_FIRST, form_structure.field(0)->heuristic_type()); @@ -1150,8 +1130,7 @@ TEST_F(FormStructureTest, // Disabled. {}); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); ASSERT_EQ(2U, form_structure.field_count()); ASSERT_EQ(1U, form_structure.autofill_count()); EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(0)->heuristic_type()); @@ -1167,8 +1146,7 @@ TEST_F(FormStructureTest, feature_list.InitAndDisableFeature( kAutofillEnforceMinRequiredFieldsForHeuristics); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); ASSERT_EQ(2U, form_structure.field_count()); ASSERT_EQ(2U, form_structure.autofill_count()); EXPECT_EQ(NAME_FIRST, form_structure.field(0)->heuristic_type()); @@ -1190,8 +1168,7 @@ TEST_F(FormStructureTest, FormData form_copy = form; form_copy.fields.pop_back(); FormStructure form_structure(form_copy); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); ASSERT_EQ(1U, form_structure.field_count()); ASSERT_EQ(1U, form_structure.autofill_count()); EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(0)->heuristic_type()); @@ -1231,8 +1208,7 @@ TEST_F(FormStructureTest, PasswordFormShouldBeQueried) { form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); EXPECT_TRUE(form_structure.ShouldBeQueried()); EXPECT_TRUE(form_structure.ShouldBeUploaded()); } @@ -1284,8 +1260,7 @@ TEST_F(FormStructureTest, HeuristicsAutocompleteAttributeWithSections) { form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); EXPECT_TRUE(form_structure.IsAutofillable()); // Expect the correct number of fields. @@ -1330,8 +1305,7 @@ TEST_F(FormStructureTest, form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); // Expect the correct number of fields. ASSERT_EQ(6U, form_structure.field_count()); @@ -1360,8 +1334,7 @@ TEST_F(FormStructureTest, HeuristicsAutocompleteAttributeWithSectionsRepeated) { form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); // Expect the correct number of fields. ASSERT_EQ(2U, form_structure.field_count()); @@ -1398,8 +1371,7 @@ TEST_F(FormStructureTest, HeuristicsDontOverrideAutocompleteAttributeSections) { form.fields.push_back(field); FormStructure form_structure(form); - form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + form_structure.DetermineHeuristicTypes(); // Expect the correct number of fields. ASSERT_EQ(4U, form_structure.field_count()); @@ -1462,8 +1434,7 @@ TEST_F(FormStructureTest, HeuristicsSample8) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(10U, form_structure->field_count()); ASSERT_EQ(9U, form_structure->autofill_count()); @@ -1529,8 +1500,7 @@ TEST_F(FormStructureTest, HeuristicsSample6) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(7U, form_structure->field_count()); ASSERT_EQ(6U, form_structure->autofill_count()); @@ -1595,8 +1565,7 @@ TEST_F(FormStructureTest, HeuristicsLabelsOnly) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(8U, form_structure->field_count()); ASSERT_EQ(7U, form_structure->autofill_count()); @@ -1653,8 +1622,7 @@ TEST_F(FormStructureTest, HeuristicsCreditCardInfo) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(6U, form_structure->field_count()); ASSERT_EQ(5U, form_structure->autofill_count()); @@ -1714,8 +1682,7 @@ TEST_F(FormStructureTest, HeuristicsCreditCardInfoWithUnknownCardField) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(7U, form_structure->field_count()); ASSERT_EQ(5U, form_structure->autofill_count()); @@ -1762,8 +1729,7 @@ TEST_F(FormStructureTest, ThreeAddressLines) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(4U, form_structure->field_count()); ASSERT_EQ(4U, form_structure->autofill_count()); @@ -1803,8 +1769,7 @@ TEST_F(FormStructureTest, SurplusAddressLinesIgnored) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); ASSERT_EQ(4U, form_structure->field_count()); ASSERT_EQ(3U, form_structure->autofill_count()); @@ -1847,8 +1812,7 @@ TEST_F(FormStructureTest, ThreeAddressLinesExpedia) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(4U, form_structure->field_count()); EXPECT_EQ(4U, form_structure->autofill_count()); @@ -1886,8 +1850,7 @@ TEST_F(FormStructureTest, TwoAddressLinesEbay) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(3U, form_structure->field_count()); ASSERT_EQ(3U, form_structure->autofill_count()); @@ -1920,8 +1883,7 @@ TEST_F(FormStructureTest, HeuristicsStateWithProvince) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(3U, form_structure->field_count()); ASSERT_EQ(3U, form_structure->autofill_count()); @@ -1987,8 +1949,7 @@ TEST_F(FormStructureTest, HeuristicsWithBilling) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(11U, form_structure->field_count()); ASSERT_EQ(11U, form_structure->autofill_count()); @@ -2037,8 +1998,7 @@ TEST_F(FormStructureTest, ThreePartPhoneNumber) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(4U, form_structure->field_count()); ASSERT_EQ(4U, form_structure->autofill_count()); @@ -2081,8 +2041,7 @@ TEST_F(FormStructureTest, HeuristicsInfernoCC) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); // Expect the correct number of fields. @@ -2136,8 +2095,7 @@ TEST_F(FormStructureTest, HeuristicsInferCCNames_NamesNotFirst) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); // Expect the correct number of fields. @@ -2195,8 +2153,7 @@ TEST_F(FormStructureTest, HeuristicsInferCCNames_NamesFirst) { form.fields.push_back(field); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); // Expect the correct number of fields. @@ -2379,8 +2336,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest) { std::vector<ServerFieldTypeSet> possible_field_types; FormData form; form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); FormFieldData field; field.form_control_type = "text"; @@ -2431,6 +2387,8 @@ TEST_F(FormStructureTest, EncodeUploadRequest) { form_structure->set_password_attributes_vote( std::make_pair(PasswordAttribute::kHasNumeric, true)); form_structure->set_password_length_vote(10u); + form_structure->set_submission_event( + PasswordForm::SubmissionIndicatorEvent::HTML_FORM_SUBMISSION); ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); for (size_t i = 0; i < form_structure->field_count(); ++i) @@ -2450,6 +2408,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest) { // Prepare the expected proto string. AutofillUploadContents upload; upload.set_submission(true); + upload.set_submission_event(AutofillUploadContents::HTML_FORM_SUBMISSION); upload.set_client_version("6.1.1715.1442/en (GGLL)"); upload.set_form_signature(8736493185895608956U); upload.set_autofill_used(false); @@ -2509,6 +2468,8 @@ TEST_F(FormStructureTest, EncodeUploadRequest) { form_structure->set_password_attributes_vote( std::make_pair(PasswordAttribute::kHasNumeric, true)); form_structure->set_password_length_vote(10u); + form_structure->set_submission_event( + PasswordForm::SubmissionIndicatorEvent::HTML_FORM_SUBMISSION); ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); for (size_t i = 0; i < form_structure->field_count(); ++i) form_structure->field(i)->set_possible_types(possible_field_types[i]); @@ -2516,18 +2477,18 @@ TEST_F(FormStructureTest, EncodeUploadRequest) { // Adjust the expected proto string. upload.set_form_signature(7816485729218079147U); upload.set_autofill_used(false); - // Create an additonal 8 fields (total of 13). - for (int i = 0; i < 8; ++i) { + // Create an additional 2 fields (total of 7). + for (int i = 0; i < 2; ++i) { test::FillUploadField(upload.add_field(), 509334676U, "address", "text", nullptr, 30U); } // Put the appropriate autofill type on the different address fields. - upload.mutable_field(6)->set_autofill_type(31U); - upload.mutable_field(7)->set_autofill_type(37U); - upload.mutable_field(8)->set_autofill_type(38U); - upload.mutable_field(10)->set_autofill_type(31U); - upload.mutable_field(11)->set_autofill_type(37U); - upload.mutable_field(12)->set_autofill_type(38U); + upload.mutable_field(5)->add_autofill_type(31U); + upload.mutable_field(5)->add_autofill_type(37U); + upload.mutable_field(5)->add_autofill_type(38U); + upload.mutable_field(6)->add_autofill_type(31U); + upload.mutable_field(6)->add_autofill_type(37U); + upload.mutable_field(6)->add_autofill_type(38U); ASSERT_TRUE(upload.SerializeToString(&expected_upload_string)); AutofillUploadContents encoded_upload3; @@ -2566,8 +2527,7 @@ TEST_F(FormStructureTest, std::vector<ServerFieldTypeSet> possible_field_types; FormData form; form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); FormFieldData field; field.label = ASCIIToUTF16("First Name"); @@ -2616,11 +2576,6 @@ TEST_F(FormStructureTest, AutofillUploadContents::Field:: MANUALLY_TRIGGERED_GENERATION_ON_SIGN_UP_FORM); form_structure->field(i)->set_generated_password_changed(true); - form_structure->field(i)->set_form_classifier_outcome( - AutofillUploadContents::Field::GENERATION_ELEMENT); - } else { - form_structure->field(i)->set_form_classifier_outcome( - AutofillUploadContents::Field::NON_GENERATION_ELEMENT); } if (form_structure->field(i)->name == ASCIIToUTF16("username")) { form_structure->field(i)->set_vote_type( @@ -2649,34 +2604,24 @@ TEST_F(FormStructureTest, AutofillUploadContents::Field* upload_firstname_field = upload.add_field(); test::FillUploadField(upload_firstname_field, 4224610201U, "firstname", "", "given-name", 3U); - upload_firstname_field->set_form_classifier_outcome( - AutofillUploadContents::Field::NON_GENERATION_ELEMENT); AutofillUploadContents::Field* upload_lastname_field = upload.add_field(); test::FillUploadField(upload_lastname_field, 2786066110U, "lastname", "", "family-name", 5U); - upload_lastname_field->set_form_classifier_outcome( - AutofillUploadContents::Field::NON_GENERATION_ELEMENT); AutofillUploadContents::Field* upload_email_field = upload.add_field(); test::FillUploadField(upload_email_field, 1029417091U, "email", "email", "email", 9U); - upload_email_field->set_form_classifier_outcome( - AutofillUploadContents::Field::NON_GENERATION_ELEMENT); AutofillUploadContents::Field* upload_username_field = upload.add_field(); test::FillUploadField(upload_username_field, 239111655U, "username", "text", "email", 86U); - upload_username_field->set_form_classifier_outcome( - AutofillUploadContents::Field::NON_GENERATION_ELEMENT); upload_username_field->set_vote_type( AutofillUploadContents::Field::CREDENTIALS_REUSED); AutofillUploadContents::Field* upload_password_field = upload.add_field(); test::FillUploadField(upload_password_field, 2051817934U, "password", "password", "email", 76U); - upload_password_field->set_form_classifier_outcome( - AutofillUploadContents::Field::GENERATION_ELEMENT); upload_password_field->set_generation_type( AutofillUploadContents::Field:: MANUALLY_TRIGGERED_GENERATION_ON_SIGN_UP_FORM); @@ -2699,8 +2644,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithAutocomplete) { std::vector<ServerFieldTypeSet> possible_field_types; FormData form; form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); FormFieldData field; field.form_control_type = "text"; @@ -2774,8 +2718,7 @@ TEST_F(FormStructureTest, EncodeUploadRequestWithPropertiesMask) { std::vector<ServerFieldTypeSet> possible_field_types; FormData form; form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); FormFieldData field; field.form_control_type = "text"; @@ -2862,8 +2805,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_ObservedSubmissionFalse) { std::vector<ServerFieldTypeSet> possible_field_types; FormData form; form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); FormFieldData field; field.form_control_type = "text"; @@ -2933,8 +2875,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithLabels) { std::vector<ServerFieldTypeSet> possible_field_types; FormData form; form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); FormFieldData field; field.form_control_type = "text"; @@ -3073,8 +3014,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithFormName) { // Setting the form name which we expect to see in the upload. form.name = ASCIIToUTF16("myform"); form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); FormFieldData field; field.form_control_type = "text"; @@ -3137,8 +3077,7 @@ TEST_F(FormStructureTest, EncodeUploadRequestPartialMetadata) { std::vector<ServerFieldTypeSet> possible_field_types; FormData form; form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); FormFieldData field; field.form_control_type = "text"; @@ -3212,8 +3151,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_DisabledMetadataTrial) { std::vector<ServerFieldTypeSet> possible_field_types; FormData form; form_structure.reset(new FormStructure(form)); - form_structure->DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure->DetermineHeuristicTypes(); FormFieldData field; field.form_control_type = "text"; @@ -3621,14 +3559,9 @@ TEST_F(FormStructureTest, CheckMultipleTypes) { form_structure->field(2)->set_possible_types(possible_field_types[2]); // Modify the expected upload. - // Put the NAME_FIRST prediction on the third field. - upload.mutable_field(2)->set_autofill_type(3); - // Replace the fourth field by the old third field. - test::FillUploadField(upload.mutable_field(3), 2404144663U, "last", "text", - nullptr, 5U); - // Re-add the old fourth field. - test::FillUploadField(upload.add_field(), 509334676U, "address", "text", - nullptr, 30U); + // Add the NAME_FIRST prediction to the third field. + upload.mutable_field(2)->add_autofill_type(3); + upload.mutable_field(2)->mutable_autofill_type()->SwapElements(0, 1); ASSERT_TRUE(upload.SerializeToString(&expected_upload_string)); @@ -3646,8 +3579,7 @@ TEST_F(FormStructureTest, CheckMultipleTypes) { possible_field_types[form_structure->field_count() - 1]); // Adjust the expected upload proto. - test::FillUploadField(upload.add_field(), 509334676U, "address", "text", - nullptr, 31U); + upload.mutable_field(3)->add_autofill_type(31U); ASSERT_TRUE(upload.SerializeToString(&expected_upload_string)); AutofillUploadContents encoded_upload3; @@ -3666,7 +3598,7 @@ TEST_F(FormStructureTest, CheckMultipleTypes) { possible_field_types[form_structure->field_count() - 1]); // Adjust the expected upload proto. - upload.mutable_field(5)->set_autofill_type(60); + upload.mutable_field(3)->set_autofill_type(1, 60); ASSERT_TRUE(upload.SerializeToString(&expected_upload_string)); AutofillUploadContents encoded_upload4; @@ -4113,7 +4045,7 @@ TEST_F(FormStructureTest, ParseQueryResponse_UnknownType) { form_data.fields.push_back(field); FormStructure form(form_data); - form.DetermineHeuristicTypes(nullptr /* ukm_service */, 0 /* source_id */); + form.DetermineHeuristicTypes(); // Setup the query response. AutofillQueryResponseContents response; @@ -4240,8 +4172,7 @@ TEST_F(FormStructureTest, ParseQueryResponse_AuthorDefinedTypes) { FormStructure form_structure(form); std::vector<FormStructure*> forms; forms.push_back(&form_structure); - forms.front()->DetermineHeuristicTypes(nullptr /* ukm_service */, - 0 /* source_id */); + forms.front()->DetermineHeuristicTypes(); AutofillQueryResponseContents response; response.add_field()->set_overall_type_prediction(EMAIL_ADDRESS); @@ -4301,7 +4232,7 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeLoneField) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormStructure::ParseQueryResponse(response_string, forms, nullptr); ASSERT_EQ(1U, forms.size()); @@ -4316,7 +4247,7 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeLoneField) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormStructure::ParseQueryResponse(response_string, forms, nullptr); ASSERT_EQ(1U, forms.size()); @@ -4363,7 +4294,7 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeCCName) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormStructure::ParseQueryResponse(response_string, forms, nullptr); ASSERT_EQ(1U, forms.size()); @@ -4377,7 +4308,7 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeCCName) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormStructure::ParseQueryResponse(response_string, forms, nullptr); ASSERT_EQ(1U, forms.size()); @@ -4436,7 +4367,7 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_1) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormStructure::ParseQueryResponse(response_string, forms, nullptr); ASSERT_EQ(1U, forms.size()); @@ -4455,7 +4386,7 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_1) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormStructure::ParseQueryResponse(response_string, forms, nullptr); ASSERT_EQ(1U, forms.size()); @@ -4513,7 +4444,7 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_2) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormStructure::ParseQueryResponse(response_string, forms, nullptr); ASSERT_EQ(1U, forms.size()); ASSERT_EQ(4U, forms[0]->field_count()); @@ -4529,7 +4460,7 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_2) { { base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature( - autofill::kAutofillRationalizeFieldTypePredictions); + autofill::features::kAutofillRationalizeFieldTypePredictions); FormStructure::ParseQueryResponse(response_string, forms, nullptr); ASSERT_EQ(1U, forms.size()); ASSERT_EQ(4U, forms[0]->field_count()); @@ -5158,8 +5089,7 @@ TEST_F(FormStructureTest, std::vector<FormStructure*> forms; forms.push_back(&form_structure); // Will identify the sections based on the heuristics types. - form_structure.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure.DetermineHeuristicTypes(); AutofillQueryResponseContents response; // Billing @@ -5250,8 +5180,7 @@ TEST_F( std::vector<FormStructure*> forms; forms.push_back(&form_structure); // Will identify the sections based on the heuristics types. - form_structure.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure.DetermineHeuristicTypes(); AutofillQueryResponseContents response; response.add_field()->set_overall_type_prediction(NAME_FULL); @@ -5350,8 +5279,7 @@ TEST_F(FormStructureTest, forms.push_back(&form_structure); // Will identify the sections based on the heuristics types. - form_structure.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); + form_structure.DetermineHeuristicTypes(); AutofillQueryResponseContents response; response.add_field()->set_overall_type_prediction(NAME_FULL); @@ -5614,9 +5542,7 @@ TEST_F(FormStructureTest, forms.push_back(&form_structure); // Will identify the sections based on the heuristics types. - form_structure.DetermineHeuristicTypes(/*ukm_service=*/nullptr, - /*source_id=*/0); - + form_structure.DetermineHeuristicTypes(); AutofillQueryResponseContents response; response.add_field()->set_overall_type_prediction(NAME_FULL); response.add_field()->set_overall_type_prediction(ADDRESS_HOME_COUNTRY); @@ -5824,4 +5750,20 @@ TEST_F(FormStructureTest, AllowBigForms) { EXPECT_EQ(1u, encoded_signatures.size()); } +// Tests that an Autofill upload for password form with 1 field should not be +// uploaded. +TEST_F(FormStructureTest, OneFieldPasswordFormShouldNotBeUpload) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /* enabled features */ {kAutofillEnforceMinRequiredFieldsForUpload}, + /* disabled features */ {kAutofillEnforceMinRequiredFieldsForQuery}); + FormData form; + FormFieldData field; + field.name = ASCIIToUTF16("Password"); + field.form_control_type = "password"; + form.fields.push_back(field); + + EXPECT_FALSE(FormStructure(form).ShouldBeUploaded()); +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/local_card_migration_manager.cc b/chromium/components/autofill/core/browser/local_card_migration_manager.cc index 0040b5748c9..643e2d84724 100644 --- a/chromium/components/autofill/core/browser/local_card_migration_manager.cc +++ b/chromium/components/autofill/core/browser/local_card_migration_manager.cc @@ -16,11 +16,19 @@ #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/form_data_importer.h" #include "components/autofill/core/browser/payments/payments_client.h" +#include "components/autofill/core/browser/payments/payments_util.h" #include "components/autofill/core/browser/personal_data_manager.h" +#include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "services/identity/public/cpp/identity_manager.h" namespace autofill { +MigratableCreditCard::MigratableCreditCard(const CreditCard& credit_card) + : credit_card_(credit_card) {} + +MigratableCreditCard::~MigratableCreditCard() {} + LocalCardMigrationManager::LocalCardMigrationManager( AutofillClient* client, payments::PaymentsClient* payments_client, @@ -29,40 +37,32 @@ LocalCardMigrationManager::LocalCardMigrationManager( : client_(client), payments_client_(payments_client), app_locale_(app_locale), - personal_data_manager_(personal_data_manager) { - if (payments_client_) - payments_client_->SetSaveDelegate(this); -} + personal_data_manager_(personal_data_manager), + weak_ptr_factory_(this) {} LocalCardMigrationManager::~LocalCardMigrationManager() {} bool LocalCardMigrationManager::ShouldOfferLocalCardMigration( int imported_credit_card_record_type) { // Must be an existing card. New cards always get Upstream or local save. - if (imported_credit_card_record_type != - FormDataImporter::ImportedCreditCardRecordType::LOCAL_CARD && - imported_credit_card_record_type != - FormDataImporter::ImportedCreditCardRecordType::SERVER_CARD) { - return false; + switch (imported_credit_card_record_type) { + case FormDataImporter::ImportedCreditCardRecordType::LOCAL_CARD: + local_card_migration_origin_ = + AutofillMetrics::LocalCardMigrationOrigin::UseOfLocalCard; + break; + case FormDataImporter::ImportedCreditCardRecordType::SERVER_CARD: + local_card_migration_origin_ = + AutofillMetrics::LocalCardMigrationOrigin::UseOfServerCard; + break; + default: + return false; } if (!IsCreditCardMigrationEnabled()) return false; - std::vector<CreditCard*> local_credit_cards = - personal_data_manager_->GetLocalCreditCards(); - - // Empty previous state. - migratable_credit_cards_.clear(); - - // Initialize the local credit card list and queue for showing and uploading. - for (CreditCard* card : local_credit_cards) { - // If the card is valid (has a valid card number, expiration date, and is - // not expired) and is not a server card, add it to the list of migratable - // cards. - if (card->IsValid() && !IsServerCard(card)) - migratable_credit_cards_.push_back(*card); - } + // Fetch all migratable credit cards and store in |migratable_credit_cards_|. + GetMigratableCreditCards(); // If the form was submitted with a local card, only offer migration instead // of Upstream if there are other local cards to migrate as well. If the form @@ -76,62 +76,167 @@ bool LocalCardMigrationManager::ShouldOfferLocalCardMigration( !migratable_credit_cards_.empty()); } -void LocalCardMigrationManager::AttemptToOfferLocalCardMigration() { +void LocalCardMigrationManager::AttemptToOfferLocalCardMigration( + bool is_from_settings_page) { // Abort the migration if |payments_client_| is nullptr. if (!payments_client_) return; - payments_client_->SetSaveDelegate(this); - upload_request_ = payments::PaymentsClient::UploadRequestDetails(); - - // Payments server determines which version of the legal message to show based - // on the existence of this experiment flag. - if (IsAutofillUpstreamUpdatePromptExplanationExperimentEnabled()) { - upload_request_.active_experiments.push_back( - kAutofillUpstreamUpdatePromptExplanation.name); - } + migration_request_ = payments::PaymentsClient::MigrationRequestDetails(); // Don't send pan_first_six, as potentially migrating multiple local cards at // once will negate its usefulness. payments_client_->GetUploadDetails( - upload_request_.profiles, GetDetectedValues(), - /*pan_first_six=*/std::string(), upload_request_.active_experiments, - app_locale_); + std::vector<AutofillProfile>(), GetDetectedValues(), + /*pan_first_six=*/std::string(), + /*active_experiments=*/std::vector<const char*>(), app_locale_, + base::BindOnce(&LocalCardMigrationManager::OnDidGetUploadDetails, + weak_ptr_factory_.GetWeakPtr(), is_from_settings_page), + payments::kMigrateCardsBillableServiceNumber); +} + +// Callback function when user agrees to migration on the intermediate dialog. +// Call ShowMainMigrationDialog() to pop up a larger, modal dialog showing the +// local cards to be uploaded. +void LocalCardMigrationManager::OnUserAcceptedIntermediateMigrationDialog() { + AutofillMetrics::LogLocalCardMigrationPromptMetric( + local_card_migration_origin_, + AutofillMetrics::INTERMEDIATE_BUBBLE_ACCEPTED); + ShowMainMigrationDialog(); +} + +// Send the migration request once risk data is available. +void LocalCardMigrationManager::OnUserAcceptedMainMigrationDialog() { + user_accepted_main_migration_dialog_ = true; + AutofillMetrics::LogLocalCardMigrationPromptMetric( + local_card_migration_origin_, AutofillMetrics::MAIN_DIALOG_ACCEPTED); + // Populating risk data and offering migration two-round pop-ups occur + // asynchronously. If |migration_risk_data_| has already been loaded, send the + // migrate local cards request. Otherwise, continue to wait and let + // OnDidGetUploadRiskData handle it. + if (!migration_request_.risk_data.empty()) + SendMigrateLocalCardsRequest(); } bool LocalCardMigrationManager::IsCreditCardMigrationEnabled() { // Confirm that the user is signed in, syncing, and the proper experiment // flags are enabled. bool migration_experiment_enabled = - IsAutofillCreditCardLocalCardMigrationExperimentEnabled(); + features::GetLocalCardMigrationExperimentalFlag() != + features::LocalCardMigrationExperimentalFlag::kMigrationDisabled; bool credit_card_upload_enabled = ::autofill::IsCreditCardUploadEnabled( client_->GetPrefs(), client_->GetSyncService(), client_->GetIdentityManager()->GetPrimaryAccountInfo().email); bool has_google_payments_account = - (static_cast<int64_t>(payments_client_->GetPrefService()->GetDouble( - prefs::kAutofillBillingCustomerNumber)) != 0); + (payments::GetBillingCustomerId(personal_data_manager_, + payments_client_->GetPrefService()) != 0); return migration_experiment_enabled && credit_card_upload_enabled && has_google_payments_account; } void LocalCardMigrationManager::OnDidGetUploadDetails( + bool is_from_settings_page, AutofillClient::PaymentsRpcResult result, const base::string16& context_token, std::unique_ptr<base::DictionaryValue> legal_message) { if (result == AutofillClient::SUCCESS) { - upload_request_.context_token = context_token; + migration_request_.context_token = context_token; legal_message_ = std::move(legal_message); + migration_request_.risk_data.clear(); // If we successfully received the legal docs, trigger the offer-to-migrate - // dialog. - // TODO(crbug.com/852904): Show intermediate migration prompt here! Relies - // on CL/1117929 first. + // dialog. If triggered from settings page, we pop-up the main prompt + // directly. If not, we pop up the intermediate bubble. + if (is_from_settings_page) { + // Set the origin to SettingsPage. + local_card_migration_origin_ = + AutofillMetrics::LocalCardMigrationOrigin::SettingsPage; + // Pops up a larger, modal dialog showing the local cards to be uploaded. + ShowMainMigrationDialog(); + } else { + client_->ShowLocalCardMigrationDialog(base::BindOnce( + &LocalCardMigrationManager::OnUserAcceptedIntermediateMigrationDialog, + weak_ptr_factory_.GetWeakPtr())); + AutofillMetrics::LogLocalCardMigrationPromptMetric( + local_card_migration_origin_, + AutofillMetrics::INTERMEDIATE_BUBBLE_SHOWN); + } + // TODO(crbug.com/876895): Clean up the LoadRiskData Bind/BindRepeating + // usages + client_->LoadRiskData(base::BindRepeating( + &LocalCardMigrationManager::OnDidGetMigrationRiskData, + weak_ptr_factory_.GetWeakPtr())); } } -// TODO(crbug.com/852904): Starts the upload of the next local card if one -// exists. -void LocalCardMigrationManager::OnDidUploadCard( +void LocalCardMigrationManager::OnDidMigrateLocalCards( AutofillClient::PaymentsRpcResult result, - const std::string& server_id) {} + std::unique_ptr<std::unordered_map<std::string, std::string>> save_result, + const std::string& display_text) { + if (!save_result) + return; + + // Traverse the migratable credit cards to update each migrated card status. + for (MigratableCreditCard& card : migratable_credit_cards_) { + // Not every card exists in the |save_result| since some cards are unchecked + // by the user and not migrated. + auto it = save_result->find(card.credit_card().guid()); + // If current card exists in the |save_result|, update its migration status. + if (it != save_result->end()) { + // Server-side response can return SUCCESS, TEMPORARY_FAILURE, or + // PERMANENT_FAILURE (see SaveResult enum). Branch here depending on which + // is received. + if (it->second == kMigrationResultPermanentFailure || + it->second == kMigrationResultTemporaryFailure) { + card.set_migration_status( + autofill::MigratableCreditCard::FAILURE_ON_UPLOAD); + } else if (it->second == kMigrationResultSuccess) { + card.set_migration_status( + autofill::MigratableCreditCard::SUCCESS_ON_UPLOAD); + } else { + NOTREACHED(); + } + } + } + // TODO(crbug.com/852904): Trigger the show result window. +} + +void LocalCardMigrationManager::OnDidGetMigrationRiskData( + const std::string& risk_data) { + migration_request_.risk_data = risk_data; + // Populating risk data and offering migration two-round pop-ups occur + // asynchronously. If the main migration dialog has already been accepted, + // send the migrate local cards request. Otherwise, continue to wait for the + // user to accept the two round dialog. + if (user_accepted_main_migration_dialog_) + SendMigrateLocalCardsRequest(); +} + +// Send the migration request. Will call payments_client to create a new +// PaymentsRequest. Also create a new callback function OnDidMigrateLocalCards. +void LocalCardMigrationManager::SendMigrateLocalCardsRequest() { + migration_request_.app_locale = app_locale_; + migration_request_.billing_customer_number = payments::GetBillingCustomerId( + personal_data_manager_, payments_client_->GetPrefService()); + payments_client_->MigrateCards( + migration_request_, migratable_credit_cards_, + base::BindOnce(&LocalCardMigrationManager::OnDidMigrateLocalCards, + weak_ptr_factory_.GetWeakPtr())); +} + +// Pops up a larger, modal dialog showing the local cards to be uploaded. Pass +// the reference of vector<MigratableCreditCard> and the callback function is +// OnUserAcceptedMainMigrationDialog(). Can be called when user agrees to +// migration on the intermediate dialog or directly from settings page. +void LocalCardMigrationManager::ShowMainMigrationDialog() { + user_accepted_main_migration_dialog_ = false; + AutofillMetrics::LogLocalCardMigrationPromptMetric( + local_card_migration_origin_, AutofillMetrics::MAIN_DIALOG_SHOWN); + // Pops up a larger, modal dialog showing the local cards to be uploaded. + client_->ConfirmMigrateLocalCardToCloud( + std::move(legal_message_), migratable_credit_cards_, + base::BindOnce( + &LocalCardMigrationManager::OnUserAcceptedMainMigrationDialog, + weak_ptr_factory_.GetWeakPtr())); +} int LocalCardMigrationManager::GetDetectedValues() const { int detected_values = 0; @@ -139,32 +244,42 @@ int LocalCardMigrationManager::GetDetectedValues() const { // If all cards to be migrated have a cardholder name, include it in the // detected values. bool all_cards_have_cardholder_name = true; - for (CreditCard card : migratable_credit_cards_) { + for (MigratableCreditCard migratable_credit_card : migratable_credit_cards_) { all_cards_have_cardholder_name &= - !card.GetInfo(AutofillType(CREDIT_CARD_NAME_FULL), app_locale_).empty(); + !migratable_credit_card.credit_card() + .GetInfo(AutofillType(CREDIT_CARD_NAME_FULL), app_locale_) + .empty(); } if (all_cards_have_cardholder_name) detected_values |= CreditCardSaveManager::DetectedValue::CARDHOLDER_NAME; // Local card migration should ONLY be offered when the user already has a // Google Payments account. - DCHECK(static_cast<int64_t>(payments_client_->GetPrefService()->GetDouble( - prefs::kAutofillBillingCustomerNumber)) != 0); + DCHECK_NE(0, payments::GetBillingCustomerId( + personal_data_manager_, payments_client_->GetPrefService())); detected_values |= CreditCardSaveManager::DetectedValue::HAS_GOOGLE_PAYMENTS_ACCOUNT; return detected_values; } -bool LocalCardMigrationManager::IsServerCard(CreditCard* local_card) const { - std::vector<CreditCard*> server_credit_cards = - personal_data_manager_->GetServerCreditCards(); - // Check whether the current card is already uploaded. - for (const CreditCard* server_card : server_credit_cards) { - if (local_card->HasSameNumberAs(*server_card)) - return true; +void LocalCardMigrationManager::GetMigratableCreditCards() { + std::vector<CreditCard*> local_credit_cards = + personal_data_manager_->GetLocalCreditCards(); + + // Empty previous state. + migratable_credit_cards_.clear(); + + // Initialize the local credit card list and queue for showing and uploading. + for (CreditCard* credit_card : local_credit_cards) { + // If the card is valid (has a valid card number, expiration date, and is + // not expired) and is not a server card, add it to the list of migratable + // cards. + if (credit_card->IsValid() && + !personal_data_manager_->IsServerCard(credit_card)) { + migratable_credit_cards_.push_back(MigratableCreditCard(*credit_card)); + } } - return false; } } // namespace autofill diff --git a/chromium/components/autofill/core/browser/local_card_migration_manager.h b/chromium/components/autofill/core/browser/local_card_migration_manager.h index 62802c86c47..7304f83af9d 100644 --- a/chromium/components/autofill/core/browser/local_card_migration_manager.h +++ b/chromium/components/autofill/core/browser/local_card_migration_manager.h @@ -11,6 +11,7 @@ #include "base/strings/string16.h" #include "components/autofill/core/browser/autofill_client.h" +#include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/payments/payments_client.h" namespace autofill { @@ -18,10 +19,61 @@ namespace autofill { class CreditCard; class PersonalDataManager; +// Server-side response can return SUCCESS, TEMPORARY_FAILURE, or +// PERMANENT_FAILURE (see SaveResult enum). Use these to extract migration +// result. +const char kMigrationResultPermanentFailure[] = "PERMANENT_FAILURE"; +const char kMigrationResultTemporaryFailure[] = "TEMPORARY_FAILURE"; +const char kMigrationResultSuccess[] = "SUCCESS"; + +// MigratableCreditCard class is used as a data structure to work as an +// intermediary between the UI side and the migration manager. Besides the basic +// credit card information, it also includes a boolean that represents whether +// the card was chosen for upload. We use each card's guid to distinguish each +// credit card for upload request/response. +// TODO(crbug.com/852904): Create one Enum to represent migration status such as +// whether the card is successfully uploaded or failure on uploading. +class MigratableCreditCard { + public: + // Possible states for the migratable local card. + enum MigrationStatus { + // Set if the migratable card have not been uploaded. + UNKNOWN, + // Set if the migratable card was successfully uploaded to the server. + SUCCESS_ON_UPLOAD, + // Set if the migratable card encountered a failure during upload. + FAILURE_ON_UPLOAD, + }; + + MigratableCreditCard(const CreditCard& credit_card); + ~MigratableCreditCard(); + + CreditCard credit_card() const { return credit_card_; } + + bool is_chosen() const { return is_chosen_; } + void ToggleChosen() { is_chosen_ = !is_chosen(); } + + MigrationStatus migration_status() const { return migration_status_; } + void set_migration_status(MigrationStatus migration_status) { + migration_status_ = migration_status; + } + + private: + // The main card information of the current migratable card. + CreditCard credit_card_; + + // Whether the user has decided to migrate the this card; shown as a checkbox + // in the UI. + bool is_chosen_ = true; + + // Migration status for this card. + MigrationStatus migration_status_ = MigrationStatus::UNKNOWN; +}; + // Manages logic for determining whether migration of locally saved credit cards // to Google Payments is available as well as multiple local card uploading. // Owned by FormDataImporter. -class LocalCardMigrationManager : public payments::PaymentsClientSaveDelegate { +class LocalCardMigrationManager { public: // The parameters should outlive the LocalCardMigrationManager. LocalCardMigrationManager(AutofillClient* client, @@ -34,9 +86,22 @@ class LocalCardMigrationManager : public payments::PaymentsClientSaveDelegate { // migration are satisfied. Initializes the local card list for upload. bool ShouldOfferLocalCardMigration(int imported_credit_card_record_type); - // Called from FormDataImporter when all migration requirements are met. - // Fetches legal documents and triggers the OnDidGetUploadDetails callback. - void AttemptToOfferLocalCardMigration(); + // Called from FormDataImporter or settings page when all migration + // requirements are met. Fetches legal documents and triggers the + // OnDidGetUploadDetails callback. |is_from_settings_page| to denote the user + // triggers the migration from settings page. It will trigger the main prompt + // directly if the get upload details call returns success. + void AttemptToOfferLocalCardMigration(bool is_from_settings_page); + + // Callback function when user agrees to migration on the intermediate dialog. + // Pops up a larger, modal dialog showing the local cards to be uploaded. + // Exposed for testing. + virtual void OnUserAcceptedIntermediateMigrationDialog(); + + // Callback function when user confirms migration on the main migration + // dialog. Sets |user_accepted_main_migration_dialog_| and sends the migration + // request once risk data is available. Exposed for testing. + virtual void OnUserAcceptedMainMigrationDialog(); // Check that the user is signed in, syncing, and the proper experiment // flags are enabled. Override in the test class. @@ -46,24 +111,28 @@ class LocalCardMigrationManager : public payments::PaymentsClientSaveDelegate { // name if it exists on all cards, and existence of Payments customer). int GetDetectedValues() const; + // Fetch all migratable credit cards and store in |migratable_credit_cards_|. + void GetMigratableCreditCards(); + protected: - // payments::PaymentsClientSaveDelegate: // Callback after successfully getting the legal documents. On success, // displays the offer-to-migrate dialog, which the user can accept or not. - void OnDidGetUploadDetails( + // When |is_from_settings_page| is true, it will trigger the main prompt + // directly. If not, trigger the intermediate prompt. Exposed for testing. + virtual void OnDidGetUploadDetails( + bool is_from_settings_page, AutofillClient::PaymentsRpcResult result, const base::string16& context_token, - std::unique_ptr<base::DictionaryValue> legal_message) override; - - // payments::PaymentsClientSaveDelegate: - // Callback after a local card was uploaded. Starts the upload of the next - // local card if one exists. - // Exposed for testing. - void OnDidUploadCard(AutofillClient::PaymentsRpcResult result, - const std::string& server_id) override; + std::unique_ptr<base::DictionaryValue> legal_message); - // Check whether a local card is already a server card. - bool IsServerCard(CreditCard* local_card) const; + // Callback after successfully getting the migration save results. Map + // migration save result to each card depending on the |save_result|. Will + // trigger a window showing the migration result together with display text to + // the user. + void OnDidMigrateLocalCards( + AutofillClient::PaymentsRpcResult result, + std::unique_ptr<std::unordered_map<std::string, std::string>> save_result, + const std::string& display_text); AutofillClient* const client_; @@ -72,6 +141,24 @@ class LocalCardMigrationManager : public payments::PaymentsClientSaveDelegate { payments::PaymentsClient* payments_client_; private: + FRIEND_TEST_ALL_PREFIXES(LocalCardMigrationManagerTest, + MigrateCreditCard_MigrationPermanentFailure); + FRIEND_TEST_ALL_PREFIXES(LocalCardMigrationManagerTest, + MigrateCreditCard_MigrationTemporaryFailure); + FRIEND_TEST_ALL_PREFIXES(LocalCardMigrationManagerTest, + MigrateCreditCard_MigrationSuccess); + + // Pops up a larger, modal dialog showing the local cards to be uploaded. + void ShowMainMigrationDialog(); + + // Callback function when migration risk data is ready. Saves risk data in + // |migration_risk_data_| and calls SendMigrateLocalCardsRequest if the user + // has accepted the main migration dialog. + void OnDidGetMigrationRiskData(const std::string& risk_data); + + // Finalizes the migration request and calls PaymentsClient. + void SendMigrateLocalCardsRequest(); + std::unique_ptr<base::DictionaryValue> legal_message_; std::string app_locale_; @@ -82,11 +169,20 @@ class LocalCardMigrationManager : public payments::PaymentsClientSaveDelegate { // May be NULL. NULL indicates OTR. PersonalDataManager* personal_data_manager_; - // Collected information about a pending upload request. - payments::PaymentsClient::UploadRequestDetails upload_request_; + // Collected information about a pending migration request. + payments::PaymentsClient::MigrationRequestDetails migration_request_; // The local credit cards to be uploaded. - std::vector<CreditCard> migratable_credit_cards_; + std::vector<MigratableCreditCard> migratable_credit_cards_; + + // |true| if the user has accepted migrating their local cards to Google Pay + // on the main dialog. + bool user_accepted_main_migration_dialog_ = false; + + // Record the triggering source of the local card migration. + AutofillMetrics::LocalCardMigrationOrigin local_card_migration_origin_; + + base::WeakPtrFactory<LocalCardMigrationManager> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(LocalCardMigrationManager); }; diff --git a/chromium/components/autofill/core/browser/local_card_migration_manager_unittest.cc b/chromium/components/autofill/core/browser/local_card_migration_manager_unittest.cc index cb6124be68f..7ad864d1053 100644 --- a/chromium/components/autofill/core/browser/local_card_migration_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/local_card_migration_manager_unittest.cc @@ -22,7 +22,6 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "build/build_config.h" -#include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_test_utils.h" @@ -40,6 +39,8 @@ #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/common/autofill_clock.h" +#include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_field_data.h" #include "components/prefs/pref_service.h" @@ -68,12 +69,11 @@ class LocalCardMigrationManagerTest : public testing::Test { autofill_driver_->SetURLRequestContext(request_context_.get()); payments_client_ = new payments::TestPaymentsClient( autofill_driver_->GetURLLoaderFactory(), autofill_client_.GetPrefs(), - autofill_client_.GetIdentityManager(), - /*unmask_delegate=*/nullptr, - /*save_delegate=*/nullptr); + autofill_client_.GetIdentityManager(), &personal_data_); credit_card_save_manager_ = new TestCreditCardSaveManager(autofill_driver_.get(), &autofill_client_, payments_client_, &personal_data_); + credit_card_save_manager_->SetCreditCardUploadEnabled(true); local_card_migration_manager_ = new TestLocalCardMigrationManager( autofill_driver_.get(), &autofill_client_, payments_client_, &personal_data_); @@ -100,12 +100,12 @@ class LocalCardMigrationManagerTest : public testing::Test { void EnableAutofillCreditCardLocalCardMigrationExperiment() { scoped_feature_list_.InitAndEnableFeature( - kAutofillCreditCardLocalCardMigration); + features::kAutofillCreditCardLocalCardMigration); } void DisableAutofillCreditCardLocalCardMigrationExperiment() { scoped_feature_list_.InitAndDisableFeature( - kAutofillCreditCardLocalCardMigration); + features::kAutofillCreditCardLocalCardMigration); } void FormsSeen(const std::vector<FormData>& forms) { @@ -145,6 +145,15 @@ class LocalCardMigrationManagerTest : public testing::Test { personal_data.AddCreditCard(local_card); } + // Set the parsed response |result| for the provided |guid|. + void SetUpMigrationResponseForGuid(const std::string& guid, + const std::string& result) { + std::unique_ptr<std::unordered_map<std::string, std::string>> save_result = + std::make_unique<std::unordered_map<std::string, std::string>>(); + save_result->insert(std::make_pair(guid, result)); + payments_client_->SetSaveResultForCardsMigration(std::move(save_result)); + } + protected: base::test::ScopedTaskEnvironment scoped_task_environment_; ukm::TestAutoSetUkmRecorder test_ukm_recorder_; @@ -166,9 +175,7 @@ class LocalCardMigrationManagerTest : public testing::Test { TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_UseLocalCardWithOneLocal) { EnableAutofillCreditCardLocalCardMigrationExperiment(); - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + // Set the billing_customer_number Priority Preference to designate // existence of a Payments account. autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, @@ -183,11 +190,17 @@ TEST_F(LocalCardMigrationManagerTest, test::CreateTestCreditCardFormData(&credit_card_form, true, false); FormsSeen(std::vector<FormData>(1, credit_card_form)); + base::HistogramTester histogram_tester; // Edit the data, and submit. EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11", test::NextYear().c_str(), "123"); FormSubmitted(credit_card_form); EXPECT_FALSE(local_card_migration_manager_->LocalCardMigrationWasTriggered()); + + // Verify that metrics are correctly logged to the UseOfLocalCard + // sub-histogram. + histogram_tester.ExpectTotalCount( + "Autofill.LocalCardMigrationOrigin.UseOfLocalCard", 0); } // Having any number of local cards on file and using a new card will not @@ -195,9 +208,7 @@ TEST_F(LocalCardMigrationManagerTest, TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_UseNewCardWithAnyLocal) { EnableAutofillCreditCardLocalCardMigrationExperiment(); - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + // Set the billing_customer_number Priority Preference to designate // existence of a Payments account. autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, @@ -227,9 +238,7 @@ TEST_F(LocalCardMigrationManagerTest, TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_UseLocalCardWithMoreLocal) { EnableAutofillCreditCardLocalCardMigrationExperiment(); - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + // Set the billing_customer_number Priority Preference to designate // existence of a Payments account. autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, @@ -247,11 +256,27 @@ TEST_F(LocalCardMigrationManagerTest, test::CreateTestCreditCardFormData(&credit_card_form, true, false); FormsSeen(std::vector<FormData>(1, credit_card_form)); + base::HistogramTester histogram_tester; // Edit the data, and submit. EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11", test::NextYear().c_str(), "123"); FormSubmitted(credit_card_form); EXPECT_TRUE(local_card_migration_manager_->LocalCardMigrationWasTriggered()); + + // Verify that metrics are correctly logged to the UseOfLocalCard + // sub-histogram. + histogram_tester.ExpectBucketCount( + "Autofill.LocalCardMigrationOrigin.UseOfLocalCard", + AutofillMetrics::INTERMEDIATE_BUBBLE_SHOWN, 1); + histogram_tester.ExpectBucketCount( + "Autofill.LocalCardMigrationOrigin.UseOfLocalCard", + AutofillMetrics::INTERMEDIATE_BUBBLE_ACCEPTED, 1); + histogram_tester.ExpectBucketCount( + "Autofill.LocalCardMigrationOrigin.UseOfLocalCard", + AutofillMetrics::MAIN_DIALOG_SHOWN, 1); + histogram_tester.ExpectBucketCount( + "Autofill.LocalCardMigrationOrigin.UseOfLocalCard", + AutofillMetrics::MAIN_DIALOG_ACCEPTED, 1); } // Using a local card will not trigger migration even if there are other local @@ -259,9 +284,7 @@ TEST_F(LocalCardMigrationManagerTest, TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_UseLocalCardWithInvalidLocal) { EnableAutofillCreditCardLocalCardMigrationExperiment(); - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + // Set the billing_customer_number Priority Preference to designate // existence of a Payments account. autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, @@ -294,9 +317,7 @@ TEST_F(LocalCardMigrationManagerTest, TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_UseServerCardWithOneValidLocal) { EnableAutofillCreditCardLocalCardMigrationExperiment(); - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + // Set the billing_customer_number Priority Preference to designate // existence of a Payments account. autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, @@ -317,11 +338,27 @@ TEST_F(LocalCardMigrationManagerTest, test::CreateTestCreditCardFormData(&credit_card_form, true, false); FormsSeen(std::vector<FormData>(1, credit_card_form)); + base::HistogramTester histogram_tester; // Edit the data, and submit. EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11", test::NextYear().c_str(), "123"); FormSubmitted(credit_card_form); EXPECT_TRUE(local_card_migration_manager_->LocalCardMigrationWasTriggered()); + + // Verify that metrics are correctly logged to the UseOfServerCard + // sub-histogram. + histogram_tester.ExpectBucketCount( + "Autofill.LocalCardMigrationOrigin.UseOfServerCard", + AutofillMetrics::INTERMEDIATE_BUBBLE_SHOWN, 1); + histogram_tester.ExpectBucketCount( + "Autofill.LocalCardMigrationOrigin.UseOfServerCard", + AutofillMetrics::INTERMEDIATE_BUBBLE_ACCEPTED, 1); + histogram_tester.ExpectBucketCount( + "Autofill.LocalCardMigrationOrigin.UseOfServerCard", + AutofillMetrics::MAIN_DIALOG_SHOWN, 1); + histogram_tester.ExpectBucketCount( + "Autofill.LocalCardMigrationOrigin.UseOfServerCard", + AutofillMetrics::MAIN_DIALOG_ACCEPTED, 1); } // Using a server card will not trigger migration even if there are other local @@ -329,9 +366,7 @@ TEST_F(LocalCardMigrationManagerTest, TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_UseServerCardWithNoneValidLocal) { EnableAutofillCreditCardLocalCardMigrationExperiment(); - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + // Set the billing_customer_number Priority Preference to designate // existence of a Payments account. autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, @@ -355,11 +390,17 @@ TEST_F(LocalCardMigrationManagerTest, test::CreateTestCreditCardFormData(&credit_card_form, true, false); FormsSeen(std::vector<FormData>(1, credit_card_form)); + base::HistogramTester histogram_tester; // Edit the data, and submit. EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11", test::NextYear().c_str(), "123"); FormSubmitted(credit_card_form); EXPECT_FALSE(local_card_migration_manager_->LocalCardMigrationWasTriggered()); + + // Verify that metrics are correctly logged to the UseOfServerCard + // sub-histogram. + histogram_tester.ExpectTotalCount( + "Autofill.LocalCardMigrationOrigin.UseOfServerCard", 0); } // Use one local card with more valid local cards available but experiment flag @@ -367,9 +408,7 @@ TEST_F(LocalCardMigrationManagerTest, TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_FeatureNotEnabled) { // Turn off the experiment flag. DisableAutofillCreditCardLocalCardMigrationExperiment(); - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + // Set the billing_customer_number Priority Preference to designate // existence of a Payments account. autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, @@ -398,9 +437,7 @@ TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_FeatureNotEnabled) { // number is blank, will not trigger migration. TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_NoPaymentsAccount) { EnableAutofillCreditCardLocalCardMigrationExperiment(); - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + // Add a local credit card whose |TypeAndLastFourDigits| matches what we will // enter below. AddLocalCrediCard(personal_data_, "Flo Master", "4111111111111111", "11", @@ -426,9 +463,7 @@ TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_NoPaymentsAccount) { TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_LocalCardMatchMaskedServerCard) { EnableAutofillCreditCardLocalCardMigrationExperiment(); - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + // Set the billing_customer_number Priority Preference to designate // existence of a Payments account. autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, @@ -465,9 +500,7 @@ TEST_F(LocalCardMigrationManagerTest, TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_LocalCardMatchFullServerCard) { EnableAutofillCreditCardLocalCardMigrationExperiment(); - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + // Set the billing_customer_number Priority Preference to designate // existence of a Payments account. autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, @@ -499,9 +532,7 @@ TEST_F(LocalCardMigrationManagerTest, // GetDetectedValues() should includes cardholder name if all cards have it. TEST_F(LocalCardMigrationManagerTest, GetDetectedValues_AllWithCardHolderName) { EnableAutofillCreditCardLocalCardMigrationExperiment(); - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + // Set the billing_customer_number Priority Preference to designate // existence of a Payments account. autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, @@ -533,9 +564,7 @@ TEST_F(LocalCardMigrationManagerTest, GetDetectedValues_AllWithCardHolderName) { TEST_F(LocalCardMigrationManagerTest, GetDetectedValues_OneCardWithoutCardHolderName) { EnableAutofillCreditCardLocalCardMigrationExperiment(); - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + // Set the billing_customer_number Priority Preference to designate // existence of a Payments account. autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, @@ -566,9 +595,7 @@ TEST_F(LocalCardMigrationManagerTest, TEST_F(LocalCardMigrationManagerTest, GetDetectedValues_IncludeGooglePaymentsAccount) { EnableAutofillCreditCardLocalCardMigrationExperiment(); - personal_data_.ClearCreditCards(); - personal_data_.ClearProfiles(); - credit_card_save_manager_->SetCreditCardUploadEnabled(true); + // Set the billing_customer_number Priority Preference to designate // existence of a Payments account. autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, @@ -596,4 +623,182 @@ TEST_F(LocalCardMigrationManagerTest, CreditCardSaveManager::DetectedValue::HAS_GOOGLE_PAYMENTS_ACCOUNT); } +// Verify that when triggering from settings page, intermediate prompt will not +// be triggered. +TEST_F(LocalCardMigrationManagerTest, + MigrateCreditCard_TriggerFromSettingsPage) { + EnableAutofillCreditCardLocalCardMigrationExperiment(); + + // Set the billing_customer_number Priority Preference to designate + // existence of a Payments account. + autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, + 12345); + // Add a local credit card. One migratable credit card will still trigger + // migration on settings page. + AddLocalCrediCard(personal_data_, "Flo Master", "4111111111111111", "11", + test::NextYear().c_str(), "1"); + + base::HistogramTester histogram_tester; + // Do the same operation as we bridge back from the settings page. + local_card_migration_manager_->GetMigratableCreditCards(); + local_card_migration_manager_->AttemptToOfferLocalCardMigration(true); + + EXPECT_FALSE(local_card_migration_manager_->IntermediatePromptWasShown()); + EXPECT_TRUE(local_card_migration_manager_->MainPromptWasShown()); + + // Verify that metrics are correctly logged to the SettingsPage sub-histogram. + // Triggering from settings page won't show intermediate bubble. + histogram_tester.ExpectBucketCount( + "Autofill.LocalCardMigrationOrigin.SettingsPage", + AutofillMetrics::INTERMEDIATE_BUBBLE_SHOWN, 0); + histogram_tester.ExpectBucketCount( + "Autofill.LocalCardMigrationOrigin.SettingsPage", + AutofillMetrics::INTERMEDIATE_BUBBLE_ACCEPTED, 0); + histogram_tester.ExpectBucketCount( + "Autofill.LocalCardMigrationOrigin.SettingsPage", + AutofillMetrics::MAIN_DIALOG_SHOWN, 1); + histogram_tester.ExpectBucketCount( + "Autofill.LocalCardMigrationOrigin.SettingsPage", + AutofillMetrics::MAIN_DIALOG_ACCEPTED, 1); +} + +// Verify that when triggering from submitted form, intermediate prompt and main +// prompt are both triggered. +TEST_F(LocalCardMigrationManagerTest, + MigrateCreditCard_TriggerFromSubmittedForm) { + EnableAutofillCreditCardLocalCardMigrationExperiment(); + + // Set the billing_customer_number Priority Preference to designate + // existence of a Payments account. + autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, + 12345); + // Add a local credit card whose |TypeAndLastFourDigits| matches what we will + // enter below. + AddLocalCrediCard(personal_data_, "Flo Master", "4111111111111111", "11", + test::NextYear().c_str(), "1"); + // Add another local credit card, so it will trigger migration. + AddLocalCrediCard(personal_data_, "Flo Master", "5555555555554444", "11", + test::NextYear().c_str(), "1"); + + // Set up our credit card form data. + FormData credit_card_form; + test::CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + + // Edit the data, and submit. + EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11", + test::NextYear().c_str(), "123"); + FormSubmitted(credit_card_form); + EXPECT_TRUE(local_card_migration_manager_->IntermediatePromptWasShown()); + EXPECT_TRUE(local_card_migration_manager_->MainPromptWasShown()); +} + +// Verify that given the parsed response from the payments client, the migration +// status is correctly set. +TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_MigrationSuccess) { + EnableAutofillCreditCardLocalCardMigrationExperiment(); + + // Set the billing_customer_number Priority Preference to designate + // existence of a Payments account. + autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, + 12345); + // Add a local credit card for migration. + AddLocalCrediCard(personal_data_, "Flo Master", "4111111111111111", "11", + test::NextYear().c_str(), "1"); + + // Get the migratable credit cards. + local_card_migration_manager_->GetMigratableCreditCards(); + + // Set the parsed response to success. + SetUpMigrationResponseForGuid( + local_card_migration_manager_->migratable_credit_cards_[0] + .credit_card() + .guid(), + autofill::kMigrationResultSuccess); + + EXPECT_EQ(local_card_migration_manager_->migratable_credit_cards_[0] + .migration_status(), + autofill::MigratableCreditCard::UNKNOWN); + + local_card_migration_manager_->AttemptToOfferLocalCardMigration(true); + + EXPECT_EQ(local_card_migration_manager_->migratable_credit_cards_[0] + .migration_status(), + autofill::MigratableCreditCard::SUCCESS_ON_UPLOAD); +} + +// Verify that given the parsed response from the payments client, the migration +// status is correctly set. +TEST_F(LocalCardMigrationManagerTest, + MigrateCreditCard_MigrationTemporaryFailure) { + EnableAutofillCreditCardLocalCardMigrationExperiment(); + + // Set the billing_customer_number Priority Preference to designate + // existence of a Payments account. + autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, + 12345); + // Add a local credit card. One migratable credit card will still trigger + // migration on settings page. + AddLocalCrediCard(personal_data_, "Flo Master", "4111111111111111", "11", + test::NextYear().c_str(), "1"); + + // Get the migratable credit cards. + local_card_migration_manager_->GetMigratableCreditCards(); + + // Set the parsed response to temporary failure. + SetUpMigrationResponseForGuid( + local_card_migration_manager_->migratable_credit_cards_[0] + .credit_card() + .guid(), + autofill::kMigrationResultTemporaryFailure); + + EXPECT_EQ(local_card_migration_manager_->migratable_credit_cards_[0] + .migration_status(), + autofill::MigratableCreditCard::UNKNOWN); + + // Start the migration. + local_card_migration_manager_->AttemptToOfferLocalCardMigration(true); + + EXPECT_EQ(local_card_migration_manager_->migratable_credit_cards_[0] + .migration_status(), + autofill::MigratableCreditCard::FAILURE_ON_UPLOAD); +} + +// Verify that given the parsed response from the payments client, the migration +// status is correctly set. +TEST_F(LocalCardMigrationManagerTest, + MigrateCreditCard_MigrationPermanentFailure) { + EnableAutofillCreditCardLocalCardMigrationExperiment(); + + // Set the billing_customer_number Priority Preference to designate + // existence of a Payments account. + autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, + 12345); + // Add a local credit card. One migratable credit card will still trigger + // migration on settings page. + AddLocalCrediCard(personal_data_, "Flo Master", "4111111111111111", "11", + test::NextYear().c_str(), "1"); + + // Get the migratable credit cards. + local_card_migration_manager_->GetMigratableCreditCards(); + + // Set the parsed response to permanent failure. + SetUpMigrationResponseForGuid( + local_card_migration_manager_->migratable_credit_cards_[0] + .credit_card() + .guid(), + autofill::kMigrationResultPermanentFailure); + + EXPECT_EQ(local_card_migration_manager_->migratable_credit_cards_[0] + .migration_status(), + autofill::MigratableCreditCard::UNKNOWN); + + // Start the migration. + local_card_migration_manager_->AttemptToOfferLocalCardMigration(true); + + EXPECT_EQ(local_card_migration_manager_->migratable_credit_cards_[0] + .migration_status(), + autofill::MigratableCreditCard::FAILURE_ON_UPLOAD); +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/password_generator_proto_fuzzer.cc b/chromium/components/autofill/core/browser/password_generator_proto_fuzzer.cc new file mode 100644 index 00000000000..2967bc68616 --- /dev/null +++ b/chromium/components/autofill/core/browser/password_generator_proto_fuzzer.cc @@ -0,0 +1,15 @@ +// Copyright 2018 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 "components/autofill/core/browser/password_generator.h" +#include "components/autofill/core/browser/proto/password_requirements.pb.h" +#include "testing/libfuzzer/proto/lpm_interface.h" + +namespace autofill { + +DEFINE_PROTO_FUZZER(const PasswordRequirementsSpec& spec) { + GeneratePassword(spec); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/password_requirements_spec_printer.cc b/chromium/components/autofill/core/browser/password_requirements_spec_printer.cc index 7a4d72eeb3b..dd7049d34da 100644 --- a/chromium/components/autofill/core/browser/password_requirements_spec_printer.cc +++ b/chromium/components/autofill/core/browser/password_requirements_spec_printer.cc @@ -4,9 +4,11 @@ #include "components/autofill/core/browser/password_requirements_spec_printer.h" +namespace autofill { + std::ostream& operator<<( std::ostream& out, - const autofill::PasswordRequirementsSpec::CharacterClass& character_class) { + const PasswordRequirementsSpec::CharacterClass& character_class) { out << "{"; if (character_class.has_character_set()) out << "character_set: \"" << character_class.character_set() << "\", "; @@ -19,7 +21,7 @@ std::ostream& operator<<( } std::ostream& operator<<(std::ostream& out, - const autofill::PasswordRequirementsSpec& spec) { + const PasswordRequirementsSpec& spec) { out << "{"; if (spec.has_priority()) out << "priority: " << spec.priority() << ", "; @@ -42,3 +44,5 @@ std::ostream& operator<<(std::ostream& out, out << "}"; return out; } + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/password_requirements_spec_printer.h b/chromium/components/autofill/core/browser/password_requirements_spec_printer.h index 55db287068c..81169340bce 100644 --- a/chromium/components/autofill/core/browser/password_requirements_spec_printer.h +++ b/chromium/components/autofill/core/browser/password_requirements_spec_printer.h @@ -9,11 +9,15 @@ #include "components/autofill/core/browser/proto/password_requirements.pb.h" +namespace autofill { + std::ostream& operator<<( std::ostream& out, - const autofill::PasswordRequirementsSpec::CharacterClass& character_class); + const PasswordRequirementsSpec::CharacterClass& character_class); std::ostream& operator<<(std::ostream& out, - const autofill::PasswordRequirementsSpec& spec); + const PasswordRequirementsSpec& spec); + +} // namespace autofill #endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_REQUIREMENTS_SPEC_PRINTER_H_ diff --git a/chromium/components/autofill/core/browser/payments/full_card_request.cc b/chromium/components/autofill/core/browser/payments/full_card_request.cc index 9fab4b42888..a787034db51 100644 --- a/chromium/components/autofill/core/browser/payments/full_card_request.cc +++ b/chromium/components/autofill/core/browser/payments/full_card_request.cc @@ -8,9 +8,9 @@ #include "base/logging.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" -#include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/payments/payments_util.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/common/autofill_clock.h" @@ -68,9 +68,8 @@ void FullCardRequest::GetFullCard(const CreditCard& card, card.ShouldUpdateExpiration(AutofillClock::Now())); if (should_unmask_card_) { payments_client_->Prepare(); - request_->billing_customer_number = - static_cast<int64_t>(payments_client_->GetPrefService()->GetDouble( - prefs::kAutofillBillingCustomerNumber)); + request_->billing_customer_number = GetBillingCustomerId( + personal_data_manager_, payments_client_->GetPrefService()); } ui_delegate_->ShowUnmaskPrompt(request_->card, reason, @@ -131,7 +130,9 @@ void FullCardRequest::OnDidGetUnmaskRiskData(const std::string& risk_data) { void FullCardRequest::SendUnmaskCardRequest() { real_pan_request_timestamp_ = AutofillClock::Now(); - payments_client_->UnmaskCard(*request_); + payments_client_->UnmaskCard(*request_, + base::BindOnce(&FullCardRequest::OnDidGetRealPan, + weak_ptr_factory_.GetWeakPtr())); } void FullCardRequest::OnDidGetRealPan(AutofillClient::PaymentsRpcResult result, diff --git a/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc b/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc index 03d1b3eda65..a71d0211bac 100644 --- a/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc @@ -17,7 +17,8 @@ #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/test_autofill_client.h" #include "components/autofill/core/browser/test_autofill_driver.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/browser/test_personal_data_manager.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" #include "components/prefs/testing_pref_service.h" @@ -57,17 +58,18 @@ class MockUIDelegate : public FullCardRequest::UIDelegate, }; // The personal data manager. -class MockPersonalDataManager : public PersonalDataManager { +class MockPersonalDataManager : public TestPersonalDataManager { public: - MockPersonalDataManager() : PersonalDataManager("en-US") {} + MockPersonalDataManager() {} ~MockPersonalDataManager() override {} + MOCK_CONST_METHOD0(IsSyncFeatureEnabled, bool()); MOCK_METHOD1(UpdateCreditCard, void(const CreditCard& credit_card)); MOCK_METHOD1(UpdateServerCreditCard, void(const CreditCard& credit_card)); }; +// TODO(crbug.com/881835): Simplify this test setup. // The test fixture for full card request. -class FullCardRequestTest : public testing::Test, - public PaymentsClientUnmaskDelegate { +class FullCardRequestTest : public testing::Test { public: FullCardRequestTest() : request_context_(new net::TestURLRequestContextGetter( @@ -82,9 +84,11 @@ class FullCardRequestTest : public testing::Test, autofill_client_.SetPrefs(std::move(pref_service)); payments_client_ = std::make_unique<PaymentsClient>( test_shared_loader_factory_, autofill_client_.GetPrefs(), - autofill_client_.GetIdentityManager(), this, nullptr); + autofill_client_.GetIdentityManager(), &personal_data_); request_ = std::make_unique<FullCardRequest>( &autofill_client_, payments_client_.get(), &personal_data_); + personal_data_.SetAccountInfoForPayments( + autofill_client_.GetIdentityManager()->GetPrimaryAccountInfo()); // Silence the warning from PaymentsClient about matching sync and Payments // server types. base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( @@ -105,9 +109,8 @@ class FullCardRequestTest : public testing::Test, MockUIDelegate* ui_delegate() { return &ui_delegate_; } - // PaymentsClientUnmaskDelegate: void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result, - const std::string& real_pan) override { + const std::string& real_pan) { request_->OnDidGetRealPan(result, real_pan); } diff --git a/chromium/components/autofill/core/browser/payments/payments_client.cc b/chromium/components/autofill/core/browser/payments/payments_client.cc index 6785c51868f..39eb28a9131 100644 --- a/chromium/components/autofill/core/browser/payments/payments_client.cc +++ b/chromium/components/autofill/core/browser/payments/payments_client.cc @@ -17,10 +17,12 @@ #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "build/build_config.h" +#include "components/autofill/core/browser/account_info_getter.h" #include "components/autofill/core/browser/autofill_data_model.h" #include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/local_card_migration_manager.h" #include "components/autofill/core/browser/payments/payments_request.h" #include "components/autofill/core/browser/payments/payments_service_url.h" #include "components/autofill/core/common/autofill_features.h" @@ -60,13 +62,16 @@ const char kUploadCardRequestFormatWithoutCvc[] = "requestContentType=application/json; charset=utf-8&request=%s" "&s7e_1_pan=%s"; +const char kMigrateCardsRequestPath[] = + "payments/apis-secure/chromepaymentsservice/migratecards" + "?s7e_suffix=chromewallet"; +const char kMigrateCardsRequestFormat[] = + "requestContentType=application/json; charset=utf-8&request=%s"; + const char kTokenFetchId[] = "wallet_client"; const char kPaymentsOAuth2Scope[] = "https://www.googleapis.com/auth/wallet.chrome"; -const int kUnmaskCardBillableServiceNumber = 70154; -const int kUploadCardBillableServiceNumber = 70073; - GURL GetRequestUrl(const std::string& path) { if (base::CommandLine::ForCurrentProcess()->HasSwitch("sync-url")) { if (IsPaymentsProductionEnabled()) { @@ -179,6 +184,34 @@ std::unique_ptr<base::DictionaryValue> BuildAddressDictionary( return address; } +// Returns a dictionary of the credit card with the structure expected by +// Payments RPCs, containing expiration month, expiration year and cardholder +// name (if any) fields in |credit_card|, formatted according to |app_locale|. +// |pan_field_name| is the field name for the encrypted pan. We use each credit +// card's guid as the unique id. +std::unique_ptr<base::DictionaryValue> BuildCreditCardDictionary( + const CreditCard& credit_card, + const std::string& app_locale, + const std::string& pan_field_name) { + std::unique_ptr<base::DictionaryValue> card(new base::DictionaryValue()); + card->SetString("unique_id", credit_card.guid()); + + const base::string16 exp_month = + credit_card.GetInfo(AutofillType(CREDIT_CARD_EXP_MONTH), app_locale); + const base::string16 exp_year = credit_card.GetInfo( + AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), app_locale); + int value = 0; + if (base::StringToInt(exp_month, &value)) + card->SetInteger("expiration_month", value); + if (base::StringToInt(exp_year, &value)) + card->SetInteger("expiration_year", value); + SetStringIfNotEmpty(credit_card, CREDIT_CARD_NAME_FULL, app_locale, + "cardholder_name", card.get()); + + card->SetString("encrypted_pan", "__param:" + pan_field_name); + return card; +} + // Populates the list of active experiments that affect either the data sent in // payments RPCs or whether the RPCs are sent or not. void SetActiveExperiments(const std::vector<const char*>& active_experiments, @@ -198,8 +231,12 @@ void SetActiveExperiments(const std::vector<const char*>& active_experiments, class UnmaskCardRequest : public PaymentsRequest { public: UnmaskCardRequest(const PaymentsClient::UnmaskRequestDetails& request_details, - PaymentsClientUnmaskDelegate* delegate) - : request_details_(request_details), delegate_(delegate) { + const bool full_sync_enabled, + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + const std::string&)> callback) + : request_details_(request_details), + full_sync_enabled_(full_sync_enabled), + callback_(std::move(callback)) { DCHECK( CreditCard::MASKED_SERVER_CARD == request_details.card.record_type() || CreditCard::FULL_SERVER_CARD == request_details.card.record_type()); @@ -227,6 +264,13 @@ class UnmaskCardRequest : public PaymentsRequest { } request_dict.Set("context", std::move(context)); + if (ShouldUseActiveSignedInAccount()) { + std::unique_ptr<base::DictionaryValue> chrome_user_context( + new base::DictionaryValue()); + chrome_user_context->SetBoolean("full_sync_enabled", full_sync_enabled_); + request_dict.Set("chrome_user_context", std::move(chrome_user_context)); + } + int value = 0; if (base::StringToInt(request_details_.user_response.exp_month, &value)) request_dict.SetInteger("expiration_month", value); @@ -252,29 +296,39 @@ class UnmaskCardRequest : public PaymentsRequest { bool IsResponseComplete() override { return !real_pan_.empty(); } void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override { - delegate_->OnDidGetRealPan(result, real_pan_); + std::move(callback_).Run(result, real_pan_); } private: PaymentsClient::UnmaskRequestDetails request_details_; - PaymentsClientUnmaskDelegate* delegate_; + const bool full_sync_enabled_; + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + const std::string&)> + callback_; std::string real_pan_; }; class GetUploadDetailsRequest : public PaymentsRequest { public: - GetUploadDetailsRequest(const std::vector<AutofillProfile>& addresses, - const int detected_values, - const std::string& pan_first_six, - const std::vector<const char*>& active_experiments, - const std::string& app_locale, - PaymentsClientSaveDelegate* delegate) + GetUploadDetailsRequest( + const std::vector<AutofillProfile>& addresses, + const int detected_values, + const std::string& pan_first_six, + const std::vector<const char*>& active_experiments, + const bool full_sync_enabled, + const std::string& app_locale, + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + const base::string16&, + std::unique_ptr<base::DictionaryValue>)> callback, + const int billable_service_number) : addresses_(addresses), detected_values_(detected_values), pan_first_six_(pan_first_six), active_experiments_(active_experiments), + full_sync_enabled_(full_sync_enabled), app_locale_(app_locale), - delegate_(delegate) {} + callback_(std::move(callback)), + billable_service_number_(billable_service_number) {} ~GetUploadDetailsRequest() override {} std::string GetRequestUrlPath() override { @@ -287,8 +341,16 @@ class GetUploadDetailsRequest : public PaymentsRequest { base::DictionaryValue request_dict; std::unique_ptr<base::DictionaryValue> context(new base::DictionaryValue()); context->SetString("language_code", app_locale_); + context->SetInteger("billable_service", billable_service_number_); request_dict.Set("context", std::move(context)); + if (ShouldUseActiveSignedInAccount()) { + std::unique_ptr<base::DictionaryValue> chrome_user_context( + new base::DictionaryValue()); + chrome_user_context->SetBoolean("full_sync_enabled", full_sync_enabled_); + request_dict.Set("chrome_user_context", std::move(chrome_user_context)); + } + std::unique_ptr<base::ListValue> addresses(new base::ListValue()); for (const AutofillProfile& profile : addresses_) { // These addresses are used by Payments to (1) accurately determine the @@ -307,7 +369,7 @@ class GetUploadDetailsRequest : public PaymentsRequest { // Payments will decide if the provided data is enough to offer upload save. request_dict.SetInteger("detected_values", detected_values_); - if (IsAutofillUpstreamSendPanFirstSixExperimentEnabled() && + if (features::IsAutofillUpstreamSendPanFirstSixExperimentEnabled() && !pan_first_six_.empty()) request_dict.SetString("pan_first6", pan_first_six_); @@ -331,8 +393,7 @@ class GetUploadDetailsRequest : public PaymentsRequest { } void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override { - delegate_->OnDidGetUploadDetails(result, context_token_, - std::move(legal_message_)); + std::move(callback_).Run(result, context_token_, std::move(legal_message_)); } private: @@ -340,17 +401,26 @@ class GetUploadDetailsRequest : public PaymentsRequest { const int detected_values_; const std::string pan_first_six_; const std::vector<const char*> active_experiments_; + const bool full_sync_enabled_; std::string app_locale_; - PaymentsClientSaveDelegate* delegate_; + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + const base::string16&, + std::unique_ptr<base::DictionaryValue>)> + callback_; base::string16 context_token_; std::unique_ptr<base::DictionaryValue> legal_message_; + const int billable_service_number_; }; class UploadCardRequest : public PaymentsRequest { public: UploadCardRequest(const PaymentsClient::UploadRequestDetails& request_details, - PaymentsClientSaveDelegate* delegate) - : request_details_(request_details), delegate_(delegate) {} + const bool full_sync_enabled, + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + const std::string&)> callback) + : request_details_(request_details), + full_sync_enabled_(full_sync_enabled), + callback_(std::move(callback)) {} ~UploadCardRequest() override {} std::string GetRequestUrlPath() override { return kUploadCardRequestPath; } @@ -378,6 +448,13 @@ class UploadCardRequest : public PaymentsRequest { } request_dict.Set("context", std::move(context)); + if (ShouldUseActiveSignedInAccount()) { + std::unique_ptr<base::DictionaryValue> chrome_user_context( + new base::DictionaryValue()); + chrome_user_context->SetBoolean("full_sync_enabled", full_sync_enabled_); + request_dict.Set("chrome_user_context", std::move(chrome_user_context)); + } + SetStringIfNotEmpty(request_details_.card, CREDIT_CARD_NAME_FULL, app_locale, "cardholder_name", &request_dict); @@ -431,15 +508,143 @@ class UploadCardRequest : public PaymentsRequest { bool IsResponseComplete() override { return true; } void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override { - delegate_->OnDidUploadCard(result, server_id_); + std::move(callback_).Run(result, server_id_); } private: const PaymentsClient::UploadRequestDetails request_details_; - PaymentsClientSaveDelegate* delegate_; + const bool full_sync_enabled_; + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + const std::string&)> + callback_; std::string server_id_; }; +class MigrateCardsRequest : public PaymentsRequest { + public: + MigrateCardsRequest( + const PaymentsClient::MigrationRequestDetails& request_details, + const std::vector<MigratableCreditCard>& migratable_credit_cards, + const bool full_sync_enabled, + MigrateCardsCallback callback) + : request_details_(request_details), + migratable_credit_cards_(migratable_credit_cards), + full_sync_enabled_(full_sync_enabled), + callback_(std::move(callback)) {} + ~MigrateCardsRequest() override {} + + std::string GetRequestUrlPath() override { return kMigrateCardsRequestPath; } + + std::string GetRequestContentType() override { + return "application/x-www-form-urlencoded"; + } + + // TODO(crbug.com/877281):Refactor DictionaryValue to base::Value + std::string GetRequestContent() override { + base::DictionaryValue request_dict; + + request_dict.SetKey("risk_data_encoded", + BuildRiskDictionary(request_details_.risk_data)); + + const std::string& app_locale = request_details_.app_locale; + std::unique_ptr<base::DictionaryValue> context(new base::DictionaryValue()); + context->SetString("language_code", app_locale); + context->SetInteger("billable_service", kMigrateCardsBillableServiceNumber); + if (request_details_.billing_customer_number != 0) { + context->SetKey("customer_context", + BuildCustomerContextDictionary( + request_details_.billing_customer_number)); + } + request_dict.Set("context", std::move(context)); + + if (ShouldUseActiveSignedInAccount()) { + std::unique_ptr<base::DictionaryValue> chrome_user_context( + new base::DictionaryValue()); + chrome_user_context->SetBoolean("full_sync_enabled", full_sync_enabled_); + request_dict.Set("chrome_user_context", std::move(chrome_user_context)); + } + + request_dict.SetString("context_token", request_details_.context_token); + + std::string all_pans_data = std::string(); + std::unique_ptr<base::ListValue> migrate_cards(new base::ListValue()); + for (size_t index = 0; index < migratable_credit_cards_.size(); ++index) { + if (migratable_credit_cards_[index].is_chosen()) { + std::string pan_field_name = GetPanFieldName(index); + // Generate credit card dictionary. + migrate_cards->Append(BuildCreditCardDictionary( + migratable_credit_cards_[index].credit_card(), app_locale, + pan_field_name)); + // Append pan data to the |all_pans_data|. + all_pans_data += + GetAppendPan(migratable_credit_cards_[index].credit_card(), + app_locale, pan_field_name); + } + } + request_dict.Set("local_card", std::move(migrate_cards)); + + std::string json_request; + base::JSONWriter::Write(request_dict, &json_request); + std::string request_content = base::StringPrintf( + kMigrateCardsRequestFormat, + net::EscapeUrlEncodedData(json_request, true).c_str()); + request_content += all_pans_data; + return request_content; + } + + void ParseResponse(std::unique_ptr<base::DictionaryValue> response) override { + const base::ListValue* save_result_list = nullptr; + if (!response->GetList("save_result", &save_result_list)) + return; + save_result_ = + std::make_unique<std::unordered_map<std::string, std::string>>(); + for (size_t i = 0; i < save_result_list->GetSize(); ++i) { + const base::DictionaryValue* single_card_save_result; + if (save_result_list->GetDictionary(i, &single_card_save_result)) { + std::string unique_id; + single_card_save_result->GetString("unique_id", &unique_id); + std::string save_result; + single_card_save_result->GetString("status", &save_result); + save_result_->insert(std::make_pair(unique_id, save_result)); + } + } + response->GetString("value_prop_display_text", &display_text_); + } + + bool IsResponseComplete() override { + return !display_text_.empty() && save_result_; + } + + void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override { + std::move(callback_).Run(result, std::move(save_result_), display_text_); + } + + private: + // Return the pan field name for the encrypted pan based on the |index|. + std::string GetPanFieldName(const size_t& index) { + return "s7e_1_pan" + std::to_string(index); + } + + // Return the formatted pan to append to the end of the request. + std::string GetAppendPan(const CreditCard& credit_card, + const std::string& app_locale, + const std::string& pan_field_name) { + const base::string16 pan = + credit_card.GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale); + std::string pan_str = + net::EscapeUrlEncodedData(base::UTF16ToASCII(pan), true).c_str(); + std::string append_pan = "&" + pan_field_name + "=" + pan_str; + return append_pan; + } + + const PaymentsClient::MigrationRequestDetails request_details_; + const std::vector<MigratableCreditCard>& migratable_credit_cards_; + const bool full_sync_enabled_; + MigrateCardsCallback callback_; + std::unique_ptr<std::unordered_map<std::string, std::string>> save_result_; + std::string display_text_; +}; + } // namespace const char PaymentsClient::kRecipientName[] = "recipient_name"; @@ -455,18 +660,21 @@ PaymentsClient::UploadRequestDetails::UploadRequestDetails( const UploadRequestDetails& other) = default; PaymentsClient::UploadRequestDetails::~UploadRequestDetails() {} +PaymentsClient::MigrationRequestDetails::MigrationRequestDetails() {} +PaymentsClient::MigrationRequestDetails::MigrationRequestDetails( + const MigrationRequestDetails& other) = default; +PaymentsClient::MigrationRequestDetails::~MigrationRequestDetails() {} + PaymentsClient::PaymentsClient( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, PrefService* pref_service, identity::IdentityManager* identity_manager, - PaymentsClientUnmaskDelegate* unmask_delegate, - PaymentsClientSaveDelegate* save_delegate, + AccountInfoGetter* account_info_getter, bool is_off_the_record) : url_loader_factory_(url_loader_factory), pref_service_(pref_service), identity_manager_(identity_manager), - unmask_delegate_(unmask_delegate), - save_delegate_(save_delegate), + account_info_getter_(account_info_getter), is_off_the_record_(is_off_the_record), has_retried_authorization_(false), weak_ptr_factory_(this) {} @@ -478,20 +686,18 @@ void PaymentsClient::Prepare() { StartTokenFetch(false); } -void PaymentsClient::SetSaveDelegate( - PaymentsClientSaveDelegate* save_delegate) { - save_delegate_ = save_delegate; -} - PrefService* PaymentsClient::GetPrefService() const { return pref_service_; } void PaymentsClient::UnmaskCard( - const PaymentsClient::UnmaskRequestDetails& request_details) { - DCHECK(unmask_delegate_); + const PaymentsClient::UnmaskRequestDetails& request_details, + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + const std::string&)> callback) { IssueRequest( - std::make_unique<UnmaskCardRequest>(request_details, unmask_delegate_), + std::make_unique<UnmaskCardRequest>( + request_details, account_info_getter_->IsSyncFeatureEnabled(), + std::move(callback)), true); } @@ -500,22 +706,41 @@ void PaymentsClient::GetUploadDetails( const int detected_values, const std::string& pan_first_six, const std::vector<const char*>& active_experiments, - const std::string& app_locale) { - DCHECK(save_delegate_); - IssueRequest(std::make_unique<GetUploadDetailsRequest>( - addresses, detected_values, pan_first_six, - active_experiments, app_locale, save_delegate_), - false); + const std::string& app_locale, + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + const base::string16&, + std::unique_ptr<base::DictionaryValue>)> callback, + const int billable_service_number) { + IssueRequest( + std::make_unique<GetUploadDetailsRequest>( + addresses, detected_values, pan_first_six, active_experiments, + account_info_getter_->IsSyncFeatureEnabled(), app_locale, + std::move(callback), billable_service_number), + false); } void PaymentsClient::UploadCard( - const PaymentsClient::UploadRequestDetails& request_details) { - DCHECK(save_delegate_); + const PaymentsClient::UploadRequestDetails& request_details, + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + const std::string&)> callback) { IssueRequest( - std::make_unique<UploadCardRequest>(request_details, save_delegate_), + std::make_unique<UploadCardRequest>( + request_details, account_info_getter_->IsSyncFeatureEnabled(), + std::move(callback)), true); } +void PaymentsClient::MigrateCards( + const MigrationRequestDetails& request_details, + const std::vector<MigratableCreditCard>& migratable_credit_cards, + MigrateCardsCallback callback) { + IssueRequest( + std::make_unique<MigrateCardsRequest>( + request_details, migratable_credit_cards, + account_info_getter_->IsSyncFeatureEnabled(), std::move(callback)), + /*authenticate=*/true); +} + void PaymentsClient::CancelRequest() { request_.reset(); resource_request_.reset(); @@ -670,20 +895,23 @@ void PaymentsClient::StartTokenFetch(bool invalidate_old) { if (!invalidate_old && token_fetcher_) return; + DCHECK(account_info_getter_); + OAuth2TokenService::ScopeSet payments_scopes; payments_scopes.insert(kPaymentsOAuth2Scope); + std::string account_id = + account_info_getter_->GetAccountInfoForPaymentsServer().account_id; if (invalidate_old) { DCHECK(!access_token_.empty()); - identity_manager_->RemoveAccessTokenFromCache( - identity_manager_->GetPrimaryAccountInfo().account_id, payments_scopes, - access_token_); + identity_manager_->RemoveAccessTokenFromCache(account_id, payments_scopes, + access_token_); } access_token_.clear(); - token_fetcher_ = std::make_unique<identity::PrimaryAccountAccessTokenFetcher>( - kTokenFetchId, identity_manager_, payments_scopes, + token_fetcher_ = identity_manager_->CreateAccessTokenFetcherForAccount( + account_id, kTokenFetchId, payments_scopes, base::BindOnce(&PaymentsClient::AccessTokenFetchFinished, base::Unretained(this)), - identity::PrimaryAccountAccessTokenFetcher::Mode::kImmediate); + identity::AccessTokenFetcher::Mode::kImmediate); } void PaymentsClient::SetOAuth2TokenAndStartRequest() { diff --git a/chromium/components/autofill/core/browser/payments/payments_client.h b/chromium/components/autofill/core/browser/payments/payments_client.h index e8eef9d974b..95b36dce181 100644 --- a/chromium/components/autofill/core/browser/payments/payments_client.h +++ b/chromium/components/autofill/core/browser/payments/payments_client.h @@ -15,11 +15,11 @@ #include "components/autofill/core/browser/credit_card.h" #include "components/prefs/pref_service.h" #include "google_apis/gaia/google_service_auth_error.h" +#include "services/identity/public/cpp/access_token_fetcher.h" #include "services/identity/public/cpp/access_token_info.h" namespace identity { class IdentityManager; -class PrimaryAccountAccessTokenFetcher; } // namespace identity namespace network { @@ -30,34 +30,28 @@ class SharedURLLoaderFactory; namespace autofill { -namespace payments { +class AccountInfoGetter; +class MigratableCreditCard; -class PaymentsRequest; +namespace payments { -class PaymentsClientUnmaskDelegate { - public: - // Returns the real PAN retrieved from Payments. |real_pan| will be empty - // on failure. - virtual void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result, - const std::string& real_pan) = 0; -}; +// Callback type for MigrateCards callback. |result| is the Payments Rpc result. +// |save_result| is an unordered_map parsed from the response whose key is the +// unique id (guid) for each card and value is the server save result string. +// |display_text| is the returned tip from Payments to show on the UI. +typedef base::OnceCallback<void( + AutofillClient::PaymentsRpcResult result, + std::unique_ptr<std::unordered_map<std::string, std::string>> save_result, + const std::string& display_text)> + MigrateCardsCallback; + +// Billable service number is defined in Payments server to distinguish +// different requests. +const int kUnmaskCardBillableServiceNumber = 70154; +const int kUploadCardBillableServiceNumber = 70073; +const int kMigrateCardsBillableServiceNumber = 70264; -class PaymentsClientSaveDelegate { - public: - // Returns the legal message retrieved from Payments. On failure or not - // meeting Payments's conditions for upload, |legal_message| will contain - // nullptr. - virtual void OnDidGetUploadDetails( - AutofillClient::PaymentsRpcResult result, - const base::string16& context_token, - std::unique_ptr<base::DictionaryValue> legal_message) = 0; - - // Returns the result of an upload request. - // If |result| == |AutofillClient::SUCCESS|, |server_id| may, optionally, - // contain the opaque identifier for the card on the server. - virtual void OnDidUploadCard(AutofillClient::PaymentsRpcResult result, - const std::string& server_id) = 0; -}; +class PaymentsRequest; // PaymentsClient issues Payments RPCs and manages responses and failure // conditions. Only one request may be active at a time. Initiating a new @@ -93,6 +87,7 @@ class PaymentsClient { ~UploadRequestDetails(); int64_t billing_customer_number = 0; + int detected_values; CreditCard card; base::string16 cvc; std::vector<AutofillProfile> profiles; @@ -102,17 +97,29 @@ class PaymentsClient { std::vector<const char*> active_experiments; }; + // A collection of the information required to make local credit cards + // migration request. + struct MigrationRequestDetails { + MigrationRequestDetails(); + MigrationRequestDetails(const MigrationRequestDetails& other); + ~MigrationRequestDetails(); + + int64_t billing_customer_number = 0; + base::string16 context_token; + std::string risk_data; + std::string app_locale; + }; + // |url_loader_factory| is reference counted so it has no lifetime or // ownership requirements. |pref_service| is used to get the registered - // preference value, |identity_manager|, |unmask_delegate| and |save_delegate| + // preference value, |identity_manager| and |account_info_getter| // must all outlive |this|. Either delegate might be nullptr. // |is_off_the_record| denotes incognito mode. PaymentsClient( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - PrefService* pref_service, - identity::IdentityManager* identity_manager, - PaymentsClientUnmaskDelegate* unmask_delegate, - PaymentsClientSaveDelegate* save_delegate, + PrefService* const pref_service, + identity::IdentityManager* const identity_manager, + AccountInfoGetter* const account_info_getter, bool is_off_the_record = false); virtual ~PaymentsClient(); @@ -124,15 +131,12 @@ class PaymentsClient { // accepted an upload prompt. void Prepare(); - // Sets up the |save_delegate_|. Necessary because CreditCardSaveManager - // requires PaymentsClient during initialization, so PaymentsClient can't - // start with save_delegate_ initialized. - virtual void SetSaveDelegate(PaymentsClientSaveDelegate* save_delegate); - PrefService* GetPrefService() const; // The user has attempted to unmask a card with the given cvc. - void UnmaskCard(const UnmaskRequestDetails& request_details); + void UnmaskCard(const UnmaskRequestDetails& request_details, + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + const std::string&)> callback); // Determine if the user meets the Payments service's conditions for upload. // The service uses |addresses| (from which names and phone numbers are @@ -141,20 +145,38 @@ class PaymentsClient { // being considered for upload. |detected_values| is a bitmask of // CreditCardSaveManager::DetectedValue values that relays what data is // actually available for upload in order to make more informed upload - // decisions. If the conditions are met, the legal message will be returned - // via OnDidGetUploadDetails. |active_experiments| is used by Payments server - // to track requests that were triggered by enabled features. + // decisions. |callback| is the callback function when get response from + // server. |billable_service_number| is used to set the billable service + // number in the GetUploadDetails request. If the conditions are met, the + // legal message will be returned via |callback|. |active_experiments| is used + // by Payments server to track requests that were triggered by enabled + // features. virtual void GetUploadDetails( const std::vector<AutofillProfile>& addresses, const int detected_values, const std::string& pan_first_six, const std::vector<const char*>& active_experiments, - const std::string& app_locale); + const std::string& app_locale, + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + const base::string16&, + std::unique_ptr<base::DictionaryValue>)> callback, + const int billable_service_number); // The user has indicated that they would like to upload a card with the given // cvc. This request will fail server-side if a successful call to // GetUploadDetails has not already been made. - virtual void UploadCard(const UploadRequestDetails& details); + virtual void UploadCard( + const UploadRequestDetails& details, + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + const std::string&)> callback); + + // The user has indicated that they would like to migrate their local credit + // cards. This request will fail server-side if a successful call to + // GetUploadDetails has not already been made. + virtual void MigrateCards( + const MigrationRequestDetails& details, + const std::vector<MigratableCreditCard>& migratable_credit_cards, + MigrateCardsCallback callback); // Cancels and clears the current |request_|. void CancelRequest(); @@ -202,12 +224,11 @@ class PaymentsClient { // The pref service for this client. PrefService* const pref_service_; + // Provided in constructor; not owned by PaymentsClient. identity::IdentityManager* const identity_manager_; - // Delegates for the results of the various requests to Payments. Both must - // outlive |this|. - PaymentsClientUnmaskDelegate* const unmask_delegate_; - PaymentsClientSaveDelegate* save_delegate_; + // Provided in constructor; not owned by PaymentsClient. + AccountInfoGetter* const account_info_getter_; // The current request. std::unique_ptr<PaymentsRequest> request_; @@ -218,8 +239,8 @@ class PaymentsClient { // The URL loader being used to issue the current request. std::unique_ptr<network::SimpleURLLoader> simple_url_loader_; - // The current OAuth2 token fetcher. - std::unique_ptr<identity::PrimaryAccountAccessTokenFetcher> token_fetcher_; + // The OAuth2 token fetcher for any account. + std::unique_ptr<identity::AccessTokenFetcher> token_fetcher_; // The OAuth2 token, or empty if not fetched. std::string access_token_; diff --git a/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc index 2d2027de3be..7e824766c4f 100644 --- a/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc @@ -17,9 +17,10 @@ #include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/credit_card_save_manager.h" +#include "components/autofill/core/browser/local_card_migration_manager.h" #include "components/autofill/core/browser/payments/payments_client.h" +#include "components/autofill/core/browser/test_personal_data_manager.h" #include "components/autofill/core/common/autofill_features.h" -#include "components/autofill/core/common/autofill_pref_names.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/testing_pref_service.h" @@ -48,11 +49,10 @@ int kAllDetectableValues = } // namespace -class PaymentsClientTest : public testing::Test, - public PaymentsClientUnmaskDelegate, - public PaymentsClientSaveDelegate { +class PaymentsClientTest : public testing::Test { public: - PaymentsClientTest() : result_(AutofillClient::NONE) {} + PaymentsClientTest() + : result_(AutofillClient::NONE), weak_ptr_factory_(this) {} ~PaymentsClientTest() override {} void SetUp() override { @@ -74,15 +74,28 @@ class PaymentsClientTest : public testing::Test, base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( &test_url_loader_factory_); TestingPrefServiceSimple pref_service_; - client_.reset( - new PaymentsClient(test_shared_loader_factory_, &pref_service_, - identity_test_env_.identity_manager(), this, this)); + client_ = std::make_unique<PaymentsClient>( + test_shared_loader_factory_, &pref_service_, + identity_test_env_.identity_manager(), &test_personal_data_); + test_personal_data_.SetAccountInfoForPayments( + identity_test_env_.MakePrimaryAccountAvailable("example@gmail.com")); } void TearDown() override { client_.reset(); } void EnableAutofillUpstreamSendPanFirstSixExperiment() { - scoped_feature_list_.InitAndEnableFeature(kAutofillUpstreamSendPanFirstSix); + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillUpstreamSendPanFirstSix); + } + + void EnableAutofillSendExperimentIdsInPaymentsRPCs() { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillSendExperimentIdsInPaymentsRPCs); + } + + void EnableAutofillGetPaymentsIdentityFromSync() { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillGetPaymentsIdentityFromSync); } void DisableAutofillSendExperimentIdsInPaymentsRPCs() { @@ -101,55 +114,65 @@ class PaymentsClientTest : public testing::Test, base::FieldTrialList::CreateFieldTrial(trial_name, group_name)->group(); } - // PaymentsClientUnmaskDelegate: void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result, - const std::string& real_pan) override { + const std::string& real_pan) { result_ = result; real_pan_ = real_pan; } - // PaymentsClientSaveDelegate: void OnDidGetUploadDetails( AutofillClient::PaymentsRpcResult result, const base::string16& context_token, - std::unique_ptr<base::DictionaryValue> legal_message) override { + std::unique_ptr<base::DictionaryValue> legal_message) { result_ = result; legal_message_ = std::move(legal_message); } + void OnDidUploadCard(AutofillClient::PaymentsRpcResult result, - const std::string& server_id) override { + const std::string& server_id) { result_ = result; server_id_ = server_id; } + void OnDidMigrateLocalCards( + AutofillClient::PaymentsRpcResult result, + std::unique_ptr<std::unordered_map<std::string, std::string>> save_result, + const std::string& display_text) { + result_ = result; + save_result_ = std::move(save_result); + display_text_ = display_text; + } + protected: base::test::ScopedFeatureList scoped_feature_list_; + // Issue an UnmaskCard request. This requires an OAuth token before starting + // the request. void StartUnmasking() { - if (!identity_test_env_.identity_manager()->HasPrimaryAccount()) - identity_test_env_.MakePrimaryAccountAvailable("example@gmail.com"); - PaymentsClient::UnmaskRequestDetails request_details; request_details.billing_customer_number = 111222333444; request_details.card = test::GetMaskedServerCard(); request_details.user_response.cvc = base::ASCIIToUTF16("123"); request_details.risk_data = "some risk data"; - client_->UnmaskCard(request_details); + client_->UnmaskCard(request_details, + base::BindOnce(&PaymentsClientTest::OnDidGetRealPan, + weak_ptr_factory_.GetWeakPtr())); } + // Issue a GetUploadDetails request. void StartGettingUploadDetails() { - if (!identity_test_env_.identity_manager()->HasPrimaryAccount()) - identity_test_env_.MakePrimaryAccountAvailable("example@gmail.com"); - - client_->GetUploadDetails(BuildTestProfiles(), kAllDetectableValues, - /*pan_first_six=*/"411111", - std::vector<const char*>(), "language-LOCALE"); + client_->GetUploadDetails( + BuildTestProfiles(), kAllDetectableValues, + /*pan_first_six=*/"411111", std::vector<const char*>(), + "language-LOCALE", + base::BindOnce(&PaymentsClientTest::OnDidGetUploadDetails, + weak_ptr_factory_.GetWeakPtr()), + /*billable_service_number=*/12345); } + // Issue an UploadCard request. This requires an OAuth token before starting + // the request. void StartUploading(bool include_cvc) { - if (!identity_test_env_.identity_manager()->HasPrimaryAccount()) - identity_test_env_.MakePrimaryAccountAvailable("example@gmail.com"); - PaymentsClient::UploadRequestDetails request_details; request_details.billing_customer_number = 111222333444; request_details.card = test::GetCreditCard(); @@ -159,7 +182,32 @@ class PaymentsClientTest : public testing::Test, request_details.risk_data = "some risk data"; request_details.app_locale = "language-LOCALE"; request_details.profiles = BuildTestProfiles(); - client_->UploadCard(request_details); + client_->UploadCard(request_details, + base::BindOnce(&PaymentsClientTest::OnDidUploadCard, + weak_ptr_factory_.GetWeakPtr())); + } + + void StartMigrating(bool uncheck_last_card, bool has_cardholder_name) { + PaymentsClient::MigrationRequestDetails request_details; + request_details.context_token = base::ASCIIToUTF16("context token"); + request_details.risk_data = "some risk data"; + request_details.app_locale = "language-LOCALE"; + + migratable_credit_cards_.clear(); + CreditCard card1 = test::GetCreditCard(); + CreditCard card2 = test::GetCreditCard2(); + if (!has_cardholder_name) { + card1.SetRawInfo(CREDIT_CARD_NAME_FULL, base::UTF8ToUTF16("")); + card2.SetRawInfo(CREDIT_CARD_NAME_FULL, base::UTF8ToUTF16("")); + } + migratable_credit_cards_.push_back(MigratableCreditCard(card1)); + migratable_credit_cards_.push_back(MigratableCreditCard(card2)); + if (uncheck_last_card) + migratable_credit_cards_.back().ToggleChosen(); + client_->MigrateCards( + request_details, migratable_credit_cards_, + base::BindOnce(&PaymentsClientTest::OnDidMigrateLocalCards, + weak_ptr_factory_.GetWeakPtr())); } network::TestURLLoaderFactory* factory() { return &test_url_loader_factory_; } @@ -168,6 +216,8 @@ class PaymentsClientTest : public testing::Test, net::HttpRequestHeaders* GetRequestHeaders() { return &intercepted_headers_; } + // Issues access token in response to any access token request. This will + // start the Payments Request which requires the authentication. void IssueOAuthToken() { identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( "totally_real_token", @@ -190,15 +240,20 @@ class PaymentsClientTest : public testing::Test, std::string server_id_; std::string real_pan_; std::unique_ptr<base::DictionaryValue> legal_message_; + std::vector<MigratableCreditCard> migratable_credit_cards_; + std::unique_ptr<std::unordered_map<std::string, std::string>> save_result_; + std::string display_text_; base::test::ScopedTaskEnvironment scoped_task_environment_; network::TestURLLoaderFactory test_url_loader_factory_; scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_; + TestPersonalDataManager test_personal_data_; std::unique_ptr<PaymentsClient> client_; identity::IdentityTestEnvironment identity_test_env_; net::HttpRequestHeaders intercepted_headers_; std::string intercepted_body_; + base::WeakPtrFactory<PaymentsClientTest> weak_ptr_factory_; private: DISALLOW_COPY_AND_ASSIGN(PaymentsClientTest); @@ -261,6 +316,60 @@ TEST_F(PaymentsClientTest, UnmaskSuccess) { EXPECT_EQ("1234", real_pan_); } +TEST_F(PaymentsClientTest, UnmaskSuccessAccountFromSyncTest) { + EnableAutofillGetPaymentsIdentityFromSync(); + StartUnmasking(); + IssueOAuthToken(); + ReturnResponse(net::HTTP_OK, "{ \"pan\": \"1234\" }"); + EXPECT_EQ(AutofillClient::SUCCESS, result_); + EXPECT_EQ("1234", real_pan_); +} + +TEST_F(PaymentsClientTest, UnmaskIncludesChromeUserContext) { + scoped_feature_list_.InitWithFeatures( + {features::kAutofillGetPaymentsIdentityFromSync}, // Enabled + {features::kAutofillEnableAccountWalletStorage}); // Disabled + + StartUnmasking(); + IssueOAuthToken(); + ReturnResponse(net::HTTP_OK, "{}"); + + // ChromeUserContext was set. + EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos); + EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos); +} + +TEST_F(PaymentsClientTest, + UnmaskIncludesChromeUserContextIfWalletStorageFlagEnabled) { + scoped_feature_list_.InitWithFeatures( + {features::kAutofillEnableAccountWalletStorage}, // Enabled + {features::kAutofillGetPaymentsIdentityFromSync}); // Disabled + + StartUnmasking(); + IssueOAuthToken(); + ReturnResponse(net::HTTP_OK, "{}"); + + // ChromeUserContext was set. + EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos); + EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos); +} + +TEST_F(PaymentsClientTest, UnmaskExcludesChromeUserContextIfExperimentsOff) { + scoped_feature_list_.InitWithFeatures( + {}, // Enabled + {features::kAutofillEnableAccountWalletStorage, + features::kAutofillGetPaymentsIdentityFromSync}); // Disabled + + StartUnmasking(); + IssueOAuthToken(); + ReturnResponse(net::HTTP_OK, "{}"); + + // ChromeUserContext was not set. + EXPECT_TRUE(!GetUploadData().empty()); + EXPECT_TRUE(GetUploadData().find("chrome_user_context") == std::string::npos); + EXPECT_TRUE(GetUploadData().find("full_sync_enabled") == std::string::npos); +} + TEST_F(PaymentsClientTest, GetDetailsSuccess) { StartGettingUploadDetails(); ReturnResponse( @@ -303,6 +412,69 @@ TEST_F(PaymentsClientTest, GetDetailsIncludesDetectedValuesInRequest) { std::string::npos); } +TEST_F(PaymentsClientTest, GetDetailsIncludesChromeUserContext) { + scoped_feature_list_.InitWithFeatures( + {features::kAutofillGetPaymentsIdentityFromSync}, // Enabled + {features::kAutofillEnableAccountWalletStorage}); // Disabled + + StartGettingUploadDetails(); + + // ChromeUserContext was set. + EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos); + EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos); +} + +TEST_F(PaymentsClientTest, + GetDetailsIncludesChromeUserContextIfWalletStorageFlagEnabled) { + scoped_feature_list_.InitWithFeatures( + {features::kAutofillEnableAccountWalletStorage}, // Enabled + {features::kAutofillGetPaymentsIdentityFromSync}); // Disabled + + StartGettingUploadDetails(); + + // ChromeUserContext was set. + EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos); + EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos); +} + +TEST_F(PaymentsClientTest, + GetDetailsExcludesChromeUserContextIfExperimentsOff) { + scoped_feature_list_.InitWithFeatures( + {}, // Enabled + {features::kAutofillEnableAccountWalletStorage, + features::kAutofillGetPaymentsIdentityFromSync}); // Disabled + + StartGettingUploadDetails(); + + // ChromeUserContext was not set. + EXPECT_TRUE(!GetUploadData().empty()); + EXPECT_TRUE(GetUploadData().find("chrome_user_context") == std::string::npos); + EXPECT_TRUE(GetUploadData().find("full_sync_enabled") == std::string::npos); +} + +TEST_F(PaymentsClientTest, GetUploadAccountFromSyncTest) { + EnableAutofillGetPaymentsIdentityFromSync(); + // Set up a different account. + const AccountInfo& secondary_account_info = + identity_test_env_.MakeAccountAvailable("secondary@gmail.com"); + test_personal_data_.SetAccountInfoForPayments(secondary_account_info); + + StartUploading(/*include_cvc=*/true); + ReturnResponse(net::HTTP_OK, "{}"); + + // Issue a token for the secondary account. + identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( + secondary_account_info.account_id, "secondary_account_token", + base::Time::Now() + base::TimeDelta::FromDays(10)); + + // Verify the auth header. + std::string auth_header_value; + EXPECT_TRUE(intercepted_headers_.GetHeader( + net::HttpRequestHeaders::kAuthorization, &auth_header_value)) + << intercepted_headers_.ToString(); + EXPECT_EQ("Bearer secondary_account_token", auth_header_value); +} + TEST_F(PaymentsClientTest, GetUploadDetailsVariationsTest) { // Register a trial and variation id, so that there is data in variations // headers. Also, the variations header provider may have been registered to @@ -410,6 +582,43 @@ TEST_F(PaymentsClientTest, UnmaskCardVariationsTestExperimentOff) { variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting(); } +TEST_F(PaymentsClientTest, MigrateCardsVariationsTest) { + // Register a trial and variation id, so that there is data in variations + // headers. Also, the variations header provider may have been registered to + // observe some other field trial list, so reset it. + EnableAutofillSendExperimentIdsInPaymentsRPCs(); + variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting(); + base::FieldTrialList field_trial_list_(nullptr); + CreateFieldTrialWithId("AutofillTest", "Group", 369); + StartMigrating(/*uncheck_last_card=*/false, /*has_cardholder_name=*/true); + IssueOAuthToken(); + + std::string value; + EXPECT_TRUE(GetRequestHeaders()->GetHeader("X-Client-Data", &value)); + // Note that experiment information is stored in X-Client-Data. + EXPECT_FALSE(value.empty()); + + variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting(); +} + +TEST_F(PaymentsClientTest, MigrateCardsVariationsTestExperimentFlagOff) { + // Register a trial and variation id, so that there is data in variations + // headers. Also, the variations header provider may have been registered to + // observe some other field trial list, so reset it. + DisableAutofillSendExperimentIdsInPaymentsRPCs(); + variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting(); + base::FieldTrialList field_trial_list_(nullptr); + CreateFieldTrialWithId("AutofillTest", "Group", 369); + StartMigrating(/*uncheck_last_card=*/false, /*has_cardholder_name=*/true); + + std::string value; + EXPECT_FALSE(GetRequestHeaders()->GetHeader("X-Client-Data", &value)); + // Note that experiment information is stored in X-Client-Data. + EXPECT_TRUE(value.empty()); + + variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting(); +} + TEST_F(PaymentsClientTest, GetDetailsIncludesPanFirstSixInRequestIfExperimentOn) { EnableAutofillUpstreamSendPanFirstSixExperiment(); @@ -430,6 +639,14 @@ TEST_F(PaymentsClientTest, std::string::npos); } +TEST_F(PaymentsClientTest, GetDetailsIncludeBillableServiceNumber) { + StartGettingUploadDetails(); + + // Verify that billable service number was included in the request. + EXPECT_TRUE(GetUploadData().find("\"billable_service\":12345") != + std::string::npos); +} + TEST_F(PaymentsClientTest, UploadSuccessWithoutServerId) { StartUploading(/*include_cvc=*/true); IssueOAuthToken(); @@ -492,9 +709,53 @@ TEST_F(PaymentsClientTest, UploadIncludesCvcInRequestIfProvided) { EXPECT_TRUE(GetUploadData().find("&s7e_13_cvc=") != std::string::npos); } +TEST_F(PaymentsClientTest, UploadIncludesChromeUserContext) { + scoped_feature_list_.InitWithFeatures( + {features::kAutofillGetPaymentsIdentityFromSync}, // Enabled + {features::kAutofillEnableAccountWalletStorage}); // Disabled + + StartUploading(/*include_cvc=*/true); + IssueOAuthToken(); + + // ChromeUserContext was set. + EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos); + EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos); +} + +TEST_F(PaymentsClientTest, + UploadIncludesChromeUserContextIfWalletStorageFlagEnabled) { + scoped_feature_list_.InitWithFeatures( + {features::kAutofillEnableAccountWalletStorage}, // Enabled + {features::kAutofillGetPaymentsIdentityFromSync}); // Disabled + + StartUploading(/*include_cvc=*/true); + IssueOAuthToken(); + + // ChromeUserContext was set. + EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos); + EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos); +} + +TEST_F(PaymentsClientTest, UploadExcludesChromeUserContextIfExperimentsOff) { + scoped_feature_list_.InitWithFeatures( + {}, // Enabled + {features::kAutofillEnableAccountWalletStorage, + features::kAutofillGetPaymentsIdentityFromSync}); // Disabled + + StartUploading(/*include_cvc=*/true); + IssueOAuthToken(); + + // ChromeUserContext was not set. + EXPECT_TRUE(!GetUploadData().empty()); + EXPECT_TRUE(GetUploadData().find("chrome_user_context") == std::string::npos); + EXPECT_TRUE(GetUploadData().find("full_sync_enabled") == std::string::npos); +} + TEST_F(PaymentsClientTest, UploadDoesNotIncludeCvcInRequestIfNotProvided) { StartUploading(/*include_cvc=*/false); + IssueOAuthToken(); + EXPECT_TRUE(!GetUploadData().empty()); // Verify that the encrypted_cvc and s7e_13_cvc parameters were not included // in the request. EXPECT_TRUE(GetUploadData().find("encrypted_cvc") == std::string::npos); @@ -502,6 +763,147 @@ TEST_F(PaymentsClientTest, UploadDoesNotIncludeCvcInRequestIfNotProvided) { EXPECT_TRUE(GetUploadData().find("&s7e_13_cvc=") == std::string::npos); } +TEST_F(PaymentsClientTest, MigrationRequestIncludesUniqueId) { + StartMigrating(/*uncheck_last_card=*/false, /*has_cardholder_name=*/true); + IssueOAuthToken(); + + // Verify that the unique id was included in the request. + EXPECT_TRUE(GetUploadData().find("unique_id") != std::string::npos); + EXPECT_TRUE( + GetUploadData().find(migratable_credit_cards_[0].credit_card().guid()) != + std::string::npos); + EXPECT_TRUE( + GetUploadData().find(migratable_credit_cards_[1].credit_card().guid()) != + std::string::npos); +} + +TEST_F(PaymentsClientTest, MigrationRequestIncludesEncryptedPan) { + StartMigrating(/*uncheck_last_card=*/false, /*has_cardholder_name=*/true); + IssueOAuthToken(); + + // Verify that the encrypted_pan and s7e_1_pan parameters were included + // in the request. + EXPECT_TRUE(GetUploadData().find("encrypted_pan") != std::string::npos); + EXPECT_TRUE(GetUploadData().find("__param:s7e_1_pan0") != std::string::npos); + EXPECT_TRUE(GetUploadData().find("&s7e_1_pan0=4111111111111111") != + std::string::npos); + EXPECT_TRUE(GetUploadData().find("__param:s7e_1_pan1") != std::string::npos); + EXPECT_TRUE(GetUploadData().find("&s7e_1_pan1=378282246310005") != + std::string::npos); +} + +TEST_F(PaymentsClientTest, MigrationRequestExcludesUncheckedCard) { + StartMigrating(/*uncheck_last_card=*/true, /*has_cardholder_name=*/true); + IssueOAuthToken(); + + // Verify that the encrypted_pan and s7e_1_pan parameters were included + // in the request. + EXPECT_TRUE(GetUploadData().find("encrypted_pan") != std::string::npos); + EXPECT_TRUE(GetUploadData().find("__param:s7e_1_pan0") != std::string::npos); + EXPECT_TRUE(GetUploadData().find("&s7e_1_pan0=4111111111111111") != + std::string::npos); + EXPECT_FALSE(GetUploadData().find("__param:s7e_1_pan1") != std::string::npos); + EXPECT_FALSE(GetUploadData().find("&s7e_1_pan1=378282246310005") != + std::string::npos); +} + +TEST_F(PaymentsClientTest, MigrationRequestIncludesCardholderNameWhenItExists) { + StartMigrating(/*uncheck_last_card=*/false, /*has_cardholder_name=*/true); + IssueOAuthToken(); + + EXPECT_TRUE(!GetUploadData().empty()); + // Verify that the cardholder name is sent if it exists. + EXPECT_TRUE(GetUploadData().find("cardholder_name") != std::string::npos); +} + +TEST_F(PaymentsClientTest, + MigrationRequestExcludesCardholderNameWhenItDoesNotExist) { + StartMigrating(/*uncheck_last_card=*/false, /*has_cardholder_name=*/false); + IssueOAuthToken(); + + EXPECT_TRUE(!GetUploadData().empty()); + // Verify that the cardholder name is not sent if it doesn't exist. + EXPECT_TRUE(GetUploadData().find("cardholder_name") == std::string::npos); +} + +TEST_F(PaymentsClientTest, MigrationRequestIncludesChromeUserContext) { + scoped_feature_list_.InitWithFeatures( + {features::kAutofillGetPaymentsIdentityFromSync}, // Enabled + {features::kAutofillEnableAccountWalletStorage}); // Disabled + + StartMigrating(/*uncheck_last_card=*/false, /*has_cardholder_name=*/true); + IssueOAuthToken(); + + // ChromeUserContext was set. + EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos); + EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos); +} + +TEST_F(PaymentsClientTest, + MigrationRequestIncludesChromeUserContextIfWalletStorageFlagEnabled) { + scoped_feature_list_.InitWithFeatures( + {features::kAutofillEnableAccountWalletStorage}, // Enabled + {features::kAutofillGetPaymentsIdentityFromSync}); // Disabled + + StartMigrating(/*uncheck_last_card=*/false, /*has_cardholder_name=*/true); + IssueOAuthToken(); + + // ChromeUserContext was set. + EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos); + EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos); +} + +TEST_F(PaymentsClientTest, + MigrationRequestExcludesChromeUserContextIfExperimentsOff) { + scoped_feature_list_.InitWithFeatures( + {}, // Enabled + {features::kAutofillEnableAccountWalletStorage, + features::kAutofillGetPaymentsIdentityFromSync}); // Disabled + + StartMigrating(/*uncheck_last_card=*/false, /*has_cardholder_name=*/true); + IssueOAuthToken(); + + // ChromeUserContext was not set. + EXPECT_TRUE(!GetUploadData().empty()); + EXPECT_TRUE(GetUploadData().find("chrome_user_context") == std::string::npos); + EXPECT_TRUE(GetUploadData().find("full_sync_enabled") == std::string::npos); +} + +TEST_F(PaymentsClientTest, MigrationSuccessWithSaveResult) { + StartMigrating(/*uncheck_last_card=*/false, /*has_cardholder_name=*/true); + IssueOAuthToken(); + ReturnResponse(net::HTTP_OK, + "{\"save_result\":[{\"unique_id\":\"0\",\"status\":" + "\"SUCCESS\"},{\"unique_id\":\"1\",\"status\":\"TEMPORARY_" + "FAILURE\"}],\"value_prop_display_text\":\"display text\"}"); + + EXPECT_EQ(AutofillClient::SUCCESS, result_); + EXPECT_TRUE(save_result_.get()); + EXPECT_TRUE(save_result_->find("0") != save_result_->end()); + EXPECT_TRUE(save_result_->at("0") == "SUCCESS"); + EXPECT_TRUE(save_result_->find("1") != save_result_->end()); + EXPECT_TRUE(save_result_->at("1") == "TEMPORARY_FAILURE"); +} + +TEST_F(PaymentsClientTest, MigrationMissingSaveResult) { + StartMigrating(/*uncheck_last_card=*/false, /*has_cardholder_name=*/true); + IssueOAuthToken(); + ReturnResponse(net::HTTP_OK, + "{\"value_prop_display_text\":\"display text\"}"); + EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_); + EXPECT_EQ(nullptr, save_result_.get()); +} + +TEST_F(PaymentsClientTest, MigrationSuccessWithDisplayText) { + StartMigrating(/*uncheck_last_card=*/false, /*has_cardholder_name=*/true); + IssueOAuthToken(); + ReturnResponse(net::HTTP_OK, + "{\"save_result\":[{\"unique_id\":\"0\",\"status\":" + "\"SUCCESS\"}],\"value_prop_display_text\":\"display text\"}"); + EXPECT_EQ(AutofillClient::SUCCESS, result_); + EXPECT_EQ("display text", display_text_); +} + TEST_F(PaymentsClientTest, GetDetailsFollowedByUploadSuccess) { StartGettingUploadDetails(); ReturnResponse( @@ -517,6 +919,23 @@ TEST_F(PaymentsClientTest, GetDetailsFollowedByUploadSuccess) { EXPECT_EQ(AutofillClient::SUCCESS, result_); } +TEST_F(PaymentsClientTest, GetDetailsFollowedByMigrationSuccess) { + StartGettingUploadDetails(); + ReturnResponse( + net::HTTP_OK, + "{ \"context_token\": \"some_token\", \"legal_message\": {} }"); + EXPECT_EQ(AutofillClient::SUCCESS, result_); + + result_ = AutofillClient::NONE; + + StartMigrating(/*uncheck_last_card=*/true, /*has_cardholder_name=*/true); + IssueOAuthToken(); + ReturnResponse( + net::HTTP_OK, + "{\"save_result\":[],\"value_prop_display_text\":\"display text\"}"); + EXPECT_EQ(AutofillClient::SUCCESS, result_); +} + TEST_F(PaymentsClientTest, UnmaskMissingPan) { StartUnmasking(); ReturnResponse(net::HTTP_OK, "{}"); diff --git a/chromium/components/autofill/core/browser/payments/payments_customer_data.h b/chromium/components/autofill/core/browser/payments/payments_customer_data.h new file mode 100644 index 00000000000..7f95892ac09 --- /dev/null +++ b/chromium/components/autofill/core/browser/payments/payments_customer_data.h @@ -0,0 +1,30 @@ +// Copyright 2018 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_CUSTOMER_DATA_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_CUSTOMER_DATA_H_ + +#include <string> + +namespace autofill { + +// Represents the Google Payments customer data. +struct PaymentsCustomerData { + explicit PaymentsCustomerData(const std::string& customer_id) + : customer_id(customer_id) {} + + bool operator==(const PaymentsCustomerData& other) const { + return customer_id == other.customer_id; + } + bool operator!=(const PaymentsCustomerData& other) const { + return !(*this == other); + } + + // The identifier by which a Google Payments account is identified. + std::string customer_id; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_CUSTOMER_DATA_H_ diff --git a/chromium/components/autofill/core/browser/payments/payments_util.cc b/chromium/components/autofill/core/browser/payments/payments_util.cc new file mode 100644 index 00000000000..6f181414143 --- /dev/null +++ b/chromium/components/autofill/core/browser/payments/payments_util.cc @@ -0,0 +1,49 @@ +// Copyright 2018 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 "components/autofill/core/browser/payments/payments_util.h" + +#include "base/feature_list.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_piece.h" +#include "components/autofill/core/browser/autofill_metrics.h" +#include "components/autofill/core/browser/payments/payments_customer_data.h" +#include "components/autofill/core/browser/personal_data_manager.h" +#include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_prefs.h" +#include "components/prefs/pref_service.h" + +namespace autofill { +namespace payments { + +int64_t GetBillingCustomerId(PersonalDataManager* personal_data_manager, + PrefService* pref_service) { + DCHECK(personal_data_manager); + DCHECK(pref_service); + + if (base::FeatureList::IsEnabled( + features::kAutofillUsePaymentsCustomerData) || + base::FeatureList::IsEnabled( + features::kAutofillEnableAccountWalletStorage)) { + // Get billing customer ID from the synced PaymentsCustomerData. + PaymentsCustomerData* customer_data = + personal_data_manager->GetPaymentsCustomerData(); + if (customer_data && !customer_data->customer_id.empty()) { + int64_t billing_customer_id = 0; + if (base::StringToInt64(base::StringPiece(customer_data->customer_id), + &billing_customer_id)) { + AutofillMetrics::LogPaymentsCustomerDataBillingIdIsValid(true); + return billing_customer_id; + } + } + AutofillMetrics::LogPaymentsCustomerDataBillingIdIsValid(false); + } + + // Get billing customer ID from priority preferences. + return static_cast<int64_t>( + pref_service->GetDouble(prefs::kAutofillBillingCustomerNumber)); +} + +} // namespace payments +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/payments/payments_util.h b/chromium/components/autofill/core/browser/payments/payments_util.h new file mode 100644 index 00000000000..364284a1397 --- /dev/null +++ b/chromium/components/autofill/core/browser/payments/payments_util.h @@ -0,0 +1,27 @@ +// Copyright 2018 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_UTIL_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_UTIL_H_ + +#include <stdint.h> + +class PrefService; + +namespace autofill { + +class PersonalDataManager; + +namespace payments { + +// Returns the billing customer ID (a.k.a. the customer number) for the Google +// Payments account for this user. Obtains it from the synced data. Returns 0 +// if the customer ID was not found. +int64_t GetBillingCustomerId(PersonalDataManager* personal_data_manager, + PrefService* pref_service); + +} // namespace payments +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_UTIL_H_ diff --git a/chromium/components/autofill/core/browser/payments/payments_util_unittest.cc b/chromium/components/autofill/core/browser/payments/payments_util_unittest.cc new file mode 100644 index 00000000000..057bade43f3 --- /dev/null +++ b/chromium/components/autofill/core/browser/payments/payments_util_unittest.cc @@ -0,0 +1,103 @@ +// Copyright 2018 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 "components/autofill/core/browser/payments/payments_util.h" + +#include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" +#include "components/autofill/core/browser/payments/payments_customer_data.h" +#include "components/autofill/core/browser/test_personal_data_manager.h" +#include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_prefs.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/testing_pref_service.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace autofill { +namespace payments { + +class PaymentsUtilTest : public testing::Test { + public: + PaymentsUtilTest() {} + ~PaymentsUtilTest() override {} + + protected: + void SetUp() override { + pref_service_.registry()->RegisterDoublePref( + prefs::kAutofillBillingCustomerNumber, 0.0); + } + + base::test::ScopedFeatureList scoped_feature_list_; + TestPersonalDataManager personal_data_manager_; + TestingPrefServiceSimple pref_service_; + + private: + DISALLOW_COPY_AND_ASSIGN(PaymentsUtilTest); +}; + +TEST_F(PaymentsUtilTest, GetBillingCustomerId_PaymentsCustomerData_Normal) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillUsePaymentsCustomerData); + base::HistogramTester histogram_tester; + + personal_data_manager_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + + EXPECT_EQ(123456, + GetBillingCustomerId(&personal_data_manager_, &pref_service_)); + + histogram_tester.ExpectUniqueSample( + "Autofill.PaymentsCustomerDataBillingIdIsValid", true, 1); +} + +TEST_F(PaymentsUtilTest, GetBillingCustomerId_PaymentsCustomerData_NoData) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillUsePaymentsCustomerData); + base::HistogramTester histogram_tester; + + // Explictly do not set PaymentsCustomerData. Nothing crashes and the returned + // customer ID is 0. + EXPECT_EQ(0, GetBillingCustomerId(&personal_data_manager_, &pref_service_)); + histogram_tester.ExpectUniqueSample( + "Autofill.PaymentsCustomerDataBillingIdIsValid", false, 1); +} + +TEST_F(PaymentsUtilTest, + GetBillingCustomerId_PaymentsCustomerData_NoDataFallback) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillUsePaymentsCustomerData); + base::HistogramTester histogram_tester; + + // Explictly do not set PaymentsCustomerData but set a fallback to prefs. + pref_service_.SetDouble(prefs::kAutofillBillingCustomerNumber, 123456.0); + + // We got the data from prefs and log that the PaymentsCustomerData is + // invalid. + EXPECT_EQ(123456, + GetBillingCustomerId(&personal_data_manager_, &pref_service_)); + histogram_tester.ExpectUniqueSample( + "Autofill.PaymentsCustomerDataBillingIdIsValid", false, 1); +} + +TEST_F(PaymentsUtilTest, GetBillingCustomerId_PriorityPrefs_Normal) { + scoped_feature_list_.InitAndDisableFeature( + features::kAutofillUsePaymentsCustomerData); + + pref_service_.SetDouble(prefs::kAutofillBillingCustomerNumber, 123456.0); + + EXPECT_EQ(123456, + GetBillingCustomerId(&personal_data_manager_, &pref_service_)); +} + +TEST_F(PaymentsUtilTest, GetBillingCustomerId_PriorityPrefs_NoData) { + scoped_feature_list_.InitAndDisableFeature( + features::kAutofillUsePaymentsCustomerData); + + // Explictly do not set Prefs data. Nothing crashes and the returned customer + // ID is 0. + EXPECT_EQ(0, GetBillingCustomerId(&personal_data_manager_, &pref_service_)); +} + +} // namespace payments +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/payments/test_payments_client.cc b/chromium/components/autofill/core/browser/payments/test_payments_client.cc index 104864965a2..3918e35b143 100644 --- a/chromium/components/autofill/core/browser/payments/test_payments_client.cc +++ b/chromium/components/autofill/core/browser/payments/test_payments_client.cc @@ -5,6 +5,7 @@ #include "components/autofill/core/browser/payments/test_payments_client.h" #include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/personal_data_manager.h" #include "services/network/public/cpp/shared_url_loader_factory.h" namespace autofill { @@ -14,14 +15,11 @@ TestPaymentsClient::TestPaymentsClient( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_, PrefService* pref_service, identity::IdentityManager* identity_manager, - payments::PaymentsClientUnmaskDelegate* unmask_delegate, - payments::PaymentsClientSaveDelegate* save_delegate) + PersonalDataManager* personal_data_manager) : PaymentsClient(url_loader_factory_, pref_service, identity_manager, - unmask_delegate, - save_delegate), - save_delegate_(save_delegate) {} + personal_data_manager) {} TestPaymentsClient::~TestPaymentsClient() {} @@ -30,33 +28,47 @@ void TestPaymentsClient::GetUploadDetails( const int detected_values, const std::string& pan_first_six, const std::vector<const char*>& active_experiments, - const std::string& app_locale) { + const std::string& app_locale, + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + const base::string16&, + std::unique_ptr<base::DictionaryValue>)> callback, + const int billable_service_number) { upload_details_addresses_ = addresses; detected_values_ = detected_values; pan_first_six_ = pan_first_six; active_experiments_ = active_experiments; - save_delegate_->OnDidGetUploadDetails( - app_locale == "en-US" ? AutofillClient::SUCCESS - : AutofillClient::PERMANENT_FAILURE, - base::ASCIIToUTF16("this is a context token"), - std::unique_ptr<base::DictionaryValue>(nullptr)); + std::move(callback).Run(app_locale == "en-US" + ? AutofillClient::SUCCESS + : AutofillClient::PERMANENT_FAILURE, + base::ASCIIToUTF16("this is a context token"), + std::unique_ptr<base::DictionaryValue>(nullptr)); } void TestPaymentsClient::UploadCard( - const payments::PaymentsClient::UploadRequestDetails& request_details) { + const payments::PaymentsClient::UploadRequestDetails& request_details, + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + const std::string&)> callback) { + upload_card_addresses_ = request_details.profiles; active_experiments_ = request_details.active_experiments; - save_delegate_->OnDidUploadCard(AutofillClient::SUCCESS, server_id_); + std::move(callback).Run(AutofillClient::SUCCESS, server_id_); } -void TestPaymentsClient::SetSaveDelegate( - payments::PaymentsClientSaveDelegate* save_delegate) { - save_delegate_ = save_delegate; - payments::PaymentsClient::SetSaveDelegate(save_delegate); +void TestPaymentsClient::MigrateCards( + const MigrationRequestDetails& details, + const std::vector<MigratableCreditCard>& migratable_credit_cards, + MigrateCardsCallback callback) { + std::move(callback).Run(AutofillClient::SUCCESS, std::move(save_result_), + "this is display text"); } void TestPaymentsClient::SetServerIdForCardUpload(std::string server_id) { server_id_ = server_id; } +void TestPaymentsClient::SetSaveResultForCardsMigration( + std::unique_ptr<std::unordered_map<std::string, std::string>> save_result) { + save_result_ = std::move(save_result); +} + } // namespace payments } // namespace autofill diff --git a/chromium/components/autofill/core/browser/payments/test_payments_client.h b/chromium/components/autofill/core/browser/payments/test_payments_client.h index 13d24e010ba..da2dba35eaf 100644 --- a/chromium/components/autofill/core/browser/payments/test_payments_client.h +++ b/chromium/components/autofill/core/browser/payments/test_payments_client.h @@ -23,41 +23,57 @@ class TestPaymentsClient : public payments::PaymentsClient { scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_, PrefService* pref_service, identity::IdentityManager* identity_manager, - payments::PaymentsClientUnmaskDelegate* unmask_delegate, - payments::PaymentsClientSaveDelegate* save_delegate); + PersonalDataManager* personal_data_manager); ~TestPaymentsClient() override; - void GetUploadDetails(const std::vector<AutofillProfile>& addresses, - const int detected_values, - const std::string& pan_first_six, - const std::vector<const char*>& active_experiments, - const std::string& app_locale) override; - - void UploadCard(const payments::PaymentsClient::UploadRequestDetails& - request_details) override; - - void SetSaveDelegate( - payments::PaymentsClientSaveDelegate* save_delegate) override; + void GetUploadDetails( + const std::vector<AutofillProfile>& addresses, + const int detected_values, + const std::string& pan_first_six, + const std::vector<const char*>& active_experiments, + const std::string& app_locale, + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + const base::string16&, + std::unique_ptr<base::DictionaryValue>)> callback, + const int billable_service_number) override; + + void UploadCard( + const payments::PaymentsClient::UploadRequestDetails& request_details, + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + const std::string&)> callback) override; + + void MigrateCards( + const MigrationRequestDetails& details, + const std::vector<MigratableCreditCard>& migratable_credit_cards, + MigrateCardsCallback callback) override; void SetServerIdForCardUpload(std::string); + void SetSaveResultForCardsMigration( + std::unique_ptr<std::unordered_map<std::string, std::string>> + save_result); + int detected_values_in_upload_details() const { return detected_values_; } const std::vector<AutofillProfile>& addresses_in_upload_details() const { return upload_details_addresses_; } std::string pan_first_six_in_upload_details() const { return pan_first_six_; } + const std::vector<AutofillProfile>& addresses_in_upload_card() const { + return upload_card_addresses_; + } const std::vector<const char*>& active_experiments_in_request() const { return active_experiments_; } private: - payments::PaymentsClientSaveDelegate* save_delegate_; std::string server_id_; std::vector<AutofillProfile> upload_details_addresses_; + std::vector<AutofillProfile> upload_card_addresses_; int detected_values_; std::string pan_first_six_; std::vector<const char*> active_experiments_; + std::unique_ptr<std::unordered_map<std::string, std::string>> save_result_; DISALLOW_COPY_AND_ASSIGN(TestPaymentsClient); }; diff --git a/chromium/components/autofill/core/browser/personal_data_manager.cc b/chromium/components/autofill/core/browser/personal_data_manager.cc index a53c36fb032..502dd53b8bb 100644 --- a/chromium/components/autofill/core/browser/personal_data_manager.cc +++ b/chromium/components/autofill/core/browser/personal_data_manager.cc @@ -40,7 +40,7 @@ #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_features.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/autofill/core/common/autofill_util.h" #include "components/prefs/pref_service.h" @@ -405,6 +405,12 @@ class PersonalDatabaseHelper return server_database_; } + // Whether we're currently using the ephemeral account storage for saving + // server cards. + bool IsUsingAccountStorageForServerCards() { + return server_database_ != profile_database_; + } + // Set whether this should use the passed in account storage for server // addresses. If false, this will use the profile_storage. // It's an error to call this if no account storage was passed in at @@ -427,9 +433,11 @@ class PersonalDatabaseHelper return; } - if (server_database_ != nullptr && server_database_ != profile_database_) { - // Remove the previous observer if we had any. - server_database_->RemoveObserver(personal_data_manager_); + if (server_database_ != nullptr) { + if (server_database_ != profile_database_) { + // Remove the previous observer if we had any. + server_database_->RemoveObserver(personal_data_manager_); + } personal_data_manager_->CancelPendingServerQueries(); } server_database_ = new_server_database; @@ -456,18 +464,7 @@ class PersonalDatabaseHelper }; PersonalDataManager::PersonalDataManager(const std::string& app_locale) - : is_data_loaded_(false), - pending_profiles_query_(0), - pending_server_profiles_query_(0), - pending_creditcards_query_(0), - pending_server_creditcards_query_(0), - app_locale_(app_locale), - pref_service_(nullptr), - identity_manager_(nullptr), - sync_service_(nullptr), - is_off_the_record_(false), - has_logged_stored_profile_metrics_(false), - has_logged_stored_credit_card_metrics_(false) { + : app_locale_(app_locale) { database_helper_ = std::make_unique<PersonalDatabaseHelper>(this); } @@ -479,7 +476,16 @@ void PersonalDataManager::Init( bool is_off_the_record) { CountryNames::SetLocaleString(app_locale_); database_helper_->Init(profile_database, account_database); + SetPrefService(pref_service); + + // Listen for the preference changes. + pref_registrar_.Init(pref_service); + pref_registrar_.Add( + prefs::kAutofillProfileValidity, + base::BindRepeating(&PersonalDataManager::ResetProfileValidity, + base::Unretained(this))); + identity_manager_ = identity_manager; is_off_the_record_ = is_off_the_record; @@ -492,7 +498,7 @@ void PersonalDataManager::Init( } LoadProfiles(); LoadCreditCards(); - + LoadPaymentsCustomerData(); // Check if profile cleanup has already been performed this major version. is_autofill_profile_cleanup_pending_ = @@ -509,6 +515,7 @@ PersonalDataManager::~PersonalDataManager() { CancelPendingLocalQuery(&pending_server_profiles_query_); CancelPendingLocalQuery(&pending_creditcards_query_); CancelPendingServerQuery(&pending_server_creditcards_query_); + CancelPendingServerQuery(&pending_customer_data_query_); } void PersonalDataManager::Shutdown() { @@ -553,20 +560,22 @@ void PersonalDataManager::OnSyncServiceInitialized( ResetFullServerCards(/*dry_run=*/!base::FeatureList::IsEnabled( features::kAutofillResetFullServerCardsOnAuthError)); } + if (base::FeatureList::IsEnabled( + autofill::features::kAutofillEnableAccountWalletStorage)) { + // Use the ephemeral account storage when the user didn't enable the sync + // feature explicitly. + database_helper_->SetUseAccountStorageForServerCards( + !sync_service->IsSyncFeatureEnabled()); + } } } -void PersonalDataManager::SetUseAccountStorageForServerCards( - bool use_account_storage_for_server_cards) { - database_helper_->SetUseAccountStorageForServerCards( - use_account_storage_for_server_cards); -} - void PersonalDataManager::OnWebDataServiceRequestDone( WebDataServiceBase::Handle h, std::unique_ptr<WDTypedResult> result) { DCHECK(pending_profiles_query_ || pending_server_profiles_query_ || - pending_creditcards_query_ || pending_server_creditcards_query_); + pending_creditcards_query_ || pending_server_creditcards_query_ || + pending_customer_data_query_); if (!result) { // Error from the web database. @@ -578,6 +587,8 @@ void PersonalDataManager::OnWebDataServiceRequestDone( pending_server_creditcards_query_ = 0; else if (h == pending_server_profiles_query_) pending_server_profiles_query_ = 0; + else if (h == pending_server_creditcards_query_) + pending_server_profiles_query_ = 0; } else { switch (result->GetType()) { case AUTOFILL_PROFILES_RESULT: @@ -609,6 +620,16 @@ void PersonalDataManager::OnWebDataServiceRequestDone( ResetFullServerCards(); } break; + case AUTOFILL_CUSTOMERDATA_RESULT: + DCHECK_EQ(h, pending_customer_data_query_) + << "received customer data from invalid request."; + pending_customer_data_query_ = 0; + + payments_customer_data_ = + static_cast<WDResult<std::unique_ptr<PaymentsCustomerData>>*>( + result.get()) + ->GetValue(); + break; default: NOTREACHED(); } @@ -620,6 +641,7 @@ void PersonalDataManager::OnWebDataServiceRequestDone( if (pending_profiles_query_ == 0 && pending_creditcards_query_ == 0 && pending_server_profiles_query_ == 0 && pending_server_creditcards_query_ == 0 && + pending_customer_data_query_ == 0 && database_helper_->GetServerDatabase()) { // On initial data load, is_data_loaded_ will be false here. if (!is_data_loaded_) { @@ -676,6 +698,13 @@ void PersonalDataManager::OnStateChanged(syncer::SyncService* sync_service) { ResetFullServerCards(/*dry_run=*/!base::FeatureList::IsEnabled( features::kAutofillResetFullServerCardsOnAuthError)); } + if (base::FeatureList::IsEnabled( + autofill::features::kAutofillEnableAccountWalletStorage)) { + // Use the ephemeral account storage when the user didn't enable the sync + // feature explicitly. + database_helper_->SetUseAccountStorageForServerCards( + !sync_service->IsSyncFeatureEnabled()); + } } void PersonalDataManager::OnSyncShutdown(syncer::SyncService* sync_service) { @@ -684,6 +713,26 @@ void PersonalDataManager::OnSyncShutdown(syncer::SyncService* sync_service) { sync_service_ = nullptr; } +AccountInfo PersonalDataManager::GetAccountInfoForPaymentsServer() const { + // If butter is enabled or the feature to get the Payment Identity from Sync + // is enabled, return the account of the active signed-in user irrespective of + // whether they enabled sync or not. + // Otherwise, return the latest cached AccountInfo of the user's primary + // account, which is empty if the user has disabled sync. + // In both cases, the AccountInfo will be empty if the user is not signed in. + return ShouldUseActiveSignedInAccount() && sync_service_ + ? sync_service_->GetAuthenticatedAccountInfo() + : identity_manager_->GetPrimaryAccountInfo(); +} + +bool PersonalDataManager::IsSyncFeatureEnabled() const { + if (!sync_service_) + return false; + + return !sync_service_->GetAuthenticatedAccountInfo().IsEmpty() && + !database_helper_->IsUsingAccountStorageForServerCards(); +} + void PersonalDataManager::AddObserver(PersonalDataManagerObserver* observer) { observers_.AddObserver(observer); } @@ -1145,9 +1194,14 @@ std::vector<CreditCard*> PersonalDataManager::GetCreditCards() const { return result; } +PaymentsCustomerData* PersonalDataManager::GetPaymentsCustomerData() const { + return payments_customer_data_ ? payments_customer_data_.get() : nullptr; +} + void PersonalDataManager::Refresh() { LoadProfiles(); LoadCreditCards(); + LoadPaymentsCustomerData(); } std::vector<AutofillProfile*> PersonalDataManager::GetProfilesToSuggest() @@ -1188,8 +1242,8 @@ void PersonalDataManager::RemoveProfilesNotUsedSinceTimestamp( void PersonalDataManager::MaybeRemoveInvalidSuggestions( const AutofillType& type, std::vector<AutofillProfile*>* profiles) { - const bool suggest_invalid = - base::FeatureList::IsEnabled(kAutofillSuggestInvalidProfileData); + const bool suggest_invalid = base::FeatureList::IsEnabled( + features::kAutofillSuggestInvalidProfileData); for (size_t i = 0; i < profiles->size(); ++i) { bool is_invalid = (*profiles)[i]->GetValidityState( @@ -1228,7 +1282,8 @@ std::vector<Suggestion> PersonalDataManager::GetProfileSuggestions( // When suggesting with no prefix to match, consider suppressing disused // address suggestions as well as those based on invalid profile data. if (field_contents_canon.empty()) { - if (base::FeatureList::IsEnabled(kAutofillSuppressDisusedAddresses)) { + if (base::FeatureList::IsEnabled( + features::kAutofillSuppressDisusedAddresses)) { const base::Time min_last_used = AutofillClock::Now() - kDisusedProfileTimeDelta; RemoveProfilesNotUsedSinceTimestamp(min_last_used, &profiles); @@ -1387,7 +1442,8 @@ std::vector<Suggestion> PersonalDataManager::GetCreditCardSuggestions( // If enabled, suppress disused address profiles when triggered from an empty // field. if (field_contents.empty() && - base::FeatureList::IsEnabled(kAutofillSuppressDisusedCreditCards)) { + base::FeatureList::IsEnabled( + features::kAutofillSuppressDisusedCreditCards)) { const base::Time min_last_used = AutofillClock::Now() - kDisusedCreditCardTimeDelta; RemoveExpiredCreditCardsNotUsedSinceTimestamp(AutofillClock::Now(), @@ -1398,19 +1454,19 @@ std::vector<Suggestion> PersonalDataManager::GetCreditCardSuggestions( } bool PersonalDataManager::IsAutofillEnabled() const { - return ::autofill::IsAutofillEnabled(pref_service_); + return ::autofill::prefs::IsAutofillEnabled(pref_service_); } bool PersonalDataManager::IsAutofillProfileEnabled() const { - return pref_service_->GetBoolean(prefs::kAutofillProfileEnabled); + return ::autofill::prefs::IsProfileAutofillEnabled(pref_service_); } bool PersonalDataManager::IsAutofillCreditCardEnabled() const { - return pref_service_->GetBoolean(prefs::kAutofillCreditCardEnabled); + return ::autofill::prefs::IsCreditCardAutofillEnabled(pref_service_); } bool PersonalDataManager::IsAutofillWalletImportEnabled() const { - return pref_service_->GetBoolean(prefs::kAutofillWalletImportEnabled); + return ::autofill::prefs::IsPaymentsIntegrationEnabled(pref_service_); } bool PersonalDataManager::ShouldSuggestServerCards() const { @@ -1437,27 +1493,26 @@ std::string PersonalDataManager::CountryCodeForCurrentTimezone() const { } void PersonalDataManager::SetPrefService(PrefService* pref_service) { - enabled_pref_ = std::make_unique<BooleanPrefMember>(); wallet_enabled_pref_ = std::make_unique<BooleanPrefMember>(); profile_enabled_pref_ = std::make_unique<BooleanPrefMember>(); credit_card_enabled_pref_ = std::make_unique<BooleanPrefMember>(); pref_service_ = pref_service; - // |pref_service_| can be nullptr in tests. + // |pref_service_| can be nullptr in tests. Using base::Unretained(this) is + // safe because observer instances are destroyed once |this| is destroyed. if (pref_service_) { credit_card_enabled_pref_->Init( prefs::kAutofillCreditCardEnabled, pref_service_, - base::Bind(&PersonalDataManager::Refresh, base::Unretained(this))); + base::BindRepeating(&PersonalDataManager::EnableAutofillPrefChanged, + base::Unretained(this))); profile_enabled_pref_->Init( prefs::kAutofillProfileEnabled, pref_service_, - base::BindRepeating(&PersonalDataManager::Refresh, + base::BindRepeating(&PersonalDataManager::EnableAutofillPrefChanged, base::Unretained(this))); - enabled_pref_->Init(prefs::kAutofillEnabled, pref_service_, - base::Bind(&PersonalDataManager::EnabledPrefChanged, - base::Unretained(this))); wallet_enabled_pref_->Init( prefs::kAutofillWalletImportEnabled, pref_service_, - base::Bind(&PersonalDataManager::EnabledPrefChanged, - base::Unretained(this))); + base::BindRepeating( + &PersonalDataManager::EnableWalletIntegrationPrefChanged, + base::Unretained(this))); } } @@ -1495,6 +1550,60 @@ void PersonalDataManager::ClearCreditCardNonSettingsOrigins() { Refresh(); } +void PersonalDataManager::MoveJapanCityToStreetAddress() { + if (!database_helper_->GetLocalDatabase()) + return; + + // Don't run if the migration has already been performed. + if (pref_service_->GetBoolean(prefs::kAutofillJapanCityFieldMigrated)) + return; + + bool has_updated = false; + base::string16 japan_country_code = base::ASCIIToUTF16("JP"); + base::string16 line_separator = base::ASCIIToUTF16("\n"); + for (AutofillProfile* profile : GetProfiles()) { + base::string16 country_code = profile->GetRawInfo(ADDRESS_HOME_COUNTRY); + base::string16 city = profile->GetRawInfo(ADDRESS_HOME_CITY); + if (country_code == japan_country_code && !city.empty()) { + base::string16 street_address = + profile->GetRawInfo(ADDRESS_HOME_STREET_ADDRESS); + street_address = street_address.empty() + ? city + : street_address + line_separator + city; + profile->SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, street_address); + profile->SetRawInfo(ADDRESS_HOME_CITY, base::EmptyString16()); + + // Make the update. + database_helper_->GetLocalDatabase()->UpdateAutofillProfile(*profile); + has_updated = true; + } + } + + // Refresh the local cache and send notifications to observers if a change was + // made. + if (has_updated) + Refresh(); + + // Set the pref so that this migration is never run again. + pref_service_->SetBoolean(prefs::kAutofillJapanCityFieldMigrated, true); +} + +const ProfileValidityMap& PersonalDataManager::GetProfileValidityByGUID( + std::string& guid) { + static const ProfileValidityMap& empty_validity_map = ProfileValidityMap(); + if (!synced_profile_validity_) { + synced_profile_validity_ = std::make_unique<UserProfileValidityMap>(); + if (!synced_profile_validity_->ParseFromString( + ::autofill::prefs::GetAllProfilesValidityMapsEncodedString( + pref_service_))) + return empty_validity_map; + } + auto it = synced_profile_validity_->profile_validity().find(guid); + if (it != synced_profile_validity_->profile_validity().end()) + return it->second; + return empty_validity_map; +} + // TODO(crbug.com/618448): Refactor MergeProfile to not depend on class // variables. std::string PersonalDataManager::MergeProfile( @@ -1634,9 +1743,7 @@ void PersonalDataManager::SetProfiles(std::vector<AutofillProfile>* profiles) { return; // Remove empty profiles from input. - profiles->erase(std::remove_if(profiles->begin(), profiles->end(), - IsEmptyFunctor<AutofillProfile>(app_locale_)), - profiles->end()); + base::EraseIf(*profiles, IsEmptyFunctor<AutofillProfile>(app_locale_)); if (!database_helper_->GetLocalDatabase()) return; @@ -1677,9 +1784,7 @@ void PersonalDataManager::SetCreditCards( return; // Remove empty credit cards from input. - credit_cards->erase(std::remove_if(credit_cards->begin(), credit_cards->end(), - IsEmptyFunctor<CreditCard>(app_locale_)), - credit_cards->end()); + base::EraseIf(*credit_cards, IsEmptyFunctor<CreditCard>(app_locale_)); if (!database_helper_->GetLocalDatabase()) return; @@ -1773,10 +1878,23 @@ void PersonalDataManager::CancelPendingServerQueries() { if (pending_server_creditcards_query_) { CancelPendingServerQuery(&pending_server_creditcards_query_); } + if (pending_customer_data_query_) { + CancelPendingServerQuery(&pending_customer_data_query_); + } // TODO(crbug.com/864519): also cancel the server addresses query once they // use the account storage. } +void PersonalDataManager::LoadPaymentsCustomerData() { + if (!database_helper_->GetServerDatabase()) + return; + + CancelPendingServerQuery(&pending_customer_data_query_); + + pending_customer_data_query_ = + database_helper_->GetServerDatabase()->GetPaymentsCustomerData(this); +} + std::string PersonalDataManager::SaveImportedProfile( const AutofillProfile& imported_profile) { if (is_off_the_record_) @@ -1904,14 +2022,20 @@ std::string PersonalDataManager::MostCommonCountryCodeFromProfiles() const { return std::string(); } -void PersonalDataManager::EnabledPrefChanged() { - default_country_code_.clear(); - if (!pref_service_->GetBoolean(prefs::kAutofillWalletImportEnabled)) { +void PersonalDataManager::EnableWalletIntegrationPrefChanged() { + if (!prefs::IsPaymentsIntegrationEnabled(pref_service_)) { // Re-mask all server cards when the user turns off wallet card // integration. ResetFullServerCards(); + NotifyPersonalDataChanged(); } - NotifyPersonalDataChanged(); +} + +void PersonalDataManager::EnableAutofillPrefChanged() { + default_country_code_.clear(); + + // Refresh our local cache and send notifications to observers. + Refresh(); } bool PersonalDataManager::IsKnownCard(const CreditCard& credit_card) { @@ -1940,6 +2064,20 @@ bool PersonalDataManager::IsKnownCard(const CreditCard& credit_card) { return false; } +bool PersonalDataManager::IsServerCard(const CreditCard* credit_card) const { + // Check whether the current card itself is a server card. + if (credit_card->record_type() != autofill::CreditCard::LOCAL_CARD) + return true; + + std::vector<CreditCard*> server_credit_cards = GetServerCreditCards(); + // Check whether the current card is already uploaded. + for (const CreditCard* server_card : server_credit_cards) { + if (credit_card->HasSameNumberAs(*server_card)) + return true; + } + return false; +} + std::vector<Suggestion> PersonalDataManager::GetSuggestionsForCards( const AutofillType& type, const base::string16& field_contents, @@ -2373,7 +2511,7 @@ void PersonalDataManager::MaybeCreateTestAddresses() { return; has_created_test_addresses_ = true; - if (!base::FeatureList::IsEnabled(kAutofillCreateDataForTest)) + if (!base::FeatureList::IsEnabled(features::kAutofillCreateDataForTest)) return; AddProfile(CreateBasicTestAddress(app_locale_)); @@ -2386,7 +2524,7 @@ void PersonalDataManager::MaybeCreateTestCreditCards() { return; has_created_test_credit_cards_ = true; - if (!base::FeatureList::IsEnabled(kAutofillCreateDataForTest)) + if (!base::FeatureList::IsEnabled(features::kAutofillCreateDataForTest)) return; AddCreditCard(CreateBasicTestCreditCard(app_locale_)); @@ -2403,7 +2541,8 @@ bool PersonalDataManager::IsCreditCardDeletable(CreditCard* card) { } bool PersonalDataManager::DeleteDisusedCreditCards() { - if (!base::FeatureList::IsEnabled(kAutofillDeleteDisusedCreditCards)) { + if (!base::FeatureList::IsEnabled( + features::kAutofillDeleteDisusedCreditCards)) { return false; } @@ -2465,7 +2604,8 @@ bool PersonalDataManager::IsAddressDeletable( } bool PersonalDataManager::DeleteDisusedAddresses() { - if (!base::FeatureList::IsEnabled(kAutofillDeleteDisusedAddresses)) { + if (!base::FeatureList::IsEnabled( + features::kAutofillDeleteDisusedAddresses)) { DVLOG(1) << "Deletion is disabled"; return false; } @@ -2527,6 +2667,7 @@ void PersonalDataManager::ApplyAddressFixesAndCleanups() { DeleteDisusedAddresses(); // Once per major version, otherwise NOP. MaybeCreateTestAddresses(); // Once per user profile startup. ClearProfileNonSettingsOrigins(); // Ran everytime it is called. + MoveJapanCityToStreetAddress(); // One-time fix, otherwise NOP. } void PersonalDataManager::ApplyCardFixesAndCleanups() { diff --git a/chromium/components/autofill/core/browser/personal_data_manager.h b/chromium/components/autofill/core/browser/personal_data_manager.h index b79c908f5a0..59718eb1f75 100644 --- a/chromium/components/autofill/core/browser/personal_data_manager.h +++ b/chromium/components/autofill/core/browser/personal_data_manager.h @@ -18,15 +18,19 @@ #include "base/observer_list.h" #include "base/strings/string16.h" #include "build/build_config.h" +#include "components/autofill/core/browser/account_info_getter.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/payments/payments_customer_data.h" +#include "components/autofill/core/browser/proto/server.pb.h" #include "components/autofill/core/browser/suggestion.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h" #include "components/keyed_service/core/keyed_service.h" #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_member.h" +#include "components/signin/core/browser/account_info.h" #include "components/sync/driver/sync_service_observer.h" #include "components/webdata/common/web_data_service_consumer.h" @@ -66,7 +70,8 @@ extern const char kFrecencyFieldTrialLimitParam[]; class PersonalDataManager : public KeyedService, public WebDataServiceConsumer, public AutofillWebDataServiceObserverOnUISequence, - public syncer::SyncServiceObserver { + public syncer::SyncServiceObserver, + public AccountInfoGetter { public: explicit PersonalDataManager(const std::string& app_locale); ~PersonalDataManager() override; @@ -93,13 +98,6 @@ class PersonalDataManager : public KeyedService, // not be started, but it's preferences can be queried. virtual void OnSyncServiceInitialized(syncer::SyncService* sync_service); - // Set whether this should use the passed in account storage for server - // cards. If false, this will use the profile_storage. - // It's an error to call this if no account storage was passed in at - // initialization time. - void SetUseAccountStorageForServerCards( - bool use_account_storage_for_server_cards); - // WebDataServiceConsumer: void OnWebDataServiceRequestDone( WebDataServiceBase::Handle h, @@ -113,6 +111,10 @@ class PersonalDataManager : public KeyedService, void OnStateChanged(syncer::SyncService* sync) override; void OnSyncShutdown(syncer::SyncService* sync) override; + // AccountInfoGetter: + AccountInfo GetAccountInfoForPaymentsServer() const override; + bool IsSyncFeatureEnabled() const override; + // Adds a listener to be notified of PersonalDataManager events. virtual void AddObserver(PersonalDataManagerObserver* observer); @@ -227,6 +229,9 @@ class PersonalDataManager : public KeyedService, // Returns all credit cards, server and local. virtual std::vector<CreditCard*> GetCreditCards() const; + // Returns the Payments customer data. Returns nullptr if no data is present. + virtual PaymentsCustomerData* GetPaymentsCustomerData() const; + // Returns the profiles to suggest to the user, ordered by frecency. std::vector<AutofillProfile*> GetProfilesToSuggest() const; @@ -335,6 +340,9 @@ class PersonalDataManager : public KeyedService, // |credit_card| is equal to any masked server card known by the browser. bool IsKnownCard(const CreditCard& credit_card); + // Check whether a card is a server card or has a duplicated server card. + bool IsServerCard(const CreditCard* credit_card) const; + // Sets the value that can skip the checks to see if we are syncing in a test. void SetSyncingForTest(bool is_syncing_for_test) { is_syncing_for_test_ = is_syncing_for_test; @@ -415,6 +423,9 @@ class PersonalDataManager : public KeyedService, ClearProfileNonSettingsOrigins); FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest, ClearCreditCardNonSettingsOrigins); + FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest, + MoveJapanCityToStreetAddress); + FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest, RequestProfileValidity); friend class autofill::AutofillInteractiveTest; friend class autofill::PersonalDataManagerFactory; @@ -457,6 +468,9 @@ class PersonalDataManager : public KeyedService, // Loads the saved credit cards from the web database. virtual void LoadCreditCards(); + // Loads the payments customer data from the web database. + virtual void LoadPaymentsCustomerData(); + // Cancels a pending query to the local web database. |handle| is a pointer // to the query handle. void CancelPendingLocalQuery(WebDataServiceBase::Handle* handle); @@ -503,11 +517,20 @@ class PersonalDataManager : public KeyedService, void ClearProfileNonSettingsOrigins(); void ClearCreditCardNonSettingsOrigins(); + // Appends the value of the city field of a JP address to its street address + // field, separated by a newline, and clears the city field. + // TODO(rouslan): Remove this migration in or after October 2019. See bug: + // https://crbug.com/871301 + void MoveJapanCityToStreetAddress(); + + // Get the profiles fields validity map by |guid|. + const ProfileValidityMap& GetProfileValidityByGUID(std::string& guid); + // Decides which database type to use for server and local cards. std::unique_ptr<PersonalDatabaseHelper> database_helper_; // True if personal data has been loaded from the web database. - bool is_data_loaded_; + bool is_data_loaded_ = false; // The loaded web profiles. These are constructed from entries on web pages // and from manually editing in the settings. @@ -516,6 +539,9 @@ class PersonalDataManager : public KeyedService, // Profiles read from the user's account stored on the server. mutable std::vector<std::unique_ptr<AutofillProfile>> server_profiles_; + // Stores the PaymentsCustomerData obtained from the database. + std::unique_ptr<PaymentsCustomerData> payments_customer_data_; + // Storage for web profiles. Contents are weak references. Lifetime managed // by |web_profiles_|. mutable std::vector<AutofillProfile*> profiles_; @@ -528,13 +554,14 @@ class PersonalDataManager : public KeyedService, // is queried on another sequence, we record the query handle until we // get called back. We store handles for both profile and credit card queries // so they can be loaded at the same time. - WebDataServiceBase::Handle pending_profiles_query_; - WebDataServiceBase::Handle pending_server_profiles_query_; - WebDataServiceBase::Handle pending_creditcards_query_; - WebDataServiceBase::Handle pending_server_creditcards_query_; + WebDataServiceBase::Handle pending_profiles_query_ = 0; + WebDataServiceBase::Handle pending_server_profiles_query_ = 0; + WebDataServiceBase::Handle pending_creditcards_query_ = 0; + WebDataServiceBase::Handle pending_server_creditcards_query_ = 0; + WebDataServiceBase::Handle pending_customer_data_query_ = 0; // The observers. - base::ObserverList<PersonalDataManagerObserver> observers_; + base::ObserverList<PersonalDataManagerObserver>::Unchecked observers_; private: // Saves |imported_credit_card| to the WebDB if it exists. Returns the guid of @@ -546,8 +573,12 @@ class PersonalDataManager : public KeyedService, // Prefers verified profiles over unverified ones. std::string MostCommonCountryCodeFromProfiles() const; - // Called when the value of prefs::kAutofillEnabled changes. - void EnabledPrefChanged(); + // Called when the value of prefs::kAutofillWalletImportEnabled changes. + void EnableWalletIntegrationPrefChanged(); + + // Called when the value of prefs::kAutofillCreditCardEnabled or + // prefs::kAutofillProfileEnabled changes. + void EnableAutofillPrefChanged(); // Returns credit card suggestions based on the |cards_to_suggest| and the // |type| and |field_contents| of the credit card field. @@ -655,29 +686,39 @@ class PersonalDataManager : public KeyedService, // Applies various fixes and cleanups on autofill credit cards. void ApplyCardFixesAndCleanups(); + // Resets |synced_profile_validity_|. + void ResetProfileValidity() { synced_profile_validity_.reset(); }; + const std::string app_locale_; // The default country code for new addresses. mutable std::string default_country_code_; // The PrefService that this instance uses. Must outlive this instance. - PrefService* pref_service_; + PrefService* pref_service_ = nullptr; + + // Pref registrar for managing the change observers. + PrefChangeRegistrar pref_registrar_; + + // Profiles validity read from the prefs. They are kept updated by + // observing changes in pref_services. + std::unique_ptr<UserProfileValidityMap> synced_profile_validity_; // The identity manager that this instance uses. Must outlive this instance. - identity::IdentityManager* identity_manager_; + identity::IdentityManager* identity_manager_ = nullptr; // The sync service this instances uses. Must outlive this instance. - syncer::SyncService* sync_service_; + syncer::SyncService* sync_service_ = nullptr; // Whether the user is currently operating in an off-the-record context. // Default value is false. - bool is_off_the_record_; + bool is_off_the_record_ = false; // Whether we have already logged the stored profile metrics this session. - mutable bool has_logged_stored_profile_metrics_; + mutable bool has_logged_stored_profile_metrics_ = false; // Whether we have already logged the stored credit card metrics this session. - mutable bool has_logged_stored_credit_card_metrics_; + mutable bool has_logged_stored_credit_card_metrics_ = false; // An observer to listen for changes to prefs::kAutofillCreditCardEnabled. std::unique_ptr<BooleanPrefMember> credit_card_enabled_pref_; @@ -685,9 +726,6 @@ class PersonalDataManager : public KeyedService, // An observer to listen for changes to prefs::kAutofillProfileEnabled. std::unique_ptr<BooleanPrefMember> profile_enabled_pref_; - // An observer to listen for changes to prefs::kAutofillEnabled. - std::unique_ptr<BooleanPrefMember> enabled_pref_; - // An observer to listen for changes to prefs::kAutofillWalletImportEnabled. std::unique_ptr<BooleanPrefMember> wallet_enabled_pref_; diff --git a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc index ad871584de3..5cc8958d85b 100644 --- a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc @@ -44,7 +44,7 @@ #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_features.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/autofill/core/common/form_data.h" #include "components/os_crypt/os_crypt_mocker.h" @@ -112,7 +112,12 @@ void ExpectSameElements(const std::vector<T*>& expectations, class PersonalDataManagerTestBase { protected: - PersonalDataManagerTestBase() : profile_autofill_table_(nullptr) {} + PersonalDataManagerTestBase() : profile_autofill_table_(nullptr) { + // Enable account storage by default, some tests will override this to be + // false. + scoped_features_.InitAndEnableFeature( + features::kAutofillEnableAccountWalletStorage); + } void SetUpTest() { OSCryptMocker::SetUp(); @@ -174,9 +179,9 @@ class PersonalDataManagerTestBase { : nullptr, prefs_.get(), identity_test_env_.identity_manager(), is_incognito); personal_data_->AddObserver(&personal_data_observer_); + sync_service_.SetIsAuthenticatedAccountPrimary(!use_account_server_storage); personal_data_->OnSyncServiceInitialized(&sync_service_); - personal_data_->SetUseAccountStorageForServerCards( - use_account_server_storage); + personal_data_->OnStateChanged(&sync_service_); // Verify that the web database has been updated and the notification sent. EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) @@ -368,6 +373,7 @@ class PersonalDataManagerTestBase { AutofillTable* account_autofill_table_; // weak ref PersonalDataLoadedObserverMock personal_data_observer_; std::unique_ptr<PersonalDataManager> personal_data_; + base::test::ScopedFeatureList scoped_features_; }; class PersonalDataManagerTest : public PersonalDataManagerTestBase, @@ -1576,17 +1582,16 @@ TEST_F(PersonalDataManagerTest, DefaultCountryCodeIsCached) { EXPECT_EQ(default_country, personal_data_->GetDefaultCountryCodeForNewAddress()); - EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(2); - // Disabling Autofill blows away this cache and shouldn't account for Autofill // profiles. - prefs_->SetBoolean(prefs::kAutofillEnabled, false); + prefs::SetAutofillEnabled(prefs_.get(), false); + WaitForOnPersonalDataChanged(); EXPECT_EQ(default_country, personal_data_->GetDefaultCountryCodeForNewAddress()); // Enabling Autofill blows away the cached value and should reflect the new // value (accounting for profiles). - prefs_->SetBoolean(prefs::kAutofillEnabled, true); + prefs::SetAutofillEnabled(prefs_.get(), true); EXPECT_EQ(base::UTF16ToUTF8(moose.GetRawInfo(ADDRESS_HOME_COUNTRY)), personal_data_->GetDefaultCountryCodeForNewAddress()); } @@ -1874,7 +1879,8 @@ TEST_F(PersonalDataManagerTest, ResetPersonalDataManager(USER_MODE_NORMAL); base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndEnableFeature(kAutofillSuppressDisusedAddresses); + scoped_features.InitAndEnableFeature( + features::kAutofillSuppressDisusedAddresses); // Query with empty string only returns profile2. { @@ -1917,7 +1923,8 @@ TEST_F(PersonalDataManagerTest, // When suppression is disabled, returns all suggestions. { base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndDisableFeature(kAutofillSuppressDisusedAddresses); + scoped_features.InitAndDisableFeature( + features::kAutofillSuppressDisusedAddresses); std::vector<Suggestion> suggestions = personal_data_->GetProfileSuggestions( AutofillType(ADDRESS_HOME_STREET_ADDRESS), base::string16(), false, std::vector<ServerFieldType>()); @@ -1954,7 +1961,8 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_InvalidData) { { base::HistogramTester histogram_tester; base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndDisableFeature(kAutofillSuggestInvalidProfileData); + scoped_features.InitAndDisableFeature( + features::kAutofillSuggestInvalidProfileData); std::vector<Suggestion> suggestions = personal_data_->GetProfileSuggestions( AutofillType(PHONE_HOME_WHOLE_NUMBER), base::string16(), false, std::vector<ServerFieldType>()); @@ -1967,7 +1975,8 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_InvalidData) { { base::HistogramTester histogram_tester; base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndEnableFeature(kAutofillSuggestInvalidProfileData); + scoped_features.InitAndEnableFeature( + features::kAutofillSuggestInvalidProfileData); std::vector<Suggestion> suggestions = personal_data_->GetProfileSuggestions( AutofillType(PHONE_HOME_WHOLE_NUMBER), base::string16(), false, std::vector<ServerFieldType>()); @@ -2008,9 +2017,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_ProfileAutofillDisabled) { profile_autofill_table_->SetServerProfiles(GetServerProfiles); // Disable Profile autofill. - personal_data_->pref_service_->SetBoolean(prefs::kAutofillProfileEnabled, - false); - personal_data_->Refresh(); + prefs::SetProfileAutofillEnabled(personal_data_->pref_service_, false); WaitForOnPersonalDataChanged(); personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); @@ -2062,9 +2069,8 @@ TEST_F(PersonalDataManagerTest, EXPECT_EQ(2U, personal_data_->GetProfiles().size()); EXPECT_EQ(2U, personal_data_->GetProfilesToSuggest().size()); - // Disable CProfile autofill. - personal_data_->pref_service_->SetBoolean(prefs::kAutofillProfileEnabled, - false); + // Disable Profile autofill. + prefs::SetProfileAutofillEnabled(personal_data_->pref_service_, false); // Reload the database. ResetPersonalDataManager(USER_MODE_NORMAL); @@ -2082,8 +2088,7 @@ TEST_F(PersonalDataManagerTest, TEST_F(PersonalDataManagerTest, GetProfileSuggestions_NoProfilesAddedIfDisabled) { // Disable Profile autofill. - personal_data_->pref_service_->SetBoolean(prefs::kAutofillProfileEnabled, - false); + prefs::SetProfileAutofillEnabled(personal_data_->pref_service_, false); // Add a local profile. AutofillProfile local_profile(base::GenerateGUID(), test::kEmptyOrigin); @@ -2193,6 +2198,102 @@ TEST_F(PersonalDataManagerTest, IsKnownCard_LastFourDoesNotMatch) { ASSERT_FALSE(personal_data_->IsKnownCard(cardToCompare)); } +TEST_F(PersonalDataManagerTest, IsServerCard_DuplicateOfFullServerCard) { + // Add a full server card. + std::vector<CreditCard> server_cards; + server_cards.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "b459")); + test::SetCreditCardInfo(&server_cards.back(), "Emmet Dalton", + "4234567890122110" /* Visa */, "12", "2999", "1"); + + SetServerCards(server_cards); + + // Add a dupe local card of a full server card. + CreditCard local_card("287151C8-6AB1-487C-9095-28E80BE5DA15", + test::kEmptyOrigin); + test::SetCreditCardInfo(&local_card, "Emmet Dalton", + "4234 5678 9012 2110" /* Visa */, "12", "2999", "1"); + personal_data_->AddCreditCard(local_card); + + // Make sure everything is set up correctly. + personal_data_->Refresh(); + WaitForOnPersonalDataChanged(); + EXPECT_EQ(2U, personal_data_->GetCreditCards().size()); + + CreditCard cardToCompare; + cardToCompare.SetNumber(base::ASCIIToUTF16("4234 5678 9012 2110") /* Visa */); + ASSERT_TRUE(personal_data_->IsServerCard(&cardToCompare)); + ASSERT_TRUE(personal_data_->IsServerCard(&local_card)); +} + +TEST_F(PersonalDataManagerTest, IsServerCard_DuplicateOfMaskedServerCard) { + // Add a masked server card. + std::vector<CreditCard> server_cards; + server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "b459")); + test::SetCreditCardInfo(&server_cards.back(), "Emmet Dalton", + "2110" /* last 4 digits */, "12", "2999", "1"); + server_cards.back().SetNetworkForMaskedCard(kVisaCard); + + SetServerCards(server_cards); + + // Add a dupe local card of a full server card. + CreditCard local_card("287151C8-6AB1-487C-9095-28E80BE5DA15", + test::kEmptyOrigin); + test::SetCreditCardInfo(&local_card, "Emmet Dalton", + "4234 5678 9012 2110" /* Visa */, "12", "2999", "1"); + personal_data_->AddCreditCard(local_card); + + // Make sure everything is set up correctly. + personal_data_->Refresh(); + WaitForOnPersonalDataChanged(); + EXPECT_EQ(2U, personal_data_->GetCreditCards().size()); + + CreditCard cardToCompare; + cardToCompare.SetNumber(base::ASCIIToUTF16("4234 5678 9012 2110") /* Visa */); + ASSERT_TRUE(personal_data_->IsServerCard(&cardToCompare)); + ASSERT_TRUE(personal_data_->IsServerCard(&local_card)); +} + +TEST_F(PersonalDataManagerTest, IsServerCard_AlreadyServerCard) { + std::vector<CreditCard> server_cards; + // Create a full server card. + CreditCard full_server_card(CreditCard::FULL_SERVER_CARD, "c789"); + test::SetCreditCardInfo(&full_server_card, "Homer Simpson", + "4234567890123456" /* Visa */, "01", "2999", "1"); + server_cards.push_back(full_server_card); + // Create a masked server card. + CreditCard masked_card(CreditCard::MASKED_SERVER_CARD, "a123"); + test::SetCreditCardInfo(&masked_card, "Homer Simpson", "2110" /* Visa */, + "01", "2999", "1"); + masked_card.SetNetworkForMaskedCard(kVisaCard); + server_cards.push_back(masked_card); + + SetServerCards(server_cards); + + // Make sure everything is set up correctly. + personal_data_->Refresh(); + WaitForOnPersonalDataChanged(); + EXPECT_EQ(2U, personal_data_->GetCreditCards().size()); + + ASSERT_TRUE(personal_data_->IsServerCard(&full_server_card)); + ASSERT_TRUE(personal_data_->IsServerCard(&masked_card)); +} + +TEST_F(PersonalDataManagerTest, IsServerCard_UniqueLocalCard) { + // Add a unique local card. + CreditCard local_card("1141084B-72D7-4B73-90CF-3D6AC154673B", + test::kEmptyOrigin); + test::SetCreditCardInfo(&local_card, "Homer Simpson", + "4234567890123456" /* Visa */, "01", "2999", "1"); + personal_data_->AddCreditCard(local_card); + + // Make sure everything is set up correctly. + personal_data_->Refresh(); + WaitForOnPersonalDataChanged(); + EXPECT_EQ(1U, personal_data_->GetCreditCards().size()); + + ASSERT_FALSE(personal_data_->IsServerCard(&local_card)); +} + // Test that a masked server card is not suggested if more that six numbers have // been typed in the field. TEST_F(PersonalDataManagerTest, @@ -2317,11 +2418,11 @@ TEST_F(PersonalDataManagerTest, base::TimeDelta::FromDays(1)); SetServerCards(server_cards); + personal_data_->Refresh(); + WaitForOnPersonalDataChanged(); // Disable Credit card autofill. - personal_data_->pref_service_->SetBoolean(prefs::kAutofillCreditCardEnabled, - false); - personal_data_->Refresh(); + prefs::SetCreditCardAutofillEnabled(personal_data_->pref_service_, false); WaitForOnPersonalDataChanged(); // Check that profiles were saved. @@ -2372,8 +2473,7 @@ TEST_F(PersonalDataManagerTest, EXPECT_EQ(5U, personal_data_->GetCreditCards().size()); // Disable Credit card autofill. - personal_data_->pref_service_->SetBoolean(prefs::kAutofillCreditCardEnabled, - false); + prefs::SetCreditCardAutofillEnabled(personal_data_->pref_service_, false); // Reload the database. ResetPersonalDataManager(USER_MODE_NORMAL); @@ -2395,8 +2495,7 @@ TEST_F(PersonalDataManagerTest, TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_NoCreditCardsAddedIfDisabled) { // Disable Profile autofill. - personal_data_->pref_service_->SetBoolean(prefs::kAutofillCreditCardEnabled, - false); + prefs::SetCreditCardAutofillEnabled(personal_data_->pref_service_, false); // Add a local credit card. CreditCard credit_card("002149C1-EE28-4213-A3B9-DA243FFF021B", @@ -2516,7 +2615,8 @@ TEST_F(PersonalDataManagerTest, // Verify no suppression if feature is disabled. { base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndDisableFeature(kAutofillSuppressDisusedCreditCards); + scoped_features.InitAndDisableFeature( + features::kAutofillSuppressDisusedCreditCards); std::vector<Suggestion> suggestions = personal_data_->GetCreditCardSuggestions( @@ -2530,7 +2630,8 @@ TEST_F(PersonalDataManagerTest, } base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndEnableFeature(kAutofillSuppressDisusedCreditCards); + scoped_features.InitAndEnableFeature( + features::kAutofillSuppressDisusedCreditCards); // Query with empty string only returns card0 and card1. Note expired // masked card2 is not suggested on empty fields. @@ -4531,8 +4632,9 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_OncePerVersion) { // Tests that DeleteDisusedAddresses is not run if the feature is disabled. TEST_F(PersonalDataManagerTest, DeleteDisusedAddresses_DoNothingWhenDisabled) { - // Make sure feature is disabled by default. - EXPECT_FALSE(base::FeatureList::IsEnabled(kAutofillDeleteDisusedAddresses)); + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndDisableFeature( + features::kAutofillDeleteDisusedAddresses); CreateDeletableDisusedProfile(); @@ -4549,7 +4651,8 @@ TEST_F(PersonalDataManagerTest, DeleteDisusedAddresses_DoNothingWhenDisabled) { TEST_F(PersonalDataManagerTest, DeleteDisusedAddresses_OncePerVersion) { // Enable the feature. base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndEnableFeature(kAutofillDeleteDisusedAddresses); + scoped_features.InitAndEnableFeature( + features::kAutofillDeleteDisusedAddresses); CreateDeletableDisusedProfile(); @@ -4575,7 +4678,8 @@ TEST_F(PersonalDataManagerTest, DeleteDisusedAddresses_DeleteDesiredAddressesOnly) { // Enable the feature. base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndEnableFeature(kAutofillDeleteDisusedAddresses); + scoped_features.InitAndEnableFeature( + features::kAutofillDeleteDisusedAddresses); auto now = AutofillClock::Now(); @@ -4658,8 +4762,9 @@ TEST_F(PersonalDataManagerTest, // Tests that DeleteDisusedCreditCards is not run if the feature is disabled. TEST_F(PersonalDataManagerTest, DeleteDisusedCreditCards_DoNothingWhenDisabled) { - // Make sure feature is disabled by default. - EXPECT_FALSE(base::FeatureList::IsEnabled(kAutofillDeleteDisusedCreditCards)); + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndDisableFeature( + features::kAutofillDeleteDisusedCreditCards); CreateDeletableExpiredAndDisusedCreditCard(); @@ -4676,7 +4781,8 @@ TEST_F(PersonalDataManagerTest, TEST_F(PersonalDataManagerTest, DeleteDisusedCreditCards_OncePerVersion) { // Enable the feature. base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndEnableFeature(kAutofillDeleteDisusedCreditCards); + scoped_features.InitAndEnableFeature( + features::kAutofillDeleteDisusedCreditCards); CreateDeletableExpiredAndDisusedCreditCard(); @@ -4702,7 +4808,8 @@ TEST_F(PersonalDataManagerTest, DeleteDisusedCreditCards_OnlyDeleteExpiredDisusedLocalCards) { // Enable the feature. base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndEnableFeature(kAutofillDeleteDisusedCreditCards); + scoped_features.InitAndEnableFeature( + features::kAutofillDeleteDisusedCreditCards); const char kHistogramName[] = "Autofill.CreditCardsDeletedForDisuse"; auto now = AutofillClock::Now(); @@ -5801,7 +5908,7 @@ TEST_F(PersonalDataManagerTest, CreateDataForTest) { // Turn on test data creation for the rest of this scope. base::test::ScopedFeatureList enabled; - enabled.InitAndEnableFeature(kAutofillCreateDataForTest); + enabled.InitAndEnableFeature(features::kAutofillCreateDataForTest); // Reloading the test profile should result in test data being created. ResetPersonalDataManager(USER_MODE_NORMAL); @@ -6099,6 +6206,8 @@ TEST_F(PersonalDataManagerTest, // Call OnSyncServiceInitialized with a sync service in auth error. TestSyncService sync_service; + sync_service.SetIsAuthenticatedAccountPrimary( + /*is_authenticated_account_primary=*/false); sync_service.SetInAuthError(true); personal_data_->OnSyncServiceInitialized(&sync_service); WaitForOnPersonalDataChanged(); @@ -6271,6 +6380,105 @@ TEST_F(PersonalDataManagerTest, ClearCreditCardNonSettingsOrigins) { personal_data_->GetCreditCardsToSuggest(false)[3]->origin()); } +// Tests that all city fields in a Japan profile are moved to the street address +// field. +TEST_F(PersonalDataManagerTest, MoveJapanCityToStreetAddress) { + // A US profile with both street address and a city. + std::string guid0 = base::GenerateGUID(); + { + AutofillProfile profile0(guid0, test::kEmptyOrigin); + test::SetProfileInfo(&profile0, "Homer", "J", "Simpson", + "homer.simpson@abc.com", "", "742. Evergreen Terrace", + "", "Springfield", "IL", "91601", "US", ""); + personal_data_->AddProfile(profile0); + } + + // A JP profile with both street address and a city. + std::string guid1 = base::GenerateGUID(); + { + AutofillProfile profile1(guid1, test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Homer", "J", "Simpson", + "homer.simpson@abc.com", "", "742. Evergreen Terrace", + "", "Springfield", "IL", "91601", "JP", ""); + personal_data_->AddProfile(profile1); + } + + // A JP profile with only a city. + std::string guid2 = base::GenerateGUID(); + { + AutofillProfile profile2(guid2, test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Homer", "J", "Simpson", + "homer.simpson@abc.com", "", "", "", "Springfield", + "IL", "91601", "JP", ""); + personal_data_->AddProfile(profile2); + } + + // A JP profile with only a street address. + std::string guid3 = base::GenerateGUID(); + { + AutofillProfile profile3(guid3, test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "Homer", "J", "Simpson", + "homer.simpson@abc.com", "", "742. Evergreen Terrace", + "", "", "IL", "91601", "JP", ""); + personal_data_->AddProfile(profile3); + } + + // A JP profile with neither a street address nor a city. + std::string guid4 = base::GenerateGUID(); + { + AutofillProfile profile4(guid4, test::kEmptyOrigin); + test::SetProfileInfo(&profile4, "Homer", "J", "Simpson", + "homer.simpson@abc.com", "", "", "", "", "IL", "91601", + "JP", ""); + personal_data_->AddProfile(profile4); + } + + WaitForOnPersonalDataChanged(); + + personal_data_->MoveJapanCityToStreetAddress(); + + WaitForOnPersonalDataChanged(); + + { + AutofillProfile* profile0 = personal_data_->GetProfileByGUID(guid0); + EXPECT_EQ(base::ASCIIToUTF16("742. Evergreen Terrace"), + profile0->GetRawInfo(ADDRESS_HOME_STREET_ADDRESS)); + EXPECT_EQ(base::ASCIIToUTF16("Springfield"), + profile0->GetRawInfo(ADDRESS_HOME_CITY)); + } + + { + AutofillProfile* profile1 = personal_data_->GetProfileByGUID(guid1); + EXPECT_EQ(base::ASCIIToUTF16("742. Evergreen Terrace\nSpringfield"), + profile1->GetRawInfo(ADDRESS_HOME_STREET_ADDRESS)); + EXPECT_EQ(base::ASCIIToUTF16("742. Evergreen Terrace"), + profile1->GetRawInfo(ADDRESS_HOME_LINE1)); + EXPECT_EQ(base::ASCIIToUTF16("Springfield"), + profile1->GetRawInfo(ADDRESS_HOME_LINE2)); + EXPECT_TRUE(profile1->GetRawInfo(ADDRESS_HOME_CITY).empty()); + } + + { + AutofillProfile* profile2 = personal_data_->GetProfileByGUID(guid2); + EXPECT_EQ(base::ASCIIToUTF16("Springfield"), + profile2->GetRawInfo(ADDRESS_HOME_STREET_ADDRESS)); + EXPECT_TRUE(profile2->GetRawInfo(ADDRESS_HOME_CITY).empty()); + } + + { + AutofillProfile* profile3 = personal_data_->GetProfileByGUID(guid3); + EXPECT_EQ(base::ASCIIToUTF16("742. Evergreen Terrace"), + profile3->GetRawInfo(ADDRESS_HOME_STREET_ADDRESS)); + EXPECT_TRUE(profile3->GetRawInfo(ADDRESS_HOME_CITY).empty()); + } + + { + AutofillProfile* profile4 = personal_data_->GetProfileByGUID(guid4); + EXPECT_TRUE(profile4->GetRawInfo(ADDRESS_HOME_STREET_ADDRESS).empty()); + EXPECT_TRUE(profile4->GetRawInfo(ADDRESS_HOME_CITY).empty()); + } +} + // Tests that all the non settings origins of autofill profiles are cleared even // if sync is disabled. TEST_F( @@ -6353,6 +6561,42 @@ TEST_F(PersonalDataManagerTest, UsePersistentServerStorage) { EXPECT_EQ(2U, personal_data_->GetServerCreditCards().size()); } +// Verify that PDM can switch at runtime between the different storages. +TEST_F(PersonalDataManagerTest, SwitchServerStorages) { + // Start with account storage. + ResetPersonalDataManager(USER_MODE_NORMAL); + SetUpThreeCardTypes(); + + // Check that we do have 2 server cards, as expected. + ASSERT_EQ(2U, personal_data_->GetServerCreditCards().size()); + + // Switch to persistent storage. + sync_service_.SetIsAuthenticatedAccountPrimary(true); + personal_data_->OnStateChanged(&sync_service_); + WaitForOnPersonalDataChanged(); + + EXPECT_EQ(0U, personal_data_->GetServerCreditCards().size()); + + CreditCard server_card; + test::SetCreditCardInfo(&server_card, "Server Card", + "4234567890123456", // Visa + "04", "2999", "1"); + server_card.set_guid("00000000-0000-0000-0000-000000000007"); + server_card.set_record_type(CreditCard::FULL_SERVER_CARD); + server_card.set_server_id("server_id"); + personal_data_->AddFullServerCreditCard(server_card); + WaitForOnPersonalDataChanged(); + + EXPECT_EQ(1U, personal_data_->GetServerCreditCards().size()); + + // Switch back to the account storage. + sync_service_.SetIsAuthenticatedAccountPrimary(false); + personal_data_->OnStateChanged(&sync_service_); + WaitForOnPersonalDataChanged(); + + EXPECT_EQ(2U, personal_data_->GetServerCreditCards().size()); +} + // Sanity check that the mode where we use the regular, persistent storage for // cards still works. TEST_F(PersonalDataManagerTest, UseCorrectStorageForDifferentCards) { @@ -6413,4 +6657,132 @@ TEST_F(PersonalDataManagerTest, UseCorrectStorageForDifferentCards) { EXPECT_EQ(profile, *profiles[0]); } +// Requests profiles fields validities: empty profiles, non-existent profiles, +// and normal ones. +TEST_F(PersonalDataManagerTest, RequestProfileValidity) { + ResetPersonalDataManager(USER_MODE_NORMAL); + + ProfileValidityMap profile_validity_map; + UserProfileValidityMap user_profile_validity_map; + std::string autofill_profile_validity; + + // Empty validity map. + ASSERT_TRUE( + user_profile_validity_map.SerializeToString(&autofill_profile_validity)); + personal_data_->pref_service_->SetString(prefs::kAutofillProfileValidity, + autofill_profile_validity); + + std::string guid = "00000000-0000-0000-0000-0000000000001"; + EXPECT_TRUE(personal_data_->GetProfileValidityByGUID(guid) + .field_validity_states() + .empty()); + + // Non-empty validity map. + std::vector<ServerFieldType> types = { + ADDRESS_HOME_LINE1, ADDRESS_HOME_STATE, ADDRESS_HOME_COUNTRY, + EMAIL_ADDRESS, ADDRESS_HOME_ZIP, NAME_FULL}; + std::vector<AutofillProfile::ValidityState> states = { + AutofillProfile::UNSUPPORTED, AutofillProfile::EMPTY, + AutofillProfile::INVALID, AutofillProfile::VALID, + AutofillProfile::UNVALIDATED, AutofillProfile::INVALID}; + ASSERT_EQ(types.size(), states.size()); + for (unsigned long i = 0; i < types.size(); ++i) { + (*profile_validity_map + .mutable_field_validity_states())[static_cast<int>(types[i])] = + static_cast<int>(states[i]); + } + (*user_profile_validity_map.mutable_profile_validity())[guid] = + profile_validity_map; + ASSERT_TRUE( + user_profile_validity_map.SerializeToString(&autofill_profile_validity)); + personal_data_->pref_service_->SetString(prefs::kAutofillProfileValidity, + autofill_profile_validity); + + // Add another non-empty valdity profile. + guid = "00000000-0000-0000-0000-0000000000002"; + profile_validity_map.Clear(); + autofill_profile_validity.clear(); + (*profile_validity_map + .mutable_field_validity_states())[static_cast<int>(EMAIL_ADDRESS)] = + static_cast<int>(AutofillProfile::VALID); + (*user_profile_validity_map.mutable_profile_validity())[guid] = + profile_validity_map; + ASSERT_TRUE( + user_profile_validity_map.SerializeToString(&autofill_profile_validity)); + personal_data_->pref_service_->SetString(prefs::kAutofillProfileValidity, + autofill_profile_validity); + + // Profile not found. + guid = "00000000-0000-0000-0000-0000000000003"; + EXPECT_TRUE(personal_data_->GetProfileValidityByGUID(guid) + .field_validity_states() + .empty()); + + // Existing Profiles. + guid = "00000000-0000-0000-0000-0000000000001"; + auto validities = + personal_data_->GetProfileValidityByGUID(guid).field_validity_states(); + ASSERT_EQ(validities.size(), types.size()); + for (unsigned long i = 0; i < types.size(); ++i) + EXPECT_EQ(validities.at(types[i]), states[i]); + + guid = "00000000-0000-0000-0000-0000000000002"; + validities = + personal_data_->GetProfileValidityByGUID(guid).field_validity_states(); + ASSERT_FALSE(validities.empty()); + EXPECT_EQ(validities.at(EMAIL_ADDRESS), AutofillProfile::VALID); +} + +TEST_F(PersonalDataManagerTest, GetAccountInfoForPaymentsServer) { + const std::string kIdentityManagerAccountEmail = "identity_account@email.com"; + const std::string kSyncServiceAccountEmail = "active_sync_account@email.com"; + + // Make the IdentityManager return a non-empty AccountInfo when + // GetPrimaryAccountInfo() is called. + identity_test_env_.SetPrimaryAccount(kIdentityManagerAccountEmail); + ResetPersonalDataManager(USER_MODE_NORMAL); + + // Make the sync service return a non-empty AccountInfo when + // GetAuthenticatedAccountInfo() is called. + AccountInfo active_info; + active_info.email = kSyncServiceAccountEmail; + sync_service_.SetAuthenticatedAccountInfo(active_info); + + // The IdentityManager's AccountInfo should be returned by default. + { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitWithFeatures( + /*enabled_features=*/{}, + /*disabled_features=*/{features::kAutofillEnableAccountWalletStorage, + features::kAutofillGetPaymentsIdentityFromSync}); + + EXPECT_EQ(kIdentityManagerAccountEmail, + personal_data_->GetAccountInfoForPaymentsServer().email); + } + + // The Active Sync AccountInfo should be returned if + // kAutofillEnableAccountWalletStorage is enabled. + { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitWithFeatures( + /*enabled_features=*/{features::kAutofillEnableAccountWalletStorage}, + /*disabled_features=*/{features::kAutofillGetPaymentsIdentityFromSync}); + + EXPECT_EQ(kSyncServiceAccountEmail, + personal_data_->GetAccountInfoForPaymentsServer().email); + } + + // The Active Sync AccountInfo should be returned if + // kAutofillGetPaymentsIdentityFromSync is enabled. + { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitWithFeatures( + /*enabled_features=*/{features::kAutofillGetPaymentsIdentityFromSync}, + /*disabled_features=*/{features::kAutofillEnableAccountWalletStorage}); + + EXPECT_EQ(kSyncServiceAccountEmail, + personal_data_->GetAccountInfoForPaymentsServer().email); + } +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/proto/BUILD.gn b/chromium/components/autofill/core/browser/proto/BUILD.gn index c6cb42e9272..04f9f54c8da 100644 --- a/chromium/components/autofill/core/browser/proto/BUILD.gn +++ b/chromium/components/autofill/core/browser/proto/BUILD.gn @@ -2,9 +2,9 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//third_party/protobuf/proto_library.gni") +import("//third_party/libprotobuf-mutator/fuzzable_proto_library.gni") -proto_library("proto") { +fuzzable_proto_library("proto") { sources = [ "autofill_sync.proto", "password_requirements.proto", diff --git a/chromium/components/autofill/core/browser/proto/server.proto b/chromium/components/autofill/core/browser/proto/server.proto index b450b8550f9..ba53eb41ea0 100644 --- a/chromium/components/autofill/core/browser/proto/server.proto +++ b/chromium/components/autofill/core/browser/proto/server.proto @@ -52,7 +52,7 @@ message AutofillQueryResponseContents { // This message contains information about the field types in a single form. // It is sent by the toolbar to contribute to the field type statistics. -// Next available id: 30 +// Next available id: 31 message AutofillUploadContents { required string client_version = 1; required fixed64 form_signature = 2; @@ -76,7 +76,7 @@ message AutofillUploadContents { // enum of types located at // components/autofill/core/browser/field_types.h // AutoFillFieldType - required fixed32 autofill_type = 7; + repeated fixed32 autofill_type = 7; // The value of the name attribute on the field, if present. Otherwise, the // value of the id attribute. See HTMLFormControlElement::nameForAutofill. @@ -99,14 +99,6 @@ message AutofillUploadContents { // The type of password generation, if it happened. optional PasswordGenerationType generation_type = 17; - enum FormClassifierOutcome { - NO_OUTCOME = 0; - NON_GENERATION_ELEMENT = 1; - GENERATION_ELEMENT = 2; - } - // The outcome of HTML parsing based form classifier. - optional FormClassifierOutcome form_classifier_outcome = 18; - // The value of the class attribute on the field, if present. optional string css_classes = 19; @@ -189,4 +181,45 @@ message AutofillUploadContents { // Noisifed password length. optional uint32 password_length = 29; // The end of the section of password attributes. + + // Event observed by the password manager which indicated that the form was + // successfully submitted. Corresponds to + // |PasswordForm::SubmissionIndicatorEvent|. + enum SubmissionIndicatorEvent { + NONE = 0; + HTML_FORM_SUBMISSION = 1; + SAME_DOCUMENT_NAVIGATION = 2; + XHR_SUCCEEDED = 3; + FRAME_DETACHED = 4; + DEPRECATED_MANUAL_SAVE = 5; // obsolete + DOM_MUTATION_AFTER_XHR = 6; + PROVISIONALLY_SAVED_FORM_ON_START_PROVISIONAL_LOAD = 7; + DEPRECATED_FILLED_FORM_ON_START_PROVISIONAL_LOAD = 8; // unused + DEPRECATED_FILLED_INPUT_ELEMENTS_ON_START_PROVISIONAL_LOAD = 9; // unused + } + + // The type of the event that was taken as an indication that the form has + // been successfully submitted. + optional SubmissionIndicatorEvent submission_event = 30; +} + +// This proto contains information about the validity of each field in an +// autofill profile. It is used to transfer the results of running the profile +// validation pipeline on the server side to the client via ChromeSync +// PriorityPreferences. An identical copy of this proto is maintained in +// the server code base. +message ProfileValidityMap { + // Map from autofill type to the validity of its value in the profile. + // + // Key should be one of the enum values from ServerFieldType. Values should be + // from the AutofillProfile::ValidityState enum above. Plain integers are used + // instead of enums because proto2 treats unknown enum values as unknown + // fields, which is confusing when the enums are in maps. + map<int32, int32> field_validity_states = 1; +} + +// Map from profile GUIDs to profile validity maps for that profile. Each +// message should contain entries for all profiles from a single user. +message UserProfileValidityMap { + map<string, ProfileValidityMap> profile_validity = 1; } diff --git a/chromium/components/autofill/core/browser/region_combobox_model.h b/chromium/components/autofill/core/browser/region_combobox_model.h index e6a89b29fe3..f42d897a35b 100644 --- a/chromium/components/autofill/core/browser/region_combobox_model.h +++ b/chromium/components/autofill/core/browser/region_combobox_model.h @@ -70,7 +70,7 @@ class RegionComboboxModel : public ui::ComboboxModel { std::vector<std::pair<std::string, std::string>> regions_; // To be called when the data for the given country code was loaded. - base::ObserverList<ui::ComboboxModelObserver> observers_; + base::ObserverList<ui::ComboboxModelObserver>::Unchecked observers_; DISALLOW_COPY_AND_ASSIGN(RegionComboboxModel); }; diff --git a/chromium/components/autofill/core/browser/region_data_loader_impl.cc b/chromium/components/autofill/core/browser/region_data_loader_impl.cc index 9415cc247a0..698c425dda9 100644 --- a/chromium/components/autofill/core/browser/region_data_loader_impl.cc +++ b/chromium/components/autofill/core/browser/region_data_loader_impl.cc @@ -34,8 +34,8 @@ void RegionDataLoaderImpl::LoadRegionData( *region_data_supplier_callback_); timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(timeout_ms), - base::Bind(&RegionDataLoaderImpl::OnRegionDataLoaded, - base::Unretained(this), false, country_code, 0)); + base::BindOnce(&RegionDataLoaderImpl::OnRegionDataLoaded, + base::Unretained(this), false, country_code, 0)); } void RegionDataLoaderImpl::ClearCallback() { @@ -61,8 +61,8 @@ void RegionDataLoaderImpl::OnRegionDataLoaded(bool success, // The deletion must be asynchronous since the caller is not quite done with // the preload supplier. base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&RegionDataLoaderImpl::DeleteThis, base::Unretained(this))); + FROM_HERE, base::BindOnce(&RegionDataLoaderImpl::DeleteThis, + base::Unretained(this))); } void RegionDataLoaderImpl::DeleteThis() { diff --git a/chromium/components/autofill/core/browser/test_autofill_client.cc b/chromium/components/autofill/core/browser/test_autofill_client.cc index 19a108d7b27..3c7897a6f46 100644 --- a/chromium/components/autofill/core/browser/test_autofill_client.cc +++ b/chromium/components/autofill/core/browser/test_autofill_client.cc @@ -60,8 +60,7 @@ TestAutofillClient::GetSecurityLevelForUmaHistograms() { return security_level_; } -void TestAutofillClient::ShowAutofillSettings() { -} +void TestAutofillClient::ShowAutofillSettings(bool show_credit_card_settings) {} void TestAutofillClient::ShowUnmaskPrompt( const CreditCard& card, @@ -72,9 +71,16 @@ void TestAutofillClient::ShowUnmaskPrompt( void TestAutofillClient::OnUnmaskVerificationResult(PaymentsRpcResult result) { } -void TestAutofillClient::ShowLocalCardMigrationPrompt( - base::OnceClosure closure) { - std::move(closure).Run(); +void TestAutofillClient::ShowLocalCardMigrationDialog( + base::OnceClosure show_migration_dialog_closure) { + std::move(show_migration_dialog_closure).Run(); +} + +void TestAutofillClient::ConfirmMigrateLocalCardToCloud( + std::unique_ptr<base::DictionaryValue> legal_message, + std::vector<MigratableCreditCard>& migratable_credit_cards, + base::OnceClosure start_migrating_cards_closure) { + std::move(start_migrating_cards_closure).Run(); } void TestAutofillClient::ConfirmSaveAutofillProfile( diff --git a/chromium/components/autofill/core/browser/test_autofill_client.h b/chromium/components/autofill/core/browser/test_autofill_client.h index cff3e370029..8cb300f8f81 100644 --- a/chromium/components/autofill/core/browser/test_autofill_client.h +++ b/chromium/components/autofill/core/browser/test_autofill_client.h @@ -37,12 +37,17 @@ class TestAutofillClient : public AutofillClient { ukm::SourceId GetUkmSourceId() override; AddressNormalizer* GetAddressNormalizer() override; security_state::SecurityLevel GetSecurityLevelForUmaHistograms() override; - void ShowAutofillSettings() override; + void ShowAutofillSettings(bool show_credit_card_settings) override; void ShowUnmaskPrompt(const CreditCard& card, UnmaskCardReason reason, base::WeakPtr<CardUnmaskDelegate> delegate) override; void OnUnmaskVerificationResult(PaymentsRpcResult result) override; - void ShowLocalCardMigrationPrompt(base::OnceClosure closure) override; + void ShowLocalCardMigrationDialog( + base::OnceClosure show_migration_dialog_closure) override; + void ConfirmMigrateLocalCardToCloud( + std::unique_ptr<base::DictionaryValue> legal_message, + std::vector<MigratableCreditCard>& migratable_credit_cards, + base::OnceClosure start_migrating_cards_closure) override; void ConfirmSaveAutofillProfile(const AutofillProfile& profile, base::OnceClosure callback) override; void ConfirmSaveCreditCardLocally(const CreditCard& card, diff --git a/chromium/components/autofill/core/browser/test_autofill_manager.cc b/chromium/components/autofill/core/browser/test_autofill_manager.cc index dfbe4a78d74..c8ac474c824 100644 --- a/chromium/components/autofill/core/browser/test_autofill_manager.cc +++ b/chromium/components/autofill/core/browser/test_autofill_manager.cc @@ -26,8 +26,7 @@ TestAutofillManager::TestAutofillManager(AutofillDriver* driver, client_(client) { set_payments_client(new payments::PaymentsClient( url_loader_factory_, client->GetPrefs(), client->GetIdentityManager(), - /*unmask_delegate=*/this, - /*save_delegate=*/nullptr)); + personal_data)); } TestAutofillManager::TestAutofillManager( @@ -150,8 +149,8 @@ void TestAutofillManager::AddSeenForm( void TestAutofillManager::AddSeenFormStructure( std::unique_ptr<FormStructure> form_structure) { - form_structure->set_form_parsed_timestamp(base::TimeTicks::Now()); - mutable_form_structures()->push_back(std::move(form_structure)); + const auto signature = form_structure->form_signature(); + (*mutable_form_structures())[signature] = std::move(form_structure); } void TestAutofillManager::ClearFormStructures() { diff --git a/chromium/components/autofill/core/browser/test_credit_card_save_manager.cc b/chromium/components/autofill/core/browser/test_credit_card_save_manager.cc index c06d9507ac4..ab8a64099d2 100644 --- a/chromium/components/autofill/core/browser/test_credit_card_save_manager.cc +++ b/chromium/components/autofill/core/browser/test_credit_card_save_manager.cc @@ -16,12 +16,7 @@ TestCreditCardSaveManager::TestCreditCardSaveManager( : CreditCardSaveManager(client, payments_client, "en-US", - personal_data_manager), - test_payments_client_(payments_client) { - if (test_payments_client_) { - test_payments_client_->SetSaveDelegate(this); - } -} + personal_data_manager) {} TestCreditCardSaveManager::~TestCreditCardSaveManager() {} diff --git a/chromium/components/autofill/core/browser/test_credit_card_save_manager.h b/chromium/components/autofill/core/browser/test_credit_card_save_manager.h index b00211b3b17..cc157fc47fa 100644 --- a/chromium/components/autofill/core/browser/test_credit_card_save_manager.h +++ b/chromium/components/autofill/core/browser/test_credit_card_save_manager.h @@ -38,7 +38,6 @@ class TestCreditCardSaveManager : public CreditCardSaveManager { void OnDidUploadCard(AutofillClient::PaymentsRpcResult result, const std::string& server_id) override; - payments::TestPaymentsClient* test_payments_client_; // Weak reference. bool credit_card_upload_enabled_ = false; bool credit_card_was_uploaded_ = false; diff --git a/chromium/components/autofill/core/browser/test_event_waiter.h b/chromium/components/autofill/core/browser/test_event_waiter.h index b7f7102e80c..be100f8fc53 100644 --- a/chromium/components/autofill/core/browser/test_event_waiter.h +++ b/chromium/components/autofill/core/browser/test_event_waiter.h @@ -31,7 +31,7 @@ template <typename Event> class EventWaiter { public: explicit EventWaiter( - std::list<Event> event_sequence, + std::list<Event> expected_event_sequence, base::TimeDelta timeout = base::TimeDelta::FromSeconds(0)); ~EventWaiter(); @@ -44,16 +44,16 @@ class EventWaiter { void OnEvent(Event event); private: - std::list<Event> events_; + std::list<Event> expected_events_; base::RunLoop run_loop_; DISALLOW_COPY_AND_ASSIGN(EventWaiter); }; template <typename Event> -EventWaiter<Event>::EventWaiter(std::list<Event> event_sequence, +EventWaiter<Event>::EventWaiter(std::list<Event> expected_event_sequence, base::TimeDelta timeout) - : events_(std::move(event_sequence)) { + : expected_events_(std::move(expected_event_sequence)) { if (!timeout.is_zero()) { base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, run_loop_.QuitClosure(), timeout); @@ -65,23 +65,23 @@ EventWaiter<Event>::~EventWaiter() {} template <typename Event> bool EventWaiter<Event>::Wait() { - if (events_.empty()) + if (expected_events_.empty()) return true; DCHECK(!run_loop_.running()); run_loop_.Run(); - return events_.empty(); + return expected_events_.empty(); } template <typename Event> -void EventWaiter<Event>::OnEvent(Event event) { - if (events_.empty()) +void EventWaiter<Event>::OnEvent(Event actual_event) { + if (expected_events_.empty()) return; - ASSERT_EQ(events_.front(), event); - events_.pop_front(); + ASSERT_EQ(expected_events_.front(), actual_event); + expected_events_.pop_front(); // Only quit the loop if no other events are expected. - if (events_.empty() && run_loop_.running()) + if (expected_events_.empty() && run_loop_.running()) run_loop_.Quit(); } diff --git a/chromium/components/autofill/core/browser/test_local_card_migration_manager.cc b/chromium/components/autofill/core/browser/test_local_card_migration_manager.cc index 9ef4888c8a0..657a894d146 100644 --- a/chromium/components/autofill/core/browser/test_local_card_migration_manager.cc +++ b/chromium/components/autofill/core/browser/test_local_card_migration_manager.cc @@ -4,9 +4,10 @@ #include "components/autofill/core/browser/test_local_card_migration_manager.h" -#include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/payments/test_payments_client.h" +#include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "services/identity/public/cpp/identity_manager.h" namespace autofill { @@ -19,17 +20,14 @@ TestLocalCardMigrationManager::TestLocalCardMigrationManager( : LocalCardMigrationManager(client, payments_client, "en-US", - personal_data_manager), - test_payments_client_(payments_client) { - if (test_payments_client_) - test_payments_client_->SetSaveDelegate(this); -} + personal_data_manager) {} TestLocalCardMigrationManager::~TestLocalCardMigrationManager() {} bool TestLocalCardMigrationManager::IsCreditCardMigrationEnabled() { bool migration_experiment_enabled = - IsAutofillCreditCardLocalCardMigrationExperimentEnabled(); + features::GetLocalCardMigrationExperimentalFlag() != + features::LocalCardMigrationExperimentalFlag::kMigrationDisabled; bool has_google_payments_account = (static_cast<int64_t>(payments_client_->GetPrefService()->GetDouble( prefs::kAutofillBillingCustomerNumber)) != 0); @@ -40,14 +38,34 @@ bool TestLocalCardMigrationManager::LocalCardMigrationWasTriggered() { return local_card_migration_was_triggered_; } +bool TestLocalCardMigrationManager::IntermediatePromptWasShown() { + return intermediate_prompt_was_shown_; +} + +bool TestLocalCardMigrationManager::MainPromptWasShown() { + return main_prompt_was_shown_; +} + +void TestLocalCardMigrationManager:: + OnUserAcceptedIntermediateMigrationDialog() { + intermediate_prompt_was_shown_ = true; + LocalCardMigrationManager::OnUserAcceptedIntermediateMigrationDialog(); +} + +void TestLocalCardMigrationManager::OnUserAcceptedMainMigrationDialog() { + main_prompt_was_shown_ = true; + LocalCardMigrationManager::OnUserAcceptedMainMigrationDialog(); +} + void TestLocalCardMigrationManager::OnDidGetUploadDetails( + bool is_from_settings_page, AutofillClient::PaymentsRpcResult result, const base::string16& context_token, std::unique_ptr<base::DictionaryValue> legal_message) { if (result == AutofillClient::SUCCESS) { local_card_migration_was_triggered_ = true; - LocalCardMigrationManager::OnDidGetUploadDetails(result, context_token, - std::move(legal_message)); + LocalCardMigrationManager::OnDidGetUploadDetails( + is_from_settings_page, result, context_token, std::move(legal_message)); } } diff --git a/chromium/components/autofill/core/browser/test_local_card_migration_manager.h b/chromium/components/autofill/core/browser/test_local_card_migration_manager.h index 07041a9dd45..944019e3252 100644 --- a/chromium/components/autofill/core/browser/test_local_card_migration_manager.h +++ b/chromium/components/autofill/core/browser/test_local_card_migration_manager.h @@ -32,18 +32,36 @@ class TestLocalCardMigrationManager : public LocalCardMigrationManager { // user is signed in/syncing. bool IsCreditCardMigrationEnabled() override; - // Returns whether the first round migration pop-up window was triggered. + // Returns whether the local card migration was triggered. bool LocalCardMigrationWasTriggered(); + // Returns whether the first round intermediate pop-up window was shown. + bool IntermediatePromptWasShown(); + + // Returns whether the main prompt window was shown. + bool MainPromptWasShown(); + + // Override the base function. When called, represents the intermediate prompt + // is shown. Set the |intermediate_prompt_was_shown_|. + void OnUserAcceptedIntermediateMigrationDialog() override; + + // Override the base function. When called, represent the main prompt is + // shown. Set the |main_prompt_was_shown_|. + void OnUserAcceptedMainMigrationDialog() override; + private: void OnDidGetUploadDetails( + bool is_from_settings_page, AutofillClient::PaymentsRpcResult result, const base::string16& context_token, std::unique_ptr<base::DictionaryValue> legal_message) override; - payments::TestPaymentsClient* test_payments_client_; // Weak reference. bool local_card_migration_was_triggered_ = false; + bool intermediate_prompt_was_shown_ = false; + + bool main_prompt_was_shown_ = false; + DISALLOW_COPY_AND_ASSIGN(TestLocalCardMigrationManager); }; diff --git a/chromium/components/autofill/core/browser/test_personal_data_manager.cc b/chromium/components/autofill/core/browser/test_personal_data_manager.cc index 583ac99edda..af7a2afcddf 100644 --- a/chromium/components/autofill/core/browser/test_personal_data_manager.cc +++ b/chromium/components/autofill/core/browser/test_personal_data_manager.cc @@ -218,6 +218,14 @@ bool TestPersonalDataManager::IsDataLoaded() const { return true; } +bool TestPersonalDataManager::IsSyncFeatureEnabled() const { + return sync_feature_enabled_; +} + +AccountInfo TestPersonalDataManager::GetAccountInfoForPaymentsServer() const { + return account_info_; +} + void TestPersonalDataManager::ClearProfiles() { web_profiles_.clear(); } diff --git a/chromium/components/autofill/core/browser/test_personal_data_manager.h b/chromium/components/autofill/core/browser/test_personal_data_manager.h index 2c2b6cd9d01..1ecacaecfaa 100644 --- a/chromium/components/autofill/core/browser/test_personal_data_manager.h +++ b/chromium/components/autofill/core/browser/test_personal_data_manager.h @@ -10,7 +10,9 @@ #include "base/optional.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/payments/payments_customer_data.h" #include "components/autofill/core/browser/personal_data_manager.h" +#include "components/signin/core/browser/account_info.h" namespace autofill { @@ -50,6 +52,8 @@ class TestPersonalDataManager : public PersonalDataManager { std::string CountryCodeForCurrentTimezone() const override; void ClearAllLocalData() override; bool IsDataLoaded() const override; + bool IsSyncFeatureEnabled() const override; + AccountInfo GetAccountInfoForPaymentsServer() const override; // Unique to TestPersonalDataManager: @@ -100,6 +104,17 @@ class TestPersonalDataManager : public PersonalDataManager { autofill_wallet_import_enabled_ = autofill_wallet_import_enabled; } + void SetPaymentsCustomerData( + std::unique_ptr<PaymentsCustomerData> customer_data) { + payments_customer_data_ = std::move(customer_data); + } + + void SetSyncFeatureEnabled(bool enabled) { sync_feature_enabled_ = enabled; } + + void SetAccountInfoForPayments(const AccountInfo& account_info) { + account_info_ = account_info; + } + private: std::string timezone_country_code_; std::string default_country_code_; @@ -109,6 +124,8 @@ class TestPersonalDataManager : public PersonalDataManager { base::Optional<bool> autofill_profile_enabled_; base::Optional<bool> autofill_credit_card_enabled_; base::Optional<bool> autofill_wallet_import_enabled_; + bool sync_feature_enabled_; + AccountInfo account_info_; DISALLOW_COPY_AND_ASSIGN(TestPersonalDataManager); }; diff --git a/chromium/components/autofill/core/browser/test_sync_service.cc b/chromium/components/autofill/core/browser/test_sync_service.cc index c1680e26a38..2f42009a83e 100644 --- a/chromium/components/autofill/core/browser/test_sync_service.cc +++ b/chromium/components/autofill/core/browser/test_sync_service.cc @@ -30,10 +30,6 @@ syncer::ModelTypeSet TestSyncService::GetActiveDataTypes() const { return data_types_; } -bool TestSyncService::IsEngineInitialized() const { - return is_engine_initialized_; -} - bool TestSyncService::IsFirstSetupComplete() const { return true; } @@ -42,6 +38,10 @@ bool TestSyncService::IsUsingSecondaryPassphrase() const { return is_using_secondary_passphrase_; } +bool TestSyncService::IsAuthenticatedAccountPrimary() const { + return is_authenticated_account_primary_; +} + const GoogleServiceAuthError& TestSyncService::GetAuthError() const { return auth_error_; } @@ -73,6 +73,10 @@ syncer::SyncTokenStatus TestSyncService::GetSyncTokenStatus() const { return token; } +AccountInfo TestSyncService::GetAuthenticatedAccountInfo() const { + return account_info_; +} + void TestSyncService::SetInAuthError(bool is_in_auth_error) { is_in_auth_error_ = is_in_auth_error; diff --git a/chromium/components/autofill/core/browser/test_sync_service.h b/chromium/components/autofill/core/browser/test_sync_service.h index 2be40aa0dec..cecf626d84e 100644 --- a/chromium/components/autofill/core/browser/test_sync_service.h +++ b/chromium/components/autofill/core/browser/test_sync_service.h @@ -19,23 +19,24 @@ class TestSyncService : public syncer::FakeSyncService { int GetDisableReasons() const override; syncer::ModelTypeSet GetPreferredDataTypes() const override; syncer::ModelTypeSet GetActiveDataTypes() const override; - bool IsEngineInitialized() const override; bool IsFirstSetupComplete() const override; bool IsUsingSecondaryPassphrase() const override; syncer::SyncCycleSnapshot GetLastCycleSnapshot() const override; const GoogleServiceAuthError& GetAuthError() const override; syncer::SyncTokenStatus GetSyncTokenStatus() const override; + bool IsAuthenticatedAccountPrimary() const override; + AccountInfo GetAuthenticatedAccountInfo() const override; void SetDisableReasons(int disable_reasons) { disable_reasons_ = disable_reasons; } - void SetDataTypes(syncer::ModelTypeSet data_types) { - data_types_ = data_types; + void SetIsAuthenticatedAccountPrimary(bool is_authenticated_account_primary) { + is_authenticated_account_primary_ = is_authenticated_account_primary; } - void SetIsEngineInitialized(bool is_engine_initialized) { - is_engine_initialized_ = is_engine_initialized; + void SetDataTypes(syncer::ModelTypeSet data_types) { + data_types_ = data_types; } void SetIsUsingSecondaryPassphrase(bool is_using_secondary_passphrase) { @@ -46,15 +47,20 @@ class TestSyncService : public syncer::FakeSyncService { void SetInAuthError(bool is_in_auth_error); + void SetAuthenticatedAccountInfo(const AccountInfo& account_info) { + account_info_ = account_info; + } + private: int disable_reasons_ = DISABLE_REASON_NONE; // Used as both "preferred" and "active" data types. syncer::ModelTypeSet data_types_; - bool is_engine_initialized_ = true; bool is_using_secondary_passphrase_ = false; bool sync_cycle_complete_ = true; GoogleServiceAuthError auth_error_; bool is_in_auth_error_ = false; + bool is_authenticated_account_primary_ = true; + AccountInfo account_info_; DISALLOW_COPY_AND_ASSIGN(TestSyncService); }; diff --git a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc index 16f4d9d4846..69818085c4a 100644 --- a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc +++ b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc @@ -17,7 +17,7 @@ #include "components/autofill/core/browser/ui/card_unmask_prompt_view.h" #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/common/autofill_clock.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/grit/components_scaled_resources.h" #include "components/prefs/pref_service.h" #include "components/strings/grit/components_strings.h" diff --git a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc index e34a39c3cf3..529554614e0 100644 --- a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc +++ b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc @@ -17,7 +17,7 @@ #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/ui/card_unmask_prompt_view.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/testing_pref_service.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/chromium/components/autofill/core/browser/ui/local_card_migration_bubble_controller.h b/chromium/components/autofill/core/browser/ui/local_card_migration_bubble_controller.h index a2dc6206656..8afce255edb 100644 --- a/chromium/components/autofill/core/browser/ui/local_card_migration_bubble_controller.h +++ b/chromium/components/autofill/core/browser/ui/local_card_migration_bubble_controller.h @@ -20,8 +20,8 @@ class LocalCardMigrationBubbleController { LocalCardMigrationBubbleController() {} virtual ~LocalCardMigrationBubbleController() {} - // Returns the title that should be displayed in the bubble. - virtual base::string16 GetWindowTitle() const = 0; + // Returns the explanatory message that should be displayed in the bubble. + virtual base::string16 GetBubbleMessage() const = 0; // Interaction. virtual void OnConfirmButtonClicked() = 0; diff --git a/chromium/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h b/chromium/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h new file mode 100644 index 00000000000..8288b82b0a4 --- /dev/null +++ b/chromium/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h @@ -0,0 +1,44 @@ +// Copyright 2018 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_LOCAL_CARD_MIGRATION_DIALOG_CONTROLLER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_LOCAL_CARD_MIGRATION_DIALOG_CONTROLLER_H_ + +#include <memory> +#include <vector> + +#include "base/macros.h" +#include "base/strings/string16.h" +#include "components/autofill/core/browser/legal_message_line.h" + +namespace autofill { + +enum class LocalCardMigrationDialogState; +class MigratableCreditCard; + +// TODO(crbug.com/867194): Add legal message. +// Interface that exposes controller functionality to local card migration +// dialog views. +class LocalCardMigrationDialogController { + public: + LocalCardMigrationDialogController() {} + virtual ~LocalCardMigrationDialogController() {} + + virtual LocalCardMigrationDialogState GetViewState() const = 0; + virtual void SetViewState(LocalCardMigrationDialogState view_state) = 0; + virtual const std::vector<MigratableCreditCard>& GetCardList() const = 0; + // TODO(crbug.com/867194): Ensure this would not be called when migration is + // happending. + virtual void SetCardList(std::vector<MigratableCreditCard>& card_list) = 0; + virtual const LegalMessageLines& GetLegalMessageLines() const = 0; + virtual void OnCardSelected(int index) = 0; + virtual void OnDialogClosed() = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(LocalCardMigrationDialogController); +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_LOCAL_CARD_MIGRATION_DIALOG_CONTROLLER_H_ diff --git a/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h b/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h index 371fc523b0c..cfc1fff5113 100644 --- a/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h +++ b/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h @@ -14,10 +14,17 @@ #include "components/signin/core/browser/account_info.h" #include "url/gurl.h" +class Profile; + +namespace signin_metrics { +enum class AccessPoint; +} + namespace autofill { class CreditCard; class SaveCardBubbleView; +enum class BubbleType; // Interface that exposes controller functionality to SaveCardBubbleView. class SaveCardBubbleController { @@ -35,6 +42,9 @@ class SaveCardBubbleController { // Returns the account info of the signed-in user. virtual const AccountInfo& GetAccountInfo() const = 0; + // Returns the profile. + virtual Profile* GetProfile() const = 0; + // Returns the card that will be uploaded if the user accepts. virtual const CreditCard& GetCard() const = 0; @@ -42,19 +52,36 @@ class SaveCardBubbleController { // to confirm/provide cardholder name. virtual bool ShouldRequestNameFromUser() const = 0; + // Returns whether or not a sign in / sync promo needs to be shown. + virtual bool ShouldShowSignInPromo() const = 0; + + // Returns true iff the card saved animation can be shown. + virtual bool CanAnimate() const = 0; + // Interaction. + // OnSyncPromoAccepted is called when the Dice Sign-in promo is clicked. + virtual void OnSyncPromoAccepted(const AccountInfo& account, + signin_metrics::AccessPoint access_point, + bool is_default_promo_account) = 0; // OnSaveButton takes in a string value representing the cardholder name // confirmed/entered by the user if it was requested, or an empty string // otherwise. virtual void OnSaveButton(const base::string16& cardholder_name) = 0; virtual void OnCancelButton() = 0; virtual void OnLegalMessageLinkClicked(const GURL& url) = 0; + virtual void OnManageCardsClicked() = 0; virtual void OnBubbleClosed() = 0; + // Once the animation ends, it shows a new bubble if needed. + virtual void OnAnimationEnded() = 0; // State. // Returns empty vector if no legal message should be shown. virtual const LegalMessageLines& GetLegalMessageLines() const = 0; + // Returns true iff is showing or has showed bubble for upload save. + virtual bool IsUploadSave() const = 0; + // Returns the current state of the bubble. + virtual BubbleType GetBubbleType() const = 0; private: DISALLOW_COPY_AND_ASSIGN(SaveCardBubbleController); diff --git a/chromium/components/autofill/core/browser/webdata/OWNERS b/chromium/components/autofill/core/browser/webdata/OWNERS new file mode 100644 index 00000000000..edcc64dbae7 --- /dev/null +++ b/chromium/components/autofill/core/browser/webdata/OWNERS @@ -0,0 +1,2 @@ +per-file *sync_bridge*=jkrcal@chromium.org +per-file *sync_bridge*=file://components/sync/OWNERS diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc index 088149b3c7d..664b9e74879 100644 --- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc +++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc @@ -50,7 +50,7 @@ const char kAutocompleteTagDelimiter[] = "|"; return ret_val; \ } -void* UserDataKey() { +void* AutocompleteSyncBridgeUserDataKey() { // Use the address of a static that COMDAT folding won't ever collide // with something else. static int user_data_key = 0; @@ -283,7 +283,7 @@ void AutocompleteSyncBridge::CreateForWebDataServiceAndBackend( AutofillWebDataService* web_data_service, AutofillWebDataBackend* web_data_backend) { web_data_service->GetDBUserData()->SetUserData( - UserDataKey(), + AutocompleteSyncBridgeUserDataKey(), std::make_unique<AutocompleteSyncBridge>( web_data_backend, std::make_unique<ClientTagBasedModelTypeProcessor>( @@ -294,7 +294,8 @@ void AutocompleteSyncBridge::CreateForWebDataServiceAndBackend( ModelTypeSyncBridge* AutocompleteSyncBridge::FromWebDataService( AutofillWebDataService* web_data_service) { return static_cast<AutocompleteSyncBridge*>( - web_data_service->GetDBUserData()->GetUserData(UserDataKey())); + web_data_service->GetDBUserData()->GetUserData( + AutocompleteSyncBridgeUserDataKey())); } AutocompleteSyncBridge::AutocompleteSyncBridge( diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc index 0dc61f9ed08..a3fae5e9209 100644 --- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc @@ -300,7 +300,7 @@ class AutocompleteSyncBridgeTest : public testing::Test { void VerifyAllData(const std::vector<AutofillSpecifics>& expected) { bridge()->GetAllDataForDebugging( - base::Bind(&VerifyDataBatch, ExpectedMap(expected))); + base::BindOnce(&VerifyDataBatch, ExpectedMap(expected))); } AutocompleteSyncBridge* bridge() { return bridge_.get(); } @@ -424,7 +424,7 @@ TEST_F(AutocompleteSyncBridgeTest, GetData) { SaveSpecificsToTable({specifics1, specifics2, specifics3}); bridge()->GetData( {GetStorageKey(specifics1), GetStorageKey(specifics3)}, - base::Bind(&VerifyDataBatch, ExpectedMap({specifics1, specifics3}))); + base::BindOnce(&VerifyDataBatch, ExpectedMap({specifics1, specifics3}))); } TEST_F(AutocompleteSyncBridgeTest, GetDataNotExist) { @@ -435,7 +435,7 @@ TEST_F(AutocompleteSyncBridgeTest, GetDataNotExist) { bridge()->GetData( {GetStorageKey(specifics1), GetStorageKey(specifics2), GetStorageKey(specifics3)}, - base::Bind(&VerifyDataBatch, ExpectedMap({specifics1, specifics2}))); + base::BindOnce(&VerifyDataBatch, ExpectedMap({specifics1, specifics2}))); } TEST_F(AutocompleteSyncBridgeTest, GetAllData) { diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc index 5f88eac4c24..9566edcf3a2 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc @@ -10,7 +10,7 @@ #include "base/metrics/histogram.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/prefs/pref_service.h" #include "components/sync/base/experiments.h" #include "components/sync/driver/sync_client.h" @@ -36,7 +36,7 @@ AutofillProfileDataTypeController::AutofillProfileDataTypeController( currently_enabled_(IsEnabled()) { pref_registrar_.Init(sync_client_->GetPrefService()); pref_registrar_.Add( - autofill::prefs::kAutofillEnabled, + autofill::prefs::kAutofillProfileEnabled, base::Bind(&AutofillProfileDataTypeController::OnUserPrefChanged, base::AsWeakPtr(this))); } @@ -134,8 +134,8 @@ bool AutofillProfileDataTypeController::IsEnabled() { DCHECK(CalledOnValidThread()); // Require the user-visible pref to be enabled to sync Autofill Profile data. - PrefService* ps = sync_client_->GetPrefService(); - return ps->GetBoolean(autofill::prefs::kAutofillEnabled); + return autofill::prefs::IsProfileAutofillEnabled( + sync_client_->GetPrefService()); } void AutofillProfileDataTypeController::DisableForPolicy() { diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc index c83262a2a2c..c9d5b41ca0e 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc @@ -42,7 +42,7 @@ std::string LimitData(const std::string& data) { return sanitized_value; } -void* UserDataKey() { +void* AutofillProfileSyncableServiceUserDataKey() { // Use the address of a static that COMDAT folding won't ever fold // with something else. static int user_data_key = 0; @@ -74,8 +74,9 @@ void AutofillProfileSyncableService::CreateForWebDataServiceAndBackend( AutofillWebDataBackend* webdata_backend, const std::string& app_locale) { web_data_service->GetDBUserData()->SetUserData( - UserDataKey(), base::WrapUnique(new AutofillProfileSyncableService( - webdata_backend, app_locale))); + AutofillProfileSyncableServiceUserDataKey(), + base::WrapUnique( + new AutofillProfileSyncableService(webdata_backend, app_locale))); } // static @@ -83,7 +84,8 @@ AutofillProfileSyncableService* AutofillProfileSyncableService::FromWebDataService( AutofillWebDataService* web_data_service) { return static_cast<AutofillProfileSyncableService*>( - web_data_service->GetDBUserData()->GetUserData(UserDataKey())); + web_data_service->GetDBUserData()->GetUserData( + AutofillProfileSyncableServiceUserDataKey())); } AutofillProfileSyncableService::AutofillProfileSyncableService() diff --git a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.cc b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.cc new file mode 100644 index 00000000000..593ce4bc14c --- /dev/null +++ b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.cc @@ -0,0 +1,61 @@ +// Copyright 2018 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 "components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.h" + +namespace autofill { + +AutofillProfile CreateServerProfile(const std::string& server_id) { + // TODO(sebsg): Set data. + return AutofillProfile(AutofillProfile::SERVER_PROFILE, server_id); +} + +CreditCard CreateServerCreditCard(const std::string& server_id) { + // TODO(sebsg): Set data. + return CreditCard(CreditCard::MASKED_SERVER_CARD, server_id); +} + +sync_pb::AutofillWalletSpecifics CreateAutofillWalletSpecificsForCard( + const std::string& specifics_id, + const std::string& billing_address_id) { + sync_pb::AutofillWalletSpecifics wallet_specifics; + wallet_specifics.set_type( + sync_pb::AutofillWalletSpecifics_WalletInfoType:: + AutofillWalletSpecifics_WalletInfoType_MASKED_CREDIT_CARD); + + sync_pb::WalletMaskedCreditCard* card_specifics = + wallet_specifics.mutable_masked_card(); + card_specifics->set_id(specifics_id); + card_specifics->set_billing_address_id(billing_address_id); + return wallet_specifics; +} + +sync_pb::AutofillWalletSpecifics CreateAutofillWalletSpecificsForAddress( + const std::string& specifics_id) { + sync_pb::AutofillWalletSpecifics wallet_specifics; + wallet_specifics.set_type( + sync_pb::AutofillWalletSpecifics_WalletInfoType:: + AutofillWalletSpecifics_WalletInfoType_POSTAL_ADDRESS); + + sync_pb::WalletPostalAddress* profile_specifics = + wallet_specifics.mutable_address(); + profile_specifics->set_id(specifics_id); + return wallet_specifics; +} + +sync_pb::AutofillWalletSpecifics +CreateAutofillWalletSpecificsForPaymentsCustomerData( + const std::string& specifics_id) { + sync_pb::AutofillWalletSpecifics wallet_specifics; + wallet_specifics.set_type( + sync_pb::AutofillWalletSpecifics_WalletInfoType:: + AutofillWalletSpecifics_WalletInfoType_CUSTOMER_DATA); + + sync_pb::PaymentsCustomerData* customer_data_specifics = + wallet_specifics.mutable_customer_data(); + customer_data_specifics->set_id(specifics_id); + return wallet_specifics; +} + +} // namespace autofill
\ No newline at end of file diff --git a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.h b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.h new file mode 100644 index 00000000000..a3119a1f4ca --- /dev/null +++ b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.h @@ -0,0 +1,33 @@ +// Copyright 2018 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_SYNC_BRIDGE_TEST_UTIL_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_SYNC_BRIDGE_TEST_UTIL_H_ + +#include <string> + +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/credit_card.h" +#include "components/sync/protocol/sync.pb.h" + +namespace autofill { + +AutofillProfile CreateServerProfile(const std::string& server_id); + +CreditCard CreateServerCreditCard(const std::string& server_id); + +sync_pb::AutofillWalletSpecifics CreateAutofillWalletSpecificsForAddress( + const std::string& specifics_id); + +sync_pb::AutofillWalletSpecifics CreateAutofillWalletSpecificsForCard( + const std::string& specifics_id, + const std::string& billing_address_id = ""); + +sync_pb::AutofillWalletSpecifics +CreateAutofillWalletSpecificsForPaymentsCustomerData( + const std::string& specifics_id); + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_SYNC_BRIDGE_TEST_UTIL_H_ diff --git a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc new file mode 100644 index 00000000000..0bea08e6a85 --- /dev/null +++ b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc @@ -0,0 +1,422 @@ +// Copyright 2018 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 "components/autofill/core/browser/webdata/autofill_sync_bridge_util.h" + +#include "base/base64.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_data_util.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/payments/payments_customer_data.h" +#include "components/autofill/core/browser/webdata/autofill_table.h" +#include "components/autofill/core/common/autofill_util.h" +#include "components/sync/model/entity_data.h" + +using autofill::data_util::TruncateUTF8; +using sync_pb::AutofillWalletSpecifics; +using syncer::EntityData; + +namespace autofill { +namespace { +sync_pb::WalletMaskedCreditCard::WalletCardStatus LocalToServerStatus( + const CreditCard& card) { + switch (card.GetServerStatus()) { + case CreditCard::OK: + return sync_pb::WalletMaskedCreditCard::VALID; + case CreditCard::EXPIRED: + return sync_pb::WalletMaskedCreditCard::EXPIRED; + } +} + +CreditCard::ServerStatus ServerToLocalStatus( + sync_pb::WalletMaskedCreditCard::WalletCardStatus status) { + switch (status) { + case sync_pb::WalletMaskedCreditCard::VALID: + return CreditCard::OK; + case sync_pb::WalletMaskedCreditCard::EXPIRED: + return CreditCard::EXPIRED; + } +} + +sync_pb::WalletMaskedCreditCard::WalletCardType WalletCardTypeFromCardNetwork( + const std::string& network) { + if (network == kAmericanExpressCard) + return sync_pb::WalletMaskedCreditCard::AMEX; + if (network == kDiscoverCard) + return sync_pb::WalletMaskedCreditCard::DISCOVER; + if (network == kJCBCard) + return sync_pb::WalletMaskedCreditCard::JCB; + if (network == kMasterCard) + return sync_pb::WalletMaskedCreditCard::MASTER_CARD; + if (network == kUnionPay) + return sync_pb::WalletMaskedCreditCard::UNIONPAY; + if (network == kVisaCard) + return sync_pb::WalletMaskedCreditCard::VISA; + + // Some cards aren't supported by the client, so just return unknown. + return sync_pb::WalletMaskedCreditCard::UNKNOWN; +} + +const char* CardNetworkFromWalletCardType( + sync_pb::WalletMaskedCreditCard::WalletCardType type) { + switch (type) { + case sync_pb::WalletMaskedCreditCard::AMEX: + return kAmericanExpressCard; + case sync_pb::WalletMaskedCreditCard::DISCOVER: + return kDiscoverCard; + case sync_pb::WalletMaskedCreditCard::JCB: + return kJCBCard; + case sync_pb::WalletMaskedCreditCard::MASTER_CARD: + return kMasterCard; + case sync_pb::WalletMaskedCreditCard::UNIONPAY: + return kUnionPay; + case sync_pb::WalletMaskedCreditCard::VISA: + return kVisaCard; + + // These aren't supported by the client, so just declare a generic card. + case sync_pb::WalletMaskedCreditCard::MAESTRO: + case sync_pb::WalletMaskedCreditCard::SOLO: + case sync_pb::WalletMaskedCreditCard::SWITCH: + case sync_pb::WalletMaskedCreditCard::UNKNOWN: + return kGenericCard; + } +} + +sync_pb::WalletMaskedCreditCard::WalletCardClass WalletCardClassFromCardType( + CreditCard::CardType card_type) { + switch (card_type) { + case CreditCard::CARD_TYPE_CREDIT: + return sync_pb::WalletMaskedCreditCard::CREDIT; + case CreditCard::CARD_TYPE_DEBIT: + return sync_pb::WalletMaskedCreditCard::DEBIT; + case CreditCard::CARD_TYPE_PREPAID: + return sync_pb::WalletMaskedCreditCard::PREPAID; + case CreditCard::CARD_TYPE_UNKNOWN: + return sync_pb::WalletMaskedCreditCard::UNKNOWN_CARD_CLASS; + } +} + +CreditCard::CardType CardTypeFromWalletCardClass( + sync_pb::WalletMaskedCreditCard::WalletCardClass card_class) { + switch (card_class) { + case sync_pb::WalletMaskedCreditCard::CREDIT: + return CreditCard::CARD_TYPE_CREDIT; + case sync_pb::WalletMaskedCreditCard::DEBIT: + return CreditCard::CARD_TYPE_DEBIT; + case sync_pb::WalletMaskedCreditCard::PREPAID: + return CreditCard::CARD_TYPE_PREPAID; + case sync_pb::WalletMaskedCreditCard::UNKNOWN_CARD_CLASS: + return CreditCard::CARD_TYPE_UNKNOWN; + } +} + +} // namespace + +std::string GetBase64EncodedServerId(const std::string& server_id) { + std::string encoded_id; + base::Base64Encode(server_id, &encoded_id); + return encoded_id; +} + +std::string GetSpecificsIdForEntryServerId(const std::string& server_id) { + return GetBase64EncodedServerId(server_id); +} + +std::string GetStorageKeyForSpecificsId(const std::string& specifics_id) { + // We use the base64 encoded |specifics_id| directly as the storage key, this + // function only hides this definition from all its call sites. + return specifics_id; +} + +std::string GetStorageKeyForEntryServerId(const std::string& server_id) { + return GetStorageKeyForSpecificsId(GetSpecificsIdForEntryServerId(server_id)); +} + +std::string GetClientTagForSpecificsId( + AutofillWalletSpecifics::WalletInfoType type, + const std::string& wallet_data_specifics_id) { + switch (type) { + case AutofillWalletSpecifics::POSTAL_ADDRESS: + return "address-" + wallet_data_specifics_id; + case AutofillWalletSpecifics::MASKED_CREDIT_CARD: + return "card-" + wallet_data_specifics_id; + case sync_pb::AutofillWalletSpecifics::CUSTOMER_DATA: + return "customer-" + wallet_data_specifics_id; + case AutofillWalletSpecifics::UNKNOWN: + NOTREACHED(); + return ""; + } +} + +void SetAutofillWalletSpecificsFromServerProfile( + const AutofillProfile& address, + AutofillWalletSpecifics* wallet_specifics) { + wallet_specifics->set_type(AutofillWalletSpecifics::POSTAL_ADDRESS); + + sync_pb::WalletPostalAddress* wallet_address = + wallet_specifics->mutable_address(); + + wallet_address->set_id(address.server_id()); + wallet_address->set_language_code(TruncateUTF8(address.language_code())); + + if (address.HasRawInfo(NAME_FULL)) { + wallet_address->set_recipient_name( + TruncateUTF8(base::UTF16ToUTF8(address.GetRawInfo(NAME_FULL)))); + } + if (address.HasRawInfo(COMPANY_NAME)) { + wallet_address->set_company_name( + TruncateUTF8(base::UTF16ToUTF8(address.GetRawInfo(COMPANY_NAME)))); + } + if (address.HasRawInfo(ADDRESS_HOME_STREET_ADDRESS)) { + wallet_address->add_street_address(TruncateUTF8( + base::UTF16ToUTF8(address.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS)))); + } + if (address.HasRawInfo(ADDRESS_HOME_STATE)) { + wallet_address->set_address_1(TruncateUTF8( + base::UTF16ToUTF8(address.GetRawInfo(ADDRESS_HOME_STATE)))); + } + if (address.HasRawInfo(ADDRESS_HOME_CITY)) { + wallet_address->set_address_2( + TruncateUTF8(base::UTF16ToUTF8(address.GetRawInfo(ADDRESS_HOME_CITY)))); + } + if (address.HasRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY)) { + wallet_address->set_address_3(TruncateUTF8(base::UTF16ToUTF8( + address.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY)))); + } + if (address.HasRawInfo(ADDRESS_HOME_ZIP)) { + wallet_address->set_postal_code( + TruncateUTF8(base::UTF16ToUTF8(address.GetRawInfo(ADDRESS_HOME_ZIP)))); + } + if (address.HasRawInfo(ADDRESS_HOME_COUNTRY)) { + wallet_address->set_country_code(TruncateUTF8( + base::UTF16ToUTF8(address.GetRawInfo(ADDRESS_HOME_COUNTRY)))); + } + if (address.HasRawInfo(PHONE_HOME_WHOLE_NUMBER)) { + wallet_address->set_phone_number(TruncateUTF8( + base::UTF16ToUTF8(address.GetRawInfo(PHONE_HOME_WHOLE_NUMBER)))); + } + if (address.HasRawInfo(ADDRESS_HOME_SORTING_CODE)) { + wallet_address->set_sorting_code(TruncateUTF8( + base::UTF16ToUTF8(address.GetRawInfo(ADDRESS_HOME_SORTING_CODE)))); + } +} + +std::unique_ptr<EntityData> CreateEntityDataFromAutofillServerProfile( + const AutofillProfile& address) { + auto entity_data = std::make_unique<EntityData>(); + + std::string specifics_id = + GetSpecificsIdForEntryServerId(address.server_id()); + entity_data->non_unique_name = GetClientTagForSpecificsId( + AutofillWalletSpecifics::POSTAL_ADDRESS, specifics_id); + + AutofillWalletSpecifics* wallet_specifics = + entity_data->specifics.mutable_autofill_wallet(); + + SetAutofillWalletSpecificsFromServerProfile(address, wallet_specifics); + + return entity_data; +} + +AutofillProfile ProfileFromSpecifics( + const sync_pb::WalletPostalAddress& address) { + AutofillProfile profile(AutofillProfile::SERVER_PROFILE, std::string()); + + // AutofillProfile stores multi-line addresses with newline separators. + std::vector<base::StringPiece> street_address( + address.street_address().begin(), address.street_address().end()); + profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, + base::UTF8ToUTF16(base::JoinString(street_address, "\n"))); + + profile.SetRawInfo(COMPANY_NAME, base::UTF8ToUTF16(address.company_name())); + profile.SetRawInfo(ADDRESS_HOME_STATE, + base::UTF8ToUTF16(address.address_1())); + profile.SetRawInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16(address.address_2())); + profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY, + base::UTF8ToUTF16(address.address_3())); + // AutofillProfile doesn't support address_4 ("sub dependent locality"). + profile.SetRawInfo(ADDRESS_HOME_ZIP, + base::UTF8ToUTF16(address.postal_code())); + profile.SetRawInfo(ADDRESS_HOME_SORTING_CODE, + base::UTF8ToUTF16(address.sorting_code())); + profile.SetRawInfo(ADDRESS_HOME_COUNTRY, + base::UTF8ToUTF16(address.country_code())); + profile.set_language_code(address.language_code()); + + // SetInfo instead of SetRawInfo so the constituent pieces will be parsed + // for these data types. + profile.SetInfo(NAME_FULL, base::UTF8ToUTF16(address.recipient_name()), + profile.language_code()); + profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, + base::UTF8ToUTF16(address.phone_number()), + profile.language_code()); + + profile.GenerateServerProfileIdentifier(); + + return profile; +} + +void SetAutofillWalletSpecificsFromServerCard( + const CreditCard& card, + AutofillWalletSpecifics* wallet_specifics) { + wallet_specifics->set_type(AutofillWalletSpecifics::MASKED_CREDIT_CARD); + + sync_pb::WalletMaskedCreditCard* wallet_card = + wallet_specifics->mutable_masked_card(); + wallet_card->set_id(card.server_id()); + wallet_card->set_status(LocalToServerStatus(card)); + if (card.HasRawInfo(CREDIT_CARD_NAME_FULL)) { + wallet_card->set_name_on_card(TruncateUTF8( + base::UTF16ToUTF8(card.GetRawInfo(CREDIT_CARD_NAME_FULL)))); + } + wallet_card->set_type(WalletCardTypeFromCardNetwork(card.network())); + wallet_card->set_last_four(base::UTF16ToUTF8(card.LastFourDigits())); + wallet_card->set_exp_month(card.expiration_month()); + wallet_card->set_exp_year(card.expiration_year()); + wallet_card->set_billing_address_id(card.billing_address_id()); + wallet_card->set_card_class(WalletCardClassFromCardType(card.card_type())); + wallet_card->set_bank_name(card.bank_name()); +} + +std::unique_ptr<EntityData> CreateEntityDataFromCard(const CreditCard& card) { + std::string specifics_id = GetSpecificsIdForEntryServerId(card.server_id()); + + auto entity_data = std::make_unique<EntityData>(); + entity_data->non_unique_name = GetClientTagForSpecificsId( + AutofillWalletSpecifics::MASKED_CREDIT_CARD, specifics_id); + + AutofillWalletSpecifics* wallet_specifics = + entity_data->specifics.mutable_autofill_wallet(); + + SetAutofillWalletSpecificsFromServerCard(card, wallet_specifics); + + return entity_data; +} + +CreditCard CardFromSpecifics(const sync_pb::WalletMaskedCreditCard& card) { + CreditCard result(CreditCard::MASKED_SERVER_CARD, card.id()); + result.SetNumber(base::UTF8ToUTF16(card.last_four())); + result.SetServerStatus(ServerToLocalStatus(card.status())); + result.SetNetworkForMaskedCard(CardNetworkFromWalletCardType(card.type())); + result.set_card_type(CardTypeFromWalletCardClass(card.card_class())); + result.SetRawInfo(CREDIT_CARD_NAME_FULL, + base::UTF8ToUTF16(card.name_on_card())); + result.SetExpirationMonth(card.exp_month()); + result.SetExpirationYear(card.exp_year()); + result.set_billing_address_id(card.billing_address_id()); + result.set_bank_name(card.bank_name()); + return result; +} + +std::unique_ptr<EntityData> CreateEntityDataFromPaymentsCustomerData( + const PaymentsCustomerData& customer_data) { + // We use customer_id as a storage key here. + auto entity_data = std::make_unique<EntityData>(); + entity_data->non_unique_name = GetClientTagForSpecificsId( + AutofillWalletSpecifics::CUSTOMER_DATA, customer_data.customer_id); + + AutofillWalletSpecifics* wallet_specifics = + entity_data->specifics.mutable_autofill_wallet(); + + SetAutofillWalletSpecificsFromPaymentsCustomerData(customer_data, + wallet_specifics); + + return entity_data; +} + +void SetAutofillWalletSpecificsFromPaymentsCustomerData( + const PaymentsCustomerData& customer_data, + AutofillWalletSpecifics* wallet_specifics) { + wallet_specifics->set_type(AutofillWalletSpecifics::CUSTOMER_DATA); + + sync_pb::PaymentsCustomerData* mutable_customer_data = + wallet_specifics->mutable_customer_data(); + mutable_customer_data->set_id(customer_data.customer_id); +} + +PaymentsCustomerData CustomerDataFromSpecifics( + const sync_pb::PaymentsCustomerData& customer_data) { + return PaymentsCustomerData{/*customer_id=*/customer_data.id()}; +} + +void CopyRelevantWalletMetadataFromDisk( + const AutofillTable& table, + std::vector<CreditCard>* cards_from_server) { + std::vector<std::unique_ptr<CreditCard>> cards_on_disk; + table.GetServerCreditCards(&cards_on_disk); + + // Since the number of cards is fairly small, the brute-force search is good + // enough. + for (const auto& saved_card : cards_on_disk) { + for (CreditCard& server_card : *cards_from_server) { + if (saved_card->server_id() == server_card.server_id()) { + // The wallet data doesn't have the use stats. Use the ones present on + // disk to not overwrite them with bad data. + server_card.set_use_count(saved_card->use_count()); + server_card.set_use_date(saved_card->use_date()); + + // Keep the billing address id of the saved cards only if it points to + // a local address. + if (saved_card->billing_address_id().length() == kLocalGuidSize) { + server_card.set_billing_address_id(saved_card->billing_address_id()); + break; + } + } + } + } +} + +void PopulateWalletTypesFromSyncData( + const syncer::EntityChangeList& entity_data, + std::vector<CreditCard>* wallet_cards, + std::vector<AutofillProfile>* wallet_addresses, + std::vector<PaymentsCustomerData>* customer_data) { + std::map<std::string, std::string> ids; + + for (const syncer::EntityChange& change : entity_data) { + DCHECK(change.data().specifics.has_autofill_wallet()); + + const sync_pb::AutofillWalletSpecifics& autofill_specifics = + change.data().specifics.autofill_wallet(); + + switch (autofill_specifics.type()) { + case sync_pb::AutofillWalletSpecifics::MASKED_CREDIT_CARD: + wallet_cards->push_back( + CardFromSpecifics(autofill_specifics.masked_card())); + break; + case sync_pb::AutofillWalletSpecifics::POSTAL_ADDRESS: + // Unlike other pointers, |wallet_addresses| can be nullptr. This means + // that addresses should not get populated (and billing address ids not + // get translated to local profile ids). + if (wallet_addresses) { + wallet_addresses->push_back( + ProfileFromSpecifics(autofill_specifics.address())); + + // Map the sync billing address id to the profile's id. + ids[autofill_specifics.address().id()] = + wallet_addresses->back().server_id(); + } + break; + case sync_pb::AutofillWalletSpecifics::CUSTOMER_DATA: + customer_data->push_back( + CustomerDataFromSpecifics(autofill_specifics.customer_data())); + break; + case sync_pb::AutofillWalletSpecifics::UNKNOWN: + // Just ignore new entry types that the client doesn't know about. + break; + } + } + + // Set the billing address of the wallet cards to the id of the appropriate + // profile. + for (CreditCard& card : *wallet_cards) { + auto it = ids.find(card.billing_address_id()); + if (it != ids.end()) + card.set_billing_address_id(it->second); + } +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h new file mode 100644 index 00000000000..c4893d7f57f --- /dev/null +++ b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h @@ -0,0 +1,101 @@ +// Copyright 2018 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_SYNC_BRIDGE_UTIL_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_SYNC_BRIDGE_UTIL_H_ + +#include <memory> +#include <string> + +#include "components/sync/model/entity_change.h" +#include "components/sync/model/entity_data.h" + +namespace autofill { + +class AutofillProfile; +class AutofillTable; +class CreditCard; +struct PaymentsCustomerData; + +// Returns the specified |server_id| encoded in base 64. +std::string GetBase64EncodedServerId(const std::string& server_id); + +// Returns the wallet specifics id for the specified |server_id|. +std::string GetSpecificsIdForEntryServerId(const std::string& server_id); + +// Returns the storage key for the specified |server_id|. +std::string GetStorageKeyForSpecificsId(const std::string& specifics_id); + +// Returns the wallet specifics storage key for the specified |server_id|. +std::string GetStorageKeyForEntryServerId(const std::string& server_id); + +// Returns the client tag for the specified wallet |type| and +// |wallet_data_specifics_id|. +std::string GetClientTagForSpecificsId( + sync_pb::AutofillWalletSpecifics::WalletInfoType type, + const std::string& wallet_data_specifics_id); + +// Sets the fields of the |wallet_specifics| based on the the specified +// |address|. +void SetAutofillWalletSpecificsFromServerProfile( + const AutofillProfile& address, + sync_pb::AutofillWalletSpecifics* wallet_specifics); + +// Creates a EntityData object corresponding to the specified |address|. +std::unique_ptr<syncer::EntityData> CreateEntityDataFromAutofillServerProfile( + const AutofillProfile& address); + +// Creates an AutofillProfile from the specified |address| specifics. +AutofillProfile ProfileFromSpecifics( + const sync_pb::WalletPostalAddress& address); + +// Sets the fields of the |wallet_specifics| based on the the specified |card|. +void SetAutofillWalletSpecificsFromServerCard( + const CreditCard& card, + sync_pb::AutofillWalletSpecifics* wallet_specifics); + +// Creates a EntityData object corresponding to the specified |card|. +std::unique_ptr<syncer::EntityData> CreateEntityDataFromCard( + const CreditCard& card); + +// Creates an AutofillProfile from the specified |card| specifics. +CreditCard CardFromSpecifics(const sync_pb::WalletMaskedCreditCard& card); + +// Creates a EntityData object corresponding to the specified |customer_data|. +std::unique_ptr<syncer::EntityData> CreateEntityDataFromPaymentsCustomerData( + const PaymentsCustomerData& customer_data); + +// Sets the fields of the |wallet_specifics| based on the specified +// |customer_data|. +void SetAutofillWalletSpecificsFromPaymentsCustomerData( + const PaymentsCustomerData& customer_data, + sync_pb::AutofillWalletSpecifics* wallet_specifics); + +// Creates a PaymentCustomerData object corresponding to the sync datatype +// |customer_data|. +PaymentsCustomerData CustomerDataFromSpecifics( + const sync_pb::PaymentsCustomerData& customer_data); + +// TODO(sebsg): This should probably copy the converted state for the address +// too. +// Copies the metadata from the local cards (if present) to the corresponding +// server cards so that they don't get overwritten. This is because the wallet +// data does not include those. They are handled by the +// AutofillWalletMetadataSyncBridge. +void CopyRelevantWalletMetadataFromDisk( + const AutofillTable& table, + std::vector<CreditCard>* cards_from_server); + +// Populates the wallet datatypes from the sync data and uses the sync data to +// link the card to its billing address. If |wallet_addresses| is a nullptr, +// this function will not extract addresses. +void PopulateWalletTypesFromSyncData( + const ::syncer::EntityChangeList& entity_data, + std::vector<CreditCard>* wallet_cards, + std::vector<AutofillProfile>* wallet_addresses, + std::vector<PaymentsCustomerData>* customer_data); + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_SYNC_BRIDGE_UTIL_H_ diff --git a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc new file mode 100644 index 00000000000..eb1f65eba3e --- /dev/null +++ b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc @@ -0,0 +1,204 @@ +// Copyright 2018 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 "components/autofill/core/browser/webdata/autofill_sync_bridge_util.h" + +#include <vector> + +#include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/payments/payments_customer_data.h" +#include "components/autofill/core/browser/test_autofill_clock.h" +#include "components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.h" +#include "components/autofill/core/browser/webdata/autofill_table.h" +#include "components/autofill/core/common/autofill_constants.h" +#include "components/sync/base/hash_util.h" +#include "components/sync/model/entity_data.h" +#include "components/sync/protocol/sync.pb.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace autofill { +namespace { + +using syncer::EntityChange; +using syncer::EntityData; + +class TestAutofillTable : public AutofillTable { + public: + explicit TestAutofillTable(std::vector<CreditCard> cards_on_disk) + : cards_on_disk_(cards_on_disk) {} + + ~TestAutofillTable() override {} + + bool GetServerCreditCards( + std::vector<std::unique_ptr<CreditCard>>* cards) const override { + for (const auto& card_on_disk : cards_on_disk_) + cards->push_back(std::make_unique<CreditCard>(card_on_disk)); + return true; + } + + private: + std::vector<CreditCard> cards_on_disk_; + + DISALLOW_COPY_AND_ASSIGN(TestAutofillTable); +}; + +EntityData SpecificsToEntity(const sync_pb::AutofillWalletSpecifics& specifics, + const std::string& client_tag) { + EntityData data; + *data.specifics.mutable_autofill_wallet() = specifics; + data.client_tag_hash = + syncer::GenerateSyncableHash(syncer::AUTOFILL_WALLET_DATA, client_tag); + return data; +} + +class AutofillSyncBridgeUtilTest : public testing::Test { + public: + AutofillSyncBridgeUtilTest() {} + ~AutofillSyncBridgeUtilTest() override {} + + private: + DISALLOW_COPY_AND_ASSIGN(AutofillSyncBridgeUtilTest); +}; + +// Tests that PopulateWalletTypesFromSyncData behaves as expected. +TEST_F(AutofillSyncBridgeUtilTest, PopulateWalletTypesFromSyncData) { + // Add an address and a card that has its billing address id set to the + // address' id. + syncer::EntityChangeList entity_data; + std::string address_id("address1"); + entity_data.push_back(EntityChange::CreateAdd( + address_id, + SpecificsToEntity(CreateAutofillWalletSpecificsForAddress(address_id), + /*client_tag=*/"address-address1") + .PassToPtr())); + entity_data.push_back(EntityChange::CreateAdd( + "card1", + SpecificsToEntity(CreateAutofillWalletSpecificsForCard( + /*id=*/"card1", /*billing_address_id=*/address_id), + /*client_tag=*/"card-card1") + .PassToPtr())); + entity_data.push_back(EntityChange::CreateAdd( + "deadbeef", + SpecificsToEntity(CreateAutofillWalletSpecificsForPaymentsCustomerData( + /*specifics_id=*/"deadbeef"), + /*client_tag=*/"customer-deadbeef") + .PassToPtr())); + + std::vector<CreditCard> wallet_cards; + std::vector<AutofillProfile> wallet_addresses; + std::vector<PaymentsCustomerData> customer_data; + PopulateWalletTypesFromSyncData(entity_data, &wallet_cards, &wallet_addresses, + &customer_data); + + ASSERT_EQ(1U, wallet_cards.size()); + ASSERT_EQ(1U, wallet_addresses.size()); + + EXPECT_EQ("deadbeef", customer_data.back().customer_id); + + // Make sure the card's billing address id is equal to the address' server id. + EXPECT_EQ(wallet_addresses.back().server_id(), + wallet_cards.back().billing_address_id()); +} + +// Verify that the billing address id from the card saved on disk is kept if it +// is a local profile guid. +TEST_F(AutofillSyncBridgeUtilTest, + CopyRelevantWalletMetadataFromDisk_KeepLocalAddresses) { + std::vector<CreditCard> cards_on_disk; + std::vector<CreditCard> wallet_cards; + + // Create a local profile to be used as a billing address. + AutofillProfile billing_address; + + // Create a card on disk that refers to that local profile as its billing + // address. + cards_on_disk.push_back(CreditCard()); + cards_on_disk.back().set_billing_address_id(billing_address.guid()); + + // Create a card pulled from wallet with the same id, but a different billing + // address id. + wallet_cards.push_back(CreditCard(cards_on_disk.back())); + wallet_cards.back().set_billing_address_id("1234"); + + // Setup the TestAutofillTable with the cards_on_disk. + TestAutofillTable table(cards_on_disk); + + CopyRelevantWalletMetadataFromDisk(table, &wallet_cards); + + ASSERT_EQ(1U, wallet_cards.size()); + + // Make sure the wallet card replace its billing address id for the one that + // was saved on disk. + EXPECT_EQ(cards_on_disk.back().billing_address_id(), + wallet_cards.back().billing_address_id()); +} + +// Verify that the billing address id from the card saved on disk is overwritten +// if it does not refer to a local profile. +TEST_F(AutofillSyncBridgeUtilTest, + CopyRelevantWalletMetadataFromDisk_OverwriteOtherAddresses) { + std::string old_billing_id = "1234"; + std::string new_billing_id = "9876"; + std::vector<CreditCard> cards_on_disk; + std::vector<CreditCard> wallet_cards; + + // Create a card on disk that does not refer to a local profile (which have 36 + // chars ids). + cards_on_disk.push_back(CreditCard()); + cards_on_disk.back().set_billing_address_id(old_billing_id); + + // Create a card pulled from wallet with the same id, but a different billing + // address id. + wallet_cards.push_back(CreditCard(cards_on_disk.back())); + wallet_cards.back().set_billing_address_id(new_billing_id); + + // Setup the TestAutofillTable with the cards_on_disk. + TestAutofillTable table(cards_on_disk); + + CopyRelevantWalletMetadataFromDisk(table, &wallet_cards); + + ASSERT_EQ(1U, wallet_cards.size()); + + // Make sure the local address billing id that was saved on disk did not + // replace the new one. + EXPECT_EQ(new_billing_id, wallet_cards.back().billing_address_id()); +} + +// Verify that the use stats on disk are kept when server cards are synced. +TEST_F(AutofillSyncBridgeUtilTest, + CopyRelevantWalletMetadataFromDisk_KeepUseStats) { + TestAutofillClock test_clock; + base::Time arbitrary_time = base::Time::FromDoubleT(25); + base::Time disk_time = base::Time::FromDoubleT(10); + test_clock.SetNow(arbitrary_time); + + std::vector<CreditCard> cards_on_disk; + std::vector<CreditCard> wallet_cards; + + // Create a card on disk with specific use stats. + cards_on_disk.push_back(CreditCard()); + cards_on_disk.back().set_use_count(3U); + cards_on_disk.back().set_use_date(disk_time); + + // Create a card pulled from wallet with the same id, but a different billing + // address id. + wallet_cards.push_back(CreditCard()); + wallet_cards.back().set_use_count(10U); + + // Setup the TestAutofillTable with the cards_on_disk. + TestAutofillTable table(cards_on_disk); + + CopyRelevantWalletMetadataFromDisk(table, &wallet_cards); + + ASSERT_EQ(1U, wallet_cards.size()); + + // Make sure the use stats from disk were kept + EXPECT_EQ(3U, wallet_cards.back().use_count()); + EXPECT_EQ(disk_time, wallet_cards.back().use_date()); +} + +} // namespace +} // namespace autofill
\ No newline at end of file diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.cc b/chromium/components/autofill/core/browser/webdata/autofill_table.cc index e64990856d6..4c7baa94eb5 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_table.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_table.cc @@ -26,6 +26,7 @@ #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/payments/payments_customer_data.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/webdata/autofill_change.h" #include "components/autofill/core/browser/webdata/autofill_entry.h" @@ -194,7 +195,7 @@ std::unique_ptr<CreditCard> CreditCardFromStatement( return credit_card; } -bool AddAutofillProfileNamesToProfile(sql::Connection* db, +bool AddAutofillProfileNamesToProfile(sql::Database* db, AutofillProfile* profile) { // TODO(estade): update schema so that multiple names are not associated per // unique profile guid. Please refer https://crbug.com/497934. @@ -218,7 +219,7 @@ bool AddAutofillProfileNamesToProfile(sql::Connection* db, return s.Succeeded(); } -bool AddAutofillProfileEmailsToProfile(sql::Connection* db, +bool AddAutofillProfileEmailsToProfile(sql::Database* db, AutofillProfile* profile) { // TODO(estade): update schema so that multiple emails are not associated per // unique profile guid. Please refer https://crbug.com/497934. @@ -236,7 +237,7 @@ bool AddAutofillProfileEmailsToProfile(sql::Connection* db, return s.Succeeded(); } -bool AddAutofillProfilePhonesToProfile(sql::Connection* db, +bool AddAutofillProfilePhonesToProfile(sql::Database* db, AutofillProfile* profile) { // TODO(estade): update schema so that multiple phone numbers are not // associated per unique profile guid. Please refer https://crbug.com/497934. @@ -255,7 +256,7 @@ bool AddAutofillProfilePhonesToProfile(sql::Connection* db, } bool AddAutofillProfileNames(const AutofillProfile& profile, - sql::Connection* db) { + sql::Database* db) { // Add the new name. sql::Statement s(db->GetUniqueStatement( "INSERT INTO autofill_profile_names" @@ -271,7 +272,7 @@ bool AddAutofillProfileNames(const AutofillProfile& profile, } bool AddAutofillProfileEmails(const AutofillProfile& profile, - sql::Connection* db) { + sql::Database* db) { // Add the new email. sql::Statement s(db->GetUniqueStatement( "INSERT INTO autofill_profile_emails (guid, email) VALUES (?,?)")); @@ -282,7 +283,7 @@ bool AddAutofillProfileEmails(const AutofillProfile& profile, } bool AddAutofillProfilePhones(const AutofillProfile& profile, - sql::Connection* db) { + sql::Database* db) { // Add the new number. sql::Statement s(db->GetUniqueStatement( "INSERT INTO autofill_profile_phones (guid, number) VALUES (?,?)")); @@ -293,7 +294,7 @@ bool AddAutofillProfilePhones(const AutofillProfile& profile, } bool AddAutofillProfilePieces(const AutofillProfile& profile, - sql::Connection* db) { + sql::Database* db) { if (!AddAutofillProfileNames(profile, db)) return false; @@ -306,7 +307,7 @@ bool AddAutofillProfilePieces(const AutofillProfile& profile, return true; } -bool RemoveAutofillProfilePieces(const std::string& guid, sql::Connection* db) { +bool RemoveAutofillProfilePieces(const std::string& guid, sql::Database* db) { sql::Statement s1(db->GetUniqueStatement( "DELETE FROM autofill_profile_names WHERE guid = ?")); s1.BindString(0, guid); @@ -413,7 +414,7 @@ bool AutofillTable::CreateTablesIfNecessary() { InitMaskedCreditCardsTable() && InitUnmaskedCreditCardsTable() && InitServerCardMetadataTable() && InitServerAddressesTable() && InitServerAddressMetadataTable() && InitAutofillSyncMetadataTable() && - InitModelTypeStateTable()); + InitModelTypeStateTable() && InitPaymentsCustomerDataTable()); } bool AutofillTable::IsSyncable() { @@ -1345,6 +1346,39 @@ bool AutofillTable::UpdateServerAddressMetadata( return db_->GetLastChangeCount() > 0; } +void AutofillTable::SetPaymentsCustomerData( + const PaymentsCustomerData* customer_data) { + sql::Transaction transaction(db_); + if (!transaction.Begin()) + return; + + // Delete all old values. + sql::Statement customer_data_delete( + db_->GetUniqueStatement("DELETE FROM payments_customer_data")); + customer_data_delete.Run(); + + if (customer_data) { + sql::Statement insert_customer_data(db_->GetUniqueStatement( + "INSERT INTO payments_customer_data (customer_id) VALUES (?)")); + insert_customer_data.BindString(0, customer_data->customer_id); + insert_customer_data.Run(); + } + + transaction.Commit(); +} + +bool AutofillTable::GetPaymentsCustomerData( + std::unique_ptr<PaymentsCustomerData>* customer_data) const { + sql::Statement s(db_->GetUniqueStatement( + "SELECT customer_id FROM payments_customer_data")); + if (s.Step()) { + customer_data->reset( + new PaymentsCustomerData(/*customer_id=*/s.ColumnString(0))); + } + + return s.Succeeded(); +} + bool AutofillTable::ClearAllServerData() { sql::Transaction transaction(db_); if (!transaction.Begin()) @@ -2393,7 +2427,9 @@ bool AutofillTable::AddFormFieldValueTime(const FormFieldData& element, bool AutofillTable::SupportsMetadataForModelType( syncer::ModelType model_type) const { return (model_type == syncer::AUTOFILL || - model_type == syncer::AUTOFILL_PROFILE); + model_type == syncer::AUTOFILL_PROFILE || + model_type == syncer::AUTOFILL_WALLET_DATA || + model_type == syncer::AUTOFILL_WALLET_METADATA); } int AutofillTable::GetKeyValueForModelType(syncer::ModelType model_type) const { @@ -2777,4 +2813,15 @@ bool AutofillTable::InitModelTypeStateTable() { return true; } +bool AutofillTable::InitPaymentsCustomerDataTable() { + if (!db_->DoesTableExist("payments_customer_data")) { + if (!db_->Execute("CREATE TABLE payments_customer_data " + "(customer_id VARCHAR)")) { + NOTREACHED(); + return false; + } + } + return true; +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.h b/chromium/components/autofill/core/browser/webdata/autofill_table.h index bb34d9c4d51..8708a94bf0a 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_table.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_table.h @@ -33,6 +33,7 @@ class AutofillProfile; class AutofillTableEncryptor; class AutofillTableTest; class CreditCard; +struct PaymentsCustomerData; struct FormFieldData; @@ -263,6 +264,11 @@ struct FormFieldData; // for one model type, there was an id column with value 1 // for the single entry. // value The serialized ModelTypeState record. +// +// payments_customer_data +// Contains Google Payments customer data. +// +// customer_id A string representing the Google Payments customer id. class AutofillTable : public WebDatabaseTable, public syncer::SyncMetadataStore { @@ -398,6 +404,14 @@ class AutofillTable : public WebDatabaseTable, bool UpdateServerCardMetadata(const CreditCard& credit_card); bool UpdateServerAddressMetadata(const AutofillProfile& profile); + // Setters and getters related to the Google Payments customer data. + // Passing null to the setter will clear the data. + void SetPaymentsCustomerData(const PaymentsCustomerData* customer_data); + // Getter returns false if it could not execute the database statement, and + // may return true but leave |customer_data| untouched if there is no data. + bool GetPaymentsCustomerData( + std::unique_ptr<PaymentsCustomerData>* customer_data) const; + // Deletes all data from the server card and profile tables. Returns true if // any data was deleted, false if not (so false means "commit not needed" // rather than "error"). @@ -593,6 +607,7 @@ class AutofillTable : public WebDatabaseTable, bool InitServerAddressMetadataTable(); bool InitAutofillSyncMetadataTable(); bool InitModelTypeStateTable(); + bool InitPaymentsCustomerDataTable(); std::unique_ptr<AutofillTableEncryptor> autofill_table_encryptor_; diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc index 283dcc5c327..a12b8bcf152 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc @@ -24,6 +24,7 @@ #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/payments/payments_customer_data.h" #include "components/autofill/core/browser/webdata/autofill_change.h" #include "components/autofill/core/browser/webdata/autofill_entry.h" #include "components/autofill/core/common/autofill_constants.h" @@ -2234,6 +2235,39 @@ TEST_F(AutofillTableTest, DeleteUnmaskedCard) { outputs.clear(); } +// Test that we can get what we set. +TEST_F(AutofillTableTest, SetGetPaymentsCustomerData) { + PaymentsCustomerData input{/*customer_id=*/"deadbeef"}; + table_->SetPaymentsCustomerData(&input); + + std::unique_ptr<PaymentsCustomerData> output; + ASSERT_TRUE(table_->GetPaymentsCustomerData(&output)); + EXPECT_EQ(input, *output); +} + +// We don't set anything in the table. Test that we don't crash. +TEST_F(AutofillTableTest, GetPaymentsCustomerData_NoData) { + std::unique_ptr<PaymentsCustomerData> output; + ASSERT_TRUE(table_->GetPaymentsCustomerData(&output)); + EXPECT_FALSE(output); +} + +// The latest PaymentsCustomerData that was set is returned. +TEST_F(AutofillTableTest, SetGetPaymentsCustomerData_MultipleSet) { + PaymentsCustomerData input{/*customer_id=*/"deadbeef"}; + table_->SetPaymentsCustomerData(&input); + + PaymentsCustomerData input2{/*customer_id=*/"wallet"}; + table_->SetPaymentsCustomerData(&input2); + + PaymentsCustomerData input3{/*customer_id=*/"latest"}; + table_->SetPaymentsCustomerData(&input3); + + std::unique_ptr<PaymentsCustomerData> output; + ASSERT_TRUE(table_->GetPaymentsCustomerData(&output)); + EXPECT_EQ(input3, *output); +} + const size_t kMaxCount = 2; struct GetFormValuesTestCase { const char* const field_suggestion[kMaxCount]; diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc new file mode 100644 index 00000000000..7f2c27615aa --- /dev/null +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc @@ -0,0 +1,327 @@ +// Copyright 2018 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 "components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h" + +#include <unordered_map> +#include <utility> + +#include "base/base64.h" +#include "base/logging.h" +#include "base/optional.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/webdata/autofill_sync_bridge_util.h" +#include "components/autofill/core/browser/webdata/autofill_table.h" +#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h" +#include "components/autofill/core/browser/webdata/autofill_webdata_service.h" +#include "components/sync/model/entity_data.h" +#include "components/sync/model/mutable_data_batch.h" +#include "components/sync/model_impl/client_tag_based_model_type_processor.h" +#include "components/sync/model_impl/sync_metadata_store_change_list.h" + +namespace autofill { + +namespace { + +using sync_pb::WalletMetadataSpecifics; +using syncer::EntityData; +using syncer::MetadataChangeList; + +// Address to this variable used as the user data key. +static int kAutofillWalletMetadataSyncBridgeUserDataKey = 0; + +std::string GetClientTagForSpecificsId(WalletMetadataSpecifics::Type type, + const std::string& specifics_id) { + switch (type) { + case WalletMetadataSpecifics::ADDRESS: + return "address-" + specifics_id; + case WalletMetadataSpecifics::CARD: + return "card-" + specifics_id; + case WalletMetadataSpecifics::UNKNOWN: + NOTREACHED(); + return ""; + } +} + +// Returns EntityData with common fields set based on |local_data_model|. +std::unique_ptr<EntityData> CreateEntityDataFromAutofillDataModel( + const AutofillDataModel& local_data_model, + WalletMetadataSpecifics::Type type, + const std::string& specifics_id) { + auto entity_data = std::make_unique<EntityData>(); + entity_data->non_unique_name = GetClientTagForSpecificsId(type, specifics_id); + + WalletMetadataSpecifics* metadata = + entity_data->specifics.mutable_wallet_metadata(); + metadata->set_type(type); + metadata->set_id(specifics_id); + metadata->set_use_count(local_data_model.use_count()); + metadata->set_use_date( + local_data_model.use_date().ToDeltaSinceWindowsEpoch().InMicroseconds()); + return entity_data; +} + +// Returns EntityData for wallet_metadata for |local_profile|. +std::unique_ptr<EntityData> CreateMetadataEntityDataFromAutofillServerProfile( + const AutofillProfile& local_profile) { + std::unique_ptr<EntityData> entity_data = + CreateEntityDataFromAutofillDataModel( + local_profile, WalletMetadataSpecifics::ADDRESS, + GetSpecificsIdForEntryServerId(local_profile.server_id())); + + WalletMetadataSpecifics* metadata = + entity_data->specifics.mutable_wallet_metadata(); + metadata->set_address_has_converted(local_profile.has_converted()); + return entity_data; +} + +// Returns EntityData for wallet_metadata for |local_card|. +std::unique_ptr<EntityData> CreateMetadataEntityDataFromCard( + const CreditCard& local_card) { + std::unique_ptr<EntityData> entity_data = + CreateEntityDataFromAutofillDataModel( + local_card, WalletMetadataSpecifics::CARD, + GetSpecificsIdForEntryServerId(local_card.server_id())); + + WalletMetadataSpecifics* metadata = + entity_data->specifics.mutable_wallet_metadata(); + // The strings must be in valid UTF-8 to sync. + std::string billing_address_id; + base::Base64Encode(local_card.billing_address_id(), &billing_address_id); + metadata->set_card_billing_address_id(billing_address_id); + return entity_data; +} + +} // namespace + +// static +void AutofillWalletMetadataSyncBridge::CreateForWebDataServiceAndBackend( + const std::string& app_locale, + AutofillWebDataBackend* web_data_backend, + AutofillWebDataService* web_data_service) { + web_data_service->GetDBUserData()->SetUserData( + &kAutofillWalletMetadataSyncBridgeUserDataKey, + std::make_unique<AutofillWalletMetadataSyncBridge>( + std::make_unique<syncer::ClientTagBasedModelTypeProcessor>( + syncer::AUTOFILL_WALLET_METADATA, + /*dump_stack=*/base::RepeatingClosure()), + web_data_backend)); +} + +// static +syncer::ModelTypeSyncBridge* +AutofillWalletMetadataSyncBridge::FromWebDataService( + AutofillWebDataService* web_data_service) { + return static_cast<AutofillWalletMetadataSyncBridge*>( + web_data_service->GetDBUserData()->GetUserData( + &kAutofillWalletMetadataSyncBridgeUserDataKey)); +} + +AutofillWalletMetadataSyncBridge::AutofillWalletMetadataSyncBridge( + std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor, + AutofillWebDataBackend* web_data_backend) + : ModelTypeSyncBridge(std::move(change_processor)), + web_data_backend_(web_data_backend), + scoped_observer_(this) { + DCHECK(web_data_backend_); + + scoped_observer_.Add(web_data_backend_); + + LoadDataCacheAndMetadata(); +} + +AutofillWalletMetadataSyncBridge::~AutofillWalletMetadataSyncBridge() {} + +std::unique_ptr<syncer::MetadataChangeList> +AutofillWalletMetadataSyncBridge::CreateMetadataChangeList() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return std::make_unique<syncer::SyncMetadataStoreChangeList>( + GetAutofillTable(), syncer::AUTOFILL_WALLET_METADATA); +} + +base::Optional<syncer::ModelError> +AutofillWalletMetadataSyncBridge::MergeSyncData( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_data) { + NOTIMPLEMENTED(); + return base::nullopt; +} + +base::Optional<syncer::ModelError> +AutofillWalletMetadataSyncBridge::ApplySyncChanges( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_data) { + NOTIMPLEMENTED(); + return base::nullopt; +} + +void AutofillWalletMetadataSyncBridge::GetData(StorageKeyList storage_keys, + DataCallback callback) { + // Build a set out of the list to allow quick lookup. + std::unordered_set<std::string> storage_keys_set(storage_keys.begin(), + storage_keys.end()); + GetDataImpl(std::move(storage_keys_set), std::move(callback)); +} + +void AutofillWalletMetadataSyncBridge::GetAllDataForDebugging( + DataCallback callback) { + // Get all data by not providing any |storage_keys| filter. + GetDataImpl(/*storage_keys=*/base::nullopt, std::move(callback)); +} + +std::string AutofillWalletMetadataSyncBridge::GetClientTag( + const syncer::EntityData& entity_data) { + const WalletMetadataSpecifics& remote_metadata = + entity_data.specifics.wallet_metadata(); + return GetClientTagForSpecificsId(remote_metadata.type(), + remote_metadata.id()); +} + +std::string AutofillWalletMetadataSyncBridge::GetStorageKey( + const syncer::EntityData& entity_data) { + return GetStorageKeyForSpecificsId( + entity_data.specifics.wallet_metadata().id()); +} + +void AutofillWalletMetadataSyncBridge::AutofillProfileChanged( + const AutofillProfileChange& change) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + const AutofillProfile* changed = change.data_model(); + if (!changed || changed->record_type() != AutofillProfile::SERVER_PROFILE) { + return; + } + + // The only legal change on a server profile is that its use count or use date + // or has-converted status gets updated. Other changes (adding, deleting) are + // only done by the AutofillWalletSyncBridge and result only in the + // AutofillMultipleChanged() notification. + DCHECK(change.type() == AutofillProfileChange::UPDATE); + SyncUpUpdatedEntity( + CreateMetadataEntityDataFromAutofillServerProfile(*changed)); +} + +void AutofillWalletMetadataSyncBridge::CreditCardChanged( + const CreditCardChange& change) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + const CreditCard* changed = change.data_model(); + if (!changed || changed->record_type() == CreditCard::LOCAL_CARD) { + return; + } + + // The only legal change on a server card is that its use count or use date or + // billing address id gets updated. Other changes (adding, deleting) are only + // done by the AutofillWalletSyncBridge and result only in the + // AutofillMultipleChanged() notification. + DCHECK(change.type() == CreditCardChange::UPDATE); + SyncUpUpdatedEntity(CreateMetadataEntityDataFromCard(*changed)); +} + +void AutofillWalletMetadataSyncBridge::AutofillMultipleChanged() { + NOTIMPLEMENTED(); +} + +void AutofillWalletMetadataSyncBridge::SyncUpUpdatedEntity( + std::unique_ptr<EntityData> entity_after_change) { + std::string storage_key = GetStorageKey(*entity_after_change); + auto it = cache_.find(storage_key); + + // This *changed* entity should already be in the cache, ignore otherwise. + if (it == cache_.end()) + return; + + const WalletMetadataSpecifics& specifics_before = it->second; + const WalletMetadataSpecifics& specifics_after = + entity_after_change->specifics.wallet_metadata(); + + if (specifics_before.use_count() < specifics_after.use_count() && + specifics_before.use_date() < specifics_after.use_date()) { + std::unique_ptr<MetadataChangeList> metadata_change_list = + CreateMetadataChangeList(); + cache_[storage_key] = specifics_after; + change_processor()->Put(storage_key, std::move(entity_after_change), + metadata_change_list.get()); + } +} + +AutofillTable* AutofillWalletMetadataSyncBridge::GetAutofillTable() { + return AutofillTable::FromWebDatabase(web_data_backend_->GetDatabase()); +} + +void AutofillWalletMetadataSyncBridge::LoadDataCacheAndMetadata() { + if (!web_data_backend_ || !web_data_backend_->GetDatabase() || + !GetAutofillTable()) { + change_processor()->ReportError( + {FROM_HERE, "Failed to load AutofillWebDatabase."}); + return; + } + + // Load the data cache. + std::vector<std::unique_ptr<AutofillProfile>> profiles; + std::vector<std::unique_ptr<CreditCard>> cards; + if (!GetAutofillTable()->GetServerProfiles(&profiles) || + !GetAutofillTable()->GetServerCreditCards(&cards)) { + change_processor()->ReportError( + {FROM_HERE, "Failed reading autofill data from WebDatabase."}); + return; + } + for (const std::unique_ptr<AutofillProfile>& entry : profiles) { + cache_[GetStorageKeyForEntryServerId(entry->server_id())] = + CreateMetadataEntityDataFromAutofillServerProfile(*entry) + ->specifics.wallet_metadata(); + } + for (const std::unique_ptr<CreditCard>& entry : cards) { + cache_[GetStorageKeyForEntryServerId(entry->server_id())] = + CreateMetadataEntityDataFromCard(*entry)->specifics.wallet_metadata(); + } + + // Load the metadata and send to the processor. + auto batch = std::make_unique<syncer::MetadataBatch>(); + if (!GetAutofillTable()->GetAllSyncMetadata(syncer::AUTOFILL_WALLET_METADATA, + batch.get())) { + change_processor()->ReportError( + {FROM_HERE, "Failed reading autofill metadata from WebDatabase."}); + return; + } + + change_processor()->ModelReadyToSync(std::move(batch)); +} + +void AutofillWalletMetadataSyncBridge::GetDataImpl( + base::Optional<std::unordered_set<std::string>> storage_keys_set, + DataCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + std::vector<std::unique_ptr<AutofillProfile>> profiles; + std::vector<std::unique_ptr<CreditCard>> cards; + if (!GetAutofillTable()->GetServerProfiles(&profiles) || + !GetAutofillTable()->GetServerCreditCards(&cards)) { + change_processor()->ReportError( + {FROM_HERE, "Failed to load entries from table."}); + return; + } + + auto batch = std::make_unique<syncer::MutableDataBatch>(); + + for (const std::unique_ptr<AutofillProfile>& entry : profiles) { + std::string key = GetStorageKeyForEntryServerId(entry->server_id()); + if (!storage_keys_set || base::ContainsKey(*storage_keys_set, key)) { + batch->Put(key, + CreateMetadataEntityDataFromAutofillServerProfile(*entry)); + } + } + for (const std::unique_ptr<CreditCard>& entry : cards) { + std::string key = GetStorageKeyForEntryServerId(entry->server_id()); + if (!storage_keys_set || base::ContainsKey(*storage_keys_set, key)) { + batch->Put(GetStorageKeyForEntryServerId(entry->server_id()), + CreateMetadataEntityDataFromCard(*entry)); + } + } + + std::move(callback).Run(std::move(batch)); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h new file mode 100644 index 00000000000..00479c19c84 --- /dev/null +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h @@ -0,0 +1,114 @@ +// Copyright 2018 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNC_BRIDGE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNC_BRIDGE_H_ + +#include <memory> +#include <string> +#include <unordered_set> + +#include "base/macros.h" +#include "base/scoped_observer.h" +#include "base/sequence_checker.h" +#include "base/supports_user_data.h" +#include "components/autofill/core/browser/webdata/autofill_change.h" +#include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h" +#include "components/sync/model/metadata_change_list.h" +#include "components/sync/model/model_error.h" +#include "components/sync/model/model_type_change_processor.h" +#include "components/sync/model/model_type_sync_bridge.h" + +namespace syncer { +struct EntityData; +} // namespace syncer + +namespace autofill { + +class AutofillTable; +class AutofillWebDataBackend; +class AutofillWebDataService; + +// Sync bridge responsible for propagating local changes to the processor and +// applying remote changes to the local database. +class AutofillWalletMetadataSyncBridge + : public base::SupportsUserData::Data, + public syncer::ModelTypeSyncBridge, + public AutofillWebDataServiceObserverOnDBSequence { + public: + // Factory method that hides dealing with change_processor and also stores the + // created bridge within |web_data_service|. This method should only be + // called on |web_data_service|'s DB thread. + static void CreateForWebDataServiceAndBackend( + const std::string& app_locale, + AutofillWebDataBackend* webdata_backend, + AutofillWebDataService* web_data_service); + + static syncer::ModelTypeSyncBridge* FromWebDataService( + AutofillWebDataService* web_data_service); + + AutofillWalletMetadataSyncBridge( + std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor, + AutofillWebDataBackend* web_data_backend); + ~AutofillWalletMetadataSyncBridge() override; + + // ModelTypeSyncBridge implementation. + std::unique_ptr<syncer::MetadataChangeList> CreateMetadataChangeList() + override; + base::Optional<syncer::ModelError> MergeSyncData( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_data) override; + base::Optional<syncer::ModelError> ApplySyncChanges( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_changes) override; + void GetData(StorageKeyList storage_keys, DataCallback callback) override; + void GetAllDataForDebugging(DataCallback callback) override; + std::string GetClientTag(const syncer::EntityData& entity_data) override; + std::string GetStorageKey(const syncer::EntityData& entity_data) override; + + // AutofillWebDataServiceObserverOnDBSequence implementation. + void AutofillProfileChanged(const AutofillProfileChange& change) override; + void CreditCardChanged(const CreditCardChange& change) override; + void AutofillMultipleChanged() override; + + private: + // Syncs up an updated entity |entity_after_change| (if needed). + void SyncUpUpdatedEntity( + std::unique_ptr<syncer::EntityData> entity_after_change); + + // Returns the table associated with the |web_data_backend_|. + AutofillTable* GetAutofillTable(); + + // Synchronously load |cache_| and sync metadata from the autofill table + // and pass the latter to the processor so that it can start tracking changes. + void LoadDataCacheAndMetadata(); + + // Reads local wallet metadata from the database and passes them into + // |callback|. If |storage_keys_set| is not set, it returns all data entries. + // Otherwise, it returns only entries with storage key in |storage_keys_set|. + void GetDataImpl( + base::Optional<std::unordered_set<std::string>> storage_keys_set, + DataCallback callback); + + // AutofillWalletMetadataSyncBridge is owned by |web_data_backend_| through + // SupportsUserData, so it's guaranteed to outlive |this|. + AutofillWebDataBackend* const web_data_backend_; + + ScopedObserver<AutofillWebDataBackend, AutofillWalletMetadataSyncBridge> + scoped_observer_; + + // Cache of the data (local data + data that hasn't synced down yet); keyed by + // storage keys. Needed for figuring out what to sync up when larger changes + // happen in the local database. + std::unordered_map<std::string, sync_pb::WalletMetadataSpecifics> cache_; + + // The bridge should be used on the same sequence where it is constructed. + SEQUENCE_CHECKER(sequence_checker_); + + DISALLOW_COPY_AND_ASSIGN(AutofillWalletMetadataSyncBridge); +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNC_BRIDGE_H_ diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc new file mode 100644 index 00000000000..435e7950da4 --- /dev/null +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc @@ -0,0 +1,500 @@ +// Copyright 2018 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 "components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h" + +#include <stddef.h> + +#include <memory> +#include <sstream> +#include <utility> + +#include "base/base64.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/files/scoped_temp_dir.h" +#include "base/message_loop/message_loop.h" +#include "base/test/bind_test_util.h" +#include "base/test/scoped_task_environment.h" +#include "base/time/time.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/country_names.h" +#include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/test_autofill_clock.h" +#include "components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.h" +#include "components/autofill/core/browser/webdata/autofill_table.h" +#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h" +#include "components/autofill/core/common/autofill_constants.h" +#include "components/sync/base/hash_util.h" +#include "components/sync/model/data_batch.h" +#include "components/sync/model/entity_data.h" +#include "components/sync/model/mock_model_type_change_processor.h" +#include "components/sync/model_impl/client_tag_based_model_type_processor.h" +#include "components/sync/protocol/sync.pb.h" +#include "components/webdata/common/web_database.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace autofill { +namespace { + +using base::ScopedTempDir; +using sync_pb::WalletMetadataSpecifics; +using syncer::DataBatch; +using syncer::EntityData; +using syncer::EntityDataPtr; +using syncer::KeyAndData; +using syncer::MockModelTypeChangeProcessor; +using syncer::ModelType; +using testing::_; +using testing::ElementsAre; +using testing::IsEmpty; +using testing::UnorderedElementsAre; + +// Non-UTF8 server IDs. +const char kAddr1ServerId[] = "addr1\xEF\xBF\xBE"; +const char kAddr2ServerId[] = "addr2\xEF\xBF\xBE"; +const char kCard1ServerId[] = "card1\xEF\xBF\xBE"; +const char kCard2ServerId[] = "card2\xEF\xBF\xBE"; + +// Base64 encodings of the server IDs, used as ids in WalletMetadataSpecifics +// (these are suitable for syncing, because they are valid UTF-8). +const char kAddr1SpecificsId[] = "YWRkcjHvv74="; +const char kAddr2SpecificsId[] = "YWRkcjLvv74="; +const char kCard1SpecificsId[] = "Y2FyZDHvv74="; +const char kCard2SpecificsId[] = "Y2FyZDLvv74="; + +// Unique sync tags for the server IDs. +const char kAddr1SyncTag[] = "address-YWRkcjHvv74="; +const char kCard1SyncTag[] = "card-Y2FyZDHvv74="; + +const char kLocaleString[] = "en-US"; +const base::Time kJune2017 = base::Time::FromDoubleT(1497552271); + +class FakeAutofillBackend : public AutofillWebDataBackend { + public: + FakeAutofillBackend() {} + ~FakeAutofillBackend() override {} + WebDatabase* GetDatabase() override { return db_; } + void AddObserver( + autofill::AutofillWebDataServiceObserverOnDBSequence* observer) override { + } + void RemoveObserver( + autofill::AutofillWebDataServiceObserverOnDBSequence* observer) override { + } + void RemoveExpiredFormElements() override {} + void NotifyOfMultipleAutofillChanges() override {} + void NotifyThatSyncHasStarted(ModelType model_type) override {} + void SetWebDatabase(WebDatabase* db) { db_ = db; } + + private: + WebDatabase* db_; +}; + +base::Time UseDateFromProtoValue(int64_t use_date_proto_value) { + return base::Time::FromDeltaSinceWindowsEpoch( + base::TimeDelta::FromMicroseconds(use_date_proto_value)); +} + +int64_t UseDateToProtoValue(base::Time use_date) { + return use_date.ToDeltaSinceWindowsEpoch().InMicroseconds(); +} + +WalletMetadataSpecifics CreateWalletMetadataSpecificsForAddressWithUseStats( + const std::string& specifics_id, + size_t use_count, + int64_t use_date) { + WalletMetadataSpecifics specifics; + specifics.set_id(specifics_id); + specifics.set_type(WalletMetadataSpecifics::ADDRESS); + specifics.set_use_count(use_count); + specifics.set_use_date(use_date); + // Set the default value according to the constructor of AutofillProfile. + specifics.set_address_has_converted(false); + return specifics; +} + +WalletMetadataSpecifics CreateWalletMetadataSpecificsForAddress( + const std::string& specifics_id) { + // Set default values according to the constructor of AutofillProfile (the + // clock value is overrided by TestAutofillClock in the test fixture). + return CreateWalletMetadataSpecificsForAddressWithUseStats( + specifics_id, /*use_count=*/1, + /*use_date=*/UseDateToProtoValue(kJune2017)); +} + +WalletMetadataSpecifics CreateWalletMetadataSpecificsForCardWithUseStats( + const std::string& specifics_id, + size_t use_count, + int64_t use_date) { + WalletMetadataSpecifics specifics; + specifics.set_id(specifics_id); + specifics.set_type(WalletMetadataSpecifics::CARD); + specifics.set_use_count(use_count); + specifics.set_use_date(use_date); + // Set the default value according to the constructor of AutofillProfile. + specifics.set_card_billing_address_id(""); + return specifics; +} + +WalletMetadataSpecifics CreateWalletMetadataSpecificsForCard( + const std::string& specifics_id) { + // Set default values according to the constructor of AutofillProfile (the + // clock value is overrided by TestAutofillClock in the test fixture). + return CreateWalletMetadataSpecificsForCardWithUseStats( + specifics_id, /*use_count=*/1, + /*use_date=*/UseDateToProtoValue(kJune2017)); +} + +AutofillProfile CreateServerProfileWithUseStats(const std::string& server_id, + size_t use_count, + int64_t use_date) { + AutofillProfile profile = CreateServerProfile(server_id); + profile.set_use_count(use_count); + profile.set_use_date(UseDateFromProtoValue(use_date)); + return profile; +} + +CreditCard CreateServerCreditCardWithUseStats(const std::string& server_id, + size_t use_count, + int64_t use_date) { + CreditCard card = CreateServerCreditCard(server_id); + card.set_use_count(use_count); + card.set_use_date(UseDateFromProtoValue(use_date)); + return card; +} + +void ExtractWalletMetadataSpecificsFromDataBatch( + std::unique_ptr<DataBatch> batch, + std::vector<WalletMetadataSpecifics>* output) { + while (batch->HasNext()) { + const KeyAndData& data_pair = batch->Next(); + output->push_back(data_pair.second->specifics.wallet_metadata()); + } +} + +std::string WalletMetadataSpecificsAsDebugString( + const WalletMetadataSpecifics& specifics) { + std::ostringstream output; + output << "[id: " << specifics.id() + << ", type: " << static_cast<int>(specifics.type()) + << ", use_count: " << specifics.use_count() + << ", use_date: " << UseDateFromProtoValue(specifics.use_date()) + << ", card_billing_address_id: " + << (specifics.has_card_billing_address_id() + ? specifics.card_billing_address_id() + : "not_set") + << ", address_has_converted: " + << (specifics.has_address_has_converted() + ? (specifics.address_has_converted() ? "true" : "false") + : "not_set") + << "]"; + return output.str(); +} + +MATCHER_P(EqualsSpecifics, expected, "") { + if (arg.SerializeAsString() != expected.SerializeAsString()) { + *result_listener << "entry\n" + << WalletMetadataSpecificsAsDebugString(arg) << "\n" + << "did not match expected\n" + << WalletMetadataSpecificsAsDebugString(expected); + return false; + } + return true; +} + +MATCHER_P(HasSpecifics, expected, "") { + const WalletMetadataSpecifics& arg_specifics = + arg->specifics.wallet_metadata(); + + if (arg_specifics.SerializeAsString() != expected.SerializeAsString()) { + *result_listener << "entry\n" + << WalletMetadataSpecificsAsDebugString(arg_specifics) + << "\ndid not match expected\n" + << WalletMetadataSpecificsAsDebugString(expected); + return false; + } + return true; +} + +} // namespace + +class AutofillWalletMetadataSyncBridgeTest : public testing::Test { + public: + AutofillWalletMetadataSyncBridgeTest() {} + ~AutofillWalletMetadataSyncBridgeTest() override {} + + void SetUp() override { + // Fix a time for implicitly constructed use_dates in AutofillProfile. + test_clock_.SetNow(kJune2017); + CountryNames::SetLocaleString(kLocaleString); + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + db_.AddTable(&table_); + db_.Init(temp_dir_.GetPath().AppendASCII("SyncTestWebDatabase")); + backend_.SetWebDatabase(&db_); + ResetProcessor(); + } + + void ResetProcessor() { + real_processor_ = + std::make_unique<syncer::ClientTagBasedModelTypeProcessor>( + syncer::AUTOFILL_WALLET_METADATA, /*dump_stack=*/base::DoNothing(), + /*commit_only=*/false); + mock_processor_.DelegateCallsByDefaultTo(real_processor_.get()); + } + + void ResetBridge() { + bridge_.reset(new AutofillWalletMetadataSyncBridge( + mock_processor_.CreateForwardingProcessor(), &backend_)); + } + + EntityData SpecificsToEntity(const WalletMetadataSpecifics& specifics) { + EntityData data; + *data.specifics.mutable_wallet_metadata() = specifics; + data.client_tag_hash = syncer::GenerateSyncableHash( + syncer::AUTOFILL_WALLET_METADATA, bridge()->GetClientTag(data)); + return data; + } + + std::vector<WalletMetadataSpecifics> GetAllLocalData() { + std::vector<WalletMetadataSpecifics> data; + // Perform an async call synchronously for testing. + base::RunLoop loop; + bridge()->GetAllDataForDebugging(base::BindLambdaForTesting( + [&loop, &data](std::unique_ptr<DataBatch> batch) { + ExtractWalletMetadataSpecificsFromDataBatch(std::move(batch), &data); + loop.Quit(); + })); + loop.Run(); + return data; + } + + std::vector<WalletMetadataSpecifics> GetLocalData( + AutofillWalletMetadataSyncBridge::StorageKeyList storage_keys) { + std::vector<WalletMetadataSpecifics> data; + // Perform an async call synchronously for testing. + base::RunLoop loop; + bridge()->GetData(storage_keys, + base::BindLambdaForTesting( + [&loop, &data](std::unique_ptr<DataBatch> batch) { + ExtractWalletMetadataSpecificsFromDataBatch( + std::move(batch), &data); + loop.Quit(); + })); + loop.Run(); + return data; + } + + AutofillWalletMetadataSyncBridge* bridge() { return bridge_.get(); } + + syncer::MockModelTypeChangeProcessor& mock_processor() { + return mock_processor_; + } + + AutofillTable* table() { return &table_; } + + FakeAutofillBackend* backend() { return &backend_; } + + private: + autofill::TestAutofillClock test_clock_; + ScopedTempDir temp_dir_; + base::test::ScopedTaskEnvironment scoped_task_environment_; + FakeAutofillBackend backend_; + AutofillTable table_; + WebDatabase db_; + testing::NiceMock<MockModelTypeChangeProcessor> mock_processor_; + std::unique_ptr<syncer::ClientTagBasedModelTypeProcessor> real_processor_; + std::unique_ptr<AutofillWalletMetadataSyncBridge> bridge_; + + DISALLOW_COPY_AND_ASSIGN(AutofillWalletMetadataSyncBridgeTest); +}; + +// The following 2 tests make sure client tags stay stable. +TEST_F(AutofillWalletMetadataSyncBridgeTest, GetClientTagForAddress) { + ResetBridge(); + WalletMetadataSpecifics specifics = + CreateWalletMetadataSpecificsForAddress(kAddr1SpecificsId); + EXPECT_EQ(bridge()->GetClientTag(SpecificsToEntity(specifics)), + kAddr1SyncTag); +} + +TEST_F(AutofillWalletMetadataSyncBridgeTest, GetClientTagForCard) { + ResetBridge(); + WalletMetadataSpecifics specifics = + CreateWalletMetadataSpecificsForCard(kCard1SpecificsId); + EXPECT_EQ(bridge()->GetClientTag(SpecificsToEntity(specifics)), + kCard1SyncTag); +} + +// The following 2 tests make sure storage keys stay stable. +TEST_F(AutofillWalletMetadataSyncBridgeTest, GetStorageKeyForAddress) { + ResetBridge(); + WalletMetadataSpecifics specifics = + CreateWalletMetadataSpecificsForAddress(kAddr1SpecificsId); + EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics)), + kAddr1SpecificsId); +} + +TEST_F(AutofillWalletMetadataSyncBridgeTest, GetStorageKeyForCard) { + ResetBridge(); + WalletMetadataSpecifics specifics = + CreateWalletMetadataSpecificsForCard(kCard1SpecificsId); + EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics)), + kCard1SpecificsId); +} + +TEST_F(AutofillWalletMetadataSyncBridgeTest, + GetAllDataForDebugging_ShouldReturnAllData) { + table()->SetServerProfiles({CreateServerProfile(kAddr1ServerId), + CreateServerProfile(kAddr2ServerId)}); + table()->SetServerCreditCards({CreateServerCreditCard(kCard1ServerId), + CreateServerCreditCard(kCard2ServerId)}); + ResetBridge(); + + EXPECT_THAT( + GetAllLocalData(), + UnorderedElementsAre( + EqualsSpecifics( + CreateWalletMetadataSpecificsForAddress(kAddr1SpecificsId)), + EqualsSpecifics( + CreateWalletMetadataSpecificsForAddress(kAddr2SpecificsId)), + EqualsSpecifics( + CreateWalletMetadataSpecificsForCard(kCard1SpecificsId)), + EqualsSpecifics( + CreateWalletMetadataSpecificsForCard(kCard2SpecificsId)))); +} + +TEST_F(AutofillWalletMetadataSyncBridgeTest, + GetData_ShouldNotReturnNonexistentData) { + ResetBridge(); + EXPECT_THAT(GetLocalData({kAddr1SpecificsId}), IsEmpty()); +} + +TEST_F(AutofillWalletMetadataSyncBridgeTest, GetData_ShouldReturnSelectedData) { + table()->SetServerProfiles({CreateServerProfile(kAddr1ServerId), + CreateServerProfile(kAddr2ServerId)}); + table()->SetServerCreditCards({CreateServerCreditCard(kCard1ServerId), + CreateServerCreditCard(kCard2ServerId)}); + ResetBridge(); + + EXPECT_THAT(GetLocalData({kAddr1SpecificsId, kCard1SpecificsId}), + UnorderedElementsAre( + EqualsSpecifics(CreateWalletMetadataSpecificsForAddress( + kAddr1SpecificsId)), + EqualsSpecifics(CreateWalletMetadataSpecificsForCard( + kCard1SpecificsId)))); +} + +TEST_F(AutofillWalletMetadataSyncBridgeTest, GetData_ShouldReturnCompleteData) { + AutofillProfile profile = CreateServerProfile(kAddr1ServerId); + profile.set_use_count(5); + profile.set_use_date(UseDateFromProtoValue(2)); + profile.set_has_converted(true); + table()->SetServerProfiles({profile}); + + CreditCard card = CreateServerCreditCard(kCard1ServerId); + card.set_use_count(6); + card.set_use_date(UseDateFromProtoValue(3)); + card.set_billing_address_id(kAddr1ServerId); + table()->SetServerCreditCards({card}); + ResetBridge(); + + // Expect to retrieve following specifics: + WalletMetadataSpecifics profile_specifics = + CreateWalletMetadataSpecificsForAddress(kAddr1SpecificsId); + profile_specifics.set_use_count(5); + profile_specifics.set_use_date(2); + profile_specifics.set_address_has_converted(true); + + WalletMetadataSpecifics card_specifics = + CreateWalletMetadataSpecificsForCard(kCard1SpecificsId); + card_specifics.set_use_count(6); + card_specifics.set_use_date(3); + card_specifics.set_card_billing_address_id(kAddr1SpecificsId); + + EXPECT_THAT(GetLocalData({kAddr1SpecificsId, kCard1SpecificsId}), + UnorderedElementsAre(EqualsSpecifics(profile_specifics), + EqualsSpecifics(card_specifics))); +} + +// Verify that lower values of metadata are not sent to the sync server when +// local metadata is updated. +TEST_F(AutofillWalletMetadataSyncBridgeTest, + DontSendLowerValueToServerOnSingleChange) { + table()->SetServerProfiles({CreateServerProfileWithUseStats( + kAddr1ServerId, /*use_count=*/2, /*use_date=*/5)}); + table()->SetServerCreditCards({CreateServerCreditCardWithUseStats( + kCard1ServerId, /*use_count=*/3, /*use_date=*/6)}); + ResetBridge(); + + AutofillProfile updated_profile = CreateServerProfileWithUseStats( + kAddr1ServerId, /*use_count=*/1, /*use_date=*/4); + CreditCard updated_card = CreateServerCreditCardWithUseStats( + kCard1ServerId, /*use_count=*/2, /*use_date=*/5); + + EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + + bridge()->AutofillProfileChanged(AutofillProfileChange( + AutofillProfileChange::UPDATE, updated_profile.guid(), &updated_profile)); + bridge()->CreditCardChanged(CreditCardChange( + CreditCardChange::UPDATE, updated_card.guid(), &updated_card)); +} + +// Verify that one-off addition of metadata is not sent to the sync +// server. Metadata add and delete trigger multiple changes notification +// instead. +TEST_F(AutofillWalletMetadataSyncBridgeTest, DontAddToServerOnSingleChange) { + table()->SetServerProfiles({CreateServerProfileWithUseStats( + kAddr1ServerId, /*use_count=*/1, /*use_date=*/2)}); + table()->SetServerCreditCards({CreateServerCreditCardWithUseStats( + kCard1ServerId, /*use_count=*/3, /*use_date=*/4)}); + ResetBridge(); + + AutofillProfile new_profile = CreateServerProfileWithUseStats( + kAddr2ServerId, /*use_count=*/10, /*use_date=*/20); + CreditCard new_card = CreateServerCreditCardWithUseStats( + kCard2ServerId, /*use_count=*/30, /*use_date=*/40); + + EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + + bridge()->AutofillProfileChanged(AutofillProfileChange( + AutofillProfileChange::UPDATE, new_profile.guid(), &new_profile)); + bridge()->CreditCardChanged( + CreditCardChange(CreditCardChange::UPDATE, new_card.guid(), &new_card)); +} + +// Verify that higher values of metadata are sent to the sync server when local +// metadata is updated. +TEST_F(AutofillWalletMetadataSyncBridgeTest, + SendHigherValuesToServerOnLocalSingleChange) { + table()->SetServerProfiles({CreateServerProfileWithUseStats( + kAddr1ServerId, /*use_count=*/1, /*use_date=*/2)}); + table()->SetServerCreditCards({CreateServerCreditCardWithUseStats( + kCard1ServerId, /*use_count=*/3, /*use_date=*/4)}); + ResetBridge(); + + AutofillProfile updated_profile = CreateServerProfileWithUseStats( + kAddr1ServerId, /*use_count=*/10, /*use_date=*/20); + CreditCard updated_card = CreateServerCreditCardWithUseStats( + kCard1ServerId, /*use_count=*/30, /*use_date=*/40); + + WalletMetadataSpecifics expected_profile_specifics = + CreateWalletMetadataSpecificsForAddressWithUseStats( + kAddr1SpecificsId, /*use_count=*/10, /*use_date=*/20); + WalletMetadataSpecifics expected_card_specifics = + CreateWalletMetadataSpecificsForCardWithUseStats( + kCard1SpecificsId, /*use_count=*/30, /*use_date=*/40); + + EXPECT_CALL( + mock_processor(), + Put(kAddr1SpecificsId, HasSpecifics(expected_profile_specifics), _)); + EXPECT_CALL(mock_processor(), + Put(kCard1SpecificsId, HasSpecifics(expected_card_specifics), _)); + + bridge()->AutofillProfileChanged(AutofillProfileChange( + AutofillProfileChange::UPDATE, updated_profile.guid(), &updated_profile)); + bridge()->CreditCardChanged(CreditCardChange( + CreditCardChange::UPDATE, updated_card.guid(), &updated_card)); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc index a1720b4f461..1d447d7d198 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc @@ -22,6 +22,7 @@ #include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/autofill/core/browser/webdata/autofill_webdata_backend.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" +#include "components/autofill/core/common/autofill_util.h" #include "components/sync/model/sync_change.h" #include "components/sync/model/sync_change_processor.h" #include "components/sync/model/sync_data.h" @@ -32,11 +33,7 @@ namespace autofill { namespace { -// The length of the GUIDs used for local autofill data. It is different than -// the length used for server autofill data. -const int kLocalGuidSize = 36; - -void* UserDataKey() { +void* AutofillWalletMetadataSyncableServiceUserDataKey() { // Use the address of a static so that COMDAT folding won't ever fold // with something else. static int user_data_key = 0; @@ -499,8 +496,9 @@ void AutofillWalletMetadataSyncableService::CreateForWebDataServiceAndBackend( AutofillWebDataBackend* web_data_backend, const std::string& app_locale) { web_data_service->GetDBUserData()->SetUserData( - UserDataKey(), base::WrapUnique(new AutofillWalletMetadataSyncableService( - web_data_backend, app_locale))); + AutofillWalletMetadataSyncableServiceUserDataKey(), + base::WrapUnique(new AutofillWalletMetadataSyncableService( + web_data_backend, app_locale))); } // static @@ -508,7 +506,8 @@ AutofillWalletMetadataSyncableService* AutofillWalletMetadataSyncableService::FromWebDataService( AutofillWebDataService* web_data_service) { return static_cast<AutofillWalletMetadataSyncableService*>( - web_data_service->GetDBUserData()->GetUserData(UserDataKey())); + web_data_service->GetDBUserData()->GetUserData( + AutofillWalletMetadataSyncableServiceUserDataKey())); } AutofillWalletMetadataSyncableService::AutofillWalletMetadataSyncableService( diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc new file mode 100644 index 00000000000..857c76e1c55 --- /dev/null +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc @@ -0,0 +1,452 @@ +// Copyright 2018 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 "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h" + +#include <utility> + +#include "base/base64.h" +#include "base/logging.h" +#include "base/metrics/histogram_macros.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/autofill_profile_sync_util.h" +#include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/payments/payments_customer_data.h" +#include "components/autofill/core/browser/webdata/autofill_sync_bridge_util.h" +#include "components/autofill/core/browser/webdata/autofill_table.h" +#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h" +#include "components/autofill/core/browser/webdata/autofill_webdata_service.h" +#include "components/autofill/core/common/autofill_util.h" +#include "components/sync/model/entity_data.h" +#include "components/sync/model/mutable_data_batch.h" +#include "components/sync/model/sync_merge_result.h" +#include "components/sync/model_impl/client_tag_based_model_type_processor.h" +#include "components/sync/model_impl/sync_metadata_store_change_list.h" + +using sync_pb::AutofillWalletSpecifics; +using syncer::EntityData; + +namespace autofill { +namespace { + +// Address to this variable used as the user data key. +static int kAutofillWalletSyncBridgeUserDataKey = 0; + +std::string GetSpecificsIdFromAutofillWalletSpecifics( + const AutofillWalletSpecifics& specifics) { + switch (specifics.type()) { + case AutofillWalletSpecifics::MASKED_CREDIT_CARD: + return specifics.masked_card().id(); + case AutofillWalletSpecifics::POSTAL_ADDRESS: + return specifics.address().id(); + case AutofillWalletSpecifics::CUSTOMER_DATA: + return specifics.customer_data().id(); + case AutofillWalletSpecifics::UNKNOWN: + NOTREACHED(); + return std::string(); + } + return std::string(); +} + +std::string GetClientTagForWalletDataSpecificsId( + const std::string& specifics_id) { + // Unlike for the wallet_metadata model type, the wallet_data expects + // specifics id directly as client tags. + return specifics_id; +} + +} // namespace + +// static +void AutofillWalletSyncBridge::CreateForWebDataServiceAndBackend( + const std::string& app_locale, + bool has_persistent_storage, + AutofillWebDataBackend* web_data_backend, + AutofillWebDataService* web_data_service) { + web_data_service->GetDBUserData()->SetUserData( + &kAutofillWalletSyncBridgeUserDataKey, + std::make_unique<AutofillWalletSyncBridge>( + std::make_unique<syncer::ClientTagBasedModelTypeProcessor>( + syncer::AUTOFILL_WALLET_DATA, + /*dump_stack=*/base::RepeatingClosure()), + has_persistent_storage, web_data_backend)); +} + +// static +syncer::ModelTypeSyncBridge* AutofillWalletSyncBridge::FromWebDataService( + AutofillWebDataService* web_data_service) { + return static_cast<AutofillWalletSyncBridge*>( + web_data_service->GetDBUserData()->GetUserData( + &kAutofillWalletSyncBridgeUserDataKey)); +} + +AutofillWalletSyncBridge::AutofillWalletSyncBridge( + std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor, + bool has_persistent_storage, + AutofillWebDataBackend* web_data_backend) + : ModelTypeSyncBridge(std::move(change_processor)), + has_persistent_storage_(has_persistent_storage), + initial_sync_done_(false), + web_data_backend_(web_data_backend) { + DCHECK(web_data_backend_); + + LoadMetadata(); +} + +AutofillWalletSyncBridge::~AutofillWalletSyncBridge() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} + +std::unique_ptr<syncer::MetadataChangeList> +AutofillWalletSyncBridge::CreateMetadataChangeList() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return std::make_unique<syncer::SyncMetadataStoreChangeList>( + GetAutofillTable(), syncer::AUTOFILL_WALLET_DATA); +} + +base::Optional<syncer::ModelError> AutofillWalletSyncBridge::MergeSyncData( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_data) { + SetSyncData(entity_data); + + // After the first sync, we are sure that initial sync is done. + initial_sync_done_ = true; + return base::nullopt; +} + +base::Optional<syncer::ModelError> AutofillWalletSyncBridge::ApplySyncChanges( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_data) { + // This bridge does not support incremental updates, so whenever this is + // called, the change list should be empty. + DCHECK(entity_data.empty()) << "Received an unsupported incremental update."; + return base::nullopt; +} + +void AutofillWalletSyncBridge::GetData(StorageKeyList storage_keys, + DataCallback callback) { + // This data type is never synced "up" so we don't need to implement this. + NOTIMPLEMENTED(); +} + +void AutofillWalletSyncBridge::GetAllDataForDebugging(DataCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + std::vector<std::unique_ptr<AutofillProfile>> profiles; + std::vector<std::unique_ptr<CreditCard>> cards; + std::unique_ptr<PaymentsCustomerData> customer_data; + if (!GetAutofillTable()->GetServerProfiles(&profiles) || + !GetAutofillTable()->GetServerCreditCards(&cards) || + !GetAutofillTable()->GetPaymentsCustomerData(&customer_data)) { + change_processor()->ReportError( + {FROM_HERE, "Failed to load entries from table."}); + return; + } + + // Convert all non base 64 strings so that they can be displayed properly. + auto batch = std::make_unique<syncer::MutableDataBatch>(); + for (const std::unique_ptr<AutofillProfile>& entry : profiles) { + std::unique_ptr<EntityData> entity_data = + CreateEntityDataFromAutofillServerProfile(*entry); + sync_pb::WalletPostalAddress* wallet_address = + entity_data->specifics.mutable_autofill_wallet()->mutable_address(); + + wallet_address->set_id(GetBase64EncodedServerId(wallet_address->id())); + + batch->Put(GetStorageKeyForEntryServerId(entry->server_id()), + std::move(entity_data)); + } + for (const std::unique_ptr<CreditCard>& entry : cards) { + std::unique_ptr<EntityData> entity_data = CreateEntityDataFromCard(*entry); + sync_pb::WalletMaskedCreditCard* wallet_card = + entity_data->specifics.mutable_autofill_wallet()->mutable_masked_card(); + + wallet_card->set_id(GetBase64EncodedServerId(wallet_card->id())); + // The billing address id might refer to a local profile guid which doesn't + // need to be encoded. + if (!base::IsStringUTF8(wallet_card->billing_address_id())) { + wallet_card->set_billing_address_id( + GetBase64EncodedServerId(wallet_card->billing_address_id())); + } + + batch->Put(GetStorageKeyForEntryServerId(entry->server_id()), + std::move(entity_data)); + } + + if (customer_data) { + batch->Put(GetStorageKeyForEntryServerId(customer_data->customer_id), + CreateEntityDataFromPaymentsCustomerData(*customer_data)); + } + std::move(callback).Run(std::move(batch)); +} + +std::string AutofillWalletSyncBridge::GetClientTag( + const syncer::EntityData& entity_data) { + DCHECK(entity_data.specifics.has_autofill_wallet()); + + return GetClientTagForWalletDataSpecificsId( + GetSpecificsIdFromAutofillWalletSpecifics( + entity_data.specifics.autofill_wallet())); +} + +std::string AutofillWalletSyncBridge::GetStorageKey( + const syncer::EntityData& entity_data) { + DCHECK(entity_data.specifics.has_autofill_wallet()); + return GetStorageKeyForSpecificsId(GetSpecificsIdFromAutofillWalletSpecifics( + entity_data.specifics.autofill_wallet())); +} + +bool AutofillWalletSyncBridge::SupportsIncrementalUpdates() const { + // The payments server always returns the full dataset whenever there's any + // change to the user's payments data. Therefore, we don't implement full + // incremental-update support in this bridge, and clear all data + // before inserting new instead. + return false; +} + +AutofillWalletSyncBridge::StopSyncResponse +AutofillWalletSyncBridge::ApplyStopSyncChanges( + std::unique_ptr<syncer::MetadataChangeList> delete_metadata_change_list) { + // If a metadata change list gets passed in, that means sync is actually + // disabled, so we want to delete the payments data. + if (delete_metadata_change_list) { + SetSyncData(syncer::EntityChangeList()); + } + return StopSyncResponse::kModelStillReadyToSync; +} + +void AutofillWalletSyncBridge::GetAllDataForTesting(DataCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + std::vector<std::unique_ptr<AutofillProfile>> profiles; + std::vector<std::unique_ptr<CreditCard>> cards; + std::unique_ptr<PaymentsCustomerData> customer_data; + if (!GetAutofillTable()->GetServerProfiles(&profiles) || + !GetAutofillTable()->GetServerCreditCards(&cards) || + !GetAutofillTable()->GetPaymentsCustomerData(&customer_data)) { + change_processor()->ReportError( + {FROM_HERE, "Failed to load entries from table."}); + return; + } + + auto batch = std::make_unique<syncer::MutableDataBatch>(); + for (const std::unique_ptr<AutofillProfile>& entry : profiles) { + batch->Put(GetStorageKeyForEntryServerId(entry->server_id()), + CreateEntityDataFromAutofillServerProfile(*entry)); + } + for (const std::unique_ptr<CreditCard>& entry : cards) { + batch->Put(GetStorageKeyForEntryServerId(entry->server_id()), + CreateEntityDataFromCard(*entry)); + } + + if (customer_data) { + batch->Put(GetStorageKeyForEntryServerId(customer_data->customer_id), + CreateEntityDataFromPaymentsCustomerData(*customer_data)); + } + std::move(callback).Run(std::move(batch)); +} + +void AutofillWalletSyncBridge::SetSyncData( + const syncer::EntityChangeList& entity_data) { + bool wallet_data_changed = false; + + // Extract the Autofill types from the sync |entity_data|. + std::vector<CreditCard> wallet_cards; + std::vector<PaymentsCustomerData> customer_data; + if (has_persistent_storage_) { + // When in persistent storage mode, we update wallet addresses. + std::vector<AutofillProfile> wallet_addresses; + PopulateWalletTypesFromSyncData(entity_data, &wallet_cards, + &wallet_addresses, &customer_data); + wallet_data_changed |= SetWalletAddresses(std::move(wallet_addresses)); + } else { + // When in ephemeral storage mode, we ignore wallet addresses. + PopulateWalletTypesFromSyncData(entity_data, &wallet_cards, nullptr, + &customer_data); + } + + // In both cases, we need to update wallet cards and payments customer data. + wallet_data_changed |= SetWalletCards(std::move(wallet_cards)); + wallet_data_changed |= SetPaymentsCustormerData(std::move(customer_data)); + + if (web_data_backend_ && wallet_data_changed) + web_data_backend_->NotifyOfMultipleAutofillChanges(); +} + +bool AutofillWalletSyncBridge::SetWalletCards( + std::vector<CreditCard> wallet_cards) { + // Users can set billing address of the server credit card locally, but that + // information does not propagate to either Chrome Sync or Google Payments + // server. To preserve user's preferred billing address and most recent use + // stats, copy them from disk into |wallet_cards|. + AutofillTable* table = GetAutofillTable(); + CopyRelevantWalletMetadataFromDisk(*table, &wallet_cards); + + // In the common case, the database won't have changed. Committing an update + // to the database will require at least one DB page write and will schedule + // a fsync. To avoid this I/O, it should be more efficient to do a read and + // only do the writes if something changed. + std::vector<std::unique_ptr<CreditCard>> existing_cards; + table->GetServerCreditCards(&existing_cards); + AutofillWalletDiff diff = + ComputeAutofillWalletDiff(existing_cards, wallet_cards); + + // Record only local changes that correspond to changes in the payments + // backend and not local changes due to initial sync. + if (initial_sync_done_) { + UMA_HISTOGRAM_COUNTS_100("Autofill.WalletCardsAdded", diff.items_added); + UMA_HISTOGRAM_COUNTS_100("Autofill.WalletCardsRemoved", diff.items_removed); + UMA_HISTOGRAM_COUNTS_100("Autofill.WalletCardsAddedOrRemoved", + diff.items_added + diff.items_removed); + } + + if (!diff.IsEmpty()) { + table->SetServerCreditCards(wallet_cards); + return true; + } + return false; +} + +bool AutofillWalletSyncBridge::SetWalletAddresses( + std::vector<AutofillProfile> wallet_addresses) { + // In the common case, the database won't have changed. Committing an update + // to the database will require at least one DB page write and will schedule + // a fsync. To avoid this I/O, it should be more efficient to do a read and + // only do the writes if something changed. + AutofillTable* table = GetAutofillTable(); + std::vector<std::unique_ptr<AutofillProfile>> existing_addresses; + table->GetServerProfiles(&existing_addresses); + AutofillWalletDiff diff = + ComputeAutofillWalletDiff(existing_addresses, wallet_addresses); + + // Record only local changes that correspond to changes in the payments + // backend and not local changes due to initial sync. + if (initial_sync_done_) { + UMA_HISTOGRAM_COUNTS_100("Autofill.WalletAddressesAdded", diff.items_added); + UMA_HISTOGRAM_COUNTS_100("Autofill.WalletAddressesRemoved", + diff.items_removed); + UMA_HISTOGRAM_COUNTS_100("Autofill.WalletAddressesAddedOrRemoved", + diff.items_added + diff.items_removed); + } + + if (!diff.IsEmpty()) { + table->SetServerProfiles(wallet_addresses); + return true; + } + return false; +} + +bool AutofillWalletSyncBridge::SetPaymentsCustormerData( + std::vector<PaymentsCustomerData> customer_data) { + // In the common case, the database won't have changed. Committing an update + // to the database will require at least one DB page write and will schedule + // a fsync. To avoid this I/O, it should be more efficient to do a read and + // only do the writes if something changed. + AutofillTable* table = GetAutofillTable(); + std::unique_ptr<PaymentsCustomerData> existing_entry; + table->GetPaymentsCustomerData(&existing_entry); + + // In case there were multiple entries (and there shouldn't!), we take the + // pointer to the first entry in the vector. + PaymentsCustomerData* new_entry = + customer_data.empty() ? nullptr : customer_data.data(); + +#if DCHECK_IS_ON() + if (customer_data.size() > 1) { + DLOG(WARNING) << "Sync wallet_data update has " << customer_data.size() + << " payments-customer-data entries; expected 0 or 1."; + } +#endif // DCHECK_IS_ON() + + if (!new_entry && existing_entry) { + // Clear the existing entry in the DB. + GetAutofillTable()->SetPaymentsCustomerData(nullptr); + return true; + } else if (new_entry && (!existing_entry || *new_entry != *existing_entry)) { + // Write the new entry in the DB as it differs from the existing one. + GetAutofillTable()->SetPaymentsCustomerData(new_entry); + return true; + } + return false; +} + +// static +template <class Item> +AutofillWalletSyncBridge::AutofillWalletDiff +AutofillWalletSyncBridge::ComputeAutofillWalletDiff( + const std::vector<std::unique_ptr<Item>>& old_data, + const std::vector<Item>& new_data) { + // Build vectors of pointers, so that we can mutate (sort) them. + std::vector<const Item*> old_ptrs; + old_ptrs.reserve(old_data.size()); + for (const std::unique_ptr<Item>& old_item : old_data) + old_ptrs.push_back(old_item.get()); + std::vector<const Item*> new_ptrs; + new_ptrs.reserve(new_data.size()); + for (const Item& new_item : new_data) + new_ptrs.push_back(&new_item); + + // Sort our vectors. + auto compare = [](const Item* lhs, const Item* rhs) { + return lhs->Compare(*rhs) < 0; + }; + std::sort(old_ptrs.begin(), old_ptrs.end(), compare); + std::sort(new_ptrs.begin(), new_ptrs.end(), compare); + + // Walk over both of them and count added/removed elements. + AutofillWalletDiff result; + auto old_it = old_ptrs.begin(); + auto new_it = new_ptrs.begin(); + while (old_it != old_ptrs.end()) { + if (new_it == new_ptrs.end()) { + result.items_removed += std::distance(old_it, old_ptrs.end()); + break; + } + int cmp = (*old_it)->Compare(**new_it); + if (cmp < 0) { + ++result.items_removed; + ++old_it; + } else if (cmp == 0) { + ++old_it; + ++new_it; + } else { + ++result.items_added; + ++new_it; + } + } + result.items_added += std::distance(new_it, new_ptrs.end()); + + DCHECK_EQ(old_data.size() + result.items_added - result.items_removed, + new_data.size()); + + return result; +} + +AutofillTable* AutofillWalletSyncBridge::GetAutofillTable() { + return AutofillTable::FromWebDatabase(web_data_backend_->GetDatabase()); +} + +void AutofillWalletSyncBridge::LoadMetadata() { + if (!web_data_backend_ || !web_data_backend_->GetDatabase() || + !GetAutofillTable()) { + change_processor()->ReportError( + {FROM_HERE, "Failed to load AutofillWebDatabase."}); + return; + } + + auto batch = std::make_unique<syncer::MetadataBatch>(); + if (!GetAutofillTable()->GetAllSyncMetadata(syncer::AUTOFILL_WALLET_DATA, + batch.get())) { + change_processor()->ReportError( + {FROM_HERE, "Failed reading autofill metadata from WebDatabase."}); + return; + } + initial_sync_done_ = batch->GetModelTypeState().initial_sync_done(); + + change_processor()->ModelReadyToSync(std::move(batch)); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h new file mode 100644 index 00000000000..b7a483742b3 --- /dev/null +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h @@ -0,0 +1,140 @@ +// Copyright 2018 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_SYNC_BRIDGE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_SYNC_BRIDGE_H_ + +#include <memory> +#include <string> +#include <unordered_set> + +#include "base/macros.h" +#include "base/sequence_checker.h" +#include "base/supports_user_data.h" +#include "components/sync/model/metadata_change_list.h" +#include "components/sync/model/model_error.h" +#include "components/sync/model/model_type_change_processor.h" +#include "components/sync/model/model_type_sync_bridge.h" + +namespace autofill { + +class AutofillProfile; +class AutofillTable; +class AutofillWebDataBackend; +class AutofillWebDataService; +class CreditCard; +struct PaymentsCustomerData; + +// Sync bridge responsible for propagating local changes to the processor and +// applying remote changes to the local database. +class AutofillWalletSyncBridge : public base::SupportsUserData::Data, + public syncer::ModelTypeSyncBridge { + public: + // Factory method that hides dealing with change_processor and also stores the + // created bridge within |web_data_service|. This method should only be + // called on |web_data_service|'s DB thread. + static void CreateForWebDataServiceAndBackend( + const std::string& app_locale, + bool has_persistent_storage_, + AutofillWebDataBackend* webdata_backend, + AutofillWebDataService* web_data_service); + + static syncer::ModelTypeSyncBridge* FromWebDataService( + AutofillWebDataService* web_data_service); + + explicit AutofillWalletSyncBridge( + std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor, + bool has_persistent_storage_, + AutofillWebDataBackend* web_data_backend); + ~AutofillWalletSyncBridge() override; + + // ModelTypeSyncBridge implementation. + std::unique_ptr<syncer::MetadataChangeList> CreateMetadataChangeList() + override; + base::Optional<syncer::ModelError> MergeSyncData( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_data) override; + base::Optional<syncer::ModelError> ApplySyncChanges( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_changes) override; + void GetData(StorageKeyList storage_keys, DataCallback callback) override; + void GetAllDataForDebugging(DataCallback callback) override; + std::string GetClientTag(const syncer::EntityData& entity_data) override; + std::string GetStorageKey(const syncer::EntityData& entity_data) override; + bool SupportsIncrementalUpdates() const override; + StopSyncResponse ApplyStopSyncChanges( + std::unique_ptr<syncer::MetadataChangeList> delete_metadata_change_list) + override; + + // Sends all Wallet Data to the |callback| and keeps all the strings in their + // original format. + void GetAllDataForTesting(DataCallback callback); + + private: + struct AutofillWalletDiff { + int items_added = 0; + int items_removed = 0; + + bool IsEmpty() const { return items_added == 0 && items_removed == 0; } + }; + + // Sets the wallet data from |entity_data| to this client and records metrics + // about added/deleted data. + void SetSyncData(const syncer::EntityChangeList& entity_data); + + // Sets |wallet_cards| to this client, records metrics about added/deleted + // data and returns whether any change has been applied (i.e., whether + // |wallet_cards| was different from local data). + bool SetWalletCards(std::vector<CreditCard> wallet_cards); + + // Sets |wallet_addresses| to this client, records metrics about added/deleted + // data and returns whether any change has been applied (i.e., whether + // |wallet_addresses| was different from local data). + bool SetWalletAddresses(std::vector<AutofillProfile> wallet_addresses); + + // Sets |customer_data| to this client and returns whether any change has been + // applied (i.e., whether |customer_data| was different from local data). + bool SetPaymentsCustormerData( + std::vector<PaymentsCustomerData> customer_data); + + // Computes a "diff" (items added, items removed) of two vectors of items, + // which should be either CreditCard or AutofillProfile. This is used for two + // purposes: + // 1) Detecting if anything has changed, so that we don't write to disk in the + // common case where nothing has changed. + // 2) Recording metrics on the number of added/removed items. + // This is exposed as a static method so that it can be tested. + template <class Item> + static AutofillWalletDiff ComputeAutofillWalletDiff( + const std::vector<std::unique_ptr<Item>>& old_data, + const std::vector<Item>& new_data); + + // Returns the table associated with the |web_data_backend_|. + AutofillTable* GetAutofillTable(); + + // Synchronously load sync metadata from the autofill table and pass it to the + // processor so that it can start tracking changes. + void LoadMetadata(); + + // Stores whether this bridge is connected to the persistent storage (as part + // of the complete sync feature) or to an ephemeral storage (as part of the + // content-area-account-based lightweight sync). + const bool has_persistent_storage_; + + // Stores whether initial sync has been done. + bool initial_sync_done_; + + // AutofillProfileSyncBridge is owned by |web_data_backend_| through + // SupportsUserData, so it's guaranteed to outlive |this|. + AutofillWebDataBackend* const web_data_backend_; + + // The bridge should be used on the same sequence where it is constructed. + SEQUENCE_CHECKER(sequence_checker_); + + DISALLOW_COPY_AND_ASSIGN(AutofillWalletSyncBridge); +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_SYNC_BRIDGE_H_ diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc new file mode 100644 index 00000000000..3ff812dedb1 --- /dev/null +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc @@ -0,0 +1,738 @@ +// Copyright 2018 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 "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h" + +#include <stddef.h> + +#include <memory> +#include <utility> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/files/scoped_temp_dir.h" +#include "base/message_loop/message_loop.h" +#include "base/test/bind_test_util.h" +#include "base/test/scoped_task_environment.h" +#include "base/time/time.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/autofill_test_utils.h" +#include "components/autofill/core/browser/country_names.h" +#include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/payments/payments_customer_data.h" +#include "components/autofill/core/browser/test_autofill_clock.h" +#include "components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.h" +#include "components/autofill/core/browser/webdata/autofill_sync_bridge_util.h" +#include "components/autofill/core/browser/webdata/autofill_table.h" +#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h" +#include "components/autofill/core/common/autofill_constants.h" +#include "components/sync/base/hash_util.h" +#include "components/sync/model/entity_data.h" +#include "components/sync/model/mock_model_type_change_processor.h" +#include "components/sync/model/sync_data.h" +#include "components/sync/model_impl/client_tag_based_model_type_processor.h" +#include "components/sync/model_impl/in_memory_metadata_change_list.h" +#include "components/sync/protocol/autofill_specifics.pb.h" +#include "components/sync/protocol/sync.pb.h" +#include "components/sync/test/test_matchers.h" +#include "components/webdata/common/web_database.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace autofill { +namespace { + +using base::ScopedTempDir; +using sync_pb::AutofillWalletSpecifics; +using sync_pb::EntityMetadata; +using sync_pb::ModelTypeState; +using syncer::DataBatch; +using syncer::EntityChange; +using syncer::EntityData; +using syncer::EntityDataPtr; +using syncer::HasInitialSyncDone; +using syncer::KeyAndData; +using syncer::MockModelTypeChangeProcessor; +using syncer::ModelType; +using testing::NiceMock; +using testing::SizeIs; +using testing::Return; +using testing::UnorderedElementsAre; + +// Base64 encodings of the server IDs, used as ids in WalletMetadataSpecifics +// (these are suitable for syncing, because they are valid UTF-8). +const char kAddr1SpecificsId[] = "YWRkcjHvv74="; +const char kCard1SpecificsId[] = "Y2FyZDHvv74="; + +// Represents a Payments customer id. +const char kCustomerDataId[] = "deadbeef"; +const char kCustomerDataId2[] = "deadcafe"; + +// Unique sync tags for the server IDs. +const char kAddr1SyncTag[] = "YWRkcjHvv74="; +const char kCard1SyncTag[] = "Y2FyZDHvv74="; +const char kCustomerDataSyncTag[] = "deadbeef"; + +const char kLocaleString[] = "en-US"; +const base::Time kJune2017 = base::Time::FromDoubleT(1497552271); + +// TODO(jkrcal): Extract this class out and reuse it for all autofill bridges. +class MockAutofillBackend : public AutofillWebDataBackend { + public: + MockAutofillBackend() {} + ~MockAutofillBackend() override {} + + MOCK_METHOD0(GetDatabase, WebDatabase*()); + MOCK_METHOD1( + AddObserver, + void(autofill::AutofillWebDataServiceObserverOnDBSequence* observer)); + MOCK_METHOD1( + RemoveObserver, + void(autofill::AutofillWebDataServiceObserverOnDBSequence* observer)); + MOCK_METHOD0(RemoveExpiredFormElements, void()); + MOCK_METHOD0(NotifyOfMultipleAutofillChanges, void()); + MOCK_METHOD1(NotifyThatSyncHasStarted, void(ModelType model_type)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockAutofillBackend); +}; + +void ExtractAutofillWalletSpecificsFromDataBatch( + std::unique_ptr<DataBatch> batch, + std::vector<AutofillWalletSpecifics>* output) { + while (batch->HasNext()) { + const KeyAndData& data_pair = batch->Next(); + output->push_back(data_pair.second->specifics.autofill_wallet()); + } +} + +std::string WalletMaskedCreditCardSpecificsAsDebugString( + const AutofillWalletSpecifics& specifics) { + std::ostringstream output; + output << "[id: " << specifics.masked_card().id() + << ", type: " << static_cast<int>(specifics.type()) + << ", name_on_card: " << specifics.masked_card().name_on_card() + << ", type: " << specifics.masked_card().type() + << ", last_four: " << specifics.masked_card().last_four() + << ", exp_month: " << specifics.masked_card().exp_month() + << ", exp_year: " << specifics.masked_card().exp_year() + << ", billing_address_id: " + << specifics.masked_card().billing_address_id() + << ", card_class: " << specifics.masked_card().card_class() + << ", bank_name: " << specifics.masked_card().bank_name() << "]"; + return output.str(); +} + +std::string WalletPostalAddressSpecificsAsDebugString( + const AutofillWalletSpecifics& specifics) { + std::ostringstream output; + output << "[id: " << specifics.address().id() + << ", type: " << static_cast<int>(specifics.type()) + << ", recipient_name: " << specifics.address().recipient_name() + << ", company_name: " << specifics.address().company_name() + << ", street_address: " + << (specifics.address().street_address_size() + ? specifics.address().street_address(0) + : "") + << ", address_1: " << specifics.address().address_1() + << ", address_2: " << specifics.address().address_2() + << ", address_3: " << specifics.address().address_3() + << ", postal_code: " << specifics.address().postal_code() + << ", country_code: " << specifics.address().country_code() + << ", phone_number: " << specifics.address().phone_number() + << ", sorting_code: " << specifics.address().sorting_code() << "]"; + return output.str(); +} + +std::string AutofillWalletSpecificsAsDebugString( + const AutofillWalletSpecifics& specifics) { + switch (specifics.type()) { + case sync_pb::AutofillWalletSpecifics_WalletInfoType:: + AutofillWalletSpecifics_WalletInfoType_MASKED_CREDIT_CARD: + return WalletMaskedCreditCardSpecificsAsDebugString(specifics); + case sync_pb::AutofillWalletSpecifics_WalletInfoType:: + AutofillWalletSpecifics_WalletInfoType_POSTAL_ADDRESS: + return WalletPostalAddressSpecificsAsDebugString(specifics); + case sync_pb::AutofillWalletSpecifics_WalletInfoType:: + AutofillWalletSpecifics_WalletInfoType_CUSTOMER_DATA: + return "CustomerData"; + case sync_pb::AutofillWalletSpecifics_WalletInfoType:: + AutofillWalletSpecifics_WalletInfoType_UNKNOWN: + return "Unknown"; + } +} + +MATCHER_P(EqualsSpecifics, expected, "") { + if (arg.SerializeAsString() != expected.SerializeAsString()) { + *result_listener << "entry\n" + << AutofillWalletSpecificsAsDebugString(arg) << "\n" + << "did not match expected\n" + << AutofillWalletSpecificsAsDebugString(expected); + return false; + } + return true; +} + +} // namespace + +class AutofillWalletSyncBridgeTest : public testing::Test { + public: + AutofillWalletSyncBridgeTest() {} + ~AutofillWalletSyncBridgeTest() override {} + + void SetUp() override { + // Fix a time for implicitly constructed use_dates in AutofillProfile. + test_clock_.SetNow(kJune2017); + CountryNames::SetLocaleString(kLocaleString); + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + db_.AddTable(&table_); + db_.Init(temp_dir_.GetPath().AppendASCII("SyncTestWebDatabase")); + ON_CALL(*backend(), GetDatabase()).WillByDefault(Return(&db_)); + ResetProcessor(); + ResetBridge(); + } + + void ResetProcessor() { + real_processor_ = + std::make_unique<syncer::ClientTagBasedModelTypeProcessor>( + syncer::AUTOFILL_WALLET_DATA, /*dump_stack=*/base::DoNothing(), + /*commit_only=*/false); + mock_processor_.DelegateCallsByDefaultTo(real_processor_.get()); + } + + void ResetBridge() { + bridge_.reset(new AutofillWalletSyncBridge( + mock_processor_.CreateForwardingProcessor(), UseFullSync(), &backend_)); + } + + void StartSyncing( + const std::vector<AutofillWalletSpecifics>& remote_data = {}) { + base::RunLoop loop; + syncer::DataTypeActivationRequest request; + request.error_handler = base::DoNothing(); + real_processor_->OnSyncStarting( + request, + base::BindLambdaForTesting( + [&loop](std::unique_ptr<syncer::DataTypeActivationResponse>) { + loop.Quit(); + })); + loop.Run(); + + // Initialize the processor with initial_sync_done. + sync_pb::ModelTypeState state; + state.set_initial_sync_done(true); + state.mutable_progress_marker() + ->mutable_gc_directive() + ->set_version_watermark(1); + syncer::UpdateResponseDataList initial_updates; + for (const AutofillWalletSpecifics& specifics : remote_data) { + initial_updates.push_back(SpecificsToUpdateResponse(specifics)); + } + real_processor_->OnUpdateReceived(state, initial_updates); + } + + EntityData SpecificsToEntity(const AutofillWalletSpecifics& specifics) { + EntityData data; + *data.specifics.mutable_autofill_wallet() = specifics; + data.client_tag_hash = syncer::GenerateSyncableHash( + syncer::AUTOFILL_WALLET_DATA, bridge()->GetClientTag(data)); + return data; + } + + std::vector<AutofillWalletSpecifics> GetAllLocalData() { + std::vector<AutofillWalletSpecifics> data; + // Perform an async call synchronously for testing. + base::RunLoop loop; + bridge()->GetAllDataForTesting(base::BindLambdaForTesting( + [&loop, &data](std::unique_ptr<DataBatch> batch) { + ExtractAutofillWalletSpecificsFromDataBatch(std::move(batch), &data); + loop.Quit(); + })); + loop.Run(); + return data; + } + + syncer::UpdateResponseData SpecificsToUpdateResponse( + const AutofillWalletSpecifics& specifics) { + syncer::UpdateResponseData data; + data.entity = SpecificsToEntity(specifics).PassToPtr(); + return data; + } + + AutofillWalletSyncBridge* bridge() { return bridge_.get(); } + + syncer::MockModelTypeChangeProcessor& mock_processor() { + return mock_processor_; + } + + AutofillTable* table() { return &table_; } + + MockAutofillBackend* backend() { return &backend_; } + + virtual bool UseFullSync() { return true; } + + private: + autofill::TestAutofillClock test_clock_; + ScopedTempDir temp_dir_; + base::test::ScopedTaskEnvironment scoped_task_environment_; + NiceMock<MockAutofillBackend> backend_; + AutofillTable table_; + WebDatabase db_; + testing::NiceMock<MockModelTypeChangeProcessor> mock_processor_; + std::unique_ptr<syncer::ClientTagBasedModelTypeProcessor> real_processor_; + std::unique_ptr<AutofillWalletSyncBridge> bridge_; + + DISALLOW_COPY_AND_ASSIGN(AutofillWalletSyncBridgeTest); +}; + +// The following 3 tests make sure client tags stay stable. +TEST_F(AutofillWalletSyncBridgeTest, GetClientTagForAddress) { + AutofillWalletSpecifics specifics = + CreateAutofillWalletSpecificsForAddress(kAddr1SpecificsId); + EXPECT_EQ(bridge()->GetClientTag(SpecificsToEntity(specifics)), + kAddr1SyncTag); +} + +TEST_F(AutofillWalletSyncBridgeTest, GetClientTagForCard) { + AutofillWalletSpecifics specifics = + CreateAutofillWalletSpecificsForCard(kCard1SpecificsId); + EXPECT_EQ(bridge()->GetClientTag(SpecificsToEntity(specifics)), + kCard1SyncTag); +} + +TEST_F(AutofillWalletSyncBridgeTest, GetClientTagForCustomerData) { + AutofillWalletSpecifics specifics = + CreateAutofillWalletSpecificsForPaymentsCustomerData( + kCustomerDataSyncTag); + EXPECT_EQ(bridge()->GetClientTag(SpecificsToEntity(specifics)), + kCustomerDataSyncTag); +} + +// The following 3 tests make sure storage keys stay stable. +TEST_F(AutofillWalletSyncBridgeTest, GetStorageKeyForAddress) { + AutofillWalletSpecifics specifics1 = + CreateAutofillWalletSpecificsForAddress(kAddr1SpecificsId); + EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics1)), + kAddr1SpecificsId); +} + +TEST_F(AutofillWalletSyncBridgeTest, GetStorageKeyForCard) { + AutofillWalletSpecifics specifics2 = + CreateAutofillWalletSpecificsForCard(kCard1SpecificsId); + EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics2)), + kCard1SpecificsId); +} + +TEST_F(AutofillWalletSyncBridgeTest, GetStorageKeyForCustomerData) { + AutofillWalletSpecifics specifics3 = + CreateAutofillWalletSpecificsForPaymentsCustomerData(kCustomerDataId); + EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics3)), + kCustomerDataId); +} + +TEST_F(AutofillWalletSyncBridgeTest, + GetAllDataForDebugging_ShouldReturnAllData) { + AutofillProfile address1 = test::GetServerProfile(); + AutofillProfile address2 = test::GetServerProfile2(); + table()->SetServerProfiles({address1, address2}); + CreditCard card1 = test::GetMaskedServerCard(); + CreditCard card2 = test::GetMaskedServerCardAmex(); + table()->SetServerCreditCards({card1, card2}); + PaymentsCustomerData customer_data{/*customer_id=*/kCustomerDataId}; + table()->SetPaymentsCustomerData(&customer_data); + + AutofillWalletSpecifics profile_specifics1; + SetAutofillWalletSpecificsFromServerProfile(address1, &profile_specifics1); + AutofillWalletSpecifics profile_specifics2; + SetAutofillWalletSpecificsFromServerProfile(address2, &profile_specifics2); + AutofillWalletSpecifics card_specifics1; + SetAutofillWalletSpecificsFromServerCard(card1, &card_specifics1); + AutofillWalletSpecifics card_specifics2; + SetAutofillWalletSpecificsFromServerCard(card2, &card_specifics2); + AutofillWalletSpecifics customer_data_specifics; + SetAutofillWalletSpecificsFromPaymentsCustomerData(customer_data, + &customer_data_specifics); + + EXPECT_THAT(GetAllLocalData(), + UnorderedElementsAre(EqualsSpecifics(profile_specifics1), + EqualsSpecifics(profile_specifics2), + EqualsSpecifics(card_specifics1), + EqualsSpecifics(card_specifics2), + EqualsSpecifics(customer_data_specifics))); +} + +// Tests that when a new wallet card and new wallet address are sent by the +// server, the client only keeps the new data. +TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_NewWalletAddressAndCard) { + // Create one profile and one card on the client. + AutofillProfile address1 = test::GetServerProfile(); + table()->SetServerProfiles({address1}); + CreditCard card1 = test::GetMaskedServerCard(); + table()->SetServerCreditCards({card1}); + PaymentsCustomerData customer_data{/*customer_id=*/kCustomerDataId}; + table()->SetPaymentsCustomerData(&customer_data); + + // Create a different profile and a different card on the server. + AutofillProfile address2 = test::GetServerProfile2(); + AutofillWalletSpecifics profile_specifics2; + SetAutofillWalletSpecificsFromServerProfile(address2, &profile_specifics2); + CreditCard card2 = test::GetMaskedServerCardAmex(); + AutofillWalletSpecifics card_specifics2; + SetAutofillWalletSpecificsFromServerCard(card2, &card_specifics2); + AutofillWalletSpecifics customer_data_specifics; + SetAutofillWalletSpecificsFromPaymentsCustomerData(customer_data, + &customer_data_specifics); + + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); + StartSyncing({profile_specifics2, card_specifics2, customer_data_specifics}); + + // Only the server card should be present on the client. + EXPECT_THAT(GetAllLocalData(), + UnorderedElementsAre(EqualsSpecifics(profile_specifics2), + EqualsSpecifics(card_specifics2), + EqualsSpecifics(customer_data_specifics))); +} + +// Test that all field values for a card sent form the server are copied on the +// card on the client. +TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_NewPaymentsCustomerData) { + // Create one profile, one card and one customer data entry on the client. + AutofillProfile address = test::GetServerProfile(); + table()->SetServerProfiles({address}); + CreditCard card = test::GetMaskedServerCard(); + table()->SetServerCreditCards({card}); + PaymentsCustomerData customer_data1{/*customer_id=*/kCustomerDataId}; + table()->SetPaymentsCustomerData(&customer_data1); + + // Create a different customer data entry on the server. + AutofillWalletSpecifics profile_specifics; + SetAutofillWalletSpecificsFromServerProfile(address, &profile_specifics); + AutofillWalletSpecifics card_specifics; + SetAutofillWalletSpecificsFromServerCard(card, &card_specifics); + PaymentsCustomerData customer_data2{/*customer_id=*/kCustomerDataId2}; + AutofillWalletSpecifics customer_data_specifics2; + SetAutofillWalletSpecificsFromPaymentsCustomerData(customer_data2, + &customer_data_specifics2); + + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); + StartSyncing({profile_specifics, card_specifics, customer_data_specifics2}); + + // Only the server card should be present on the client. + EXPECT_THAT(GetAllLocalData(), + UnorderedElementsAre(EqualsSpecifics(profile_specifics), + EqualsSpecifics(card_specifics), + EqualsSpecifics(customer_data_specifics2))); +} + +// Tests that when the server sends no cards or address, the client should +// delete all it's existing data. +TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_NoWalletAddressOrCard) { + // Create one profile and one card on the client. + AutofillProfile local_profile = test::GetServerProfile(); + table()->SetServerProfiles({local_profile}); + CreditCard local_card = test::GetMaskedServerCard(); + table()->SetServerCreditCards({local_card}); + + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); + StartSyncing({}); + + EXPECT_TRUE(GetAllLocalData().empty()); +} + +// Test that when the server sends the same address and card as the client has, +// nothing changes on the client. +TEST_F(AutofillWalletSyncBridgeTest, + MergeSyncData_SameWalletAddressAndCardAndCustomerData) { + // Create one profile and one card on the client. + AutofillProfile profile = test::GetServerProfile(); + table()->SetServerProfiles({profile}); + CreditCard card = test::GetMaskedServerCard(); + table()->SetServerCreditCards({card}); + PaymentsCustomerData customer_data{/*customer_id=*/kCustomerDataId}; + table()->SetPaymentsCustomerData(&customer_data); + + // Create the same profile and card on the server. + AutofillWalletSpecifics profile_specifics; + SetAutofillWalletSpecificsFromServerProfile(profile, &profile_specifics); + AutofillWalletSpecifics card_specifics; + SetAutofillWalletSpecificsFromServerCard(card, &card_specifics); + AutofillWalletSpecifics customer_data_specifics; + SetAutofillWalletSpecificsFromPaymentsCustomerData(customer_data, + &customer_data_specifics); + + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); + StartSyncing({profile_specifics, card_specifics, customer_data_specifics}); + + EXPECT_THAT(GetAllLocalData(), + UnorderedElementsAre(EqualsSpecifics(profile_specifics), + EqualsSpecifics(card_specifics), + EqualsSpecifics(customer_data_specifics))); +} + +// Tests that when there are multiple changes happening at the same time, the +// data from the server is what the client ends up with, +TEST_F(AutofillWalletSyncBridgeTest, + MergeSyncData_AddRemoveAndPreserveWalletAddressAndCard) { + // Create two profile and one card on the client. + AutofillProfile profile = test::GetServerProfile(); + AutofillProfile profile2 = test::GetServerProfile2(); + table()->SetServerProfiles({profile, profile2}); + CreditCard card = test::GetMaskedServerCard(); + table()->SetServerCreditCards({card}); + + // Create one of the same profiles and a different card on the server. + AutofillWalletSpecifics profile_specifics; + SetAutofillWalletSpecificsFromServerProfile(profile, &profile_specifics); + // The Amex card has different values for the relevant fields. + CreditCard card2 = test::GetMaskedServerCardAmex(); + AutofillWalletSpecifics card_specifics; + SetAutofillWalletSpecificsFromServerCard(card, &card_specifics); + + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); + StartSyncing({profile_specifics, card_specifics}); + + // Make sure that the client only has the data from the server. + EXPECT_THAT(GetAllLocalData(), + UnorderedElementsAre(EqualsSpecifics(profile_specifics), + EqualsSpecifics(card_specifics))); +} + +// Test that all field values for a address sent form the server are copied on +// the address on the client. +TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_SetsAllWalletAddressData) { + // Create a profile to be synced from the server. + AutofillProfile profile = test::GetServerProfile(); + AutofillWalletSpecifics profile_specifics; + SetAutofillWalletSpecificsFromServerProfile(profile, &profile_specifics); + + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); + StartSyncing({profile_specifics}); + + EXPECT_THAT(GetAllLocalData(), + UnorderedElementsAre(EqualsSpecifics(profile_specifics))); + + std::vector<std::unique_ptr<AutofillProfile>> profiles; + table()->GetServerProfiles(&profiles); + ASSERT_EQ(1U, profiles.size()); + + // Make sure that all the data was set properly. + EXPECT_EQ(profile.GetRawInfo(NAME_FULL), profiles[0]->GetRawInfo(NAME_FULL)); + EXPECT_EQ(profile.GetRawInfo(COMPANY_NAME), + profiles[0]->GetRawInfo(COMPANY_NAME)); + EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS), + profiles[0]->GetRawInfo(ADDRESS_HOME_STREET_ADDRESS)); + EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_STATE), + profiles[0]->GetRawInfo(ADDRESS_HOME_STATE)); + EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_CITY), + profiles[0]->GetRawInfo(ADDRESS_HOME_CITY)); + EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY), + profiles[0]->GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY)); + EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_ZIP), + profiles[0]->GetRawInfo(ADDRESS_HOME_ZIP)); + EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_COUNTRY), + profiles[0]->GetRawInfo(ADDRESS_HOME_COUNTRY)); + EXPECT_EQ(profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER), + profiles[0]->GetRawInfo(PHONE_HOME_WHOLE_NUMBER)); + EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE), + profiles[0]->GetRawInfo(ADDRESS_HOME_SORTING_CODE)); + EXPECT_EQ(profile.language_code(), profiles[0]->language_code()); + + // Also make sure that those types are not empty, to exercice all the code + // paths. + EXPECT_FALSE(profile.GetRawInfo(NAME_FULL).empty()); + EXPECT_FALSE(profile.GetRawInfo(COMPANY_NAME).empty()); + EXPECT_FALSE(profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS).empty()); + EXPECT_FALSE(profile.GetRawInfo(ADDRESS_HOME_STATE).empty()); + EXPECT_FALSE(profile.GetRawInfo(ADDRESS_HOME_CITY).empty()); + EXPECT_FALSE(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY).empty()); + EXPECT_FALSE(profile.GetRawInfo(ADDRESS_HOME_ZIP).empty()); + EXPECT_FALSE(profile.GetRawInfo(ADDRESS_HOME_COUNTRY).empty()); + EXPECT_FALSE(profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER).empty()); + EXPECT_FALSE(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE).empty()); + EXPECT_FALSE(profile.language_code().empty()); +} + +// Test that all field values for a card sent form the server are copied on the +// card on the client. +TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_SetsAllWalletCardData) { + // Create a card to be synced from the server. + CreditCard card = test::GetMaskedServerCard(); + // Add this value type as it is not added by default but should be synced. + card.set_bank_name("The Bank"); + AutofillWalletSpecifics card_specifics; + SetAutofillWalletSpecificsFromServerCard(card, &card_specifics); + + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); + StartSyncing({card_specifics}); + + EXPECT_THAT(GetAllLocalData(), + UnorderedElementsAre(EqualsSpecifics(card_specifics))); + + std::vector<std::unique_ptr<CreditCard>> cards; + table()->GetServerCreditCards(&cards); + ASSERT_EQ(1U, cards.size()); + + // Make sure that all the data was set properly. + EXPECT_EQ(card.network(), cards[0]->network()); + EXPECT_EQ(card.LastFourDigits(), cards[0]->LastFourDigits()); + EXPECT_EQ(card.expiration_month(), cards[0]->expiration_month()); + EXPECT_EQ(card.expiration_year(), cards[0]->expiration_year()); + EXPECT_EQ(card.billing_address_id(), cards[0]->billing_address_id()); + EXPECT_EQ(card.card_type(), cards[0]->card_type()); + EXPECT_EQ(card.bank_name(), cards[0]->bank_name()); + + // Also make sure that those types are not empty, to exercice all the code + // paths. + EXPECT_FALSE(card.network().empty()); + EXPECT_FALSE(card.LastFourDigits().empty()); + EXPECT_NE(0, card.expiration_month()); + EXPECT_NE(0, card.expiration_year()); + EXPECT_FALSE(card.billing_address_id().empty()); + EXPECT_NE(CreditCard::CARD_TYPE_UNKNOWN, card.card_type()); + EXPECT_FALSE(card.bank_name().empty()); +} + +TEST_F(AutofillWalletSyncBridgeTest, LoadMetadataCalled) { + ModelTypeState model_type_state; + model_type_state.set_initial_sync_done(true); + EXPECT_TRUE(table()->UpdateModelTypeState(syncer::AUTOFILL_WALLET_DATA, + model_type_state)); + EXPECT_TRUE(table()->UpdateSyncMetadata(syncer::AUTOFILL_WALLET_DATA, "key", + EntityMetadata())); + + ResetProcessor(); + EXPECT_CALL(mock_processor(), ModelReadyToSync(MetadataBatchContains( + /*state=*/HasInitialSyncDone(), + /*entities=*/SizeIs(1)))); + ResetBridge(); +} + +TEST_F(AutofillWalletSyncBridgeTest, ApplyStopSyncChanges_ClearAllData) { + // Create one profile and one card on the client. + AutofillProfile local_profile = test::GetServerProfile(); + table()->SetServerProfiles({local_profile}); + CreditCard local_card = test::GetMaskedServerCard(); + table()->SetServerCreditCards({local_card}); + + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); + // Passing in a non-null metadata change list indicates to the bridge that + // sync is stopping because it was disabled. + bridge()->ApplyStopSyncChanges( + std::make_unique<syncer::InMemoryMetadataChangeList>()); + + EXPECT_TRUE(GetAllLocalData().empty()); +} + +TEST_F(AutofillWalletSyncBridgeTest, ApplyStopSyncChanges_KeepData) { + // Create one profile and one card on the client. + AutofillProfile local_profile = test::GetServerProfile(); + table()->SetServerProfiles({local_profile}); + CreditCard local_card = test::GetMaskedServerCard(); + table()->SetServerCreditCards({local_card}); + + // Passing in a non-null metadata change list indicates to the bridge that + // sync is stopping but the data type is not disabled. + bridge()->ApplyStopSyncChanges(/*delete_metadata_change_list=*/nullptr); + + EXPECT_FALSE(GetAllLocalData().empty()); +} + +class AutofillWalletEphemeralSyncBridgeTest + : public AutofillWalletSyncBridgeTest { + public: + AutofillWalletEphemeralSyncBridgeTest() {} + ~AutofillWalletEphemeralSyncBridgeTest() override {} + + bool UseFullSync() override { return false; } +}; + +// Tests that when the server sends no cards, the client should +// delete all it's existing data. +TEST_F(AutofillWalletEphemeralSyncBridgeTest, + MergeSyncData_NoWalletAddressOrCard) { + // Create one card on the client. + CreditCard local_card = test::GetMaskedServerCard(); + table()->SetServerCreditCards({local_card}); + + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); + StartSyncing({}); + + EXPECT_TRUE(GetAllLocalData().empty()); +} + +// Test that when the server sends the same card as the client has, nothing +// changes on the client. +TEST_F(AutofillWalletEphemeralSyncBridgeTest, MergeSyncData_SameWalletCard) { + // Create one card on the client. + CreditCard card = test::GetMaskedServerCard(); + table()->SetServerCreditCards({card}); + + // Create the same card on the server. + AutofillWalletSpecifics card_specifics; + SetAutofillWalletSpecificsFromServerCard(card, &card_specifics); + + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); + StartSyncing({card_specifics}); + + EXPECT_THAT(GetAllLocalData(), + UnorderedElementsAre(EqualsSpecifics(card_specifics))); +} + +// Tests that when a new wallet card is sent by the server, the client only +// keeps the new data. +TEST_F(AutofillWalletEphemeralSyncBridgeTest, MergeSyncData_NewWalletCard) { + // Create one card on the client. + CreditCard card1 = test::GetMaskedServerCard(); + table()->SetServerCreditCards({card1}); + PaymentsCustomerData customer_data{/*customer_id=*/kCustomerDataId}; + table()->SetPaymentsCustomerData(&customer_data); + + // Create a different card on the server. + CreditCard card2 = test::GetMaskedServerCardAmex(); + AutofillWalletSpecifics card_specifics2; + SetAutofillWalletSpecificsFromServerCard(card2, &card_specifics2); + AutofillWalletSpecifics customer_data_specifics; + SetAutofillWalletSpecificsFromPaymentsCustomerData(customer_data, + &customer_data_specifics); + + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); + StartSyncing({card_specifics2, customer_data_specifics}); + + // Only the server card should be present on the client. + EXPECT_THAT(GetAllLocalData(), + UnorderedElementsAre(EqualsSpecifics(card_specifics2), + EqualsSpecifics(customer_data_specifics))); +} + +// Tests that when a new wallet card and new wallet address are sent by the +// server, the client only keeps the new data. +TEST_F(AutofillWalletEphemeralSyncBridgeTest, + MergeSyncData_AddressesAreDropped) { + // Create one card on the client. + CreditCard card1 = test::GetMaskedServerCard(); + table()->SetServerCreditCards({card1}); + PaymentsCustomerData customer_data{/*customer_id=*/kCustomerDataId}; + table()->SetPaymentsCustomerData(&customer_data); + + // Create a new profile and a different card on the server. + AutofillProfile address = test::GetServerProfile(); + AutofillWalletSpecifics profile_specifics; + SetAutofillWalletSpecificsFromServerProfile(address, &profile_specifics); + CreditCard card2 = test::GetMaskedServerCardAmex(); + AutofillWalletSpecifics card_specifics2; + SetAutofillWalletSpecificsFromServerCard(card2, &card_specifics2); + AutofillWalletSpecifics customer_data_specifics; + SetAutofillWalletSpecificsFromPaymentsCustomerData(customer_data, + &customer_data_specifics); + + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); + StartSyncing({profile_specifics, card_specifics2, customer_data_specifics}); + + // Only the server card should be present on the client; the server profile is + // ignored. + EXPECT_THAT(GetAllLocalData(), + UnorderedElementsAre(EqualsSpecifics(card_specifics2), + EqualsSpecifics(customer_data_specifics))); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc index 10f35b38615..f13179aaf79 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc @@ -18,6 +18,7 @@ #include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/autofill/core/browser/webdata/autofill_webdata_backend.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" +#include "components/autofill/core/common/autofill_util.h" #include "components/sync/model/sync_error_factory.h" #include "components/sync/protocol/sync.pb.h" @@ -25,18 +26,14 @@ namespace autofill { namespace { -// The length of the GUIDs used for local autofill data. It is different than -// the length used for server autofill data. -const int kLocalGuidSize = 36; - -void* UserDataKey() { +void* AutofillWalletSyncableServiceUserDataKey() { // Use the address of a static so that COMDAT folding won't ever fold // with something else. static int user_data_key = 0; return reinterpret_cast<void*>(&user_data_key); } -const char* CardNetworkFromWalletCardType( +const char* CardNetworkFromAutofillWalletCardType( sync_pb::WalletMaskedCreditCard::WalletCardType type) { switch (type) { case sync_pb::WalletMaskedCreditCard::AMEX: @@ -61,7 +58,7 @@ const char* CardNetworkFromWalletCardType( } } -CreditCard::CardType CardTypeFromWalletCardClass( +CreditCard::CardType CardTypeFromAutofillWalletCardClass( sync_pb::WalletMaskedCreditCard::WalletCardClass card_class) { switch (card_class) { case sync_pb::WalletMaskedCreditCard::CREDIT: @@ -75,7 +72,7 @@ CreditCard::CardType CardTypeFromWalletCardClass( } } -CreditCard::ServerStatus ServerToLocalStatus( +CreditCard::ServerStatus ServerToLocalWalletCardStatus( sync_pb::WalletMaskedCreditCard::WalletCardStatus status) { switch (status) { case sync_pb::WalletMaskedCreditCard::VALID: @@ -87,12 +84,14 @@ CreditCard::ServerStatus ServerToLocalStatus( } } -CreditCard CardFromSpecifics(const sync_pb::WalletMaskedCreditCard& card) { +CreditCard CardFromWalletCardSpecifics( + const sync_pb::WalletMaskedCreditCard& card) { CreditCard result(CreditCard::MASKED_SERVER_CARD, card.id()); result.SetNumber(base::UTF8ToUTF16(card.last_four())); - result.SetServerStatus(ServerToLocalStatus(card.status())); - result.SetNetworkForMaskedCard(CardNetworkFromWalletCardType(card.type())); - result.set_card_type(CardTypeFromWalletCardClass(card.card_class())); + result.SetServerStatus(ServerToLocalWalletCardStatus(card.status())); + result.SetNetworkForMaskedCard( + CardNetworkFromAutofillWalletCardType(card.type())); + result.set_card_type(CardTypeFromAutofillWalletCardClass(card.card_class())); result.SetRawInfo(CREDIT_CARD_NAME_FULL, base::UTF8ToUTF16(card.name_on_card())); result.SetExpirationMonth(card.exp_month()); @@ -102,7 +101,7 @@ CreditCard CardFromSpecifics(const sync_pb::WalletMaskedCreditCard& card) { return result; } -AutofillProfile ProfileFromSpecifics( +AutofillProfile ProfileFromWalletCardSpecifics( const sync_pb::WalletPostalAddress& address) { AutofillProfile profile(AutofillProfile::SERVER_PROFILE, std::string()); @@ -140,6 +139,11 @@ AutofillProfile ProfileFromSpecifics( return profile; } +PaymentsCustomerData CustomerDataFromSyncSpecifics( + const sync_pb::PaymentsCustomerData& customer_data) { + return PaymentsCustomerData{/*customer_id=*/customer_data.id()}; +} + } // namespace // static @@ -245,8 +249,9 @@ void AutofillWalletSyncableService::CreateForWebDataServiceAndBackend( AutofillWebDataBackend* webdata_backend, const std::string& app_locale) { web_data_service->GetDBUserData()->SetUserData( - UserDataKey(), base::WrapUnique(new AutofillWalletSyncableService( - webdata_backend, app_locale))); + AutofillWalletSyncableServiceUserDataKey(), + base::WrapUnique( + new AutofillWalletSyncableService(webdata_backend, app_locale))); } // static @@ -254,7 +259,8 @@ AutofillWalletSyncableService* AutofillWalletSyncableService::FromWebDataService( AutofillWebDataService* web_data_service) { return static_cast<AutofillWalletSyncableService*>( - web_data_service->GetDBUserData()->GetUserData(UserDataKey())); + web_data_service->GetDBUserData()->GetUserData( + AutofillWalletSyncableServiceUserDataKey())); } void AutofillWalletSyncableService::InjectStartSyncFlare( @@ -263,10 +269,11 @@ void AutofillWalletSyncableService::InjectStartSyncFlare( } // static -void AutofillWalletSyncableService::PopulateWalletCardsAndAddresses( +void AutofillWalletSyncableService::PopulateWalletTypesFromSyncData( const syncer::SyncDataList& data_list, std::vector<CreditCard>* wallet_cards, - std::vector<AutofillProfile>* wallet_addresses) { + std::vector<AutofillProfile>* wallet_addresses, + std::vector<PaymentsCustomerData>* customer_data) { std::map<std::string, std::string> ids; for (const syncer::SyncData& data : data_list) { @@ -276,16 +283,20 @@ void AutofillWalletSyncableService::PopulateWalletCardsAndAddresses( switch (autofill_specifics.type()) { case sync_pb::AutofillWalletSpecifics::MASKED_CREDIT_CARD: wallet_cards->push_back( - CardFromSpecifics(autofill_specifics.masked_card())); + CardFromWalletCardSpecifics(autofill_specifics.masked_card())); break; case sync_pb::AutofillWalletSpecifics::POSTAL_ADDRESS: wallet_addresses->push_back( - ProfileFromSpecifics(autofill_specifics.address())); + ProfileFromWalletCardSpecifics(autofill_specifics.address())); // Map the sync billing address id to the profile's id. ids[autofill_specifics.address().id()] = wallet_addresses->back().server_id(); break; + case sync_pb::AutofillWalletSpecifics::CUSTOMER_DATA: + customer_data->push_back( + CustomerDataFromSyncSpecifics(autofill_specifics.customer_data())); + break; case sync_pb::AutofillWalletSpecifics::UNKNOWN: // Just ignore new entry types that the client doesn't know about. break; @@ -333,7 +344,9 @@ syncer::SyncMergeResult AutofillWalletSyncableService::SetSyncData( bool is_initial_data) { std::vector<CreditCard> wallet_cards; std::vector<AutofillProfile> wallet_addresses; - PopulateWalletCardsAndAddresses(data_list, &wallet_cards, &wallet_addresses); + std::vector<PaymentsCustomerData> customer_data; + PopulateWalletTypesFromSyncData(data_list, &wallet_cards, &wallet_addresses, + &customer_data); // Users can set billing address of the server credit card locally, but that // information does not propagate to either Chrome Sync or Google Payments @@ -365,6 +378,16 @@ syncer::SyncMergeResult AutofillWalletSyncableService::SetSyncData( merge_result.set_num_items_after_association( static_cast<int>(wallet_cards.size() + wallet_addresses.size())); + if (customer_data.empty()) { + // Clears the data only. + table->SetPaymentsCustomerData(nullptr); + } else { + // In case there were multiple entries (and there shouldn't!), we take the + // first entry in the vector. + DCHECK_EQ(1u, customer_data.size()); + table->SetPaymentsCustomerData(&customer_data.front()); + } + if (!is_initial_data) { UMA_HISTOGRAM_COUNTS_100("Autofill.WalletCardsAdded", cards_diff.items_added); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h index c27626c36fd..bcaa296bdd2 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h @@ -14,6 +14,7 @@ #include "base/threading/thread_checker.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/payments/payments_customer_data.h" #include "components/sync/model/syncable_service.h" namespace autofill { @@ -72,11 +73,13 @@ class AutofillWalletSyncableService CopyRelevantMetadataFromDisk_OverwriteOtherAddresses); FRIEND_TEST_ALL_PREFIXES( AutofillWalletSyncableServiceTest, - PopulateWalletCardsAndAddresses_BillingAddressIdTransfer); + PopulateWalletTypesFromSyncData_BillingAddressIdTransfer); FRIEND_TEST_ALL_PREFIXES(AutofillWalletSyncableServiceTest, CopyRelevantMetadataFromDisk_KeepUseStats); FRIEND_TEST_ALL_PREFIXES(AutofillWalletSyncableServiceTest, NewWalletCard); FRIEND_TEST_ALL_PREFIXES(AutofillWalletSyncableServiceTest, EmptyNameOnCard); + FRIEND_TEST_ALL_PREFIXES(AutofillWalletSyncableServiceTest, + PaymentsCustomerData); FRIEND_TEST_ALL_PREFIXES(AutofillWalletSyncableServiceTest, ComputeCardsDiff); FRIEND_TEST_ALL_PREFIXES(AutofillWalletSyncableServiceTest, ComputeAddressesDiff); @@ -102,12 +105,13 @@ class AutofillWalletSyncableService syncer::SyncMergeResult SetSyncData(const syncer::SyncDataList& data_list, bool is_initial_data); - // Populates the wallet cards and addresses from the sync data and uses the - // sync data to link the card to its billing address. - static void PopulateWalletCardsAndAddresses( + // Populates the wallet datatypes from the sync data and uses the sync data to + // link the card to its billing address. + static void PopulateWalletTypesFromSyncData( const syncer::SyncDataList& data_list, std::vector<CreditCard>* wallet_cards, - std::vector<AutofillProfile>* wallet_addresses); + std::vector<AutofillProfile>* wallet_addresses, + std::vector<PaymentsCustomerData>* customer_data); // Finds the copies of the same credit card from the server and on disk and // overwrites the server version with the use stats saved on disk, and the diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service_unittest.cc index c31ea73a9d5..2530bfcf151 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service_unittest.cc @@ -10,6 +10,7 @@ #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/payments/payments_customer_data.h" #include "components/autofill/core/browser/test_autofill_clock.h" #include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/sync/protocol/autofill_specifics.pb.h" @@ -52,6 +53,21 @@ syncer::SyncData CreateSyncDataForWalletAddress(const std::string& id) { return syncer::SyncData::CreateLocalData(id, id, specifics); } +syncer::SyncData CreateSyncDataForPaymentsCustomerData(const std::string& id) { + sync_pb::EntitySpecifics specifics; + + sync_pb::AutofillWalletSpecifics* wallet_specifics = + specifics.mutable_autofill_wallet(); + wallet_specifics->set_type( + sync_pb::AutofillWalletSpecifics_WalletInfoType:: + AutofillWalletSpecifics_WalletInfoType_CUSTOMER_DATA); + + sync_pb::PaymentsCustomerData* customer_data_specifics = + wallet_specifics->mutable_customer_data(); + customer_data_specifics->set_id(id); + return syncer::SyncData::CreateLocalData(id, id, specifics); +} + class TestAutofillTable : public AutofillTable { public: explicit TestAutofillTable(std::vector<CreditCard> cards_on_disk) @@ -77,9 +93,10 @@ class TestAutofillTable : public AutofillTable { // Verify that the link between a card and its billing address from sync is // present in the generated Autofill objects. TEST(AutofillWalletSyncableServiceTest, - PopulateWalletCardsAndAddresses_BillingAddressIdTransfer) { + PopulateWalletTypesFromSyncData_BillingAddressIdTransfer) { std::vector<CreditCard> wallet_cards; std::vector<AutofillProfile> wallet_addresses; + std::vector<PaymentsCustomerData> customer_data; syncer::SyncDataList data_list; // Create a Sync data for a card and its billing address. @@ -87,8 +104,8 @@ TEST(AutofillWalletSyncableServiceTest, data_list.push_back(CreateSyncDataForWalletCreditCard( "card1" /* id */, "1" /* billing_address_id */)); - AutofillWalletSyncableService::PopulateWalletCardsAndAddresses( - data_list, &wallet_cards, &wallet_addresses); + AutofillWalletSyncableService::PopulateWalletTypesFromSyncData( + data_list, &wallet_cards, &wallet_addresses, &customer_data); ASSERT_EQ(1U, wallet_cards.size()); ASSERT_EQ(1U, wallet_addresses.size()); @@ -206,6 +223,7 @@ TEST(AutofillWalletSyncableServiceTest, NewWalletCard) { std::vector<AutofillProfile> wallet_addresses; std::vector<CreditCard> wallet_cards; + std::vector<PaymentsCustomerData> customer_data; syncer::SyncDataList data_list; // Create a Sync data for a card and its billing address. @@ -213,8 +231,8 @@ TEST(AutofillWalletSyncableServiceTest, NewWalletCard) { data_list.push_back(CreateSyncDataForWalletCreditCard( "card1" /* id */, "1" /* billing_address_id */)); - AutofillWalletSyncableService::PopulateWalletCardsAndAddresses( - data_list, &wallet_cards, &wallet_addresses); + AutofillWalletSyncableService::PopulateWalletTypesFromSyncData( + data_list, &wallet_cards, &wallet_addresses, &customer_data); ASSERT_EQ(1U, wallet_cards.size()); @@ -227,14 +245,15 @@ TEST(AutofillWalletSyncableServiceTest, NewWalletCard) { TEST(AutofillWalletSyncableServiceTest, EmptyNameOnCard) { std::vector<CreditCard> wallet_cards; std::vector<AutofillProfile> wallet_addresses; + std::vector<PaymentsCustomerData> customer_data; syncer::SyncDataList data_list; // Create a Sync data for a card and its billing address. data_list.push_back(CreateSyncDataForWalletCreditCard( "card1" /* id */, "1" /* billing_address_id */)); - AutofillWalletSyncableService::PopulateWalletCardsAndAddresses( - data_list, &wallet_cards, &wallet_addresses); + AutofillWalletSyncableService::PopulateWalletTypesFromSyncData( + data_list, &wallet_cards, &wallet_addresses, &customer_data); ASSERT_EQ(1U, wallet_cards.size()); @@ -247,6 +266,23 @@ TEST(AutofillWalletSyncableServiceTest, EmptyNameOnCard) { wallet_cards.back().GetRawInfo(autofill::CREDIT_CARD_NAME_LAST).empty()); } +TEST(AutofillWalletSyncableServiceTest, PaymentsCustomerData) { + std::vector<CreditCard> wallet_cards; + std::vector<AutofillProfile> wallet_addresses; + std::vector<PaymentsCustomerData> customer_data; + syncer::SyncDataList data_list; + + // Create Sync data for Payments Customer data. + data_list.push_back( + CreateSyncDataForPaymentsCustomerData("deadbeef" /* id */)); + + AutofillWalletSyncableService::PopulateWalletTypesFromSyncData( + data_list, &wallet_cards, &wallet_addresses, &customer_data); + + // Make sure the Payments customer id is there. + EXPECT_EQ("deadbeef", customer_data.back().customer_id); +} + TEST(AutofillWalletSyncableServiceTest, ComputeCardsDiff) { // Some arbitrary cards for testing. CreditCard card0(CreditCard::MASKED_SERVER_CARD, "a"); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata.h index fc715a0aa31..3ae94e14cae 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata.h @@ -112,6 +112,13 @@ class AutofillWebData { const base::string16& full_number) = 0; virtual void MaskServerCreditCard(const std::string& id) = 0; + // Initiates the request for Payments customer data. The method + // OnWebDataServiceRequestDone of |consumer| gets called when the request is + // finished, with the customer data included in the argument |result|. The + // consumer owns the data. + virtual WebDataServiceBase::Handle GetPaymentsCustomerData( + WebDataServiceConsumer* consumer) = 0; + // Updates the metadata for a server card (masked or not). virtual void UpdateServerCardMetadata(const CreditCard& credit_card) = 0; diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc index d57b01c6b04..1a038008a9c 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc @@ -11,6 +11,7 @@ #include "components/autofill/core/browser/autofill_country.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/payments/payments_customer_data.h" #include "components/autofill/core/browser/webdata/autofill_change.h" #include "components/autofill/core/browser/webdata/autofill_entry.h" #include "components/autofill/core/browser/webdata/autofill_table.h" @@ -82,8 +83,8 @@ void AutofillWebDataBackendImpl::NotifyThatSyncHasStarted( return; // UI sequence notification. - ui_task_runner_->PostTask(FROM_HERE, - base::Bind(on_sync_started_callback_, model_type)); + ui_task_runner_->PostTask( + FROM_HERE, base::BindOnce(on_sync_started_callback_, model_type)); } base::SupportsUserData* AutofillWebDataBackendImpl::GetDBUserData() { @@ -419,6 +420,15 @@ WebDatabase::State AutofillWebDataBackendImpl::UpdateServerAddressMetadata( return WebDatabase::COMMIT_NEEDED; } +std::unique_ptr<WDTypedResult> +AutofillWebDataBackendImpl::GetPaymentsCustomerData(WebDatabase* db) { + DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); + std::unique_ptr<PaymentsCustomerData> customer_data; + AutofillTable::FromWebDatabase(db)->GetPaymentsCustomerData(&customer_data); + return std::make_unique<WDResult<std::unique_ptr<PaymentsCustomerData>>>( + AUTOFILL_CUSTOMERDATA_RESULT, std::move(customer_data)); +} + WebDatabase::State AutofillWebDataBackendImpl::ClearAllServerData( WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h index 91c379f30d2..070287977d2 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h @@ -163,6 +163,9 @@ class AutofillWebDataBackendImpl WebDatabase::State UpdateServerAddressMetadata(const AutofillProfile& profile, WebDatabase* db); + // Returns the PaymentsCustomerData from the database. + std::unique_ptr<WDTypedResult> GetPaymentsCustomerData(WebDatabase* db); + WebDatabase::State ClearAllServerData(WebDatabase* db); WebDatabase::State ClearAllLocalData(WebDatabase* db); @@ -214,7 +217,7 @@ class AutofillWebDataBackendImpl WebDatabase::State RemoveExpiredFormElementsImpl(WebDatabase* db); - base::ObserverList<AutofillWebDataServiceObserverOnDBSequence> + base::ObserverList<AutofillWebDataServiceObserverOnDBSequence>::Unchecked db_observer_list_; // WebDatabaseBackend allows direct access to DB. diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc index 4d9db9dd58b..dd40364ed89 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc @@ -67,7 +67,7 @@ void AutofillWebDataService::ShutdownOnUISequence() { weak_ptr_factory_.InvalidateWeakPtrs(); db_task_runner_->PostTask( FROM_HERE, - Bind(&AutofillWebDataBackendImpl::ResetUserData, autofill_backend_)); + BindOnce(&AutofillWebDataBackendImpl::ResetUserData, autofill_backend_)); WebDataServiceBase::ShutdownOnUISequence(); } @@ -213,6 +213,15 @@ void AutofillWebDataService::MaskServerCreditCard(const std::string& id) { autofill_backend_, id)); } +WebDataServiceBase::Handle AutofillWebDataService::GetPaymentsCustomerData( + WebDataServiceConsumer* consumer) { + return wdbs_->ScheduleDBTaskWithResult( + FROM_HERE, + Bind(&AutofillWebDataBackendImpl::GetPaymentsCustomerData, + autofill_backend_), + consumer); +} + void AutofillWebDataService::ClearAllServerData() { wdbs_->ScheduleDBTask( FROM_HERE, @@ -298,7 +307,8 @@ base::SupportsUserData* AutofillWebDataService::GetDBUserData() { void AutofillWebDataService::GetAutofillBackend( const base::Callback<void(AutofillWebDataBackend*)>& callback) { db_task_runner_->PostTask( - FROM_HERE, base::Bind(callback, base::RetainedRef(autofill_backend_))); + FROM_HERE, + base::BindOnce(callback, base::RetainedRef(autofill_backend_))); } base::SingleThreadTaskRunner* AutofillWebDataService::GetDBTaskRunner() { diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h index 8b26dc1c8ad..a1db37c055a 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h @@ -98,6 +98,10 @@ class AutofillWebDataService : public AutofillWebData, const base::string16& full_number) override; void MaskServerCreditCard(const std::string& id) override; + // PaymentsCustomerData. + WebDataServiceBase::Handle GetPaymentsCustomerData( + WebDataServiceConsumer* consumer) override; + void ClearAllServerData(); void ClearAllLocalData(); @@ -145,7 +149,7 @@ class AutofillWebDataService : public AutofillWebData, } private: - base::ObserverList<AutofillWebDataServiceObserverOnUISequence> + base::ObserverList<AutofillWebDataServiceObserverOnUISequence>::Unchecked ui_observer_list_; // The task runner that this class uses for UI tasks. diff --git a/chromium/components/autofill/core/browser/webdata/web_data_model_type_controller.cc b/chromium/components/autofill/core/browser/webdata/web_data_model_type_controller.cc deleted file mode 100644 index d21981e122e..00000000000 --- a/chromium/components/autofill/core/browser/webdata/web_data_model_type_controller.cc +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2017 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 "components/autofill/core/browser/webdata/web_data_model_type_controller.h" - -#include "base/bind.h" -#include "base/bind_helpers.h" - -using syncer::ModelType; -using syncer::ModelTypeController; -using syncer::SyncClient; - -namespace autofill { - -WebDataModelTypeController::WebDataModelTypeController( - ModelType type, - SyncClient* sync_client, - const scoped_refptr<base::SingleThreadTaskRunner>& model_thread, - const scoped_refptr<AutofillWebDataService>& web_data_service, - const DelegateFromWebData& delegate_from_web_data) - : ModelTypeController(type, sync_client, model_thread), - web_data_service_(web_data_service), - delegate_from_web_data_(delegate_from_web_data) {} - -WebDataModelTypeController::~WebDataModelTypeController() {} - -ModelTypeController::DelegateProvider -WebDataModelTypeController::GetDelegateProvider() { - // As opposed to the default implementation, get the delegate on demand, the - // web data service requires us to be on the model thread. - return base::Bind(delegate_from_web_data_, - base::RetainedRef(web_data_service_)); -} - -} // namespace autofill diff --git a/chromium/components/autofill/core/browser/webdata/web_data_model_type_controller.h b/chromium/components/autofill/core/browser/webdata/web_data_model_type_controller.h deleted file mode 100644 index 1a80c1e7be1..00000000000 --- a/chromium/components/autofill/core/browser/webdata/web_data_model_type_controller.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2017 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. - -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_WEB_DATA_MODEL_TYPE_CONTROLLER_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_WEB_DATA_MODEL_TYPE_CONTROLLER_H_ - -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "components/autofill/core/browser/webdata/autofill_webdata_service.h" -#include "components/sync/driver/model_type_controller.h" - -namespace syncer { -class ModelTypeControllerDelegate; -} // namespace syncer - -namespace autofill { - -class WebDataModelTypeController : public syncer::ModelTypeController { - public: - using DelegateFromWebData = - base::Callback<base::WeakPtr<syncer::ModelTypeControllerDelegate>( - AutofillWebDataService*)>; - - WebDataModelTypeController( - syncer::ModelType type, - syncer::SyncClient* sync_client, - const scoped_refptr<base::SingleThreadTaskRunner>& model_thread, - const scoped_refptr<AutofillWebDataService>& web_data_service, - const DelegateFromWebData& delegate_from_web_data); - - ~WebDataModelTypeController() override; - - private: - // syncer::ModelTypeController implementation. - syncer::ModelTypeController::DelegateProvider GetDelegateProvider() override; - - // A reference to the AutofillWebDataService for this controller. - scoped_refptr<AutofillWebDataService> web_data_service_; - - // How to grab the correct delegate from a web data. - DelegateFromWebData delegate_from_web_data_; - - DISALLOW_COPY_AND_ASSIGN(WebDataModelTypeController); -}; - -} // namespace autofill - -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_WEB_DATA_MODEL_TYPE_CONTROLLER_H_ diff --git a/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc b/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc index 9058c7eeccc..97f8650618b 100644 --- a/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc @@ -16,8 +16,8 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/synchronization/waitable_event.h" -#include "base/task_scheduler/post_task.h" -#include "base/task_scheduler/task_scheduler.h" +#include "base/task/post_task.h" +#include "base/task/task_scheduler/task_scheduler.h" #include "base/test/scoped_task_environment.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" @@ -151,7 +151,7 @@ class WebDataServiceAutofillTest : public WebDataServiceTest { AutofillWebDataServiceObserverOnDBSequence*) = &AutofillWebDataService::AddObserver; wds_->GetDBTaskRunner()->PostTask( - FROM_HERE, base::Bind(add_observer_func, wds_, &observer_)); + FROM_HERE, base::BindOnce(add_observer_func, wds_, &observer_)); base::TaskScheduler::GetInstance()->FlushForTesting(); } @@ -160,7 +160,7 @@ class WebDataServiceAutofillTest : public WebDataServiceTest { AutofillWebDataServiceObserverOnDBSequence*) = &AutofillWebDataService::RemoveObserver; wds_->GetDBTaskRunner()->PostTask( - FROM_HERE, base::Bind(remove_observer_func, wds_, &observer_)); + FROM_HERE, base::BindOnce(remove_observer_func, wds_, &observer_)); WebDataServiceTest::TearDown(); } diff --git a/chromium/components/autofill/core/common/BUILD.gn b/chromium/components/autofill/core/common/BUILD.gn index 32aa82cca98..2fc6a1f2c95 100644 --- a/chromium/components/autofill/core/common/BUILD.gn +++ b/chromium/components/autofill/core/common/BUILD.gn @@ -1,8 +1,9 @@ # Copyright 2014 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. +import("//build/config/jumbo.gni") -static_library("common") { +jumbo_static_library("common") { sources = [ "autofill_clock.cc", "autofill_clock.h", @@ -14,8 +15,8 @@ static_library("common") { "autofill_features.h", "autofill_l10n_util.cc", "autofill_l10n_util.h", - "autofill_pref_names.cc", - "autofill_pref_names.h", + "autofill_prefs.cc", + "autofill_prefs.h", "autofill_regex_constants.cc", "autofill_regex_constants.h", "autofill_regexes.cc", @@ -52,16 +53,14 @@ static_library("common") { deps = [ "//base", "//base:i18n", + "//components/pref_registry", + "//components/prefs", "//components/variations", "//ui/base", "//ui/gfx/geometry", "//url", ] - if (is_android) { - # deps += [ 'autofill_jni_headers' ] TODO(GYP) - } - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] } @@ -69,6 +68,7 @@ source_set("unit_tests") { testonly = true sources = [ "autofill_l10n_util_unittest.cc", + "autofill_prefs_unittest.cc", "autofill_regexes_unittest.cc", "autofill_util_unittest.cc", "form_data_unittest.cc", @@ -82,6 +82,9 @@ source_set("unit_tests") { "//base", "//base:i18n", "//base/test:test_support", + "//components/pref_registry", + "//components/prefs", + "//components/prefs:test_support", "//testing/gmock", "//testing/gtest", "//url", diff --git a/chromium/components/autofill/core/common/autofill_features.cc b/chromium/components/autofill/core/common/autofill_features.cc index 7534892decf..e61fee0bb26 100644 --- a/chromium/components/autofill/core/common/autofill_features.cc +++ b/chromium/components/autofill/core/common/autofill_features.cc @@ -4,6 +4,20 @@ #include "components/autofill/core/common/autofill_features.h" +#include "base/command_line.h" +#include "base/feature_list.h" +#include "base/metrics/field_trial_params.h" +#include "base/strings/string16.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" +#include "components/autofill/core/common/autofill_prefs.h" +#include "components/autofill/core/common/autofill_switches.h" +#include "components/prefs/pref_service.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/ui_base_features.h" + namespace autofill { namespace features { @@ -12,11 +26,32 @@ namespace features { const base::Feature kAutofillAddressNormalizer{ "AutofillAddressNormalizer", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kAutofillAlwaysFillAddresses{ + "AlwaysFillAddresses", base::FEATURE_ENABLED_BY_DEFAULT}; + // Controls the use of GET (instead of POST) to fetch cacheable autofill query // responses. const base::Feature kAutofillCacheQueryResponses{ "AutofillCacheQueryResponses", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kAutofillCreateDataForTest{ + "AutofillCreateDataForTest", base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kAutofillCreditCardAblationExperiment{ + "AutofillCreditCardAblationExperiment", base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kAutofillCreditCardAssist{ + "AutofillCreditCardAssist", base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kAutofillCreditCardLocalCardMigration{ + "AutofillCreditCardLocalCardMigration", base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kAutofillDeleteDisusedAddresses{ + "AutofillDeleteDisusedAddresses", base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kAutofillDeleteDisusedCreditCards{ + "AutofillDeleteDisusedCreditCards", base::FEATURE_DISABLED_BY_DEFAULT}; + // Controls whether the credit card downstream keyboard accessory shows // the Google Pay logo animation on iOS. const base::Feature kAutofillDownstreamUseGooglePayBrandingOniOS{ @@ -32,28 +67,19 @@ const base::Feature kAutofillDynamicForms{"AutofillDynamicForms", const base::Feature kAutofillEnableAccountWalletStorage{ "AutofillEnableAccountWalletStorage", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kAutofillEnableCompanyName{ + "AutofillEnableCompanyName", base::FEATURE_ENABLED_BY_DEFAULT}; + // Controls whether the server credit cards are offered to be filled and // uploaded to Google Pay if the sync service is in auth error. const base::Feature kAutofillEnablePaymentsInteractionsOnAuthError{ "AutofillDontOfferServerCardsOnAuthError", base::FEATURE_DISABLED_BY_DEFAULT}; -// Controls whether Autofill should fill fields previously filled by the -// website. -const base::Feature kAutofillPrefilledFields{"AutofillPrefilledFields", - base::FEATURE_ENABLED_BY_DEFAULT}; - -// Controls whether autofill suggestions are filtered by field values previously -// filled by website. -const base::Feature kAutofillShowAllSuggestionsOnPrefilledForms{ - "AutofillShowAllSuggestionsOnPrefilledForms", - base::FEATURE_DISABLED_BY_DEFAULT}; - -// Controls whether Autofill should rationalize repeated server type -// predictions. -const base::Feature kAutofillRationalizeRepeatedServerPredictions{ - "kAutofillRationalizeRepeatedServerPredictions", - base::FEATURE_ENABLED_BY_DEFAULT}; +// When enabled, no local copy of server card will be saved when upload +// succeeds. +const base::Feature kAutofillNoLocalSaveOnUploadSuccess{ + "AutofillNoLocalSaveOnUploadSuccess", base::FEATURE_DISABLED_BY_DEFAULT}; // Controls whether or not a minimum number of fields is required before // heuristic field type prediction is run for a form. @@ -73,10 +99,43 @@ const base::Feature kAutofillEnforceMinRequiredFieldsForUpload{ "AutofillEnforceMinRequiredFieldsForUpload", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kAutofillExpandedPopupViews{ + "AutofillExpandedPopupViews", base::FEATURE_DISABLED_BY_DEFAULT}; + +// When enabled, gets payment identity from sync service instead of +// identity manager. +const base::Feature kAutofillGetPaymentsIdentityFromSync{ + "AutofillGetPaymentsIdentityFromSync", base::FEATURE_DISABLED_BY_DEFAULT}; + +// When enabled, the local card migration dialog will show the progress +// and result of the migration after starting the migration. When disabled, +// there is no feedback for the migration. +const base::Feature kAutofillLocalCardMigrationShowFeedback{ + "AutofillLocalCardMigrationShowFeedback", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Controls whether the manual fill fallback will be present. const base::Feature kAutofillManualFallback{"AutofillManualFallback", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kAutofillPreferServerNamePredictions{ + "AutofillPreferServerNamePredictions", base::FEATURE_DISABLED_BY_DEFAULT}; + +// Controls whether Autofill should fill fields previously filled by the +// website. +const base::Feature kAutofillPrefilledFields{"AutofillPrefilledFields", + base::FEATURE_ENABLED_BY_DEFAULT}; + +const base::Feature kAutofillRationalizeFieldTypePredictions{ + "AutofillRationalizeFieldTypePredictions", + base::FEATURE_ENABLED_BY_DEFAULT}; + +// Controls whether Autofill should rationalize repeated server type +// predictions. +const base::Feature kAutofillRationalizeRepeatedServerPredictions{ + "kAutofillRationalizeRepeatedServerPredictions", + base::FEATURE_ENABLED_BY_DEFAULT}; + // Controls whether Full Server credit cards should be reset when the sync // service is in an auth error state. const base::Feature kAutofillResetFullServerCardsOnAuthError{ @@ -90,6 +149,18 @@ const base::Feature kAutofillRestrictUnownedFieldsToFormlessCheckout{ "AutofillRestrictUnownedFieldsToFormlessCheckout", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kAutofillSaveCardDialogUnlabeledExpirationDate{ + "AutofillSaveCardDialogUnlabeledExpirationDate", + base::FEATURE_ENABLED_BY_DEFAULT}; + +// When enabled, a sign in promo will show up right after the user +// saves a card locally. This also introduces a "Manage Cards" bubble. +const base::Feature kAutofillSaveCardSignInAfterLocalSave{ + "AutofillSaveCardSignInAfterLocalSave", base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kAutofillScanCardholderName{ + "AutofillScanCardholderName", base::FEATURE_DISABLED_BY_DEFAULT}; + // Controls whether experiment ids should be sent through // Google Payments RPCs or not. const base::Feature kAutofillSendExperimentIdsInPaymentsRPCs{ @@ -103,11 +174,26 @@ const base::Feature kAutofillSendOnlyCountryInGetUploadDetails{ "AutofillSendOnlyCountryInGetUploadDetails", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enables or Disables (mostly for hermetic testing) autofill server +// communication. The URL of the autofill server can further be controlled via +// the autofill-server-url param. The given URL should specify the complete +// autofill server API url up to the parent "directory" of the "query" and +// "upload" resources. +// i.e., https://other.autofill.server:port/tbproxy/af/ +const base::Feature kAutofillServerCommunication{ + "kAutofillServerCommunication", base::FEATURE_ENABLED_BY_DEFAULT}; + +// Controls whether autofill suggestions are filtered by field values previously +// filled by website. +const base::Feature kAutofillShowAllSuggestionsOnPrefilledForms{ + "AutofillShowAllSuggestionsOnPrefilledForms", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Controls whether we show warnings in the Dev console for misused autocomplete // types. const base::Feature kAutofillShowAutocompleteConsoleWarnings{ "AutofillShowAutocompleteConsoleWarnings", - base::FEATURE_ENABLED_BY_DEFAULT}; + base::FEATURE_DISABLED_BY_DEFAULT}; // Controls attaching the autofill type predictions to their respective // element in the DOM. @@ -119,6 +205,29 @@ const base::Feature kAutofillShowTypePredictions{ const base::Feature kAutofillSkipComparingInferredLabels{ "AutofillSkipComparingInferredLabels", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kAutofillSuggestInvalidProfileData{ + "AutofillSuggestInvalidProfileData", base::FEATURE_ENABLED_BY_DEFAULT}; + +const base::Feature kAutofillSuppressDisusedAddresses{ + "AutofillSuppressDisusedAddresses", base::FEATURE_ENABLED_BY_DEFAULT}; + +const base::Feature kAutofillSuppressDisusedCreditCards{ + "AutofillSuppressDisusedCreditCards", base::FEATURE_ENABLED_BY_DEFAULT}; + +const base::Feature kAutofillUpstream{"AutofillUpstream", + base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kAutofillUpstreamAllowAllEmailDomains{ + "AutofillUpstreamAllowAllEmailDomains", base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kAutofillUpstreamAlwaysRequestCardholderName{ + "AutofillUpstreamAlwaysRequestCardholderName", + base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kAutofillUpstreamBlankCardholderNameField{ + "AutofillUpstreamBlankCardholderNameField", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Controls whether ELO cards should be uploaded to Google Payments. const base::Feature kAutofillUpstreamDisallowElo{ "AutofillUpstreamDisallowElo", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -127,20 +236,137 @@ const base::Feature kAutofillUpstreamDisallowElo{ const base::Feature kAutofillUpstreamDisallowJcb{ "AutofillUpstreamDisallowJcb", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kAutofillUpstreamEditableCardholderName{ + "AutofillUpstreamEditableCardholderName", + base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kAutofillUpstreamSendPanFirstSix{ + "AutofillUpstreamSendPanFirstSix", base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kAutofillUpstreamUpdatePromptExplanation{ + "AutofillUpstreamUpdatePromptExplanation", + base::FEATURE_ENABLED_BY_DEFAULT}; + // Controls whether the credit card upload bubble shows the Google Pay logo and // a shorter "Save card?" header message on mobile. const base::Feature kAutofillUpstreamUseGooglePayBrandingOnMobile{ "AutofillUpstreamUseGooglePayOnAndroidBranding", base::FEATURE_ENABLED_BY_DEFAULT}; +// Controls whether the PaymentsCustomerData is used to make requests to +// Google Payments. +const base::Feature kAutofillUsePaymentsCustomerData{ + "AutofillUsePaymentsCustomerData", base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kAutofillVoteUsingInvalidProfileData{ + "AutofillVoteUsingInvalidProfileData", base::FEATURE_ENABLED_BY_DEFAULT}; + // Controls whether password generation is offered automatically on fields -// percieved as eligible for generation. +// perceived as eligible for generation. +#if defined(OS_ANDROID) const base::Feature kAutomaticPasswordGeneration = { "AutomaticPasswordGeneration", base::FEATURE_DISABLED_BY_DEFAULT}; +#else +const base::Feature kAutomaticPasswordGeneration = { + "AutomaticPasswordGeneration", base::FEATURE_ENABLED_BY_DEFAULT}; +#endif // Controls whether or not the autofill UI triggers on a single click. const base::Feature kSingleClickAutofill{"SingleClickAutofill", base::FEATURE_ENABLED_BY_DEFAULT}; +const char kAutofillLocalCardMigrationCloseButtonDelay[] = + "show_close_migration_dialog_button_delay"; + +const char kAutofillCreditCardLocalCardMigrationParameterName[] = "variant"; + +const char kAutofillCreditCardLocalCardMigrationParameterWithoutSettingsPage[] = + "without-settings-page"; + +const char kCreditCardSigninPromoImpressionLimitParamKey[] = "impression_limit"; + +#if defined(OS_MACOSX) +const base::Feature kMacViewsAutofillPopup{"MacViewsAutofillPopup", + base::FEATURE_ENABLED_BY_DEFAULT}; +#endif // defined(OS_MACOSX) + +bool IsAutofillCreditCardAssistEnabled() { +#if !defined(OS_ANDROID) && !defined(OS_IOS) + return false; +#else + return base::FeatureList::IsEnabled(kAutofillCreditCardAssist); +#endif +} + +LocalCardMigrationExperimentalFlag GetLocalCardMigrationExperimentalFlag() { + if (!base::FeatureList::IsEnabled(kAutofillCreditCardLocalCardMigration)) + return LocalCardMigrationExperimentalFlag::kMigrationDisabled; + + std::string param = base::GetFieldTrialParamValueByFeature( + kAutofillCreditCardLocalCardMigration, + kAutofillCreditCardLocalCardMigrationParameterName); + + if (param == + kAutofillCreditCardLocalCardMigrationParameterWithoutSettingsPage) { + return LocalCardMigrationExperimentalFlag::kMigrationWithoutSettingsPage; + } + return LocalCardMigrationExperimentalFlag::kMigrationIncludeSettingsPage; +} + +base::TimeDelta GetTimeoutForMigrationPromptFeedbackCloseButton() { + constexpr int show_close_button_timeout_in_seconds = 5; + return base::TimeDelta::FromSeconds(base::GetFieldTrialParamByFeatureAsInt( + kAutofillCreditCardLocalCardMigration, + kAutofillLocalCardMigrationCloseButtonDelay, + show_close_button_timeout_in_seconds)); +} + +bool IsAutofillUpstreamAlwaysRequestCardholderNameExperimentEnabled() { + return base::FeatureList::IsEnabled( + features::kAutofillUpstreamAlwaysRequestCardholderName); +} + +bool IsAutofillUpstreamBlankCardholderNameFieldExperimentEnabled() { + return base::FeatureList::IsEnabled( + features::kAutofillUpstreamBlankCardholderNameField); +} + +bool IsAutofillUpstreamEditableCardholderNameExperimentEnabled() { + return base::FeatureList::IsEnabled(kAutofillUpstreamEditableCardholderName); +} + +bool IsAutofillUpstreamSendPanFirstSixExperimentEnabled() { + return base::FeatureList::IsEnabled(kAutofillUpstreamSendPanFirstSix); +} + +bool IsAutofillUpstreamUpdatePromptExplanationExperimentEnabled() { + return base::FeatureList::IsEnabled(kAutofillUpstreamUpdatePromptExplanation); +} + +#if defined(OS_MACOSX) +bool IsMacViewsAutofillPopupExperimentEnabled() { +#if BUILDFLAG(MAC_VIEWS_BROWSER) + if (!::features::IsViewsBrowserCocoa()) + return true; +#endif + + return base::FeatureList::IsEnabled(kMacViewsAutofillPopup); +} +#endif // defined(OS_MACOSX) + +bool ShouldUseNativeViews() { +#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) + return base::FeatureList::IsEnabled(kAutofillExpandedPopupViews) || + base::FeatureList::IsEnabled(::features::kExperimentalUi); +#else + return false; +#endif +} + +bool IsAutofillSaveCardDialogUnlabeledExpirationDateEnabled() { + return base::FeatureList::IsEnabled( + kAutofillSaveCardDialogUnlabeledExpirationDate); +} + } // namespace features } // namespace autofill diff --git a/chromium/components/autofill/core/common/autofill_features.h b/chromium/components/autofill/core/common/autofill_features.h index 7da46eb4253..c708629722a 100644 --- a/chromium/components/autofill/core/common/autofill_features.h +++ b/chromium/components/autofill/core/common/autofill_features.h @@ -5,38 +5,158 @@ #ifndef COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_FEATURES_H_ #define COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_FEATURES_H_ +#include <string> + #include "base/feature_list.h" +#include "base/strings/string16.h" +#include "build/build_config.h" + +class PrefService; + +namespace base { +struct Feature; +} namespace autofill { namespace features { // All features in alphabetical order. extern const base::Feature kAutofillAddressNormalizer; +extern const base::Feature kAutofillAlwaysFillAddresses; extern const base::Feature kAutofillCacheQueryResponses; +extern const base::Feature kAutofillCreateDataForTest; +extern const base::Feature kAutofillCreditCardAblationExperiment; +extern const base::Feature kAutofillCreditCardAssist; +extern const base::Feature kAutofillCreditCardLocalCardMigration; +extern const base::Feature kAutofillDeleteDisusedAddresses; +extern const base::Feature kAutofillDeleteDisusedCreditCards; extern const base::Feature kAutofillDownstreamUseGooglePayBrandingOniOS; extern const base::Feature kAutofillDynamicForms; extern const base::Feature kAutofillEnableAccountWalletStorage; +extern const base::Feature kAutofillEnableCompanyName; extern const base::Feature kAutofillEnablePaymentsInteractionsOnAuthError; extern const base::Feature kAutofillEnforceMinRequiredFieldsForHeuristics; extern const base::Feature kAutofillEnforceMinRequiredFieldsForQuery; extern const base::Feature kAutofillEnforceMinRequiredFieldsForUpload; +extern const base::Feature kAutofillExpandedPopupViews; +extern const base::Feature kAutofillGetPaymentsIdentityFromSync; +extern const base::Feature kAutofillLocalCardMigrationShowFeedback; extern const base::Feature kAutofillManualFallback; +extern const base::Feature kAutofillPreferServerNamePredictions; +extern const base::Feature kAutofillNoLocalSaveOnUploadSuccess; extern const base::Feature kAutofillPrefilledFields; +extern const base::Feature kAutofillRationalizeFieldTypePredictions; +extern const base::Feature kAutofillRationalizeRepeatedServerPredictions; extern const base::Feature kAutofillResetFullServerCardsOnAuthError; extern const base::Feature kAutofillRestrictUnownedFieldsToFormlessCheckout; +extern const base::Feature kAutofillSaveCardDialogUnlabeledExpirationDate; +extern const base::Feature kAutofillSaveCardSignInAfterLocalSave; +extern const base::Feature kAutofillScanCardholderName; extern const base::Feature kAutofillSendExperimentIdsInPaymentsRPCs; extern const base::Feature kAutofillSendOnlyCountryInGetUploadDetails; +extern const base::Feature kAutofillServerCommunication; extern const base::Feature kAutofillShowAllSuggestionsOnPrefilledForms; extern const base::Feature kAutofillShowAutocompleteConsoleWarnings; extern const base::Feature kAutofillShowTypePredictions; extern const base::Feature kAutofillSkipComparingInferredLabels; +extern const base::Feature kAutofillSuggestInvalidProfileData; +extern const base::Feature kAutofillSuppressDisusedAddresses; +extern const base::Feature kAutofillSuppressDisusedCreditCards; +extern const base::Feature kAutofillUpstream; +extern const base::Feature kAutofillUpstreamAllowAllEmailDomains; +extern const base::Feature kAutofillUpstreamAlwaysRequestCardholderName; +extern const base::Feature kAutofillUpstreamBlankCardholderNameField; extern const base::Feature kAutofillUpstreamDisallowElo; extern const base::Feature kAutofillUpstreamDisallowJcb; +extern const base::Feature kAutofillUpstreamEditableCardholderName; +extern const base::Feature kAutofillUpstreamSendPanFirstSix; +extern const base::Feature kAutofillUpstreamUpdatePromptExplanation; extern const base::Feature kAutofillUpstreamUseGooglePayBrandingOnMobile; +extern const base::Feature kAutofillUsePaymentsCustomerData; +extern const base::Feature kAutofillVoteUsingInvalidProfileData; extern const base::Feature kAutomaticPasswordGeneration; extern const base::Feature kSingleClickAutofill; -extern const base::Feature kAutofillPrefilledFields; -extern const base::Feature kAutofillRationalizeRepeatedServerPredictions; +extern const base::Feature kAutofillCreditCardLocalCardMigration; +extern const char kAutofillCreditCardLastUsedDateShowExpirationDateKey[]; +extern const char kAutofillLocalCardMigrationCloseButtonDelay[]; +extern const char kAutofillCreditCardLocalCardMigrationParameterName[]; +extern const char kAutofillUpstreamMaxMinutesSinceAutofillProfileUseKey[]; +extern const char kCreditCardSigninPromoImpressionLimitParamKey[]; +extern const char + kAutofillCreditCardLocalCardMigrationParameterWithoutSettingsPage[]; + +#if defined(OS_MACOSX) +extern const base::Feature kMacViewsAutofillPopup; +#endif // defined(OS_MACOSX) + +// Returns whether the Autofill credit card assist infobar should be shown. +bool IsAutofillCreditCardAssistEnabled(); + +// Enum for local card migration experimental flag states. +enum class LocalCardMigrationExperimentalFlag { + // Local card migration disabled. + kMigrationDisabled, + // Only migrate local cards when user submits form. + kMigrationWithoutSettingsPage, + // Migrate both on submitted form and from settings page. + kMigrationIncludeSettingsPage, +}; + +// Returns kMigrationDisabled if no experimental behavior is enabled for +// kAutofillCreditCardLocalCardMigration; Return kMigrationIncludeSettingsPage +// if user enables the local card migration and does not exclude the settings +// page. Return kMigrationWithoutSettingsPage if user chooses to exclude the +// settings page migration. +LocalCardMigrationExperimentalFlag GetLocalCardMigrationExperimentalFlag(); + +// Returns the time delay for the local card migration dialog to show the close +// button. +base::TimeDelta GetTimeoutForMigrationPromptFeedbackCloseButton(); + +// For testing purposes; not to be launched. When enabled, Chrome Upstream +// always requests that the user enters/confirms cardholder name in the +// offer-to-save dialog, regardless of if it was present or if the user is a +// Google Payments customer. Note that this will override the detected +// cardholder name, if one was found. +bool IsAutofillUpstreamAlwaysRequestCardholderNameExperimentEnabled(); + +// For experimental purposes; not to be made available in chrome://flags. When +// enabled and Chrome Upstream requests the cardholder name in the offer-to-save +// dialog, the field will be blank instead of being prefilled with the name from +// the user's Google Account. +bool IsAutofillUpstreamBlankCardholderNameFieldExperimentEnabled(); + +// Returns whether the experiment is enabled where Chrome Upstream can request +// the user to enter/confirm cardholder name in the offer-to-save bubble if it +// was not detected or was conflicting during the checkout flow and the user is +// NOT a Google Payments customer. +bool IsAutofillUpstreamEditableCardholderNameExperimentEnabled(); + +// Returns whether the experiment is enabled where Chrome Upstream sends the +// first six digits of the card PAN to Google Payments to help determine whether +// card upload is possible. +bool IsAutofillUpstreamSendPanFirstSixExperimentEnabled(); + +// Returns whether the experiment is enbabled where upstream sends updated +// prompt explanation which changes 'save this card' to 'save your card and +// billing address.' +bool IsAutofillUpstreamUpdatePromptExplanationExperimentEnabled(); + +#if defined(OS_MACOSX) +// Returns true if whether the views autofill popup feature is enabled or the +// we're using the views browser. +bool IsMacViewsAutofillPopupExperimentEnabled(); +#endif // defined(OS_MACOSX) + +// Returns true if the native Views implementation of the Desktop dropdown +// should be used. This will also be true if the kExperimentalUi flag is true, +// which forces a bunch of forthcoming UI changes on. +bool ShouldUseNativeViews(); + +// Returns true if expiration dates on the save card dialog should be +// unlabeled, i.e. not preceded by "Exp." +bool IsAutofillSaveCardDialogUnlabeledExpirationDateEnabled(); + } // namespace features } // namespace autofill diff --git a/chromium/components/autofill/core/common/autofill_pref_names.cc b/chromium/components/autofill/core/common/autofill_pref_names.cc deleted file mode 100644 index 5cd3354a4c0..00000000000 --- a/chromium/components/autofill/core/common/autofill_pref_names.cc +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 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 "components/autofill/core/common/autofill_pref_names.h" - -namespace autofill { -namespace prefs { - -// Integer that is set to the last choice user made when prompted for saving a -// credit card. The prompt is for user's consent in saving the card in the -// server for signed in users and saving the card locally for non signed-in -// users. -const char kAutofillAcceptSaveCreditCardPromptState[] = - "autofill.accept_save_credit_card_prompt_state"; - -// Integer that is set to the billing customer number fetched from priority -// preference. -const char kAutofillBillingCustomerNumber[] = "billing_customer_number"; - -// Boolean that is true if Autofill is enabled and allowed to save credit card -// data. -const char kAutofillCreditCardEnabled[] = "autofill.credit_card_enabled"; - -// Number of times the credit card signin promo has been shown. -const char kAutofillCreditCardSigninPromoImpressionCount[] = - "autofill.credit_card_signin_promo_impression_count"; - -// Boolean that is true if Autofill is enabled and allowed to save profile data. -const char kAutofillProfileEnabled[] = "autofill.profile_enabled"; - -// Boolean that is true if Autofill is enabled and allowed to save data. -const char kAutofillEnabled[] = "autofill.enabled"; - -// Integer that is set to the last version where the profile deduping routine -// was run. This routine will be run once per version. -const char kAutofillLastVersionDeduped[] = "autofill.last_version_deduped"; - -// Integer that is set to the last version where disused addresses were -// deleted. This deletion will be run once per version. -const char kAutofillLastVersionDisusedAddressesDeleted[] = - "autofill.last_version_disused_addresses_deleted"; - -// Integer that is set to the last version where disused credit cards were -// deleted. This deletion will be run once per version. -const char kAutofillLastVersionDisusedCreditCardsDeleted[] = - "autofill.last_version_disused_credit_cards_deleted"; - -// Boolean that is true if the orphan rows in the autofill table were removed. -const char kAutofillOrphanRowsRemoved[] = "autofill.orphan_rows_removed"; - -// Boolean that's true when Wallet card and address import is enabled by the -// user. -const char kAutofillWalletImportEnabled[] = "autofill.wallet_import_enabled"; - -// Boolean that is set to the last choice user made when prompted for saving an -// unmasked server card locally. -const char kAutofillWalletImportStorageCheckboxState[] = - "autofill.wallet_import_storage_checkbox_state"; - -} // namespace prefs -} // namespace autofill diff --git a/chromium/components/autofill/core/common/autofill_pref_names.h b/chromium/components/autofill/core/common/autofill_pref_names.h deleted file mode 100644 index ee224e8aa8c..00000000000 --- a/chromium/components/autofill/core/common/autofill_pref_names.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 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. - -#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_PREF_NAMES_H_ -#define COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_PREF_NAMES_H_ - -namespace autofill { -namespace prefs { - -// Alphabetical list of preference names specific to the Autofill -// component. Keep alphabetized, and document each in the .cc file. - -extern const char kAutofillAcceptSaveCreditCardPromptState[]; -extern const char kAutofillBillingCustomerNumber[]; -extern const char kAutofillCreditCardEnabled[]; -extern const char kAutofillCreditCardSigninPromoImpressionCount[]; -extern const char kAutofillProfileEnabled[]; -extern const char kAutofillEnabled[]; -extern const char kAutofillLastVersionDeduped[]; -extern const char kAutofillLastVersionDisusedAddressesDeleted[]; -extern const char kAutofillLastVersionDisusedCreditCardsDeleted[]; -extern const char kAutofillOrphanRowsRemoved[]; -extern const char kAutofillWalletImportEnabled[]; -extern const char kAutofillWalletImportStorageCheckboxState[]; - -// Possible values for previous user decision when we displayed a save credit -// card prompt. -enum PreviousSaveCreditCardPromptUserDecision { - PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_NONE, - PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_ACCEPTED, - PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_DENIED, - NUM_PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISIONS -}; - -} // namespace prefs -} // namespace autofill - -#endif // COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_PREF_NAMES_H_ diff --git a/chromium/components/autofill/core/common/autofill_prefs.cc b/chromium/components/autofill/core/common/autofill_prefs.cc new file mode 100644 index 00000000000..5b9c0dcf69d --- /dev/null +++ b/chromium/components/autofill/core/common/autofill_prefs.cc @@ -0,0 +1,195 @@ +// Copyright 2018 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 "components/autofill/core/common/autofill_prefs.h" + +#include "components/pref_registry/pref_registry_syncable.h" +#include "components/prefs/pref_service.h" + +namespace autofill { +namespace prefs { + +// Integer that is set to the last choice user made when prompted for saving a +// credit card. The prompt is for user's consent in saving the card in the +// server for signed in users and saving the card locally for non signed-in +// users. +const char kAutofillAcceptSaveCreditCardPromptState[] = + "autofill.accept_save_credit_card_prompt_state"; + +// Integer that is set to the billing customer number fetched from priority +// preference. +const char kAutofillBillingCustomerNumber[] = "billing_customer_number"; + +// The field type, validity state map of all profiles. +const char kAutofillProfileValidity[] = "autofill.profile_validity"; + +// Boolean that is true if Autofill is enabled and allowed to save credit card +// data. +const char kAutofillCreditCardEnabled[] = "autofill.credit_card_enabled"; + +// Number of times the credit card signin promo has been shown. +const char kAutofillCreditCardSigninPromoImpressionCount[] = + "autofill.credit_card_signin_promo_impression_count"; + +// Boolean that is true if Autofill is enabled and allowed to save data. +const char kAutofillEnabledDeprecated[] = "autofill.enabled"; + +// Boolean that is true if Japan address city field has been migrated to be a +// part of the street field. +const char kAutofillJapanCityFieldMigrated[] = + "autofill.japan_city_field_migrated_to_street_address"; + +// Integer that is set to the last version where the profile deduping routine +// was run. This routine will be run once per version. +const char kAutofillLastVersionDeduped[] = "autofill.last_version_deduped"; + +// Integer that is set to the last version where disused addresses were +// deleted. This deletion will be run once per version. +const char kAutofillLastVersionDisusedAddressesDeleted[] = + "autofill.last_version_disused_addresses_deleted"; + +// Integer that is set to the last version where disused credit cards were +// deleted. This deletion will be run once per version. +const char kAutofillLastVersionDisusedCreditCardsDeleted[] = + "autofill.last_version_disused_credit_cards_deleted"; + +// Boolean that is true if the orphan rows in the autofill table were removed. +const char kAutofillOrphanRowsRemoved[] = "autofill.orphan_rows_removed"; + +// Boolean that is true if Autofill is enabled and allowed to save profile data. +const char kAutofillProfileEnabled[] = "autofill.profile_enabled"; + +// Boolean that's true when Wallet card and address import is enabled by the +// user. +const char kAutofillWalletImportEnabled[] = "autofill.wallet_import_enabled"; + +// Boolean that is set to the last choice user made when prompted for saving an +// unmasked server card locally. +const char kAutofillWalletImportStorageCheckboxState[] = + "autofill.wallet_import_storage_checkbox_state"; + +void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { + // Synced prefs. Used for cross-device choices, e.g., credit card Autofill. + registry->RegisterDoublePref( + prefs::kAutofillBillingCustomerNumber, 0.0, + user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); + registry->RegisterBooleanPref( + prefs::kAutofillEnabledDeprecated, true, + user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); + registry->RegisterBooleanPref( + prefs::kAutofillProfileEnabled, true, + user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); + registry->RegisterIntegerPref( + prefs::kAutofillLastVersionDeduped, 0, + user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); + registry->RegisterIntegerPref( + prefs::kAutofillLastVersionDisusedAddressesDeleted, 0, + user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); + registry->RegisterBooleanPref( + prefs::kAutofillCreditCardEnabled, true, + user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); + registry->RegisterStringPref( + prefs::kAutofillProfileValidity, "", + user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); + + // Non-synced prefs. Used for per-device choices, e.g., signin promo. + registry->RegisterIntegerPref( + prefs::kAutofillCreditCardSigninPromoImpressionCount, 0); + registry->RegisterBooleanPref(prefs::kAutofillJapanCityFieldMigrated, false); + registry->RegisterBooleanPref(prefs::kAutofillWalletImportEnabled, true); + registry->RegisterBooleanPref( + prefs::kAutofillWalletImportStorageCheckboxState, true); + registry->RegisterIntegerPref( + prefs::kAutofillAcceptSaveCreditCardPromptState, + prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_NONE); + registry->RegisterIntegerPref( + prefs::kAutofillLastVersionDisusedCreditCardsDeleted, 0); + registry->RegisterBooleanPref(prefs::kAutofillOrphanRowsRemoved, false); +} + +void MigrateDeprecatedAutofillPrefs(PrefService* prefs) { + // If kAutofillCreditCardEnabled and kAutofillProfileEnabled prefs are + // currently using their default value and kAutofillEnabledDeprecated has a + // non-default value, override the valuAues of the new prefs. The following + // blocks should execute only once and are needed for those users who had + // Autofill disabled before introduction of the fine-grained prefs. + // TODO(crbug.com/870328): Remove these once M70- users are sufficiently low. + const PrefService::Preference* deprecated_autofill_pref = + prefs->FindPreference(prefs::kAutofillEnabledDeprecated); + DCHECK(deprecated_autofill_pref); + + const PrefService::Preference* autofill_credit_card_pref = + prefs->FindPreference(prefs::kAutofillCreditCardEnabled); + DCHECK(autofill_credit_card_pref); + if (autofill_credit_card_pref->IsDefaultValue() && + !deprecated_autofill_pref->IsDefaultValue()) { + prefs->SetBoolean(kAutofillCreditCardEnabled, + prefs->GetBoolean(kAutofillEnabledDeprecated)); + } + + const PrefService::Preference* autofill_profile_pref = + prefs->FindPreference(prefs::kAutofillProfileEnabled); + DCHECK(autofill_profile_pref); + if (autofill_profile_pref->IsDefaultValue() && + !deprecated_autofill_pref->IsDefaultValue()) { + prefs->SetBoolean(kAutofillProfileEnabled, + prefs->GetBoolean(kAutofillEnabledDeprecated)); + } +} + +bool IsAutocompleteEnabled(const PrefService* prefs) { + return IsProfileAutofillEnabled(prefs); +} + +bool IsAutofillEnabled(const PrefService* prefs) { + return IsProfileAutofillEnabled(prefs) || IsCreditCardAutofillEnabled(prefs); +} + +void SetAutofillEnabled(PrefService* prefs, bool enabled) { + SetProfileAutofillEnabled(prefs, enabled); + SetCreditCardAutofillEnabled(prefs, enabled); +} + +bool IsAutofillManaged(const PrefService* prefs) { + return prefs->IsManagedPreference(kAutofillEnabledDeprecated); +} + +bool IsProfileAutofillManaged(const PrefService* prefs) { + return prefs->IsManagedPreference(kAutofillProfileEnabled); +} + +bool IsCreditCardAutofillManaged(const PrefService* prefs) { + return prefs->IsManagedPreference(kAutofillCreditCardEnabled); +} + +bool IsProfileAutofillEnabled(const PrefService* prefs) { + return prefs->GetBoolean(kAutofillProfileEnabled); +} + +void SetProfileAutofillEnabled(PrefService* prefs, bool enabled) { + prefs->SetBoolean(kAutofillProfileEnabled, enabled); +} + +bool IsCreditCardAutofillEnabled(const PrefService* prefs) { + return prefs->GetBoolean(kAutofillCreditCardEnabled); +} + +void SetCreditCardAutofillEnabled(PrefService* prefs, bool enabled) { + prefs->SetBoolean(kAutofillCreditCardEnabled, enabled); +} + +bool IsPaymentsIntegrationEnabled(const PrefService* prefs) { + return prefs->GetBoolean(kAutofillWalletImportEnabled); +} + +void SetPaymentsIntegrationEnabled(PrefService* prefs, bool enabled) { + prefs->SetBoolean(kAutofillWalletImportEnabled, enabled); +} + +std::string GetAllProfilesValidityMapsEncodedString(const PrefService* prefs) { + return prefs->GetString(kAutofillProfileValidity); +} + +} // namespace prefs +} // namespace autofill diff --git a/chromium/components/autofill/core/common/autofill_prefs.h b/chromium/components/autofill/core/common/autofill_prefs.h new file mode 100644 index 00000000000..4dc9d14ee74 --- /dev/null +++ b/chromium/components/autofill/core/common/autofill_prefs.h @@ -0,0 +1,83 @@ +// Copyright 2018 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_PREFS_H_ +#define COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_PREFS_H_ + +#include <string> + +class PrefService; + +namespace user_prefs { +class PrefRegistrySyncable; +} // namespace user_prefs + +namespace autofill { +namespace prefs { + +// Alphabetical list of preference names specific to the Autofill +// component. Keep alphabetized, and document each in the .cc file. +extern const char kAutofillAcceptSaveCreditCardPromptState[]; +extern const char kAutofillBillingCustomerNumber[]; +// Do not get/set the value of this pref directly. Use provided getter/setter. +extern const char kAutofillCreditCardEnabled[]; +extern const char kAutofillCreditCardSigninPromoImpressionCount[]; +// Please use kAutofillCreditCardEnabled and kAutofillProfileEnabled instead. +extern const char kAutofillEnabledDeprecated[]; +extern const char kAutofillJapanCityFieldMigrated[]; +extern const char kAutofillLastVersionDeduped[]; +extern const char kAutofillLastVersionDisusedAddressesDeleted[]; +extern const char kAutofillLastVersionDisusedCreditCardsDeleted[]; +extern const char kAutofillOrphanRowsRemoved[]; +// Do not get/set the value of this pref directly. Use provided getter/setter. +extern const char kAutofillProfileEnabled[]; +extern const char kAutofillWalletImportEnabled[]; +extern const char kAutofillWalletImportStorageCheckboxState[]; +extern const char kAutofillProfileValidity[]; + +// Possible values for previous user decision when we displayed a save credit +// card prompt. +enum PreviousSaveCreditCardPromptUserDecision { + PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_NONE, + PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_ACCEPTED, + PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_DENIED, + NUM_PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISIONS +}; + +// Registers Autofill prefs. +void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); + +// Migrates deprecated Autofill prefs values. +void MigrateDeprecatedAutofillPrefs(PrefService* prefs); + +bool IsAutocompleteEnabled(const PrefService* prefs); + +bool IsAutofillEnabled(const PrefService* prefs); + +void SetAutofillEnabled(PrefService* prefs, bool enabled); + +bool IsAutofillManaged(const PrefService* prefs); + +bool IsProfileAutofillManaged(const PrefService* prefs); + +bool IsCreditCardAutofillManaged(const PrefService* prefs); + +bool IsProfileAutofillEnabled(const PrefService* prefs); + +void SetProfileAutofillEnabled(PrefService* prefs, bool enabled); + +bool IsCreditCardAutofillEnabled(const PrefService* prefs); + +void SetCreditCardAutofillEnabled(PrefService* prefs, bool enabled); + +bool IsPaymentsIntegrationEnabled(const PrefService* prefs); + +void SetPaymentsIntegrationEnabled(PrefService* prefs, bool enabled); + +std::string GetAllProfilesValidityMapsEncodedString(const PrefService* prefs); + +} // namespace prefs +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_PREFS_H_ diff --git a/chromium/components/autofill/core/common/autofill_prefs_unittest.cc b/chromium/components/autofill/core/common/autofill_prefs_unittest.cc new file mode 100644 index 00000000000..af9d814f3e9 --- /dev/null +++ b/chromium/components/autofill/core/common/autofill_prefs_unittest.cc @@ -0,0 +1,77 @@ +// Copyright 2018 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 "components/autofill/core/common/autofill_prefs.h" + +#include <memory> + +#include "components/pref_registry/pref_registry_syncable.h" +#include "components/prefs/pref_service.h" +#include "components/prefs/pref_service_factory.h" +#include "components/prefs/testing_pref_store.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace autofill { +namespace prefs { + +class AutofillPrefsTest : public testing::Test { + protected: + AutofillPrefsTest() {} + ~AutofillPrefsTest() override {} + + void SetUp() override { pref_service_ = CreatePrefServiceAndRegisterPrefs(); } + + // Creates a PrefService and registers Autofill prefs. + std::unique_ptr<PrefService> CreatePrefServiceAndRegisterPrefs() { + scoped_refptr<user_prefs::PrefRegistrySyncable> registry( + new user_prefs::PrefRegistrySyncable()); + RegisterProfilePrefs(registry.get()); + PrefServiceFactory factory; + factory.set_user_prefs(base::MakeRefCounted<TestingPrefStore>()); + return factory.Create(registry); + } + + PrefService* pref_service() { return pref_service_.get(); } + + private: + std::unique_ptr<PrefService> pref_service_; +}; + +// Tests migrating the value of the deprecated Autofill master pref to the new +// prefs and that this operation takes place only once. +TEST_F(AutofillPrefsTest, MigrateDeprecatedAutofillPrefs) { + // All prefs should be enabled by default. + ASSERT_TRUE(pref_service()->GetBoolean(kAutofillEnabledDeprecated)); + ASSERT_TRUE(pref_service()->GetBoolean(kAutofillProfileEnabled)); + ASSERT_TRUE(pref_service()->GetBoolean(kAutofillCreditCardEnabled)); + + // Disable the deprecated master pref and make sure the new fine-grained prefs + // are not affected by that. + pref_service()->SetBoolean(kAutofillEnabledDeprecated, false); + EXPECT_FALSE(pref_service()->GetBoolean(kAutofillEnabledDeprecated)); + EXPECT_TRUE(pref_service()->GetBoolean(kAutofillProfileEnabled)); + EXPECT_TRUE(pref_service()->GetBoolean(kAutofillCreditCardEnabled)); + + // Migrate the deprecated master pref's value to the new fine-grained prefs. + // Their values should become the same as the deprecated master pref's value. + MigrateDeprecatedAutofillPrefs(pref_service()); + EXPECT_FALSE(pref_service()->GetBoolean(kAutofillProfileEnabled)); + EXPECT_FALSE(pref_service()->GetBoolean(kAutofillCreditCardEnabled)); + + // Enable the deprecated master pref and make sure the new fine-grained prefs + // are not affected by that. + pref_service()->SetBoolean(kAutofillEnabledDeprecated, true); + EXPECT_TRUE(pref_service()->GetBoolean(kAutofillEnabledDeprecated)); + EXPECT_FALSE(pref_service()->GetBoolean(kAutofillProfileEnabled)); + EXPECT_FALSE(pref_service()->GetBoolean(kAutofillCreditCardEnabled)); + + // Migrate the deprecated master pref's value to the new fine-grained prefs. + // Their values should not be affected when migration happens a second time. + MigrateDeprecatedAutofillPrefs(pref_service()); + EXPECT_FALSE(pref_service()->GetBoolean(kAutofillProfileEnabled)); + EXPECT_FALSE(pref_service()->GetBoolean(kAutofillCreditCardEnabled)); +} + +} // namespace prefs +} // namespace autofill
\ No newline at end of file diff --git a/chromium/components/autofill/core/common/autofill_regex_constants.cc b/chromium/components/autofill/core/common/autofill_regex_constants.cc index fe72126c7a2..d861aa9ea87 100644 --- a/chromium/components/autofill/core/common/autofill_regex_constants.cc +++ b/chromium/components/autofill/core/common/autofill_regex_constants.cc @@ -28,6 +28,7 @@ const char kCompanyRe[] = "|会社" // ja-JP "|название.?компании" // ru "|单位|公司" // zh-CN + "|شرکت" // fa "|회사|직장"; // ko-KR const char kAddressLine1Re[] = "^address$|address[_-]?line(one)?|address1|addr1|street" @@ -78,10 +79,11 @@ const char kAddressLinesExtraRe[] = const char kAddressLookupRe[] = "lookup"; const char kCountryRe[] = "country|countries" - "|país|pais" // es - "|国" // ja-JP - "|国家" // zh-CN - "|국가|나라"; // ko-KR + "|país|pais" // es + "|国" // ja-JP + "|国家" // zh-CN + "|국가|나라" // ko-KR + "|کشور"; // fa const char kCountryLocationRe[] = "location"; const char kZipCodeRe[] = "zip|postal|post.*code|pcode" @@ -111,6 +113,7 @@ const char kCityRe[] = "|Город" // ru "|市" // zh-CN "|分區" // zh-TW + "|شهر" // fa "|^시[^도·・]|시[·・]?군[·・]?구"; // ko-KR const char kStateRe[] = "(?<!(united|hist|history).?)state|county|region|province" @@ -121,6 +124,7 @@ const char kStateRe[] = "|область" // ru "|省" // zh-CN "|地區" // zh-TW + "|استان" // fa "|^시[·・]?도"; // ko-KR ///////////////////////////////////////////////////////////////////////////// @@ -156,14 +160,14 @@ const char kNameOnCardRe[] = const char kNameOnCardContextualRe[] = "name"; const char kCardNumberRe[] = "(add)?(?:card|cc|acct).?(?:number|#|no|num|field)" - "|(?<!telefon|haus)nummer" // de-DE - "|credito|numero|número" // es - "|numéro" // fr-FR - "|カード番号" // ja-JP - "|Номер.*карты" // ru - "|信用卡号|信用卡号码" // zh-CN - "|信用卡卡號" // zh-TW - "|카드"; // ko-KR + "|(?<!telefon|haus)nummer" // de-DE + "|カード番号" // ja-JP + "|Номер.*карты" // ru + "|信用卡号|信用卡号码" // zh-CN + "|信用卡卡號" // zh-TW + "|카드" // ko-KR + "|(numero|número|numéro)(?!.*(document|fono|phone))"; // es/pt/fr + const char kCardCvcRe[] = "verification|card.?identification|security.?code|card.?code" "|security.?value" @@ -243,6 +247,7 @@ const char kEmailRe[] = "|Электронной.?Почты" // ru "|邮件|邮箱" // zh-CN "|電郵地址" // zh-TW + "|ایمیل|پست.*الکترونیک" // fa "|(?:이메일|전자.?우편|[Ee]-?mail)(.?주소)?"; // ko-KR ///////////////////////////////////////////////////////////////////////////// @@ -260,6 +265,7 @@ const char kNameRe[] = "|^nom" // fr-FR "|お名前|氏名" // ja-JP "|^nome" // pt-BR, pt-PT + "|نام.*نام.*خانوادگی" // fa "|姓名" // zh-CN "|성명"; // ko-KR const char kNameSpecificRe[] = @@ -274,6 +280,7 @@ const char kFirstNameRe[] = "|名" // ja-JP "|nome" // pt-BR, pt-PT "|Имя" // ru + "|نام" // fa "|이름"; // ko-KR const char kMiddleInitialRe[] = "middle.*initial|m\\.i\\.|mi$|\\bmi\\b"; const char kMiddleNameRe[] = @@ -288,6 +295,7 @@ const char kLastNameRe[] = "|姓" // ja-JP "|morada|apelidos|surename|sobrenome" // pt-BR, pt-PT "|Фамилия" // ru + "|نام.*خانوادگی" // fa "|\\b성(?:[^명]|\\b)"; // ko-KR ///////////////////////////////////////////////////////////////////////////// @@ -303,7 +311,8 @@ const char kPhoneRe[] = "|телефон" // ru "|电话" // zh-CN "|(?:전화|핸드폰|휴대폰|휴대전화)(?:.?번호)?"; // ko-KR -const char kCountryCodeRe[] = "country.*code|ccode|_cc"; +const char kCountryCodeRe[] = + "country.*code|ccode|_cc|phone.*code|user.*phone.*code"; const char kAreaCodeNotextRe[] = "^\\($"; const char kAreaCodeRe[] = "area.*code|acode|area" diff --git a/chromium/components/autofill/core/common/autofill_util.h b/chromium/components/autofill/core/common/autofill_util.h index 92ddb896a0e..3f8f74f6d70 100644 --- a/chromium/components/autofill/core/common/autofill_util.h +++ b/chromium/components/autofill/core/common/autofill_util.h @@ -24,6 +24,10 @@ extern const char kAutofillKeyboardAccessoryAnimationDurationKey[]; extern const char kAutofillKeyboardAccessoryLimitLabelWidthKey[]; extern const char kAutofillKeyboardAccessoryHintKey[]; +// The length of the GUIDs used for local autofill data. It is different than +// the length used for server autofill data. +constexpr int kLocalGuidSize = 36; + // Returns true when command line switch |kEnableSuggestionsWithSubstringMatch| // is on. bool IsFeatureSubstringMatchEnabled(); diff --git a/chromium/components/autofill/core/common/form_data.cc b/chromium/components/autofill/core/common/form_data.cc index 0bf0ff8ad6f..50bc6173b7e 100644 --- a/chromium/components/autofill/core/common/form_data.cc +++ b/chromium/components/autofill/core/common/form_data.cc @@ -17,7 +17,7 @@ namespace autofill { namespace { -const int kPickleVersion = 6; +const int kFormDataPickleVersion = 6; bool ReadGURL(base::PickleIterator* iter, GURL* url) { std::string spec; @@ -152,7 +152,7 @@ std::ostream& operator<<(std::ostream& os, const FormData& form) { } void SerializeFormData(const FormData& form_data, base::Pickle* pickle) { - pickle->WriteInt(kPickleVersion); + pickle->WriteInt(kFormDataPickleVersion); pickle->WriteString16(form_data.name); pickle->WriteString(form_data.origin.spec()); pickle->WriteString(form_data.action.spec()); @@ -179,7 +179,7 @@ bool DeserializeFormData(base::PickleIterator* iter, FormData* form_data) { return false; } - if (version < 1 || version > kPickleVersion) { + if (version < 1 || version > kFormDataPickleVersion) { DVLOG(1) << "Unknown FormData pickle version " << version; return false; } diff --git a/chromium/components/autofill/core/common/form_field_data.cc b/chromium/components/autofill/core/common/form_field_data.cc index 69f2f3e416e..9aa08333f6b 100644 --- a/chromium/components/autofill/core/common/form_field_data.cc +++ b/chromium/components/autofill/core/common/form_field_data.cc @@ -15,8 +15,8 @@ namespace autofill { namespace { // Increment this anytime pickle format is modified as well as provide -// deserialization routine from previous kPickleVersion format. -const int kPickleVersion = 7; +// deserialization routine from previous kFormFieldDataPickleVersion format. +const int kFormFieldDataPickleVersion = 7; void AddVectorToPickle(std::vector<base::string16> strings, base::Pickle* pickle) { @@ -147,7 +147,6 @@ FormFieldData::FormFieldData() properties_mask(0), is_enabled(false), is_readonly(false), - is_default(false), label_source(LabelSource::UNKNOWN) {} FormFieldData::FormFieldData(const FormFieldData& other) = default; @@ -281,7 +280,7 @@ bool FormFieldData::operator<(const FormFieldData& field) const { void SerializeFormFieldData(const FormFieldData& field_data, base::Pickle* pickle) { - pickle->WriteInt(kPickleVersion); + pickle->WriteInt(kFormFieldDataPickleVersion); pickle->WriteString16(field_data.label); pickle->WriteString16(field_data.name); pickle->WriteString16(field_data.value); @@ -455,7 +454,6 @@ std::ostream& operator<<(std::ostream& os, const FormFieldData& field) { << "text_direction=" << field.text_direction << " " << "is_enabled=" << field.is_enabled << " " << "is_readonly=" << field.is_readonly << " " - << "is_default=" << field.is_default << " " << "typed_value=" << field.typed_value << " " << "properties_mask=" << field.properties_mask << " " << "label_source=" << field.label_source; diff --git a/chromium/components/autofill/core/common/form_field_data.h b/chromium/components/autofill/core/common/form_field_data.h index 8f9e3cd942d..aedef09f757 100644 --- a/chromium/components/autofill/core/common/form_field_data.h +++ b/chromium/components/autofill/core/common/form_field_data.h @@ -155,7 +155,6 @@ struct FormFieldData { // serialised for storage. bool is_enabled; bool is_readonly; - bool is_default; base::string16 typed_value; // For the HTML snippet |<option value="US">United States</option>|, the diff --git a/chromium/components/autofill/core/common/password_form.cc b/chromium/components/autofill/core/common/password_form.cc index 9fc16b198a2..6e6a16ad9ce 100644 --- a/chromium/components/autofill/core/common/password_form.cc +++ b/chromium/components/autofill/core/common/password_form.cc @@ -36,14 +36,10 @@ void PasswordFormToJSON(const PasswordForm& form, target->SetString("username_value", form.username_value); target->SetString("password_elem", form.password_element); target->SetString("password_value", form.password_value); - target->SetBoolean("password_value_is_default", - form.password_value_is_default); target->SetString("new_password_element", form.new_password_element); target->SetInteger("password_element_renderer_id", form.password_element_renderer_id); target->SetString("new_password_value", form.new_password_value); - target->SetBoolean("new_password_value_is_default", - form.new_password_value_is_default); target->SetBoolean("new_password_marked_by_site", form.new_password_marked_by_site); target->SetString("other_possible_usernames", @@ -86,8 +82,6 @@ PasswordForm::PasswordForm() : scheme(SCHEME_HTML), username_marked_by_site(false), form_has_autofilled_value(false), - password_value_is_default(false), - new_password_value_is_default(false), new_password_marked_by_site(false), preferred(false), blacklisted_by_user(false), diff --git a/chromium/components/autofill/core/common/password_form.h b/chromium/components/autofill/core/common/password_form.h index cc168863b0f..06c316d8a4f 100644 --- a/chromium/components/autofill/core/common/password_form.h +++ b/chromium/components/autofill/core/common/password_form.h @@ -226,10 +226,6 @@ struct PasswordForm { // When parsing an HTML form, this is typically empty. base::string16 password_value; - // Whether the password value is the same as specified in the "value" - // attribute of the input element. Only used in the renderer. - bool password_value_is_default; - // If the form was a sign-up or a change password form, the name of the input // element corresponding to the new password. Optional, and not persisted. base::string16 new_password_element; @@ -241,10 +237,6 @@ struct PasswordForm { // The new password. Optional, and not persisted. base::string16 new_password_value; - // Whether the password value is the same as specified in the "value" - // attribute of the input element. Only used in the renderer. - bool new_password_value_is_default; - // Whether the |new_password_element| has an autocomplete=new-password // attribute. This is only used in parsed HTML forms. bool new_password_marked_by_site; diff --git a/chromium/components/autofill/core/common/password_form_fill_data.cc b/chromium/components/autofill/core/common/password_form_fill_data.cc index bcc0766b2b2..6dcaa7b85f5 100644 --- a/chromium/components/autofill/core/common/password_form_fill_data.cc +++ b/chromium/components/autofill/core/common/password_form_fill_data.cc @@ -11,18 +11,7 @@ namespace autofill { -UsernamesCollectionKey::UsernamesCollectionKey() {} - -UsernamesCollectionKey::~UsernamesCollectionKey() {} - -bool UsernamesCollectionKey::operator<( - const UsernamesCollectionKey& other) const { - return std::tie(username, password, realm) < - std::tie(other.username, other.password, other.realm); -} - -PasswordFormFillData::PasswordFormFillData() - : wait_for_username(false), is_possible_change_password_form(false) {} +PasswordFormFillData::PasswordFormFillData() : wait_for_username(false) {} PasswordFormFillData::PasswordFormFillData(const PasswordFormFillData& other) = default; @@ -58,8 +47,6 @@ void InitPasswordFormFillData( result->username_field = username_field; result->password_field = password_field; result->wait_for_username = wait_for_username_before_autofill; - result->is_possible_change_password_form = - form_on_page.IsPossibleChangePasswordForm(); result->has_renderer_ids = form_on_page.has_renderer_ids; if (preferred_match->is_public_suffix_match || diff --git a/chromium/components/autofill/core/common/password_form_fill_data.h b/chromium/components/autofill/core/common/password_form_fill_data.h index cc90089ee7e..5db0c17b244 100644 --- a/chromium/components/autofill/core/common/password_form_fill_data.h +++ b/chromium/components/autofill/core/common/password_form_fill_data.h @@ -12,19 +12,6 @@ namespace autofill { -// Helper struct for PasswordFormFillData -struct UsernamesCollectionKey { - UsernamesCollectionKey(); - ~UsernamesCollectionKey(); - - // Defined so that this struct can be used as a key in a std::map. - bool operator<(const UsernamesCollectionKey& other) const; - - base::string16 username; - base::string16 password; - std::string realm; -}; - struct PasswordAndRealm { base::string16 password; std::string realm; @@ -35,8 +22,6 @@ struct PasswordAndRealm { // form that we are filling. struct PasswordFormFillData { typedef std::map<base::string16, PasswordAndRealm> LoginCollection; - typedef std::map<UsernamesCollectionKey, - std::vector<base::string16> > UsernamesCollection; // If |has_renderer_ids| == true then |form_renderer_id| contains the unique // renderer form id. No special values for |has_renderer_ids| == false case @@ -81,9 +66,6 @@ struct PasswordFormFillData { // and our saved representation don't match up. bool wait_for_username; - // True if this form is a change password form. - bool is_possible_change_password_form; - // True if renderer ids for form, username and password fields are present. // TODO(https://crbug.com/831123): Remove this field when old parsing is // removed and filling by renderer ids is by default. diff --git a/chromium/components/autofill/core/common/password_generation_util.cc b/chromium/components/autofill/core/common/password_generation_util.cc index c040a3ea40a..b96f81de574 100644 --- a/chromium/components/autofill/core/common/password_generation_util.cc +++ b/chromium/components/autofill/core/common/password_generation_util.cc @@ -58,6 +58,10 @@ void LogPasswordGenerationEvent(PasswordGenerationEvent event) { event, EVENT_ENUM_COUNT); } +void LogPasswordGenerationUserEvent(PasswordGenerationUserEvent event) { + UMA_HISTOGRAM_ENUMERATION("PasswordGeneration.UserEvent", event); +} + bool IsPasswordGenerationEnabled() { if (base::FeatureList::IsEnabled( autofill::features::kAutomaticPasswordGeneration)) diff --git a/chromium/components/autofill/core/common/password_generation_util.h b/chromium/components/autofill/core/common/password_generation_util.h index 5543655fef3..40cefd89ce0 100644 --- a/chromium/components/autofill/core/common/password_generation_util.h +++ b/chromium/components/autofill/core/common/password_generation_util.h @@ -75,6 +75,25 @@ enum PasswordGenerationEvent { EVENT_ENUM_COUNT }; +// These values are used for metrics. Entries should not be renumbered and +// numeric values should never be reused. +// Metric: PasswordGeneration.UserEvent +enum class PasswordGenerationUserEvent { + // The generated password was accepted by the user. + kPasswordAccepted = 0, + // The generated password was edited by the user in the field in which + // it was filled after being accepted. + kPasswordEdited = 1, + // The generated password was deleted by the user from the field + // in which it was filled after being accepted. + kPasswordDeleted = 2, + // The generated password was rejected by the user from the modal + // dialog, either by pressing "Cancel" in the dialog or by dismissing it. + // Only used on Android. + kPasswordRejectedInDialog = 3, + kMaxValue = kPasswordRejectedInDialog +}; + // Wrapper to store the user interactions with the password generation bubble. struct PasswordGenerationActions { // Whether the user has clicked on the learn more link. @@ -124,6 +143,8 @@ void LogUserActions(PasswordGenerationActions actions); void LogPasswordGenerationEvent(PasswordGenerationEvent event); +void LogPasswordGenerationUserEvent(PasswordGenerationUserEvent event); + // Enumerates user actions after password generation bubble is shown. // These are visible for testing purposes. enum UserAction { diff --git a/chromium/components/autofill/ios/browser/BUILD.gn b/chromium/components/autofill/ios/browser/BUILD.gn index ab38995664f..3a3c11ebb98 100644 --- a/chromium/components/autofill/ios/browser/BUILD.gn +++ b/chromium/components/autofill/ios/browser/BUILD.gn @@ -49,16 +49,21 @@ source_set("test_support") { testonly = true configs += [ "//build/config/compiler:enable_arc" ] sources = [ + "credit_card_save_manager_test_observer_bridge.h", + "credit_card_save_manager_test_observer_bridge.mm", "fake_autofill_agent.h", "fake_autofill_agent.mm", "fake_js_autofill_manager.h", "fake_js_autofill_manager.mm", + "ios_test_event_waiter.h", ] public_deps = [ ":browser", ] deps = [ "//base", + "//base/test:test_support", + "//components/autofill/core/browser", "//ios/web/public", ] } @@ -89,3 +94,14 @@ source_set("unit_tests") { "//third_party/ocmock", ] } + +bundle_data("autofill_test_bundle_data") { + testonly = true + sources = [ + "//components/test/data/autofill/credit_card_upload_form_address_and_cc.html", + ] + outputs = [ + "{{bundle_resources_dir}}/" + + "{{source_root_relative_dir}}/{{source_file_part}}", + ] +} diff --git a/chromium/components/autofill/ios/browser/autofill_agent.mm b/chromium/components/autofill/ios/browser/autofill_agent.mm index 1073e8642c5..8c5255c4acc 100644 --- a/chromium/components/autofill/ios/browser/autofill_agent.mm +++ b/chromium/components/autofill/ios/browser/autofill_agent.mm @@ -27,7 +27,7 @@ #include "components/autofill/core/browser/popup_item_ids.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_features.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/autofill_util.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_field_data.h" @@ -212,7 +212,9 @@ void GetFormAndField(autofill::FormData* form, prefObserverBridge_ = std::make_unique<PrefObserverBridge>(self); prefChangeRegistrar_.Init(prefService); prefObserverBridge_->ObserveChangesForPreference( - autofill::prefs::kAutofillEnabled, &prefChangeRegistrar_); + autofill::prefs::kAutofillCreditCardEnabled, &prefChangeRegistrar_); + prefObserverBridge_->ObserveChangesForPreference( + autofill::prefs::kAutofillProfileEnabled, &prefChangeRegistrar_); jsAutofillManager_ = [[JsAutofillManager alloc] initWithReceiver:webState_->GetJSInjectionReceiver()]; @@ -689,9 +691,6 @@ void GetFormAndField(autofill::FormData* form, #pragma mark - PrefObserverDelegate - (void)onPreferenceChanged:(const std::string&)preferenceName { - if (preferenceName != autofill::prefs::kAutofillEnabled) - return; - // Processing the page can be needed here if Autofill is enabled in settings // when the page is already loaded. if ([self isAutofillEnabled]) @@ -701,7 +700,7 @@ void GetFormAndField(autofill::FormData* form, #pragma mark - Private methods. - (BOOL)isAutofillEnabled { - if (!prefService_->GetBoolean(autofill::prefs::kAutofillEnabled)) + if (!autofill::prefs::IsAutofillEnabled(prefService_)) return NO; web::URLVerificationTrustLevel trustLevel; diff --git a/chromium/components/autofill/ios/browser/autofill_agent_unittests.mm b/chromium/components/autofill/ios/browser/autofill_agent_unittests.mm index 5f8c2b44a20..ca73deea805 100644 --- a/chromium/components/autofill/ios/browser/autofill_agent_unittests.mm +++ b/chromium/components/autofill/ios/browser/autofill_agent_unittests.mm @@ -8,7 +8,7 @@ #import "base/test/ios/wait_util.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/popup_item_ids.h" -#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/form_data.h" #import "components/autofill/ios/browser/js_autofill_manager.h" #include "components/prefs/pref_service.h" @@ -46,7 +46,7 @@ class AutofillAgentTests : public PlatformTest { test_web_state_.SetCurrentURL(GURL("https://example.com")); prefs_ = autofill::test::PrefServiceForTesting(); - prefs_->SetBoolean(autofill::prefs::kAutofillEnabled, true); + autofill::prefs::SetAutofillEnabled(prefs_.get(), true); autofill_agent_ = [[AutofillAgent alloc] initWithPrefService:prefs_.get() webState:&test_web_state_]; diff --git a/chromium/components/autofill/ios/browser/credit_card_save_manager_test_observer_bridge.h b/chromium/components/autofill/ios/browser/credit_card_save_manager_test_observer_bridge.h new file mode 100644 index 00000000000..85b804d80b7 --- /dev/null +++ b/chromium/components/autofill/ios/browser/credit_card_save_manager_test_observer_bridge.h @@ -0,0 +1,53 @@ +// Copyright 2018 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. + +#ifndef COMPONENTS_AUTOFILL_IOS_BROWSER_CREDIT_CARD_SAVE_MANAGER_TEST_OBSERVER_BRIDGE_H_ +#define COMPONENTS_AUTOFILL_IOS_BROWSER_CREDIT_CARD_SAVE_MANAGER_TEST_OBSERVER_BRIDGE_H_ + +#import <Foundation/Foundation.h> + +#include "base/macros.h" +#include "components/autofill/core/browser/credit_card_save_manager.h" + +// A protocol to be adopted by EarlGrey tests to get notified of actions that +// occur in autofill::CreditCardSaveManager. +@protocol CreditCardSaveManagerTestObserver<NSObject> + +- (void)offeredLocalSave; + +- (void)decidedToRequestUploadSave; + +- (void)receivedGetUploadDetailsResponse; + +- (void)sentUploadCardRequest; + +@end + +namespace autofill { + +// Forwards actions from autofill::CreditCardSaveManager to the Objective-C +// observer, CreditCardSaveManagerTestObserver. +class CreditCardSaveManagerTestObserverBridge + : public CreditCardSaveManager::ObserverForTest { + public: + explicit CreditCardSaveManagerTestObserverBridge( + CreditCardSaveManager* credit_card_save_manager, + id<CreditCardSaveManagerTestObserver> observer); + virtual ~CreditCardSaveManagerTestObserverBridge() = default; + + // CreditCardSaveManager::ObserverForTest: + void OnOfferLocalSave() override; + void OnDecideToRequestUploadSave() override; + void OnReceivedGetUploadDetailsResponse() override; + void OnSentUploadCardRequest() override; + + private: + __weak id<CreditCardSaveManagerTestObserver> observer_ = nil; + + DISALLOW_COPY_AND_ASSIGN(CreditCardSaveManagerTestObserverBridge); +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_IOS_BROWSER_CREDIT_CARD_SAVE_MANAGER_TEST_OBSERVER_BRIDGE_H_ diff --git a/chromium/components/autofill/ios/browser/credit_card_save_manager_test_observer_bridge.mm b/chromium/components/autofill/ios/browser/credit_card_save_manager_test_observer_bridge.mm new file mode 100644 index 00000000000..c85b844d426 --- /dev/null +++ b/chromium/components/autofill/ios/browser/credit_card_save_manager_test_observer_bridge.mm @@ -0,0 +1,42 @@ +// Copyright 2018 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. + +#import "components/autofill/ios/browser/credit_card_save_manager_test_observer_bridge.h" + +#include "base/logging.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace autofill { + +CreditCardSaveManagerTestObserverBridge:: + CreditCardSaveManagerTestObserverBridge( + CreditCardSaveManager* credit_card_save_manager, + id<CreditCardSaveManagerTestObserver> observer) + : observer_(observer) { + DCHECK(observer_); + DCHECK(credit_card_save_manager); + credit_card_save_manager->SetEventObserverForTesting(this); +} + +void CreditCardSaveManagerTestObserverBridge::OnOfferLocalSave() { + [observer_ offeredLocalSave]; +} + +void CreditCardSaveManagerTestObserverBridge::OnDecideToRequestUploadSave() { + [observer_ decidedToRequestUploadSave]; +} + +void CreditCardSaveManagerTestObserverBridge:: + OnReceivedGetUploadDetailsResponse() { + [observer_ receivedGetUploadDetailsResponse]; +} + +void CreditCardSaveManagerTestObserverBridge::OnSentUploadCardRequest() { + [observer_ sentUploadCardRequest]; +} + +} // namespace autofill diff --git a/chromium/components/autofill/ios/browser/ios_test_event_waiter.h b/chromium/components/autofill/ios/browser/ios_test_event_waiter.h new file mode 100644 index 00000000000..0cd8eff237a --- /dev/null +++ b/chromium/components/autofill/ios/browser/ios_test_event_waiter.h @@ -0,0 +1,85 @@ +// Copyright 2018 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. + +#ifndef COMPONENTS_AUTOFILL_IOS_BROWSER_IOS_TEST_EVENT_WAITER_H_ +#define COMPONENTS_AUTOFILL_IOS_BROWSER_IOS_TEST_EVENT_WAITER_H_ + +#include <list> + +#import "base/test/ios/wait_util.h" + +namespace autofill { + +// IOSTestEventWaiter is used to wait on given events that may have occurred +// before call to Wait(), or after, in which case a |timeout| should be provided +// to wait for those events to occur until |timeout| expires. +// +// Usage: +// waiter_ = std::make_unique<IOSTestEventWaiter>({ ... }); +// +// Do stuff, which (a)synchronously calls waiter_->OnEvent(...). +// +// waiter_->Wait(); +template <typename Event> +class IOSTestEventWaiter { + public: + explicit IOSTestEventWaiter(std::list<Event> expected_events, + double timeout = 0); + ~IOSTestEventWaiter() = default; + + // Either returns true right away if all events were observed between this + // object's construction and this call to Wait(); or returns true if that + // condition is met before |timeout|; Otherwise returns false. If |timeout| is + // zero, a reasonable default is used. Returns false if the current NSRunLoop + // is already running. + bool Wait(); + + // Observes an event. Returns false if the event is unexpected and true + // Otherwise. + bool OnEvent(Event event); + + private: + std::list<Event> expected_events_; + bool runloop_running_; + double timeout_; + + DISALLOW_COPY_AND_ASSIGN(IOSTestEventWaiter); +}; + +template <typename Event> +IOSTestEventWaiter<Event>::IOSTestEventWaiter(std::list<Event> expected_events, + double timeout) + : expected_events_(std::move(expected_events)), + runloop_running_(false), + timeout_(timeout) {} + +template <typename Event> +bool IOSTestEventWaiter<Event>::Wait() { + if (expected_events_.empty()) + return true; + + if (runloop_running_) + return false; + + runloop_running_ = true; + bool result = base::test::ios::WaitUntilConditionOrTimeout(timeout_, ^{ + return expected_events_.empty(); + }); + runloop_running_ = false; + + return result; +} + +template <typename Event> +bool IOSTestEventWaiter<Event>::OnEvent(Event event) { + if (expected_events_.empty() || expected_events_.front() != event) + return false; + + expected_events_.pop_front(); + return true; +} + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_IOS_BROWSER_IOS_TEST_EVENT_WAITER_H_ diff --git a/chromium/components/autofill/ios/browser/personal_data_manager_observer_bridge.h b/chromium/components/autofill/ios/browser/personal_data_manager_observer_bridge.h index d3c7cf1c1b0..1f996b6839f 100644 --- a/chromium/components/autofill/ios/browser/personal_data_manager_observer_bridge.h +++ b/chromium/components/autofill/ios/browser/personal_data_manager_observer_bridge.h @@ -10,10 +10,10 @@ #include "base/macros.h" #include "components/autofill/core/browser/personal_data_manager_observer.h" -// PersonalDataManagerObserverBridgeDelegate is used by PersonalDataManager to -// informs its client implemented in Objective-C when it has finished loading -// personal data from the web database. -@protocol PersonalDataManagerObserverBridgeDelegate<NSObject> +// PersonalDataManagerObserver is used by PersonalDataManager to informs its +// client implemented in Objective-C when it has finished loading personal data +// from the web database. +@protocol PersonalDataManagerObserver<NSObject> // Called when the PersonalDataManager changed in some way. - (void)onPersonalDataChanged; @@ -32,7 +32,7 @@ namespace autofill { class PersonalDataManagerObserverBridge : public PersonalDataManagerObserver { public: explicit PersonalDataManagerObserverBridge( - id<PersonalDataManagerObserverBridgeDelegate> delegate); + id<PersonalDataManagerObserver> delegate); ~PersonalDataManagerObserverBridge() override; // PersonalDataManagerObserver implementation. @@ -40,7 +40,7 @@ class PersonalDataManagerObserverBridge : public PersonalDataManagerObserver { void OnInsufficientFormData() override; private: - __unsafe_unretained id<PersonalDataManagerObserverBridgeDelegate> delegate_; + __weak id<PersonalDataManagerObserver> delegate_; DISALLOW_COPY_AND_ASSIGN(PersonalDataManagerObserverBridge); }; diff --git a/chromium/components/autofill/ios/browser/personal_data_manager_observer_bridge.mm b/chromium/components/autofill/ios/browser/personal_data_manager_observer_bridge.mm index bb3c48f63da..ed247acd3c5 100644 --- a/chromium/components/autofill/ios/browser/personal_data_manager_observer_bridge.mm +++ b/chromium/components/autofill/ios/browser/personal_data_manager_observer_bridge.mm @@ -13,7 +13,7 @@ namespace autofill { PersonalDataManagerObserverBridge::PersonalDataManagerObserverBridge( - id<PersonalDataManagerObserverBridgeDelegate> delegate) + id<PersonalDataManagerObserver> delegate) : delegate_(delegate) { DCHECK(delegate_); } diff --git a/chromium/components/autofill/ios/form_util/BUILD.gn b/chromium/components/autofill/ios/form_util/BUILD.gn index 3b0c7ee87ba..30daeef241f 100644 --- a/chromium/components/autofill/ios/form_util/BUILD.gn +++ b/chromium/components/autofill/ios/form_util/BUILD.gn @@ -56,7 +56,6 @@ source_set("unit_tests") { "//ios/chrome/browser/browser_state:test_support", "//ios/chrome/browser/tabs:tabs_internal", "//ios/chrome/browser/web:test_support", - "//ios/testing:ios_test_support", "//ios/web/public/test", "//ios/web/public/test/fakes", "//ios/web/web_state/js", diff --git a/chromium/components/autofill/ios/form_util/DEPS b/chromium/components/autofill/ios/form_util/DEPS deleted file mode 100644 index 4c30da6e895..00000000000 --- a/chromium/components/autofill/ios/form_util/DEPS +++ /dev/null @@ -1,6 +0,0 @@ -specific_include_rules = { - # Unittests using form.js need page_script_util to inject the script. - "form_unittest\.mm": [ - "+ios/web/web_state/js/page_script_util.h", - ], -} diff --git a/chromium/components/autofill/ios/form_util/form_activity_tab_helper.h b/chromium/components/autofill/ios/form_util/form_activity_tab_helper.h index ef98869b5d8..631770bce6d 100644 --- a/chromium/components/autofill/ios/form_util/form_activity_tab_helper.h +++ b/chromium/components/autofill/ios/form_util/form_activity_tab_helper.h @@ -64,7 +64,7 @@ class FormActivityTabHelper web::WebState* web_state_ = nullptr; // The observers. - base::ObserverList<FormActivityObserver> observers_; + base::ObserverList<FormActivityObserver>::Unchecked observers_; DISALLOW_COPY_AND_ASSIGN(FormActivityTabHelper); }; diff --git a/chromium/components/autofill/ios/form_util/form_activity_tab_helper_unittest.mm b/chromium/components/autofill/ios/form_util/form_activity_tab_helper_unittest.mm index 27731e1b829..38e9f605e9a 100644 --- a/chromium/components/autofill/ios/form_util/form_activity_tab_helper_unittest.mm +++ b/chromium/components/autofill/ios/form_util/form_activity_tab_helper_unittest.mm @@ -10,17 +10,26 @@ #import "ios/web/public/test/fakes/test_web_client.h" #import "ios/web/public/test/fakes/test_web_state.h" #import "ios/web/public/test/fakes/test_web_state_observer_util.h" +#import "ios/web/public/test/js_test_util.h" #import "ios/web/public/test/web_js_test.h" #import "ios/web/public/test/web_test_with_web_state.h" #include "testing/platform_test.h" +class FormTestClient : public web::TestWebClient { + public: + NSString* GetDocumentStartScriptForAllFrames( + web::BrowserState* browser_state) const override { + return web::test::GetPageScript(@"form"); + } +}; + // Test fixture for autofill::FormActivityTabHelper class. class FormActivityTabHelperTest : public web::WebJsTest<web::WebTestWithWebState> { public: FormActivityTabHelperTest() : web::WebJsTest<web::WebTestWithWebState>( - @[ @"chrome_bundle_all_frames" ]) {} + std::make_unique<FormTestClient>()) {} void SetUp() override { web::WebJsTest<web::WebTestWithWebState>::SetUp(); diff --git a/chromium/components/autofill/ios/form_util/form_unittest.mm b/chromium/components/autofill/ios/form_util/form_unittest.mm index 6ff183c2143..6f535c37f0b 100644 --- a/chromium/components/autofill/ios/form_util/form_unittest.mm +++ b/chromium/components/autofill/ios/form_util/form_unittest.mm @@ -7,9 +7,9 @@ #import "ios/web/public/browser_state.h" #import "ios/web/public/test/fakes/test_web_client.h" #include "ios/web/public/test/fakes/test_web_state_observer.h" +#import "ios/web/public/test/js_test_util.h" #import "ios/web/public/test/web_js_test.h" #import "ios/web/public/test/web_test_with_web_state.h" -#import "ios/web/web_state/js/page_script_util.h" #include "testing/gtest/include/gtest/gtest.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -20,7 +20,7 @@ class FormTestClient : public web::TestWebClient { public: NSString* GetDocumentStartScriptForAllFrames( web::BrowserState* browser_state) const override { - return web::GetPageScript(@"form"); + return web::test::GetPageScript(@"form"); } }; diff --git a/chromium/components/autofill/ios/form_util/resources/form.js b/chromium/components/autofill/ios/form_util/resources/form.js index efb0aaf6a59..7c3fa23c232 100644 --- a/chromium/components/autofill/ios/form_util/resources/form.js +++ b/chromium/components/autofill/ios/form_util/resources/form.js @@ -73,7 +73,7 @@ __gCrWeb.form.lastFocusedElement = null; * programmatically. * If the map is null, the source of changed is not track. */ - __gCrWeb.form.wasEditedByUser = null; +__gCrWeb.form.wasEditedByUser = null; /** * Based on Element::isFormControlElement() (WebKit) @@ -310,7 +310,8 @@ __gCrWeb.form.getFormElementFromIdentifier = function(name) { * If called multiple times on the same runloop, only the last message is really * sent. */ -var sendMessageOnNextLoop_ = function(mesg) { +var sendMessageOnNextLoop_ = + function(mesg) { if (!__gCrWeb.form.messageToSend) { setTimeout(function() { __gCrWeb.message.invokeOnHost(__gCrWeb.form.messageToSend); @@ -343,7 +344,8 @@ var formActivity_ = function(evt) { if (evt.type != 'blur') { __gCrWeb.form.lastFocusedElement = document.activeElement; } - if (['change', 'input'].includes(evt.type)) { + if (['change', 'input'].includes(evt.type) && + __gCrWeb.form.wasEditedByUser !== null) { __gCrWeb.form.wasEditedByUser.set(target, evt.isTrusted); } if (target != __gCrWeb.form.lastFocusedElement) return; @@ -397,8 +399,7 @@ var getFullyQualifiedUrl_ = function(originalURL) { * to this function are ignored. */ var sendFormMutationMessageAfterDelay_ = function(msg, delay) { - if (__gCrWeb.form.formMutationMessageToSend) - return; + if (__gCrWeb.form.formMutationMessageToSend) return; __gCrWeb.form.formMutationMessageToSend = msg; setTimeout(function() { @@ -419,12 +420,12 @@ var attachListeners_ = function() { document.addEventListener('change', formActivity_, true); document.addEventListener('input', formActivity_, true); - /** - * Other events are watched at the bubbling phase as this seems adequate in - * practice and it is less obtrusive to page scripts than capture phase. - */ + /** + * Other events are watched at the bubbling phase as this seems adequate in + * practice and it is less obtrusive to page scripts than capture phase. + */ document.addEventListener('keyup', formActivity_, false); - document.addEventListener('submit',submitHandler_, false); + document.addEventListener('submit', submitHandler_, false); }; // Attach the listeners immediatly to try to catch early actions of the user. @@ -447,22 +448,19 @@ __gCrWeb.form['trackFormMutations'] = function(delay) { __gCrWeb.form.formMutationObserver = null; } - if (!delay) - return; + if (!delay) return; __gCrWeb.form.formMutationObserver = new MutationObserver(function(mutations) { for (var i = 0; i < mutations.length; i++) { var mutation = mutations[i]; // Only process mutations to the tree of nodes. - if (mutation.type != 'childList') - continue; + if (mutation.type != 'childList') continue; var addedElements = []; for (var j = 0; j < mutation.addedNodes.length; j++) { var node = mutation.addedNodes[j]; // Ignore non-element nodes. - if (node.nodeType != Node.ELEMENT_NODE) - continue; + if (node.nodeType != Node.ELEMENT_NODE) continue; addedElements.push(node); [].push.apply( addedElements, [].slice.call(node.getElementsByTagName('*'))); @@ -492,7 +490,8 @@ __gCrWeb.form['trackFormMutations'] = function(delay) { /** * Enables or disables the tracking of input event sources. */ -__gCrWeb.form['toggleTrackingUserEditedFields'] = function(track) { +__gCrWeb.form['toggleTrackingUserEditedFields'] = + function(track) { if (track) { __gCrWeb.form.wasEditedByUser = __gCrWeb.form.wasEditedByUser || new WeakMap(); @@ -501,11 +500,12 @@ __gCrWeb.form['toggleTrackingUserEditedFields'] = function(track) { } } -/** - * Returns whether the last |input| or |change| event on |element| was triggered - * by a user action (was "trusted"). - */ -__gCrWeb.form['fieldWasEditedByUser'] = function(element) { + /** + * Returns whether the last |input| or |change| event on |element| was + * triggered by a user action (was "trusted"). + */ + __gCrWeb.form['fieldWasEditedByUser'] = + function(element) { if (__gCrWeb.form.wasEditedByUser === null) { // Input event sources is not tracked. // Return true to preserve previous behavior. |