diff --git a/chrome/browser/companion/core/constants.h b/chrome/browser/companion/core/constants.h index b2c26fe7f6e3f..799def6eb7131 100644 --- a/chrome/browser/companion/core/constants.h +++ b/chrome/browser/companion/core/constants.h @@ -20,6 +20,11 @@ const char kExpsPromoShownCountPref[] = "Companion.Promo.Exps.Shown.Count"; const char kExpsOptInStatusGrantedPref[] = "Companion.Exps.OptIn.Status.Granted"; +// Pref name used for tracking whether the user has ever successfully navigated +// to exps registration success page. +const char kHasNavigatedToExpsSuccessPage[] = + "Companion.HasNavigatedToExpsSuccessPage"; + } // namespace companion #endif // CHROME_BROWSER_COMPANION_CORE_CONSTANTS_H_ diff --git a/chrome/browser/companion/core/features.cc b/chrome/browser/companion/core/features.cc index 5480c386284bc..4ff58704ef379 100644 --- a/chrome/browser/companion/core/features.cc +++ b/chrome/browser/companion/core/features.cc @@ -17,6 +17,12 @@ namespace features { BASE_FEATURE(kSidePanelCompanion, "SidePanelCompanion", base::FEATURE_DISABLED_BY_DEFAULT); +// Dynamically enables the search companion if the user has experiments +// enabled. +BASE_FEATURE(kCompanionEnabledByObservingExpsNavigations, + "CompanionEnabledByObservingExpsNavigations", + base::FEATURE_DISABLED_BY_DEFAULT); + constexpr base::FeatureParam kHomepageURLForCompanion{ &kSidePanelCompanion, "companion-homepage-url", "https://lens.google.com/companion"}; @@ -28,10 +34,13 @@ constexpr base::FeatureParam kEnableOpenCompanionForImageSearch{ &kSidePanelCompanion, "open-companion-for-image-search", true}; constexpr base::FeatureParam kEnableOpenCompanionForWebSearch{ &kSidePanelCompanion, "open-companion-for-web-search", true}; - constexpr base::FeatureParam kOpenLinksInCurrentTab{ &kSidePanelCompanion, "open-links-in-current-tab", true}; +constexpr base::FeatureParam kExpsRegistrationSuccessPageURLs{ + &kCompanionEnabledByObservingExpsNavigations, + "exps-registration-success-page-urls", ""}; + } // namespace features namespace switches { diff --git a/chrome/browser/companion/core/features.h b/chrome/browser/companion/core/features.h index 7d28b3b06d884..f964d6a8eff70 100644 --- a/chrome/browser/companion/core/features.h +++ b/chrome/browser/companion/core/features.h @@ -14,8 +14,10 @@ namespace companion { namespace features { BASE_DECLARE_FEATURE(kSidePanelCompanion); +BASE_DECLARE_FEATURE(kCompanionEnabledByObservingExpsNavigations); extern const base::FeatureParam kHomepageURLForCompanion; extern const base::FeatureParam kImageUploadURLForCompanion; +extern const base::FeatureParam kExpsRegistrationSuccessPageURLs; extern const base::FeatureParam kEnableOpenCompanionForImageSearch; extern const base::FeatureParam kEnableOpenCompanionForWebSearch; extern const base::FeatureParam kOpenLinksInCurrentTab; diff --git a/chrome/browser/companion/core/promo_handler.cc b/chrome/browser/companion/core/promo_handler.cc index b800d05eabeaa..8d351adeb0faa 100644 --- a/chrome/browser/companion/core/promo_handler.cc +++ b/chrome/browser/companion/core/promo_handler.cc @@ -26,6 +26,7 @@ void PromoHandler::RegisterProfilePrefs(PrefRegistrySimple* registry) { registry->RegisterIntegerPref(kExpsPromoShownCountPref, 0); // TODO(shaktisahu): Move the pref registration to a better location. registry->RegisterBooleanPref(kExpsOptInStatusGrantedPref, false); + registry->RegisterBooleanPref(kHasNavigatedToExpsSuccessPage, false); } void PromoHandler::OnPromoAction(PromoType promo_type, diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 9e536d6f48970..742bcf66760a6 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn @@ -4446,6 +4446,8 @@ static_library("ui") { "side_panel/companion/companion_tab_helper.h", "side_panel/companion/companion_utils.cc", "side_panel/companion/companion_utils.h", + "side_panel/companion/exps_registration_success_observer.cc", + "side_panel/companion/exps_registration_success_observer.h", "side_panel/customize_chrome/customize_chrome_side_panel_controller_utils.h", "side_panel/customize_chrome/customize_chrome_tab_helper.cc", "side_panel/customize_chrome/customize_chrome_tab_helper.h", diff --git a/chrome/browser/ui/side_panel/companion/exps_registration_success_observer.cc b/chrome/browser/ui/side_panel/companion/exps_registration_success_observer.cc new file mode 100644 index 0000000000000..823973237d6c2 --- /dev/null +++ b/chrome/browser/ui/side_panel/companion/exps_registration_success_observer.cc @@ -0,0 +1,57 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/side_panel/companion/exps_registration_success_observer.h" + +#include "base/strings/string_split.h" +#include "chrome/browser/companion/core/constants.h" +#include "chrome/browser/companion/core/features.h" +#include "chrome/browser/profiles/profile.h" +#include "components/prefs/pref_service.h" +#include "content/public/browser/web_contents.h" + +namespace companion { + +ExpsRegistrationSuccessObserver::ExpsRegistrationSuccessObserver( + content::WebContents* web_contents) + : content::WebContentsObserver(web_contents), + content::WebContentsUserData( + *web_contents) { + const auto& url_strings_to_match = base::SplitString( + companion::features::kExpsRegistrationSuccessPageURLs.Get(), ",", + base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + for (const auto& url_string : url_strings_to_match) { + urls_to_match_against_.emplace_back(url_string); + } +} + +ExpsRegistrationSuccessObserver::~ExpsRegistrationSuccessObserver() = default; + +void ExpsRegistrationSuccessObserver::PrimaryPageChanged(content::Page& page) { + PrefService* pref_service = + Profile::FromBrowserContext(web_contents()->GetBrowserContext()) + ->GetPrefs(); + if (pref_service->GetBoolean(kHasNavigatedToExpsSuccessPage)) { + return; + } + bool matches_exps_url = false; + const GURL& url = page.GetMainDocument().GetLastCommittedURL(); + for (const auto& url_to_match : urls_to_match_against_) { + if (url == url_to_match) { + matches_exps_url = true; + break; + } + } + + if (!matches_exps_url) { + return; + } + + // Save the status to a pref. + pref_service->SetBoolean(kHasNavigatedToExpsSuccessPage, true); +} + +WEB_CONTENTS_USER_DATA_KEY_IMPL(ExpsRegistrationSuccessObserver); + +} // namespace companion diff --git a/chrome/browser/ui/side_panel/companion/exps_registration_success_observer.h b/chrome/browser/ui/side_panel/companion/exps_registration_success_observer.h new file mode 100644 index 0000000000000..b9ffb92c8b571 --- /dev/null +++ b/chrome/browser/ui/side_panel/companion/exps_registration_success_observer.h @@ -0,0 +1,50 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_SIDE_PANEL_COMPANION_EXPS_REGISTRATION_SUCCESS_OBSERVER_H_ +#define CHROME_BROWSER_UI_SIDE_PANEL_COMPANION_EXPS_REGISTRATION_SUCCESS_OBSERVER_H_ + +#include + +#include "content/public/browser/web_contents_observer.h" +#include "content/public/browser/web_contents_user_data.h" +#include "url/gurl.h" + +namespace content { +class Page; +class WebContents; +} // namespace content + +namespace companion { + +// An observer that observes page navigations on a tab and determines if the +// user has laned on the success page of exps registration. . +class ExpsRegistrationSuccessObserver + : public content::WebContentsObserver, + public content::WebContentsUserData { + public: + explicit ExpsRegistrationSuccessObserver(content::WebContents* web_contents); + ~ExpsRegistrationSuccessObserver() override; + + // Disallow copy/assign. + ExpsRegistrationSuccessObserver(const ExpsRegistrationSuccessObserver&) = + delete; + ExpsRegistrationSuccessObserver& operator=( + const ExpsRegistrationSuccessObserver&) = delete; + + private: + friend class content::WebContentsUserData; + + // content::WebContentsObserver overrides. + void PrimaryPageChanged(content::Page& page) override; + + // The list of URLs to search for a match. + std::vector urls_to_match_against_; + + WEB_CONTENTS_USER_DATA_KEY_DECL(); +}; + +} // namespace companion + +#endif // CHROME_BROWSER_UI_SIDE_PANEL_COMPANION_EXPS_REGISTRATION_SUCCESS_OBSERVER_H_ diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc index 78dc13c6b78ff..091bbeaf2ea19 100644 --- a/chrome/browser/ui/tab_helpers.cc +++ b/chrome/browser/ui/tab_helpers.cc @@ -177,6 +177,7 @@ #include "chrome/browser/ui/sad_tab_helper.h" #include "chrome/browser/ui/search/search_tab_helper.h" #include "chrome/browser/ui/side_panel/companion/companion_tab_helper.h" +#include "chrome/browser/ui/side_panel/companion/exps_registration_success_observer.h" #include "chrome/browser/ui/side_panel/customize_chrome/customize_chrome_tab_helper.h" #include "chrome/browser/ui/side_panel/customize_chrome/customize_chrome_utils.h" #include "chrome/browser/ui/side_panel/history_clusters/history_clusters_tab_helper.h" @@ -526,6 +527,11 @@ void TabHelpers::AttachTabHelpers(WebContents* web_contents) { if (base::FeatureList::IsEnabled(companion::features::kSidePanelCompanion)) { companion::CompanionTabHelper::CreateForWebContents(web_contents); } + if (base::FeatureList::IsEnabled( + companion::features::kCompanionEnabledByObservingExpsNavigations)) { + companion::ExpsRegistrationSuccessObserver::CreateForWebContents( + web_contents); + } #endif #if BUILDFLAG(IS_MAC) diff --git a/chrome/browser/ui/views/side_panel/search_companion/companion_page_browsertest.cc b/chrome/browser/ui/views/side_panel/search_companion/companion_page_browsertest.cc index a0c54e75822f9..9324b33e45af5 100644 --- a/chrome/browser/ui/views/side_panel/search_companion/companion_page_browsertest.cc +++ b/chrome/browser/ui/views/side_panel/search_companion/companion_page_browsertest.cc @@ -72,6 +72,7 @@ const char kSearchQueryUrl[] = "https://www.google.com/search?q=xyz"; const char kExpectedExpsPromoUrl[] = "https://foobar.com/"; const char kPhReportingUrl[] = "https://foobar.com/"; +const char kExpsRegistrationSuccessUrl[] = "https://foobar.com/experiments"; } // namespace @@ -370,8 +371,21 @@ class CompanionPageBrowserTest : public InProcessBrowserTest { params["companion-image-upload-url"] = companion_server_.GetURL("/upload").spec(); params["open-links-in-current-tab"] = ShouldOpenLinkInCurrentTab(); - feature_list_.InitAndEnableFeatureWithParameters( - companion::features::kSidePanelCompanion, params); + base::FieldTrialParams params2; + params2["exps-registration-success-page-urls"] = + kExpsRegistrationSuccessUrl; + + std::vector enabled_features; + if (enable_feature_side_panel_companion_) { + enabled_features.emplace_back(companion::features::kSidePanelCompanion, + params); + } + enabled_features.emplace_back( + companion::features::kCompanionEnabledByObservingExpsNavigations, + params2); + + feature_list_.InitWithFeaturesAndParameters(enabled_features, + /*disabled_features=*/{}); } virtual std::string ShouldOpenLinkInCurrentTab() { return "false"; } @@ -445,6 +459,7 @@ class CompanionPageBrowserTest : public InProcessBrowserTest { size_t requests_received_on_server_ = 0; std::string last_sourcelang_; std::string last_targetlang_; + bool enable_feature_side_panel_companion_ = true; }; IN_PROC_BROWSER_TEST_F(CompanionPageBrowserTest, InitialNavigationWithoutMsbb) { @@ -1228,6 +1243,29 @@ IN_PROC_BROWSER_TEST_F(CompanionPageBrowserTest, static_cast(SidePanelOpenTrigger::kPinnedEntryToolbarButton)); } +class CompanionPageDisabledBrowserTest : public CompanionPageBrowserTest { + public: + CompanionPageDisabledBrowserTest() : CompanionPageBrowserTest() { + enable_feature_side_panel_companion_ = false; + } +}; + +IN_PROC_BROWSER_TEST_F(CompanionPageDisabledBrowserTest, + ObservesExpsRegistrationSuccessURL) { + // Navigate to a random page. + ASSERT_TRUE( + ui_test_utils::NavigateToURL(browser(), CreateUrl(kHost, kRelativeUrl1))); + EXPECT_FALSE(browser()->profile()->GetPrefs()->GetBoolean( + companion::kHasNavigatedToExpsSuccessPage)); + + // Navigate to exps registration success page. It should enable the pref. + ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), + GURL(kExpsRegistrationSuccessUrl))); + // Verify that the pref. + EXPECT_TRUE(browser()->profile()->GetPrefs()->GetBoolean( + companion::kHasNavigatedToExpsSuccessPage)); +} + class CompanionPagePolicyBrowserTest : public CompanionPageBrowserTest { public: void EnableCompanionByPolicy(bool enable_companion_by_policy) {