diff --git a/DEPS b/DEPS index 47def3f9..593a119 100644 --- a/DEPS +++ b/DEPS
@@ -44,7 +44,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': 'bfd28fa684ee3c9efcfc3bbe6bae4f9464212ef2', + 'v8_revision': '144ff1bd42847cd3016044051c6cadd28d2230da', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other.
diff --git a/chrome/browser/android/bookmarks/partner_bookmarks_shim.cc b/chrome/browser/android/bookmarks/partner_bookmarks_shim.cc index b1cc322..3be4556c 100644 --- a/chrome/browser/android/bookmarks/partner_bookmarks_shim.cc +++ b/chrome/browser/android/bookmarks/partner_bookmarks_shim.cc
@@ -65,7 +65,8 @@ data = new PartnerBookmarksShim( Profile::FromBrowserContext(browser_context)->GetPrefs()); - browser_context->SetUserData(kPartnerBookmarksShimUserDataKey, data); + browser_context->SetUserData(kPartnerBookmarksShimUserDataKey, + base::WrapUnique(data)); data->ReloadNodeMapping(); return data; }
diff --git a/chrome/browser/android/bookmarks/partner_bookmarks_shim.h b/chrome/browser/android/bookmarks/partner_bookmarks_shim.h index e0d3e53..b43cb638 100644 --- a/chrome/browser/android/bookmarks/partner_bookmarks_shim.h +++ b/chrome/browser/android/bookmarks/partner_bookmarks_shim.h
@@ -33,6 +33,8 @@ // Note that node->GetTitle() returns an original (unmodified) title. class PartnerBookmarksShim : public base::SupportsUserData::Data { public: + ~PartnerBookmarksShim() override; + // Returns an instance of the shim for a given |browser_context|. static PartnerBookmarksShim* BuildForBrowserContext( content::BrowserContext* browser_context); @@ -126,7 +128,6 @@ private: explicit PartnerBookmarksShim(PrefService* prefs); - ~PartnerBookmarksShim() override; const bookmarks::BookmarkNode* GetNodeByID( const bookmarks::BookmarkNode* parent,
diff --git a/chrome/browser/android/download/chrome_download_delegate.h b/chrome/browser/android/download/chrome_download_delegate.h index 9e0347b..d1a6e69 100644 --- a/chrome/browser/android/download/chrome_download_delegate.h +++ b/chrome/browser/android/download/chrome_download_delegate.h
@@ -11,6 +11,8 @@ class ChromeDownloadDelegate : public content::WebContentsUserData<ChromeDownloadDelegate> { public: + ~ChromeDownloadDelegate() override; + // Returns true iff this request resulted in the tab creating the download // to close. static bool EnqueueDownloadManagerRequest(jobject chrome_download_delegate, @@ -33,7 +35,6 @@ private: explicit ChromeDownloadDelegate(content::WebContents* contents); friend class content::WebContentsUserData<ChromeDownloadDelegate>; - ~ChromeDownloadDelegate() override; // A reference to the Java ChromeDownloadDelegate object. jobject java_ref_;
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc index b933c69..b1d8dd3b5 100644 --- a/chrome/browser/extensions/api/downloads/downloads_api.cc +++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -620,7 +620,7 @@ determined_conflict_action_( downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - download_item->SetUserData(kKey, this); + download_item->SetUserData(kKey, base::WrapUnique(this)); } ~ExtensionDownloadsEventRouterData() override { @@ -954,7 +954,7 @@ const std::string& name) : id_(id), name_(name) { - item->SetUserData(kKey, this); + item->SetUserData(kKey, base::WrapUnique(this)); } DownloadsDownloadFunction::DownloadsDownloadFunction() {}
diff --git a/chrome/browser/extensions/api/tab_capture/offscreen_tab.h b/chrome/browser/extensions/api/tab_capture/offscreen_tab.h index 1df9a346..7d42cd4 100644 --- a/chrome/browser/extensions/api/tab_capture/offscreen_tab.h +++ b/chrome/browser/extensions/api/tab_capture/offscreen_tab.h
@@ -36,7 +36,7 @@ // // This class operates exclusively on the UI thread and so is not thread-safe. class OffscreenTabsOwner - : protected content::WebContentsUserData<OffscreenTabsOwner> { + : public content::WebContentsUserData<OffscreenTabsOwner> { public: ~OffscreenTabsOwner() final;
diff --git a/chrome/browser/extensions/chrome_extension_web_contents_observer.h b/chrome/browser/extensions/chrome_extension_web_contents_observer.h index 11ab88c..898dd61 100644 --- a/chrome/browser/extensions/chrome_extension_web_contents_observer.h +++ b/chrome/browser/extensions/chrome_extension_web_contents_observer.h
@@ -26,12 +26,14 @@ class ChromeExtensionWebContentsObserver : public ExtensionWebContentsObserver, public content::WebContentsUserData<ChromeExtensionWebContentsObserver> { + public: + ~ChromeExtensionWebContentsObserver() override; + private: friend class content::WebContentsUserData<ChromeExtensionWebContentsObserver>; explicit ChromeExtensionWebContentsObserver( content::WebContents* web_contents); - ~ChromeExtensionWebContentsObserver() override; // ExtensionWebContentsObserver: void InitializeRenderFrame(
diff --git a/chrome/browser/extensions/user_script_listener_unittest.cc b/chrome/browser/extensions/user_script_listener_unittest.cc index ec0f8111..bdc92d7 100644 --- a/chrome/browser/extensions/user_script_listener_unittest.cc +++ b/chrome/browser/extensions/user_script_listener_unittest.cc
@@ -10,6 +10,7 @@ #include "base/files/file_util.h" #include "base/json/json_file_value_serializer.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/threading/thread.h" #include "chrome/browser/chrome_notification_types.h" @@ -184,8 +185,8 @@ bool defer = false; if (throttle) { - request->SetUserData(nullptr, - new ThrottleDelegate(request.get(), throttle)); + request->SetUserData( + nullptr, base::MakeUnique<ThrottleDelegate>(request.get(), throttle)); throttle->WillStartRequest(&defer); } @@ -358,7 +359,8 @@ ResourceThrottle* throttle = listener_->CreateResourceThrottle(url, content::RESOURCE_TYPE_MAIN_FRAME); ASSERT_TRUE(throttle); - request->SetUserData(nullptr, new ThrottleDelegate(request.get(), throttle)); + request->SetUserData( + nullptr, base::MakeUnique<ThrottleDelegate>(request.get(), throttle)); ASSERT_FALSE(request->is_pending());
diff --git a/chrome/browser/extensions/webstore_installer.cc b/chrome/browser/extensions/webstore_installer.cc index 75320e06..3e7ff15 100644 --- a/chrome/browser/extensions/webstore_installer.cc +++ b/chrome/browser/extensions/webstore_installer.cc
@@ -496,12 +496,12 @@ if (version_required.IsValid()) { approval->minimum_version.reset(new base::Version(version_required)); } - download_item_->SetUserData(kApprovalKey, approval.release()); + download_item_->SetUserData(kApprovalKey, std::move(approval)); } else { // It is for the main module of the extension. We should use the provided // |approval_|. if (approval_) - download_item_->SetUserData(kApprovalKey, approval_.release()); + download_item_->SetUserData(kApprovalKey, std::move(approval_)); } if (!download_started_) {
diff --git a/chrome/browser/ui/views/payments/contact_info_editor_view_controller.cc b/chrome/browser/ui/views/payments/contact_info_editor_view_controller.cc index 32bbdd9..a9cede0f 100644 --- a/chrome/browser/ui/views/payments/contact_info_editor_view_controller.cc +++ b/chrome/browser/ui/views/payments/contact_info_editor_view_controller.cc
@@ -78,6 +78,7 @@ if (profile_to_edit_) { PopulateProfile(profile_to_edit_); state()->GetPersonalDataManager()->UpdateProfile(*profile_to_edit_); + state()->profile_comparator()->Invalidate(*profile_to_edit_); } else { std::unique_ptr<autofill::AutofillProfile> profile = base::MakeUnique<autofill::AutofillProfile>();
diff --git a/chrome/browser/ui/views/payments/order_summary_view_controller_browsertest.cc b/chrome/browser/ui/views/payments/order_summary_view_controller_browsertest.cc index b33d48a..c8e6070 100644 --- a/chrome/browser/ui/views/payments/order_summary_view_controller_browsertest.cc +++ b/chrome/browser/ui/views/payments/order_summary_view_controller_browsertest.cc
@@ -59,7 +59,7 @@ DialogViewID::SHIPPING_ADDRESS_SHEET_LIST_VIEW); // Michigan address is selected and has standard shipping. - std::vector<base::string16> shipping_address_labels = GetThreeLineLabelValues( + std::vector<base::string16> shipping_address_labels = GetProfileLabelValues( DialogViewID::PAYMENT_SHEET_SHIPPING_ADDRESS_SECTION); EXPECT_EQ(base::ASCIIToUTF16("Jane A. Smith"), shipping_address_labels[0]); EXPECT_EQ( @@ -95,7 +95,7 @@ DialogViewID::SHIPPING_ADDRESS_SHEET_LIST_VIEW); // California address is selected and has free shipping. - shipping_address_labels = GetThreeLineLabelValues( + shipping_address_labels = GetProfileLabelValues( DialogViewID::PAYMENT_SHEET_SHIPPING_ADDRESS_SECTION); EXPECT_EQ(base::ASCIIToUTF16("John H. Doe"), shipping_address_labels[0]); EXPECT_EQ(base::ASCIIToUTF16(
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc index 513e143..4f0383b5 100644 --- a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc +++ b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
@@ -428,7 +428,7 @@ } std::vector<base::string16> -PaymentRequestBrowserTestBase::GetThreeLineLabelValues( +PaymentRequestBrowserTestBase::GetProfileLabelValues( DialogViewID parent_view_id) { std::vector<base::string16> line_labels; views::View* parent_view = @@ -436,15 +436,19 @@ EXPECT_TRUE(parent_view); views::View* view = parent_view->GetViewByID( - static_cast<int>(DialogViewID::THREE_LINE_LABEL_LINE_1)); + static_cast<int>(DialogViewID::PROFILE_LABEL_LINE_1)); if (view) line_labels.push_back(static_cast<views::Label*>(view)->text()); view = parent_view->GetViewByID( - static_cast<int>(DialogViewID::THREE_LINE_LABEL_LINE_2)); + static_cast<int>(DialogViewID::PROFILE_LABEL_LINE_2)); if (view) line_labels.push_back(static_cast<views::Label*>(view)->text()); view = parent_view->GetViewByID( - static_cast<int>(DialogViewID::THREE_LINE_LABEL_LINE_3)); + static_cast<int>(DialogViewID::PROFILE_LABEL_LINE_3)); + if (view) + line_labels.push_back(static_cast<views::Label*>(view)->text()); + view = parent_view->GetViewByID( + static_cast<int>(DialogViewID::PROFILE_LABEL_ERROR)); if (view) line_labels.push_back(static_cast<views::Label*>(view)->text());
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest_base.h b/chrome/browser/ui/views/payments/payment_request_browsertest_base.h index 2ecb66c..1b328f6 100644 --- a/chrome/browser/ui/views/payments/payment_request_browsertest_base.h +++ b/chrome/browser/ui/views/payments/payment_request_browsertest_base.h
@@ -148,8 +148,8 @@ void ClickOnChildInListViewAndWait(int child_index, int total_num_children, DialogViewID list_view_id); - // Returns "three-line label" values under |parent_view|. - std::vector<base::string16> GetThreeLineLabelValues( + // Returns profile label values under |parent_view|. + std::vector<base::string16> GetProfileLabelValues( DialogViewID parent_view_id); // Returns the shipping option labels under |parent_view_id|. std::vector<base::string16> GetShippingOptionLabelValues(
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h b/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h index 55ef6331..cce2f80 100644 --- a/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h +++ b/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h
@@ -45,10 +45,11 @@ SHIPPING_OPTION_DESCRIPTION, SHIPPING_OPTION_AMOUNT, - // Used in "three line labels" to annotate each Label of the grouping. - THREE_LINE_LABEL_LINE_1, - THREE_LINE_LABEL_LINE_2, - THREE_LINE_LABEL_LINE_3, + // Used in profile labels to annotate each line of the grouping. + PROFILE_LABEL_LINE_1, + PROFILE_LABEL_LINE_2, + PROFILE_LABEL_LINE_3, + PROFILE_LABEL_ERROR, // The following are views contained within the Payment Method Sheet. CONTACT_INFO_SHEET_LIST_VIEW,
diff --git a/chrome/browser/ui/views/payments/payment_request_views_util.cc b/chrome/browser/ui/views/payments/payment_request_views_util.cc index 62cc31e..cbdb5d8 100644 --- a/chrome/browser/ui/views/payments/payment_request_views_util.cc +++ b/chrome/browser/ui/views/payments/payment_request_views_util.cc
@@ -19,6 +19,7 @@ #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/field_types.h" #include "components/payments/core/payment_options_provider.h" +#include "components/payments/core/payments_profile_comparator.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" @@ -27,6 +28,7 @@ #include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/point_f.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/native_theme/native_theme.h" #include "ui/vector_icons/vector_icons.h" #include "ui/views/border.h" #include "ui/views/bubble/bubble_frame_view.h" @@ -63,10 +65,15 @@ return profile.ConstructInferredLabel(fields, fields.size(), locale); } -std::unique_ptr<views::View> GetThreeLineLabel(AddressStyleType type, - const base::string16& s1, - const base::string16& s2, - const base::string16& s3) { +// |s1|, |s2|, and |s3| are lines identifying the profile. |s1| is the +// "headline" which may be emphasized depending on |type|. |error| is a +// message indicating errors that need to be resolved before using this +// profile. +std::unique_ptr<views::View> GetProfileLabel(AddressStyleType type, + const base::string16& s1, + const base::string16& s2, + const base::string16& s3, + const base::string16& error) { std::unique_ptr<views::View> container = base::MakeUnique<views::View>(); std::unique_ptr<views::BoxLayout> layout = base::MakeUnique<views::BoxLayout>(views::BoxLayout::kVertical, 0, 0, 0); @@ -80,26 +87,33 @@ const gfx::FontList& font_list = label->font_list(); label->SetFontList(font_list.DeriveWithWeight(gfx::Font::Weight::BOLD)); } - label->set_id(static_cast<int>(DialogViewID::THREE_LINE_LABEL_LINE_1)); + label->set_id(static_cast<int>(DialogViewID::PROFILE_LABEL_LINE_1)); label->SetHorizontalAlignment(gfx::ALIGN_LEFT); container->AddChildView(label.release()); } if (!s2.empty()) { std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>(s2); - label->set_id(static_cast<int>(DialogViewID::THREE_LINE_LABEL_LINE_2)); + label->set_id(static_cast<int>(DialogViewID::PROFILE_LABEL_LINE_2)); label->SetHorizontalAlignment(gfx::ALIGN_LEFT); container->AddChildView(label.release()); } if (!s3.empty()) { std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>(s3); - label->set_id(static_cast<int>(DialogViewID::THREE_LINE_LABEL_LINE_3)); + label->set_id(static_cast<int>(DialogViewID::PROFILE_LABEL_LINE_3)); label->SetHorizontalAlignment(gfx::ALIGN_LEFT); container->AddChildView(label.release()); } - // TODO(anthonyvd): add the error label + if (!error.empty()) { + std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>(error); + label->set_id(static_cast<int>(DialogViewID::PROFILE_LABEL_ERROR)); + label->SetFontList(label->GetDefaultFontList().DeriveWithSizeDelta(-1)); + label->SetEnabledColor(label->GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_LinkEnabled)); + container->AddChildView(label.release()); + } return container; } @@ -231,7 +245,9 @@ std::unique_ptr<views::View> GetShippingAddressLabel( AddressStyleType type, const std::string& locale, - const autofill::AutofillProfile& profile) { + const autofill::AutofillProfile& profile, + const PaymentOptionsProvider& options, + const PaymentsProfileComparator& comp) { base::string16 name = profile.GetInfo(autofill::AutofillType(autofill::NAME_FULL), locale); @@ -240,7 +256,9 @@ base::string16 phone = profile.GetInfo( autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER), locale); - return GetThreeLineLabel(type, name, address, phone); + base::string16 error = comp.GetStringForMissingShippingFields(profile); + + return GetProfileLabel(type, name, address, phone, error); } // TODO(anthonyvd): unit test the label layout. @@ -248,7 +266,8 @@ AddressStyleType type, const std::string& locale, const autofill::AutofillProfile& profile, - const PaymentOptionsProvider& options) { + const PaymentOptionsProvider& options, + const PaymentsProfileComparator& comp) { base::string16 name = options.request_payer_name() ? profile.GetInfo(autofill::AutofillType(autofill::NAME_FULL), locale) @@ -267,7 +286,9 @@ locale) : base::string16(); - return GetThreeLineLabel(type, name, phone, email); + base::string16 error = comp.GetStringForMissingContactFields(profile); + + return GetProfileLabel(type, name, phone, email, error); } std::unique_ptr<views::Border> CreatePaymentRequestRowBorder() {
diff --git a/chrome/browser/ui/views/payments/payment_request_views_util.h b/chrome/browser/ui/views/payments/payment_request_views_util.h index 92515391..5821f18c 100644 --- a/chrome/browser/ui/views/payments/payment_request_views_util.h +++ b/chrome/browser/ui/views/payments/payment_request_views_util.h
@@ -26,6 +26,7 @@ namespace payments { class PaymentOptionsProvider; +class PaymentsProfileComparator; enum class PaymentShippingType; constexpr int kPaymentRequestRowHorizontalInsets = 16; @@ -81,7 +82,9 @@ std::unique_ptr<views::View> GetShippingAddressLabel( AddressStyleType type, const std::string& locale, - const autofill::AutofillProfile& profile); + const autofill::AutofillProfile& profile, + const PaymentOptionsProvider& options, + const PaymentsProfileComparator& comp); // Extracts and formats descriptive text from the given |profile| to represent // the contact info in the context specified by |type|. Includes/excludes name, @@ -90,7 +93,8 @@ AddressStyleType type, const std::string& locale, const autofill::AutofillProfile& profile, - const PaymentOptionsProvider& options); + const PaymentOptionsProvider& options, + const PaymentsProfileComparator& comp); // Creates a views::Border object that can paint the gray horizontal ruler used // as a separator between items in the Payment Request dialog.
diff --git a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc index 32a1d22..e413ea9 100644 --- a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc +++ b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
@@ -600,10 +600,11 @@ } else { auto* profile = state()->selected_shipping_profile(); - return profile ? GetShippingAddressLabel(AddressStyleType::SUMMARY, - state()->GetApplicationLocale(), - *profile) - : base::MakeUnique<views::Label>(base::string16()); + return profile + ? GetShippingAddressLabel( + AddressStyleType::SUMMARY, state()->GetApplicationLocale(), + *profile, *spec(), *(state()->profile_comparator())) + : base::MakeUnique<views::Label>(base::string16()); } } @@ -736,10 +737,11 @@ std::unique_ptr<views::View> PaymentSheetViewController::CreateContactInfoSectionContent() { autofill::AutofillProfile* profile = state()->selected_contact_profile(); - return profile ? payments::GetContactInfoLabel( - AddressStyleType::SUMMARY, - state()->GetApplicationLocale(), *profile, *spec()) - : base::MakeUnique<views::Label>(base::string16()); + return profile + ? payments::GetContactInfoLabel( + AddressStyleType::SUMMARY, state()->GetApplicationLocale(), + *profile, *spec(), *(state()->profile_comparator())) + : base::MakeUnique<views::Label>(base::string16()); } // Creates the Contact Info row, which contains a "Contact info" label; the
diff --git a/chrome/browser/ui/views/payments/profile_list_view_controller.cc b/chrome/browser/ui/views/payments/profile_list_view_controller.cc index 4ff1043..bf552f5 100644 --- a/chrome/browser/ui/views/payments/profile_list_view_controller.cc +++ b/chrome/browser/ui/views/payments/profile_list_view_controller.cc
@@ -11,6 +11,7 @@ #include "chrome/grit/generated_resources.h" #include "components/payments/content/payment_request_spec.h" #include "components/payments/content/payment_request_state.h" +#include "components/payments/core/payments_profile_comparator.h" #include "components/payments/core/strings_util.h" #include "components/strings/grit/components_strings.h" #include "ui/base/l10n/l10n_util.h" @@ -75,9 +76,7 @@ } bool CanBeSelected() const override { - // TODO(crbug.com/709454): Check for profile completeness. Currently a giant - // hack to test the UI. - return !profile_->GetRawInfo(autofill::ADDRESS_HOME_ZIP).empty(); + return parent_view_->IsValidProfile(*profile_); } void PerformSelectionFallback() override { @@ -108,7 +107,8 @@ std::unique_ptr<views::View> GetLabel( autofill::AutofillProfile* profile) override { return GetShippingAddressLabel(AddressStyleType::DETAILED, - state()->GetApplicationLocale(), *profile); + state()->GetApplicationLocale(), *profile, + *spec(), *(state()->profile_comparator())); } void SelectProfile(autofill::AutofillProfile* profile) override { @@ -130,6 +130,10 @@ return state()->selected_shipping_profile(); } + bool IsValidProfile(const autofill::AutofillProfile& profile) override { + return state()->profile_comparator()->IsShippingComplete(&profile); + } + std::vector<autofill::AutofillProfile*> GetProfiles() override { return state()->shipping_profiles(); } @@ -175,7 +179,7 @@ autofill::AutofillProfile* profile) override { return GetContactInfoLabel(AddressStyleType::DETAILED, state()->GetApplicationLocale(), *profile, - *spec()); + *spec(), *(state()->profile_comparator())); } void SelectProfile(autofill::AutofillProfile* profile) override { @@ -190,6 +194,10 @@ return state()->selected_contact_profile(); } + bool IsValidProfile(const autofill::AutofillProfile& profile) override { + return state()->profile_comparator()->IsContactInfoComplete(&profile); + } + std::vector<autofill::AutofillProfile*> GetProfiles() override { return state()->contact_profiles(); }
diff --git a/chrome/browser/ui/views/payments/profile_list_view_controller.h b/chrome/browser/ui/views/payments/profile_list_view_controller.h index 7e1af22..1f1705a 100644 --- a/chrome/browser/ui/views/payments/profile_list_view_controller.h +++ b/chrome/browser/ui/views/payments/profile_list_view_controller.h
@@ -65,6 +65,8 @@ virtual autofill::AutofillProfile* GetSelectedProfile() = 0; + virtual bool IsValidProfile(const autofill::AutofillProfile& profile) = 0; + protected: // Does not take ownership of the arguments, which should outlive this object. ProfileListViewController(PaymentRequestSpec* spec,
diff --git a/chrome/browser/ui/views/payments/shipping_address_editor_view_controller.cc b/chrome/browser/ui/views/payments/shipping_address_editor_view_controller.cc index 1a868b56..19d1039 100644 --- a/chrome/browser/ui/views/payments/shipping_address_editor_view_controller.cc +++ b/chrome/browser/ui/views/payments/shipping_address_editor_view_controller.cc
@@ -26,6 +26,7 @@ #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/payments/content/payment_request_state.h" +#include "components/payments/core/payments_profile_comparator.h" #include "components/strings/grit/components_strings.h" #include "third_party/libaddressinput/messages.h" #include "ui/base/l10n/l10n_util.h" @@ -129,6 +130,7 @@ DCHECK(success); profile_to_edit_->set_origin(autofill::kSettingsOrigin); state()->GetPersonalDataManager()->UpdateProfile(*profile_to_edit_); + state()->profile_comparator()->Invalidate(*profile_to_edit_); std::move(on_edited_).Run(); on_added_.Reset(); }
diff --git a/chrome/browser/ui/views/payments/shipping_option_view_controller_browsertest.cc b/chrome/browser/ui/views/payments/shipping_option_view_controller_browsertest.cc index 9764dca..f5fe1dc0 100644 --- a/chrome/browser/ui/views/payments/shipping_option_view_controller_browsertest.cc +++ b/chrome/browser/ui/views/payments/shipping_option_view_controller_browsertest.cc
@@ -52,7 +52,7 @@ DialogViewID::SHIPPING_ADDRESS_SHEET_LIST_VIEW); // Michigan address is selected and has standard shipping. - std::vector<base::string16> shipping_address_labels = GetThreeLineLabelValues( + std::vector<base::string16> shipping_address_labels = GetProfileLabelValues( DialogViewID::PAYMENT_SHEET_SHIPPING_ADDRESS_SECTION); EXPECT_EQ(base::ASCIIToUTF16("Jane A. Smith"), shipping_address_labels[0]); EXPECT_EQ(
diff --git a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc index d655542..6d53266 100644 --- a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc
@@ -4,12 +4,14 @@ #include "chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h" +#include <cmath> #include <string> #include <utility> #include "ash/system/devicetype_utils.h" #include "base/command_line.h" #include "base/files/file_path.h" +#include "base/metrics/histogram_macros.h" #include "base/sys_info.h" #include "base/task_scheduler/post_task.h" #include "chrome/browser/browser_process.h" @@ -46,11 +48,47 @@ constexpr char kJsApiSkipMigration[] = "skipMigration"; constexpr char kJsApiRequestRestart[] = "requestRestart"; +// UMA names. +constexpr char kUmaNameFirstScreen[] = "Cryptohome.MigrationUI.FirstScreen"; +constexpr char kUmaNameUserChoice[] = "Cryptohome.MigrationUI.UserChoice"; +constexpr char kUmaNameConsumedBatteryPercent[] = + "Cryptohome.MigrationUI.ConsumedBatteryPercent"; + +// This enum must match the numbering for Cryptohome.MigrationUI.FirstScreen in +// histograms.xml. Do not reorder or remove items, only add new items before +// FIRST_SCREEN_MAX. +enum class FirstScreen { + FIRST_SCREEN_READY = 0, + FIRST_SCREEN_RESUME = 1, + FIRST_SCREEN_LOW_STORAGE = 2, + FIRST_SCREEN_COUNT +}; + +// This enum must match the numbering for Cryptohome.MigrationUI.UserChoice in +// histograms.xml. Do not reorder or remove items, only add new items before +// FIRST_SCREEN_MAX. +enum class UserChoice { + USER_CHOICE_UPDATE = 0, + USER_CHOICE_SKIP = 1, + USER_CHOICE_COUNT +}; + bool IsTestingUI() { return base::CommandLine::ForCurrentProcess()->HasSwitch( chromeos::switches::kTestEncryptionMigrationUI); } +// Wrapper functions for histogram macros to avoid duplication of expanded code. +void RecordFirstScreen(FirstScreen first_screen) { + UMA_HISTOGRAM_ENUMERATION(kUmaNameFirstScreen, static_cast<int>(first_screen), + static_cast<int>(FirstScreen::FIRST_SCREEN_COUNT)); +} + +void RecordUserChoice(UserChoice user_choice) { + UMA_HISTOGRAM_ENUMERATION(kUmaNameUserChoice, static_cast<int>(user_choice), + static_cast<int>(UserChoice::USER_CHOICE_COUNT)); +} + } // namespace namespace chromeos { @@ -187,10 +225,12 @@ } void EncryptionMigrationScreenHandler::HandleStartMigration() { + RecordUserChoice(UserChoice::USER_CHOICE_UPDATE); WaitBatteryAndMigrate(); } void EncryptionMigrationScreenHandler::HandleSkipMigration() { + RecordUserChoice(UserChoice::USER_CHOICE_SKIP); // If the user skips migration, we mount the cryptohome without performing the // migration by reusing UserContext and LoginPerformer which were used in the // previous attempt and dropping |is_forcing_dircrypto| flag in UserContext. @@ -239,11 +279,14 @@ void EncryptionMigrationScreenHandler::OnGetAvailableStorage(int64_t size) { if (size >= kMinimumAvailableStorage || IsTestingUI()) { if (should_resume_) { + RecordFirstScreen(FirstScreen::FIRST_SCREEN_RESUME); WaitBatteryAndMigrate(); } else { + RecordFirstScreen(FirstScreen::FIRST_SCREEN_READY); UpdateUIState(UIState::READY); } } else { + RecordFirstScreen(FirstScreen::FIRST_SCREEN_LOW_STORAGE); CallJS("setAvailableSpaceInString", ui::FormatBytes(size)); CallJS("setNecessarySpaceInString", ui::FormatBytes(kMinimumAvailableStorage)); @@ -264,6 +307,7 @@ void EncryptionMigrationScreenHandler::StartMigration() { UpdateUIState(UIState::MIGRATING); + initial_battery_percent_ = current_battery_percent_; // Mount the existing eCryptfs vault to a temporary location for migration. cryptohome::MountParameters mount(false); @@ -362,6 +406,14 @@ CallJS("setMigrationProgress", static_cast<double>(current) / total); break; case cryptohome::DIRCRYPTO_MIGRATION_SUCCESS: + // If the battery level decreased during migration, record the consumed + // battery level. + if (current_battery_percent_ < initial_battery_percent_) { + UMA_HISTOGRAM_PERCENTAGE( + kUmaNameConsumedBatteryPercent, + static_cast<int>(std::round(initial_battery_percent_ - + current_battery_percent_))); + } // Restart immediately after successful migration. DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart(); break;
diff --git a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h index e65979e..26bbd9a8 100644 --- a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h
@@ -113,6 +113,9 @@ // sufficient. bool should_migrate_on_enough_battery_ = false; + // The battery level at the timing that the migration starts. + double initial_battery_percent_ = 0.0; + std::unique_ptr<device::PowerSaveBlocker> power_save_blocker_; base::WeakPtrFactory<EncryptionMigrationScreenHandler> weak_ptr_factory_;
diff --git a/components/autofill/core/browser/autofill_profile_comparator.h b/components/autofill/core/browser/autofill_profile_comparator.h index 4b69d184..8222c53 100644 --- a/components/autofill/core/browser/autofill_profile_comparator.h +++ b/components/autofill/core/browser/autofill_profile_comparator.h
@@ -215,6 +215,8 @@ const AutofillProfile& p2, NameInfo* info) const; + const std::string app_locale() const { return app_locale_; } + private: l10n::CaseInsensitiveCompare case_insensitive_compare_; std::unique_ptr<icu::Transliterator> transliterator_;
diff --git a/components/payments/content/payment_request_state.cc b/components/payments/content/payment_request_state.cc index afa3213..c43f691 100644 --- a/components/payments/content/payment_request_state.cc +++ b/components/payments/content/payment_request_state.cc
@@ -17,8 +17,8 @@ #include "components/payments/content/payment_response_helper.h" #include "components/payments/core/autofill_payment_instrument.h" #include "components/payments/core/payment_instrument.h" +#include "components/payments/core/payment_request_data_util.h" #include "components/payments/core/payment_request_delegate.h" -#include "components/payments/core/profile_util.h" namespace payments { @@ -37,7 +37,8 @@ selected_shipping_profile_(nullptr), selected_contact_profile_(nullptr), selected_instrument_(nullptr), - payment_request_delegate_(payment_request_delegate) { + payment_request_delegate_(payment_request_delegate), + profile_comparator_(app_locale, *spec) { PopulateProfileCache(); SetDefaultProfileSelections(); spec_->AddObserver(this); @@ -163,10 +164,8 @@ // Start the normalization of the shipping address. // Use the country code from the profile if it is set, otherwise infer it // from the |app_locale_|. - std::string country_code = base::UTF16ToUTF8( - selected_shipping_profile_->GetRawInfo(autofill::ADDRESS_HOME_COUNTRY)); - if (!autofill::data_util::IsValidCountryCode(country_code)) - country_code = autofill::AutofillCountry::CountryCodeForLocale(app_locale_); + std::string country_code = data_util::GetCountryCodeWithFallback( + selected_shipping_profile_, app_locale_); payment_request_delegate_->GetAddressNormalizer()->StartAddressNormalization( *selected_shipping_profile_, country_code, /*timeout_seconds=*/2, this); } @@ -218,8 +217,8 @@ return p.get(); }); - contact_profiles_ = profile_util::FilterProfilesForContact( - raw_profiles_for_filtering, GetApplicationLocale(), *spec_); + contact_profiles_ = profile_comparator()->FilterProfilesForContact( + raw_profiles_for_filtering); // Create the list of available instruments. const std::vector<autofill::CreditCard*>& cards = @@ -274,15 +273,13 @@ } bool PaymentRequestState::ArePaymentOptionsSatisfied() { - // TODO(mathp): Have a measure of shipping address completeness. - if (spec_->request_shipping() && selected_shipping_profile_ == nullptr) - return false; - if (is_waiting_for_merchant_validation_) return false; - profile_util::PaymentsProfileComparator comparator(app_locale_, *spec_); - return comparator.IsContactInfoComplete(selected_contact_profile_); + if (!profile_comparator()->IsShippingComplete(selected_shipping_profile_)) + return false; + + return profile_comparator()->IsContactInfoComplete(selected_contact_profile_); } } // namespace payments
diff --git a/components/payments/content/payment_request_state.h b/components/payments/content/payment_request_state.h index 9749ca45..ece3bc0 100644 --- a/components/payments/content/payment_request_state.h +++ b/components/payments/content/payment_request_state.h
@@ -14,6 +14,7 @@ #include "components/payments/content/payment_request_spec.h" #include "components/payments/content/payment_response_helper.h" #include "components/payments/core/address_normalizer.h" +#include "components/payments/core/payments_profile_comparator.h" #include "components/payments/mojom/payment_request.mojom.h" namespace autofill { @@ -157,6 +158,10 @@ Delegate* delegate() { return delegate_; } + PaymentsProfileComparator* profile_comparator() { + return &profile_comparator_; + } + private: // Fetches the Autofill Profiles for this user from the PersonalDataManager, // and stores copies of them, owned by this PaymentRequestState, in @@ -211,6 +216,8 @@ std::unique_ptr<PaymentResponseHelper> response_helper_; + PaymentsProfileComparator profile_comparator_; + base::ObserverList<Observer> observers_; DISALLOW_COPY_AND_ASSIGN(PaymentRequestState);
diff --git a/components/payments/core/BUILD.gn b/components/payments/core/BUILD.gn index 291a885..8d94990 100644 --- a/components/payments/core/BUILD.gn +++ b/components/payments/core/BUILD.gn
@@ -25,8 +25,8 @@ "payment_request_data_util.cc", "payment_request_data_util.h", "payment_request_delegate.h", - "profile_util.cc", - "profile_util.h", + "payments_profile_comparator.cc", + "payments_profile_comparator.h", "strings_util.cc", "strings_util.h", ] @@ -74,7 +74,7 @@ "payment_address_unittest.cc", "payment_method_data_unittest.cc", "payment_request_data_util_unittest.cc", - "profile_util_unittest.cc", + "payments_profile_comparator_unittest.cc", ] deps = [
diff --git a/components/payments/core/payment_request_data_util.cc b/components/payments/core/payment_request_data_util.cc index 3fd13c9..87ad961 100644 --- a/components/payments/core/payment_request_data_util.cc +++ b/components/payments/core/payment_request_data_util.cc
@@ -7,6 +7,8 @@ #include "base/strings/string16.h" #include "base/strings/string_split.h" #include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_country.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/field_types.h" @@ -162,5 +164,14 @@ PhoneNumberUtil::PhoneNumberFormat::E164); } +std::string GetCountryCodeWithFallback(const autofill::AutofillProfile* profile, + const std::string& app_locale) { + std::string country_code = + base::UTF16ToUTF8(profile->GetRawInfo(autofill::ADDRESS_HOME_COUNTRY)); + if (!autofill::data_util::IsValidCountryCode(country_code)) + country_code = autofill::AutofillCountry::CountryCodeForLocale(app_locale); + return country_code; +} + } // namespace data_util } // namespace payments
diff --git a/components/payments/core/payment_request_data_util.h b/components/payments/core/payment_request_data_util.h index 984fc8b..29593f6 100644 --- a/components/payments/core/payment_request_data_util.h +++ b/components/payments/core/payment_request_data_util.h
@@ -66,6 +66,12 @@ std::string FormatPhoneForResponse(const std::string& phone_number, const std::string& country_code); +// Returns a country code to be used when validating this profile. If the +// profile has a valid country code set, it is returned. If not, a country code +// associated with |app_locale| is used as a fallback. +std::string GetCountryCodeWithFallback(const autofill::AutofillProfile* profile, + const std::string& app_locale); + } // namespace data_util } // namespace payments
diff --git a/components/payments/core/payments_profile_comparator.cc b/components/payments/core/payments_profile_comparator.cc new file mode 100644 index 0000000..832e005 --- /dev/null +++ b/components/payments/core/payments_profile_comparator.cc
@@ -0,0 +1,251 @@ +// 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/payments/core/payments_profile_comparator.h" + +#include <algorithm> +#include <memory> + +#include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/address_i18n.h" +#include "components/autofill/core/browser/autofill_country.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/validation.h" +#include "components/payments/core/payment_options_provider.h" +#include "components/payments/core/payment_request_data_util.h" +#include "components/strings/grit/components_strings.h" +#include "third_party/libaddressinput/chromium/addressinput_util.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h" +#include "ui/base/l10n/l10n_util.h" + +namespace payments { + +PaymentsProfileComparator::PaymentsProfileComparator( + const std::string& app_locale, + const PaymentOptionsProvider& options) + : autofill::AutofillProfileComparator(app_locale), options_(options) {} + +PaymentsProfileComparator::~PaymentsProfileComparator() {} + +PaymentsProfileComparator::ProfileFields +PaymentsProfileComparator::GetMissingProfileFields( + const autofill::AutofillProfile* profile) const { + if (!profile) + return kName | kPhone | kEmail | kAddress; + + if (!cache_.count(profile->guid())) { + cache_[profile->guid()] = ComputeMissingFields(*profile); + } else { + // Cache hit. In debug mode, recompute and check that invalidation has + // occurred where necessary. + DCHECK_EQ(cache_[profile->guid()], ComputeMissingFields(*profile)) + << "Profiles must be invalidated when their contents change."; + } + + return cache_[profile->guid()]; +} + +std::vector<autofill::AutofillProfile*> +PaymentsProfileComparator::FilterProfilesForContact( + const std::vector<autofill::AutofillProfile*>& profiles) const { + // We will be removing profiles, so we operate on a copy. + std::vector<autofill::AutofillProfile*> processed = profiles; + + // Stable sort, since profiles are expected to be passed in frecency order. + std::stable_sort( + processed.begin(), processed.end(), + std::bind(&PaymentsProfileComparator::IsContactMoreComplete, this, + std::placeholders::_1, std::placeholders::_2)); + + auto it = processed.begin(); + while (it != processed.end()) { + if (GetContactCompletenessScore(*it) == 0) { + // Since profiles are sorted by completeness, this and any further + // profiles can be discarded. + processed.erase(it, processed.end()); + break; + } + + // Attempt to find a matching element in the vector before the current. + // This is quadratic, but the number of elements is generally small + // (< 10), so a more complicated algorithm would be overkill. + if (std::find_if(processed.begin(), it, + [&](autofill::AutofillProfile* prior) { + return IsContactEqualOrSuperset(*prior, **it); + }) != it) { + // Remove the subset profile. |it| will point to the next element after + // erasure. + it = processed.erase(it); + } else { + it++; + } + } + + return processed; +} + +bool PaymentsProfileComparator::IsContactEqualOrSuperset( + const autofill::AutofillProfile& super, + const autofill::AutofillProfile& sub) const { + if (options_.request_payer_name()) { + if (sub.HasInfo(autofill::NAME_FULL) && + !super.HasInfo(autofill::NAME_FULL)) { + return false; + } + if (!HaveMergeableNames(super, sub)) + return false; + } + if (options_.request_payer_phone()) { + if (sub.HasInfo(autofill::PHONE_HOME_WHOLE_NUMBER) && + !super.HasInfo(autofill::PHONE_HOME_WHOLE_NUMBER)) { + return false; + } + if (!HaveMergeablePhoneNumbers(super, sub)) + return false; + } + if (options_.request_payer_email()) { + if (sub.HasInfo(autofill::EMAIL_ADDRESS) && + !super.HasInfo(autofill::EMAIL_ADDRESS)) { + return false; + } + if (!HaveMergeableEmailAddresses(super, sub)) + return false; + } + return true; +} + +int PaymentsProfileComparator::GetContactCompletenessScore( + const autofill::AutofillProfile* profile) const { + if (!profile) + return 0; + + // Create a bitmask of the fields that are both present and required. + ProfileFields present = + ~GetMissingProfileFields(profile) & GetRequiredProfileFieldsForContact(); + + // Count how many are set. + return !!(present & kName) + !!(present & kPhone) + !!(present & kEmail); +} + +bool PaymentsProfileComparator::IsContactInfoComplete( + const autofill::AutofillProfile* profile) const { + // Mask the fields that are missing with those that are requried. If any bits + // are set (i.e., the result is nonzero), then contact info is incomplete. + return !(GetMissingProfileFields(profile) & + GetRequiredProfileFieldsForContact()); +} + +bool PaymentsProfileComparator::IsContactMoreComplete( + const autofill::AutofillProfile* p1, + const autofill::AutofillProfile* p2) const { + return GetContactCompletenessScore(p1) > GetContactCompletenessScore(p2); +} + +base::string16 PaymentsProfileComparator::GetStringForMissingContactFields( + const autofill::AutofillProfile& profile) const { + return GetStringForMissingFields(GetMissingProfileFields(&profile) & + GetRequiredProfileFieldsForContact()); +} + +bool PaymentsProfileComparator::IsShippingComplete( + const autofill::AutofillProfile* profile) const { + // Mask the fields that are missing with those that are requried. If any bits + // are set (i.e., the result is nonzero), then shipping is incomplete. + return !(GetMissingProfileFields(profile) & + GetRequiredProfileFieldsForShipping()); +} + +base::string16 PaymentsProfileComparator::GetStringForMissingShippingFields( + const autofill::AutofillProfile& profile) const { + return GetStringForMissingFields(GetMissingProfileFields(&profile) & + GetRequiredProfileFieldsForShipping()); +} + +void PaymentsProfileComparator::Invalidate( + const autofill::AutofillProfile& profile) { + cache_.erase(profile.guid()); +} + +PaymentsProfileComparator::ProfileFields +PaymentsProfileComparator::ComputeMissingFields( + const autofill::AutofillProfile& profile) const { + ProfileFields missing = 0; + + if (!profile.HasInfo(autofill::NAME_FULL)) + missing |= kName; + + // Determine the country code to use when validating the phone number. Use + // the profile's country if it has one, or the code for the app locale + // otherwise. Note that international format numbers will always work--this + // is just the region that will be used to check if the number is + // potentially in a local format. + std::string country = + data_util::GetCountryCodeWithFallback(&profile, app_locale()); + + base::string16 phone = profile.GetInfo( + autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER), app_locale()); + if (!autofill::IsValidPhoneNumber(phone, country)) + missing |= kPhone; + + base::string16 email = profile.GetInfo( + autofill::AutofillType(autofill::EMAIL_ADDRESS), app_locale()); + if (!autofill::IsValidEmailAddress(email)) + missing |= kEmail; + + if (!AreRequiredAddressFieldsPresent(profile)) + missing |= kAddress; + + return missing; +} + +PaymentsProfileComparator::ProfileFields +PaymentsProfileComparator::GetRequiredProfileFieldsForContact() const { + ProfileFields required = 0; + if (options_.request_payer_name()) + required |= kName; + if (options_.request_payer_phone()) + required |= kPhone; + if (options_.request_payer_email()) + required |= kEmail; + return required; +} + +PaymentsProfileComparator::ProfileFields +PaymentsProfileComparator::GetRequiredProfileFieldsForShipping() const { + return options_.request_shipping() ? (kAddress | kName | kPhone) : 0; +} + +base::string16 PaymentsProfileComparator::GetStringForMissingFields( + PaymentsProfileComparator::ProfileFields fields) const { + switch (fields) { + case 0: + // No bits are set, so no fields are missing. + return base::string16(); + case kName: + return l10n_util::GetStringUTF16(IDS_PAYMENTS_NAME_REQUIRED); + case kPhone: + return l10n_util::GetStringUTF16(IDS_PAYMENTS_PHONE_NUMBER_REQUIRED); + case kEmail: + return l10n_util::GetStringUTF16(IDS_PAYMENTS_EMAIL_REQUIRED); + case kAddress: + return l10n_util::GetStringUTF16(IDS_PAYMENTS_INVALID_ADDRESS); + default: + // Either multiple bits are set (likely) or one bit that doesn't + // correspond to a named constant is set (shouldn't happen). Return a + // generic "More information" message. + return l10n_util::GetStringUTF16(IDS_PAYMENTS_MORE_INFORMATION_REQUIRED); + } +} + +bool PaymentsProfileComparator::AreRequiredAddressFieldsPresent( + const autofill::AutofillProfile& profile) const { + std::unique_ptr<::i18n::addressinput::AddressData> data = + autofill::i18n::CreateAddressDataFromAutofillProfile(profile, + app_locale()); + + return autofill::addressinput::HasAllRequiredFields(*data); +} + +} // namespace payments
diff --git a/components/payments/core/payments_profile_comparator.h b/components/payments/core/payments_profile_comparator.h new file mode 100644 index 0000000..2c8b934a --- /dev/null +++ b/components/payments/core/payments_profile_comparator.h
@@ -0,0 +1,112 @@ +// 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_PAYMENTS_CORE_PAYMENTS_PROFILE_COMPARATOR_H_ +#define COMPONENTS_PAYMENTS_CORE_PAYMENTS_PROFILE_COMPARATOR_H_ + +#include <map> +#include <string> +#include <vector> + +#include "components/autofill/core/browser/autofill_profile_comparator.h" + +// Utility functions used for processing and filtering address profiles +// (AutofillProfile). + +namespace autofill { +class AutofillProfile; +} // namespace autofill + +namespace payments { + +class PaymentOptionsProvider; + +// Helper class which evaluates profiles for similarity and completeness. +// Profiles are evaluated once for completeness, and the result is cached, +// meaning one instance of this class should be used per-request to avoid +// redoing expensive validation checks. +// Note that, if a profile is modified and saved during the course of the +// PaymentRequest, it is important to call the Invalidate method to ensure +// it is properly evaluated. +class PaymentsProfileComparator : public autofill::AutofillProfileComparator { + public: + // Bitmask of potentially-required fields used in evaluating completeness. + using ProfileFields = uint32_t; + const static ProfileFields kName = 1 << 0; + const static ProfileFields kPhone = 1 << 1; + const static ProfileFields kEmail = 1 << 2; + const static ProfileFields kAddress = 1 << 3; + + PaymentsProfileComparator(const std::string& app_locale, + const PaymentOptionsProvider& options); + ~PaymentsProfileComparator(); + + // Returns a bitmask indicating which fields (or groups of fields) on this + // profile are not complete and valid. + ProfileFields GetMissingProfileFields( + const autofill::AutofillProfile* profile) const; + + // Returns profiles for contact info, ordered by completeness and + // deduplicated. |profiles| should be passed in order of frecency, and this + // order will be preserved among equally-complete profiles. Deduplication here + // means that profiles returned are excluded if they are a subset of a more + // complete or more frecent profile. Completeness here refers only to the + // presence of the fields requested per the request_payer_* fields in + // |options|. + std::vector<autofill::AutofillProfile*> FilterProfilesForContact( + const std::vector<autofill::AutofillProfile*>& profiles) const; + + // Returns true iff all of the contact info in |sub| also appears in |super|. + // Only operates on fields requested in |options|. + bool IsContactEqualOrSuperset(const autofill::AutofillProfile& super, + const autofill::AutofillProfile& sub) const; + + // Returns the number of contact fields requested in |options| which are + // nonempty in |profile|. + int GetContactCompletenessScore( + const autofill::AutofillProfile* profile) const; + + // Returns true iff every contact field requested in |options| is nonempty in + // |profile|. + bool IsContactInfoComplete(const autofill::AutofillProfile* profile) const; + + // Comparison function suitable for sorting profiles by contact completeness + // score with std::sort. + bool IsContactMoreComplete(const autofill::AutofillProfile* p1, + const autofill::AutofillProfile* p2) const; + + // Returns a localized string to be displayed in UI indicating what action, + // if any, must be taken for the given profile to be used as contact info. + base::string16 GetStringForMissingContactFields( + const autofill::AutofillProfile& profile) const; + + // Returns true iff every field needed to use |profile| as a shipping address + // is populated. + bool IsShippingComplete(const autofill::AutofillProfile* profile) const; + + // Returns a localized string to be displayed in UI indicating what action, + // if any, must be taken for the given profile to be used as a shipping + // address. + base::string16 GetStringForMissingShippingFields( + const autofill::AutofillProfile& profile) const; + + // Clears the cached evaluation result for |profile|. Must be called when a + // profile is modified and saved during the course of a PaymentRequest. + void Invalidate(const autofill::AutofillProfile& profile); + + private: + ProfileFields ComputeMissingFields( + const autofill::AutofillProfile& profile) const; + ProfileFields GetRequiredProfileFieldsForContact() const; + ProfileFields GetRequiredProfileFieldsForShipping() const; + base::string16 GetStringForMissingFields(ProfileFields fields) const; + bool AreRequiredAddressFieldsPresent( + const autofill::AutofillProfile& profile) const; + mutable std::map<std::string, ProfileFields> cache_; + const PaymentOptionsProvider& options_; +}; + +} // namespace payments + +#endif // COMPONENTS_PAYMENTS_CORE_PAYMENTS_PROFILE_COMPARATOR_H_ \ No newline at end of file
diff --git a/components/payments/core/payments_profile_comparator_unittest.cc b/components/payments/core/payments_profile_comparator_unittest.cc new file mode 100644 index 0000000..ac0691e --- /dev/null +++ b/components/payments/core/payments_profile_comparator_unittest.cc
@@ -0,0 +1,367 @@ +// 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/payments/core/payments_profile_comparator.h" + +#include <memory> +#include <vector> + +#include "base/guid.h" +#include "base/memory/ptr_util.h" +#include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/autofill_test_utils.h" +#include "components/payments/core/payment_options_provider.h" +#include "components/strings/grit/components_strings.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/l10n/l10n_util.h" + +using autofill::AutofillProfile; + +namespace payments { + +constexpr uint32_t kRequestPayerName = 1 << 0; +constexpr uint32_t kRequestPayerEmail = 1 << 1; +constexpr uint32_t kRequestPayerPhone = 1 << 2; +constexpr uint32_t kRequestShipping = 1 << 3; + +class MockPaymentOptionsProvider : public PaymentOptionsProvider { + public: + MockPaymentOptionsProvider(uint32_t options) : options_(options) {} + + ~MockPaymentOptionsProvider() override {} + bool request_payer_name() const override { + return options_ & kRequestPayerName; + } + bool request_payer_email() const override { + return options_ & kRequestPayerEmail; + } + bool request_payer_phone() const override { + return options_ & kRequestPayerPhone; + } + bool request_shipping() const override { return options_ & kRequestShipping; } + PaymentShippingType shipping_type() const override { + return PaymentShippingType::SHIPPING; + } + + private: + uint32_t options_; +}; + +AutofillProfile CreateProfileWithContactInfo(const char* name, + const char* email, + const char* phone) { + AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/"); + autofill::test::SetProfileInfo(&profile, name, "", "", email, "", "", "", "", + "", "", "", phone); + return profile; +} + +AutofillProfile CreateProfileWithCompleteAddress(const char* name, + const char* phone) { + AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/"); + autofill::test::SetProfileInfo(&profile, name, "", "", "", "", "123 Fake St.", + "", "Fakesville", "MN", "54000", "US", phone); + return profile; +} + +AutofillProfile CreateProfileWithPartialAddress(const char* name, + const char* phone) { + AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/"); + autofill::test::SetProfileInfo(&profile, name, "", "", "", "", "123 Fake St.", + "", "", "", "54000", "", phone); + return profile; +} + +TEST(PaymentRequestProfileUtilTest, FilterProfilesForContact) { + // These profiles are subset/equal, so only the first complete one is + // included. + AutofillProfile exclude_1 = + CreateProfileWithContactInfo("Homer", "", "6515553226"); + + AutofillProfile exclude_2 = + CreateProfileWithContactInfo("Homer", "homer@simpson.net", ""); + + AutofillProfile include_1 = + CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226"); + + AutofillProfile exclude_3 = + CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226"); + + // This profile is different, so it should also be included. Since it is + // less complete than |include_1|, it will appear after. + AutofillProfile include_2 = + CreateProfileWithContactInfo("Marge", "marge@simpson.net", ""); + + // This profile is different, so it should also be included. Since it is + // equally complete with |include_1|, it will appear before |include_2|, but + // after |include_1| since order is preserved amongst profiles of equal + // completeness. + AutofillProfile include_3 = CreateProfileWithContactInfo( + "Bart", "eatmyshorts@simpson.net", "6515553226"); + + std::vector<AutofillProfile*> profiles = {&exclude_1, &exclude_2, &include_1, + &exclude_3, &include_2, &include_3}; + + MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerEmail | + kRequestPayerPhone); + PaymentsProfileComparator comp("en-US", provider); + + std::vector<AutofillProfile*> filtered = + comp.FilterProfilesForContact(profiles); + + ASSERT_EQ(3u, filtered.size()); + EXPECT_EQ(&include_1, filtered[0]); + EXPECT_EQ(&include_3, filtered[1]); + EXPECT_EQ(&include_2, filtered[2]); + + // Repeat the filter using a provider set to only request phone numbers. + // Under these rules, since all profiles have the same (or no) phone number, + // we should only see the first profile with a phone number, |exclude_1|. + MockPaymentOptionsProvider phone_only_provider(kRequestPayerPhone); + PaymentsProfileComparator phone_only_comp("en-US", phone_only_provider); + std::vector<AutofillProfile*> filtered_phones = + phone_only_comp.FilterProfilesForContact(profiles); + ASSERT_EQ(1u, filtered_phones.size()); + EXPECT_EQ(&exclude_1, filtered_phones[0]); +} + +TEST(PaymentRequestProfileUtilTest, IsContactEqualOrSuperset) { + MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerEmail | + kRequestPayerPhone); + PaymentsProfileComparator comp("en-US", provider); + + AutofillProfile p1 = + CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226"); + + // Candidate subset profile is equal. + AutofillProfile p2 = + CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226"); + EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p2)); + EXPECT_TRUE(comp.IsContactEqualOrSuperset(p2, p1)); + + // Candidate subset profile has non-matching fields. + AutofillProfile p3 = CreateProfileWithContactInfo( + "Homer", "homer@springfieldnuclear.gov", "6515553226"); + EXPECT_FALSE(comp.IsContactEqualOrSuperset(p1, p3)); + EXPECT_FALSE(comp.IsContactEqualOrSuperset(p3, p1)); + + // Candidate subset profile is equal, except for missing fields. + AutofillProfile p4 = + CreateProfileWithContactInfo("Homer", "homer@simpson.net", ""); + EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p4)); + EXPECT_FALSE(comp.IsContactEqualOrSuperset(p4, p1)); + + // One field is common, but each has a field which the other is missing. + AutofillProfile p5 = + CreateProfileWithContactInfo("Homer", "homer@simpson.net", ""); + AutofillProfile p6 = CreateProfileWithContactInfo("Homer", "", "6515553226"); + EXPECT_FALSE(comp.IsContactEqualOrSuperset(p5, p6)); + EXPECT_FALSE(comp.IsContactEqualOrSuperset(p6, p5)); +} + +TEST(PaymentRequestProfileUtilTest, IsContactEqualOrSuperset_WithFieldIgnored) { + // Discrepancies in email should be ignored throughout this test. + MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerPhone); + PaymentsProfileComparator comp("en-US", provider); + + AutofillProfile p1 = + CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226"); + + // Candidate subset profile is equal. + AutofillProfile p2 = + CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226"); + EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p2)); + EXPECT_TRUE(comp.IsContactEqualOrSuperset(p2, p1)); + + // Email fields don't match, but profiles are still equal. + AutofillProfile p3 = CreateProfileWithContactInfo( + "Homer", "homer@springfieldnuclear.gov", "6515553226"); + EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p3)); + EXPECT_TRUE(comp.IsContactEqualOrSuperset(p3, p1)); + + // Profile without an email is mutual subset of profile with an email. + AutofillProfile p4 = CreateProfileWithContactInfo("Homer", "", "6515553226"); + EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p4)); + EXPECT_TRUE(comp.IsContactEqualOrSuperset(p4, p1)); +} + +TEST(PaymentRequestProfileUtilTest, GetContactCompletenessScore) { + MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerPhone); + PaymentsProfileComparator comp("en-US", provider); + + // Two completeness points: One each for name and phone number, but not email + // as it was not requested. + AutofillProfile p1 = + CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226"); + EXPECT_EQ(2, comp.GetContactCompletenessScore(&p1)); + + // One completeness point for name, no points for phone number (missing) or + // email (not requested). + AutofillProfile p2 = + CreateProfileWithContactInfo("Homer", "homer@simpson.net", ""); + EXPECT_EQ(1, comp.GetContactCompletenessScore(&p2)); + + // No completeness points, as the only field present was not requested. + AutofillProfile p3 = + CreateProfileWithContactInfo("", "homer@simpson.net", ""); + EXPECT_EQ(0, comp.GetContactCompletenessScore(&p3)); + + // Null profile returns 0. + EXPECT_EQ(0, comp.GetContactCompletenessScore(nullptr)); +} + +TEST(PaymentRequestProfileUtilTest, IsContactInfoComplete) { + MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerEmail); + PaymentsProfileComparator comp("en-US", provider); + + // If name and email are present, return true regardless of the (ignored) + // phone value. + AutofillProfile p1 = + CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226"); + AutofillProfile p2 = + CreateProfileWithContactInfo("Homer", "homer@simpson.net", ""); + + EXPECT_TRUE(comp.IsContactInfoComplete(&p1)); + EXPECT_TRUE(comp.IsContactInfoComplete(&p2)); + + // If name is not present, return false regardless of the (ignored) + // phone value. + AutofillProfile p3 = + CreateProfileWithContactInfo("", "homer@simpson.net", "6515553226"); + AutofillProfile p4 = + CreateProfileWithContactInfo("", "homer@simpson.net", ""); + + EXPECT_FALSE(comp.IsContactInfoComplete(&p3)); + EXPECT_FALSE(comp.IsContactInfoComplete(&p4)); + + // If no fields are requested, any profile (even empty or null) is complete. + MockPaymentOptionsProvider empty_provider(0); + PaymentsProfileComparator empty_comp("en-US", empty_provider); + + AutofillProfile p5 = CreateProfileWithContactInfo("", "", ""); + + EXPECT_TRUE(empty_comp.IsContactInfoComplete(&p1)); + EXPECT_TRUE(empty_comp.IsContactInfoComplete(&p5)); + EXPECT_TRUE(empty_comp.IsContactInfoComplete(nullptr)); +} + +TEST(PaymentRequestProfileUtilTest, IsShippingComplete) { + MockPaymentOptionsProvider provider(kRequestShipping); + PaymentsProfileComparator comp("en-US", provider); + + // True if name, phone, and address are all populated. + AutofillProfile p1 = CreateProfileWithCompleteAddress("Homer", "6515553226"); + EXPECT_TRUE(comp.IsShippingComplete(&p1)); + + // False if address is partially populated. + AutofillProfile p2 = CreateProfileWithPartialAddress("Homer", "6515553226"); + EXPECT_FALSE(comp.IsShippingComplete(&p2)); + + // False if name isn't populated. + AutofillProfile p3 = CreateProfileWithCompleteAddress("", "6515553226"); + EXPECT_FALSE(comp.IsShippingComplete(&p3)); + + // False if phone isn't populated. + AutofillProfile p4 = CreateProfileWithCompleteAddress("Homer", ""); + EXPECT_FALSE(comp.IsShippingComplete(&p4)); + + // False if only contact info (no address fields) is populated. + AutofillProfile p5 = + CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226"); + EXPECT_FALSE(comp.IsShippingComplete(&p5)); + + MockPaymentOptionsProvider provider_no_shipping(0); + PaymentsProfileComparator comp_no_shipping("en-US", provider_no_shipping); + // nullptr is handled correctly: false if shipping requested, true if not. + EXPECT_FALSE(comp.IsShippingComplete(nullptr)); + EXPECT_TRUE(comp_no_shipping.IsShippingComplete(nullptr)); +} + +TEST(PaymentRequestProfileUtilTest, GetStringForMissingContactFields) { + MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerPhone | + kRequestPayerEmail | kRequestShipping); + PaymentsProfileComparator comp("en-US", provider); + + // No error message for complete profile. + AutofillProfile p1 = + CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226"); + EXPECT_TRUE(comp.GetStringForMissingContactFields(p1).empty()); + + MockPaymentOptionsProvider provider_no_email( + kRequestPayerName | kRequestPayerPhone | kRequestShipping); + PaymentsProfileComparator comp_no_email("en-US", provider_no_email); + + // No error message if missing field wasn't required. + AutofillProfile p2 = CreateProfileWithContactInfo("Homer", "", "6515553226"); + EXPECT_TRUE(comp_no_email.GetStringForMissingContactFields(p2).empty()); + + // Error message for email address if email address is missing and required. + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_EMAIL_REQUIRED), + comp.GetStringForMissingContactFields(p2)); + + // Error message for phone number if phone is missing and required. + AutofillProfile p3 = + CreateProfileWithContactInfo("Homer", "homer@simpson.net", ""); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_PHONE_NUMBER_REQUIRED), + comp.GetStringForMissingContactFields(p3)); + + // Error message for name if name is missing and required. + AutofillProfile p4 = + CreateProfileWithContactInfo("", "homer@simpson.net", "6515553226"); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_NAME_REQUIRED), + comp.GetStringForMissingContactFields(p4)); + + // Generic error message if multiple fields missing. + AutofillProfile p5 = + CreateProfileWithContactInfo("", "homer@simpson.net", ""); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_MORE_INFORMATION_REQUIRED), + comp.GetStringForMissingContactFields(p5)); +} + +TEST(PaymentRequestProfileUtilTest, GetStringForMissingShippingFields) { + MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerPhone | + kRequestPayerEmail | kRequestShipping); + PaymentsProfileComparator comp("en-US", provider); + + // No error message for complete profile. + AutofillProfile p1 = CreateProfileWithCompleteAddress("Homer", "6515553226"); + EXPECT_TRUE(comp.GetStringForMissingShippingFields(p1).empty()); + + // Error message for shipping if shipping requested and not present. + AutofillProfile p2 = + CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226"); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_INVALID_ADDRESS), + comp.GetStringForMissingShippingFields(p2)); + + // Error message for shipping if shipping requested and only partially + // complete. + AutofillProfile p3 = CreateProfileWithPartialAddress("Homer", "6515553226"); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_INVALID_ADDRESS), + comp.GetStringForMissingShippingFields(p3)); + + // Error message for name if name requested and missing. + AutofillProfile p4 = CreateProfileWithCompleteAddress("", "6515553226"); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_NAME_REQUIRED), + comp.GetStringForMissingShippingFields(p4)); + + // Error message for phone if phone requested and missing. + AutofillProfile p5 = CreateProfileWithCompleteAddress("Homer", ""); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_PHONE_NUMBER_REQUIRED), + comp.GetStringForMissingShippingFields(p5)); + + // Generic error message if multiple fields missing. + AutofillProfile p6 = CreateProfileWithContactInfo("", "", ""); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_MORE_INFORMATION_REQUIRED), + comp.GetStringForMissingShippingFields(p6)); + + MockPaymentOptionsProvider provider_no_shipping( + kRequestPayerName | kRequestPayerPhone | kRequestPayerEmail); + PaymentsProfileComparator comp_no_shipping("en-US", provider_no_shipping); + + // No error message if everything is missing but shipping wasn't requested. + EXPECT_TRUE(comp_no_shipping.GetStringForMissingShippingFields(p6).empty()); +} + +} // namespace payments
diff --git a/components/payments/core/profile_util.cc b/components/payments/core/profile_util.cc deleted file mode 100644 index c1149c8..0000000 --- a/components/payments/core/profile_util.cc +++ /dev/null
@@ -1,123 +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/payments/core/profile_util.h" - -#include <algorithm> - -#include "components/autofill/core/browser/autofill_profile.h" -#include "components/autofill/core/browser/field_types.h" -#include "components/payments/core/payment_options_provider.h" - -namespace payments { -namespace profile_util { - -std::vector<autofill::AutofillProfile*> FilterProfilesForContact( - const std::vector<autofill::AutofillProfile*>& profiles, - const std::string& app_locale, - const PaymentOptionsProvider& options) { - // We will be removing profiles, so we operate on a copy. - std::vector<autofill::AutofillProfile*> processed = profiles; - - PaymentsProfileComparator comparator(app_locale, options); - - // Stable sort, since profiles are expected to be passed in frecency order. - std::stable_sort( - processed.begin(), processed.end(), - std::bind(&PaymentsProfileComparator::IsContactMoreComplete, &comparator, - std::placeholders::_1, std::placeholders::_2)); - - auto it = processed.begin(); - while (it != processed.end()) { - if (comparator.GetContactCompletenessScore(*it) == 0) { - // Since profiles are sorted by completeness, this and any further - // profiles can be discarded. - processed.erase(it, processed.end()); - break; - } - - // Attempt to find a matching element in the vector before the current. - // This is quadratic, but the number of elements is generally small - // (< 10), so a more complicated algorithm would be overkill. - if (std::find_if(processed.begin(), it, - [&](autofill::AutofillProfile* prior) { - return comparator.IsContactEqualOrSuperset(*prior, **it); - }) != it) { - // Remove the subset profile. |it| will point to the next element after - // erasure. - it = processed.erase(it); - } else { - it++; - } - } - - return processed; -} - -PaymentsProfileComparator::PaymentsProfileComparator( - const std::string& app_locale, - const PaymentOptionsProvider& options) - : autofill::AutofillProfileComparator(app_locale), options_(options) {} - -PaymentsProfileComparator::~PaymentsProfileComparator() {} - -bool PaymentsProfileComparator::IsContactEqualOrSuperset( - const autofill::AutofillProfile& super, - const autofill::AutofillProfile& sub) { - if (options_.request_payer_name()) { - if (sub.HasInfo(autofill::NAME_FULL) && - !super.HasInfo(autofill::NAME_FULL)) { - return false; - } - if (!HaveMergeableNames(super, sub)) - return false; - } - if (options_.request_payer_phone()) { - if (sub.HasInfo(autofill::PHONE_HOME_WHOLE_NUMBER) && - !super.HasInfo(autofill::PHONE_HOME_WHOLE_NUMBER)) { - return false; - } - if (!HaveMergeablePhoneNumbers(super, sub)) - return false; - } - if (options_.request_payer_email()) { - if (sub.HasInfo(autofill::EMAIL_ADDRESS) && - !super.HasInfo(autofill::EMAIL_ADDRESS)) { - return false; - } - if (!HaveMergeableEmailAddresses(super, sub)) - return false; - } - return true; -} - -int PaymentsProfileComparator::GetContactCompletenessScore( - const autofill::AutofillProfile* profile) { - if (!profile) - return 0; - - return (options_.request_payer_name() && - profile->HasInfo(autofill::NAME_FULL)) + - (options_.request_payer_phone() && - profile->HasInfo(autofill::PHONE_HOME_WHOLE_NUMBER)) + - (options_.request_payer_email() && - profile->HasInfo(autofill::EMAIL_ADDRESS)); -} - -bool PaymentsProfileComparator::IsContactInfoComplete( - const autofill::AutofillProfile* profile) { - int desired_score = options_.request_payer_name() + - options_.request_payer_phone() + - options_.request_payer_email(); - return GetContactCompletenessScore(profile) == desired_score; -} - -bool PaymentsProfileComparator::IsContactMoreComplete( - const autofill::AutofillProfile* p1, - const autofill::AutofillProfile* p2) { - return GetContactCompletenessScore(p1) > GetContactCompletenessScore(p2); -} - -} // namespace profile_util -} // namespace payments
diff --git a/components/payments/core/profile_util.h b/components/payments/core/profile_util.h deleted file mode 100644 index 6693fe8..0000000 --- a/components/payments/core/profile_util.h +++ /dev/null
@@ -1,69 +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_PAYMENTS_CONTENT_PROFILE_UTIL_H_ -#define COMPONENTS_PAYMENTS_CONTENT_PROFILE_UTIL_H_ - -#include <string> -#include <vector> - -#include "components/autofill/core/browser/autofill_profile_comparator.h" - -// Utility functions used for processing and filtering address profiles -// (AutofillProfile). - -namespace autofill { -class AutofillProfile; -} // namespace autofill - -namespace payments { - -class PaymentOptionsProvider; - -namespace profile_util { - -// Returns profiles for contact info, ordered by completeness and deduplicated. -// |profiles| should be passed in order of frecency, and this order will be -// preserved among equally-complete profiles. Deduplication here means that -// profiles returned are excluded if they are a subset of a more complete or -// more frecent profile. Completeness here refers only to the presence of the -// fields requested per the request_payer_* fields in |options|. -std::vector<autofill::AutofillProfile*> FilterProfilesForContact( - const std::vector<autofill::AutofillProfile*>& profiles, - const std::string& app_locale, - const PaymentOptionsProvider& options); - -// Helper class which evaluates profiles for similarity and completeness. -class PaymentsProfileComparator : public autofill::AutofillProfileComparator { - public: - PaymentsProfileComparator(const std::string& app_locale, - const PaymentOptionsProvider& options); - ~PaymentsProfileComparator(); - - // Returns true iff all of the contact info in |sub| also appears in |super|. - // Only operates on fields requested in |options|. - bool IsContactEqualOrSuperset(const autofill::AutofillProfile& super, - const autofill::AutofillProfile& sub); - - // Returns the number of contact fields requested in |options| which are - // nonempty in |profile|. - int GetContactCompletenessScore(const autofill::AutofillProfile* profile); - - // Returns true iff every contact field requested in |options| is nonempty in - // |profile|. - bool IsContactInfoComplete(const autofill::AutofillProfile* profile); - - // Comparison function suitable for sorting profiles by contact completeness - // score with std::sort. - bool IsContactMoreComplete(const autofill::AutofillProfile* p1, - const autofill::AutofillProfile* p2); - - private: - const PaymentOptionsProvider& options_; -}; - -} // namespace profile_util -} // namespace payments - -#endif // COMPONENTS_PAYMENTS_CONTENT_PROFILE_UTIL_H_ \ No newline at end of file
diff --git a/components/payments/core/profile_util_unittest.cc b/components/payments/core/profile_util_unittest.cc deleted file mode 100644 index 5ff1d7e..0000000 --- a/components/payments/core/profile_util_unittest.cc +++ /dev/null
@@ -1,231 +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/payments/core/profile_util.h" - -#include <memory> -#include <vector> - -#include "base/guid.h" -#include "base/memory/ptr_util.h" -#include "base/strings/utf_string_conversions.h" -#include "components/autofill/core/browser/autofill_profile.h" -#include "components/autofill/core/browser/autofill_test_utils.h" -#include "components/payments/core/payment_options_provider.h" -#include "testing/gtest/include/gtest/gtest.h" - -using autofill::AutofillProfile; - -namespace payments { -namespace profile_util { - -constexpr uint32_t kRequestPayerName = 1 << 0; -constexpr uint32_t kRequestPayerEmail = 1 << 1; -constexpr uint32_t kRequestPayerPhone = 1 << 2; -constexpr uint32_t kRequestShipping = 1 << 3; - -class MockPaymentOptionsProvider : public PaymentOptionsProvider { - public: - MockPaymentOptionsProvider(uint32_t options) : options_(options) {} - - ~MockPaymentOptionsProvider() override {} - bool request_payer_name() const override { - return options_ & kRequestPayerName; - } - bool request_payer_email() const override { - return options_ & kRequestPayerEmail; - } - bool request_payer_phone() const override { - return options_ & kRequestPayerPhone; - } - bool request_shipping() const override { return options_ & kRequestShipping; } - PaymentShippingType shipping_type() const override { - return PaymentShippingType::SHIPPING; - } - - private: - uint32_t options_; -}; - -AutofillProfile CreateProfileWithContactInfo(const char* name, - const char* email, - const char* phone) { - AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/"); - autofill::test::SetProfileInfo(&profile, name, "", "", email, "", "", "", "", - "", "", "", phone); - return profile; -} - -TEST(PaymentRequestProfileUtilTest, FilterProfilesForContact) { - // These profiles are subset/equal, so only the first complete one is - // included. - AutofillProfile exclude_1 = - CreateProfileWithContactInfo("Homer", "", "5551234567"); - - AutofillProfile exclude_2 = - CreateProfileWithContactInfo("Homer", "homer@simpson.net", ""); - - AutofillProfile include_1 = - CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567"); - - AutofillProfile exclude_3 = - CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567"); - - // This profile is different, so it should also be included. Since it is - // less complete than |include_1|, it will appear after. - AutofillProfile include_2 = - CreateProfileWithContactInfo("Marge", "marge@simpson.net", ""); - - // This profile is different, so it should also be included. Since it is - // equally complete with |include_1|, it will appear before |include_2|, but - // after |include_1| since order is preserved amongst profiles of equal - // completeness. - AutofillProfile include_3 = CreateProfileWithContactInfo( - "Bart", "eatmyshorts@simpson.net", "5551234567"); - - std::vector<AutofillProfile*> profiles = {&exclude_1, &exclude_2, &include_1, - &exclude_3, &include_2, &include_3}; - - MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerEmail | - kRequestPayerPhone); - std::vector<AutofillProfile*> filtered = - FilterProfilesForContact(profiles, "en-US", provider); - - ASSERT_EQ(3u, filtered.size()); - EXPECT_EQ(&include_1, filtered[0]); - EXPECT_EQ(&include_3, filtered[1]); - EXPECT_EQ(&include_2, filtered[2]); - - // Repeat the filter using a provider set to only request phone numbers. - // Under these rules, since all profiles have the same (or no) phone number, - // we should only see the first profile with a phone number, |exclude_1|. - MockPaymentOptionsProvider phone_only_provider(kRequestPayerPhone); - std::vector<AutofillProfile*> filtered_phones = - FilterProfilesForContact(profiles, "en-US", phone_only_provider); - ASSERT_EQ(1u, filtered_phones.size()); - EXPECT_EQ(&exclude_1, filtered_phones[0]); -} - -TEST(PaymentRequestProfileUtilTest, IsContactEqualOrSuperset) { - MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerEmail | - kRequestPayerPhone); - PaymentsProfileComparator comp("en-US", provider); - - AutofillProfile p1 = - CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567"); - - // Candidate subset profile is equal. - AutofillProfile p2 = - CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567"); - EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p2)); - EXPECT_TRUE(comp.IsContactEqualOrSuperset(p2, p1)); - - // Candidate subset profile has non-matching fields. - AutofillProfile p3 = CreateProfileWithContactInfo( - "Homer", "homer@springfieldnuclear.gov", "5551234567"); - EXPECT_FALSE(comp.IsContactEqualOrSuperset(p1, p3)); - EXPECT_FALSE(comp.IsContactEqualOrSuperset(p3, p1)); - - // Candidate subset profile is equal, except for missing fields. - AutofillProfile p4 = - CreateProfileWithContactInfo("Homer", "homer@simpson.net", ""); - EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p4)); - EXPECT_FALSE(comp.IsContactEqualOrSuperset(p4, p1)); - - // One field is common, but each has a field which the other is missing. - AutofillProfile p5 = - CreateProfileWithContactInfo("Homer", "homer@simpson.net", ""); - AutofillProfile p6 = CreateProfileWithContactInfo("Homer", "", "5551234567"); - EXPECT_FALSE(comp.IsContactEqualOrSuperset(p5, p6)); - EXPECT_FALSE(comp.IsContactEqualOrSuperset(p6, p5)); -} - -TEST(PaymentRequestProfileUtilTest, IsContactEqualOrSuperset_WithFieldIgnored) { - // Discrepancies in email should be ignored throughout this test. - MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerPhone); - PaymentsProfileComparator comp("en-US", provider); - - AutofillProfile p1 = - CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567"); - - // Candidate subset profile is equal. - AutofillProfile p2 = - CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567"); - EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p2)); - EXPECT_TRUE(comp.IsContactEqualOrSuperset(p2, p1)); - - // Email fields don't match, but profiles are still equal. - AutofillProfile p3 = CreateProfileWithContactInfo( - "Homer", "homer@springfieldnuclear.gov", "5551234567"); - EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p3)); - EXPECT_TRUE(comp.IsContactEqualOrSuperset(p3, p1)); - - // Profile without an email is mutual subset of profile with an email. - AutofillProfile p4 = CreateProfileWithContactInfo("Homer", "", "5551234567"); - EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p4)); - EXPECT_TRUE(comp.IsContactEqualOrSuperset(p4, p1)); -} - -TEST(PaymentRequestProfileUtilTest, GetContactCompletenessScore) { - MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerPhone); - PaymentsProfileComparator comp("en-US", provider); - - // Two completeness points: One each for name and phone number, but not email - // as it was not requested. - AutofillProfile p1 = - CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567"); - EXPECT_EQ(2, comp.GetContactCompletenessScore(&p1)); - - // One completeness point for name, no points for phone number (missing) or - // email (not requested). - AutofillProfile p2 = - CreateProfileWithContactInfo("Homer", "homer@simpson.net", ""); - EXPECT_EQ(1, comp.GetContactCompletenessScore(&p2)); - - // No completeness points, as the only field present was not requested. - AutofillProfile p3 = - CreateProfileWithContactInfo("", "homer@simpson.net", ""); - EXPECT_EQ(0, comp.GetContactCompletenessScore(&p3)); - - // Null profile returns 0. - EXPECT_EQ(0, comp.GetContactCompletenessScore(nullptr)); -} - -TEST(PaymentRequestProfileUtilTest, IsContactInfoComplete) { - MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerEmail); - PaymentsProfileComparator comp("en-US", provider); - - // If name and email are present, return true regardless of the (ignored) - // phone value. - AutofillProfile p1 = - CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567"); - AutofillProfile p2 = - CreateProfileWithContactInfo("Homer", "homer@simpson.net", ""); - - EXPECT_TRUE(comp.IsContactInfoComplete(&p1)); - EXPECT_TRUE(comp.IsContactInfoComplete(&p2)); - - // If name is not present, return false regardless of the (ignored) - // phone value. - AutofillProfile p3 = - CreateProfileWithContactInfo("", "homer@simpson.net", "5551234567"); - AutofillProfile p4 = - CreateProfileWithContactInfo("", "homer@simpson.net", ""); - - EXPECT_FALSE(comp.IsContactInfoComplete(&p3)); - EXPECT_FALSE(comp.IsContactInfoComplete(&p4)); - - // If no fields are requested, any profile (even empty or null) is complete. - MockPaymentOptionsProvider empty_provider(0); - PaymentsProfileComparator empty_comp("en-US", empty_provider); - - AutofillProfile p5 = CreateProfileWithContactInfo("", "", ""); - - EXPECT_TRUE(empty_comp.IsContactInfoComplete(&p1)); - EXPECT_TRUE(empty_comp.IsContactInfoComplete(&p5)); - EXPECT_TRUE(empty_comp.IsContactInfoComplete(nullptr)); -} - -} // namespace profile_util -} // namespace payments
diff --git a/ios/chrome/browser/payments/payment_request.mm b/ios/chrome/browser/payments/payment_request.mm index 3b9fe0a..784c86a 100644 --- a/ios/chrome/browser/payments/payment_request.mm +++ b/ios/chrome/browser/payments/payment_request.mm
@@ -11,7 +11,7 @@ #include "components/autofill/core/browser/personal_data_manager.h" #include "components/payments/core/currency_formatter.h" #include "components/payments/core/payment_request_data_util.h" -#include "components/payments/core/profile_util.h" +#include "components/payments/core/payments_profile_comparator.h" #include "ios/chrome/browser/application_context.h" #include "ios/web/public/payments/payment_request.h" @@ -98,17 +98,20 @@ contact_profiles_.push_back(&profile_cache_.back()); } + payments::PaymentsProfileComparator comparator( + GetApplicationContext()->GetApplicationLocale(), *this); + // TODO(crbug.com/602666): Implement deduplication and prioritization rules // for shipping profiles. - contact_profiles_ = payments::profile_util::FilterProfilesForContact( - contact_profiles_, GetApplicationContext()->GetApplicationLocale(), - *this); + contact_profiles_ = comparator.FilterProfilesForContact(contact_profiles_); if (!shipping_profiles_.empty()) selected_shipping_profile_ = shipping_profiles_[0]; - if (!contact_profiles_.empty()) + if (!contact_profiles_.empty() && + comparator.IsContactInfoComplete(contact_profiles_[0])) { selected_contact_profile_ = contact_profiles_[0]; + } } void PaymentRequest::PopulateCreditCardCache() {
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp index 959fc43..9ceb4b53 100644 --- a/third_party/WebKit/Source/core/dom/Document.cpp +++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -6666,6 +6666,13 @@ SendSensitiveInputVisibility(); } +CoreProbeSink* Document::GetProbeSink() { + LocalFrame* frame = GetFrame(); + if (!frame && TemplateDocumentHost()) + frame = TemplateDocumentHost()->GetFrame(); + return probe::ToCoreProbeSink(frame); +} + DEFINE_TRACE(Document) { visitor->Trace(imports_controller_); visitor->Trace(doc_type_);
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h index 177068b..3875843 100644 --- a/third_party/WebKit/Source/core/dom/Document.h +++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -1318,6 +1318,8 @@ void IncrementPasswordCount(); void DecrementPasswordCount(); + CoreProbeSink* GetProbeSink() final; + protected: Document(const DocumentInit&, DocumentClassFlags = kDefaultDocumentClass);
diff --git a/third_party/WebKit/Source/core/dom/ExecutionContext.h b/third_party/WebKit/Source/core/dom/ExecutionContext.h index 0929c3e..d8b0f58 100644 --- a/third_party/WebKit/Source/core/dom/ExecutionContext.h +++ b/third_party/WebKit/Source/core/dom/ExecutionContext.h
@@ -43,14 +43,15 @@ namespace blink { -class SuspendableObject; class ConsoleMessage; +class CoreProbeSink; class DOMTimerCoordinator; class ErrorEvent; class EventQueue; class EventTarget; class ExecutionContextTask; class LocalDOMWindow; +class SuspendableObject; class PublicURLManager; class SecurityOrigin; class ScriptState; @@ -181,6 +182,8 @@ void SetReferrerPolicy(ReferrerPolicy); virtual ReferrerPolicy GetReferrerPolicy() const { return referrer_policy_; } + virtual CoreProbeSink* GetProbeSink() { return nullptr; } + protected: ExecutionContext(); virtual ~ExecutionContext();
diff --git a/third_party/WebKit/Source/core/probe/CoreProbes.cpp b/third_party/WebKit/Source/core/probe/CoreProbes.cpp index 40fcaf9..fb0477c 100644 --- a/third_party/WebKit/Source/core/probe/CoreProbes.cpp +++ b/third_party/WebKit/Source/core/probe/CoreProbes.cpp
@@ -41,11 +41,8 @@ #include "core/inspector/InspectorTraceEvents.h" #include "core/inspector/MainThreadDebugger.h" #include "core/inspector/ThreadDebugger.h" -#include "core/inspector/WorkerInspectorController.h" #include "core/page/Page.h" -#include "core/workers/MainThreadWorkletGlobalScope.h" #include "core/workers/WorkerGlobalScope.h" -#include "core/workers/WorkerThread.h" #include "platform/instrumentation/tracing/TraceEvent.h" #include "platform/loader/fetch/FetchInitiatorInfo.h" @@ -139,22 +136,5 @@ DidReceiveResourceResponseButCanceled(frame, loader, identifier, r, resource); } -CoreProbeSink* ToCoreProbeSink(WorkerGlobalScope* worker_global_scope) { - if (!worker_global_scope) - return nullptr; - if (WorkerInspectorController* controller = - worker_global_scope->GetThread()->GetWorkerInspectorController()) - return controller->InstrumentingAgents(); - return nullptr; -} - -CoreProbeSink* ToCoreProbeSinkForNonDocumentContext(ExecutionContext* context) { - if (context->IsWorkerGlobalScope()) - return ToCoreProbeSink(ToWorkerGlobalScope(context)); - if (context->IsMainThreadWorkletGlobalScope()) - return ToCoreProbeSink(ToMainThreadWorkletGlobalScope(context)->GetFrame()); - return nullptr; -} - } // namespace probe } // namespace blink
diff --git a/third_party/WebKit/Source/core/probe/CoreProbes.h b/third_party/WebKit/Source/core/probe/CoreProbes.h index c9971199..6a7e26f 100644 --- a/third_party/WebKit/Source/core/probe/CoreProbes.h +++ b/third_party/WebKit/Source/core/probe/CoreProbes.h
@@ -45,7 +45,6 @@ class CoreProbeSink; class Resource; class ThreadDebugger; -class WorkerGlobalScope; namespace probe { @@ -66,19 +65,12 @@ }; // Called from generated instrumentation code. -CORE_EXPORT CoreProbeSink* ToCoreProbeSink(WorkerGlobalScope*); -CORE_EXPORT CoreProbeSink* ToCoreProbeSinkForNonDocumentContext( - ExecutionContext*); - inline CoreProbeSink* ToCoreProbeSink(LocalFrame* frame) { return frame ? frame->InstrumentingAgents() : nullptr; } inline CoreProbeSink* ToCoreProbeSink(Document& document) { - LocalFrame* frame = document.GetFrame(); - if (!frame && document.TemplateDocumentHost()) - frame = document.TemplateDocumentHost()->GetFrame(); - return ToCoreProbeSink(frame); + return document.GetProbeSink(); } inline CoreProbeSink* ToCoreProbeSink(Document* document) { @@ -86,10 +78,7 @@ } inline CoreProbeSink* ToCoreProbeSink(ExecutionContext* context) { - if (!context) - return nullptr; - return context->IsDocument() ? ToCoreProbeSink(*ToDocument(context)) - : ToCoreProbeSinkForNonDocumentContext(context); + return context ? context->GetProbeSink() : nullptr; } inline CoreProbeSink* ToCoreProbeSink(Node* node) {
diff --git a/third_party/WebKit/Source/core/workers/MainThreadWorkletGlobalScope.cpp b/third_party/WebKit/Source/core/workers/MainThreadWorkletGlobalScope.cpp index f39eb045..c91165cf 100644 --- a/third_party/WebKit/Source/core/workers/MainThreadWorkletGlobalScope.cpp +++ b/third_party/WebKit/Source/core/workers/MainThreadWorkletGlobalScope.cpp
@@ -11,6 +11,7 @@ #include "core/frame/FrameConsole.h" #include "core/frame/LocalFrame.h" #include "core/inspector/MainThreadDebugger.h" +#include "core/probe/CoreProbes.h" namespace blink { @@ -124,6 +125,10 @@ MainThreadDebugger::Instance()->ExceptionThrown(this, event); } +CoreProbeSink* MainThreadWorkletGlobalScope::GetProbeSink() { + return probe::ToCoreProbeSink(GetFrame()); +} + DEFINE_TRACE(MainThreadWorkletGlobalScope) { visitor->Trace(loader_map_); WorkletGlobalScope::Trace(visitor);
diff --git a/third_party/WebKit/Source/core/workers/MainThreadWorkletGlobalScope.h b/third_party/WebKit/Source/core/workers/MainThreadWorkletGlobalScope.h index 8e5552df..6c7887bd 100644 --- a/third_party/WebKit/Source/core/workers/MainThreadWorkletGlobalScope.h +++ b/third_party/WebKit/Source/core/workers/MainThreadWorkletGlobalScope.h
@@ -53,6 +53,7 @@ // ExecutionContext void AddConsoleMessage(ConsoleMessage*) final; void ExceptionThrown(ErrorEvent*) final; + CoreProbeSink* GetProbeSink() final; DECLARE_VIRTUAL_TRACE();
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp index 467e46c..a15ff06 100644 --- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp +++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
@@ -39,6 +39,7 @@ #include "core/frame/DOMTimerCoordinator.h" #include "core/inspector/ConsoleMessage.h" #include "core/inspector/ConsoleMessageStorage.h" +#include "core/inspector/WorkerInspectorController.h" #include "core/inspector/WorkerThreadDebugger.h" #include "core/loader/WorkerFetchContext.h" #include "core/loader/WorkerThreadableLoader.h" @@ -283,6 +284,13 @@ return event_queue_.Get(); } +CoreProbeSink* WorkerGlobalScope::GetProbeSink() { + if (WorkerInspectorController* controller = + GetThread()->GetWorkerInspectorController()) + return controller->InstrumentingAgents(); + return nullptr; +} + bool WorkerGlobalScope::IsSecureContext(String& error_message) const { // Until there are APIs that are available in workers and that // require a privileged context test that checks ancestors, just do
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h index d419218..de61519 100644 --- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h +++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
@@ -135,6 +135,8 @@ WorkerEventQueue* GetEventQueue() const final; bool IsSecureContext(String& error_message) const override; + CoreProbeSink* GetProbeSink() final; + // EventTarget ExecutionContext* GetExecutionContext() const final;
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index e14472e3..d849f9e 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -9545,6 +9545,35 @@ </summary> </histogram> +<histogram name="Cryptohome.MigrationUI.ConsumedBatteryPercent" units="%"> + <owner>fukino@chromium.org</owner> + <summary> + The amount of consumed battery level during cryptohome encryption migration. + This is logged when the battery level decreases during migration, and the + data is used to check if the minimum battery level required to start + migration is appropriate. + </summary> +</histogram> + +<histogram name="Cryptohome.MigrationUI.FirstScreen" + enum="MigrationUIFirstScreen"> + <owner>fukino@chromium.org</owner> + <summary> + The first screen in the encryption migration UI, which is shown when a user + attempts to log in to the system and old encryption (eCryptfs) is detected. + </summary> +</histogram> + +<histogram name="Cryptohome.MigrationUI.UserChoice" + enum="MigrationUIUserChoice"> + <owner>fukino@chromium.org</owner> + <summary> + User's choice when the system is ready to migrate encryption. The user can + start migration or skip it. It is used to know how many users have skipped + migration. + </summary> +</histogram> + <histogram name="Cryptohome.TimeToCompleteDircryptoMigration" units="ms"> <owner>dspaid@chromium.org</owner> <summary> @@ -105917,6 +105946,17 @@ <int value="2" label="IPsec"/> </enum> +<enum name="MigrationUIFirstScreen" type="int"> + <int value="0" label="Ready"/> + <int value="1" label="Resume"/> + <int value="2" label="LowStorage"/> +</enum> + +<enum name="MigrationUIUserChoice" type="int"> + <int value="0" label="Update"/> + <int value="1" label="Skip"/> +</enum> + <enum name="MissingStartType" type="int"> <int value="0" label="Nothing missing"/> <int value="1" label="Start missing"/>