Skip to content

Commit

Permalink
Added search promotion button in omnibox
Browse files Browse the repository at this point in the history
  • Loading branch information
simonhong committed Sep 11, 2024
1 parent 33ed755 commit cad4c85
Show file tree
Hide file tree
Showing 19 changed files with 722 additions and 5 deletions.
7 changes: 7 additions & 0 deletions app/brave_generated_resources.grd
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,13 @@ Or change later at <ph name="SETTINGS_EXTENIONS_LINK">$2<ex>brave://settings/ext
<message name="IDS_ACC_BRAVE_SEARCH_CONVERSION_DISMISS_BUTTON" desc="Announcement when the dismiss button is focused.">
Dismiss Brave search conversion, press Enter to remove this suggestion
</message>
<message name="IDS_BRAVE_SEARCH_CONVERSION_BUTTON_LABEL" desc="The text for the search conversion promotion button">
Switch to Brave Search
</message>
<message name="IDS_BRAVE_SEARCH_CONVERSION_BUTTON_TOOLTIP" desc="The text for the search conversion button tooltip">
Switch to Brave Search
</message>

<!-- web Discovery InfoBar -->
<message name="IDS_WEB_DISCOVERY_INFOBAR_MESSAGE" desc="The text for web discovery infobar message">
Help improve <ph name="SEARCH_NAME">$1<ex>Brave Search</ex></ph> by sending anonymous usage data. <ph name="MORE_INFO">$2<ex>More info</ex></ph>
Expand Down
3 changes: 2 additions & 1 deletion app/theme/brave_theme_resources.grd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>

<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
<outputs>
<output filename="grit/brave_theme_resources.h" type="rc_header" context="default_100_percent">
Expand Down Expand Up @@ -105,6 +105,7 @@
<structure type="chrome_scaled_image" name="IDR_BRAVE_SEARCH_CONVERSION_BANNER_GRAPHIC_DARK" file="brave/brave_search_conversion_banner_graphic_dark.png" />
<structure type="chrome_scaled_image" name="IDR_BRAVE_SEARCH_CONVERSION_BANNER_GRAPHIC_DDG" file="brave/brave_search_conversion_banner_graphic_ddg.png" />
<structure type="chrome_scaled_image" name="IDR_BRAVE_SEARCH_CONVERSION_BANNER_GRAPHIC_DDG_DARK" file="brave/brave_search_conversion_banner_graphic_ddg_dark.png" />
<structure type="chrome_scaled_image" name="IDR_BRAVE_SEARCH_CONVERSION_BUTTON_BRAVE_SEARCH_ICON" file="brave/brave_search_conversion_button_brave_search_icon.png" />
<structure type="chrome_scaled_image" name="IDR_BRAVE_SEARCH_LOGO_IN_SEARCH_PROMOTION" file="brave/brave_search_logo_in_search_promotion.png" />
</if>
</structures>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions browser/ui/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,10 @@ source_set("ui") {
"views/frame/vertical_tab_strip_widget_delegate_view.h",
"views/location_bar/brave_location_bar_view.cc",
"views/location_bar/brave_location_bar_view.h",
"views/location_bar/brave_search_conversion/promotion_button_controller.cc",
"views/location_bar/brave_search_conversion/promotion_button_controller.h",
"views/location_bar/brave_search_conversion/promotion_button_view.cc",
"views/location_bar/brave_search_conversion/promotion_button_view.h",
"views/location_bar/brave_star_view.cc",
"views/location_bar/brave_star_view.h",
"views/profiles/brave_avatar_toolbar_button.cc",
Expand Down
11 changes: 10 additions & 1 deletion browser/ui/color/brave_color_id.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,16 @@
E_CPONLY(kColorSearchConversionBannerTypeBackgroundBorderHovered) \
E_CPONLY(kColorSearchConversionBannerTypeBackgroundGradientFrom) \
E_CPONLY(kColorSearchConversionBannerTypeBackgroundGradientTo) \
E_CPONLY(kColorSearchConversionBannerTypeDescText)
E_CPONLY(kColorSearchConversionBannerTypeDescText) \
E_CPONLY(kColorSearchConversionButtonBorder) \
E_CPONLY(kColorSearchConversionButtonBackground) \
E_CPONLY(kColorSearchConversionButtonBackgroundHovered) \
E_CPONLY(kColorSearchConversionButtonText) \
E_CPONLY(kColorSearchConversionButtonCaratRight) \
E_CPONLY(kColorSearchConversionButtonCloseButton) \
E_CPONLY(kColorSearchConversionButtonCloseButtonHovered) \
E_CPONLY(kColorSearchConversionButtonShadow1) \
E_CPONLY(kColorSearchConversionButtonShadow2)

#define BRAVE_SIDEBAR_COLOR_IDS \
E_CPONLY(kColorSidebarAddBubbleBackground) \
Expand Down
21 changes: 21 additions & 0 deletions browser/ui/color/brave_color_mixer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,26 @@ void AddBraveColorMixerForAllThemes(ui::ColorProvider* provider,
mixer[kColorToolbarButtonActivated] = {SkColorSetRGB(0x7C, 0x91, 0xFF)};
mixer[kColorSidebarButtonPressed] = {kColorToolbarButtonActivated};
mixer[kColorToolbarContentAreaSeparator] = {kColorToolbar};

// Search conversion button in omnibox.
mixer[kColorSearchConversionButtonText] = {nala::kColorPrimary60};
mixer[kColorSearchConversionButtonBorder] = {nala::kColorPrimary20};
mixer[kColorSearchConversionButtonBackground] = {nala::kColorPrimary10};
mixer[kColorSearchConversionButtonBackgroundHovered] = {
nala::kColorPrimary20};
mixer[kColorSearchConversionButtonText] = {nala::kColorPrimary60};
mixer[kColorSearchConversionButtonCloseButton] = {
ui::AlphaBlend({nala::kColorIconInteractive},
{kColorSearchConversionButtonBackground}, 0.5 * 0xff)};
mixer[kColorSearchConversionButtonCloseButtonHovered] = {
ui::AlphaBlend({nala::kColorIconInteractive},
{kColorSearchConversionButtonBackground}, 0.7 * 0xff)};
mixer[kColorSearchConversionButtonCaratRight] = {
kColorSearchConversionButtonCloseButton};
mixer[kColorSearchConversionButtonShadow1] = {
SkColorSetA(SK_ColorBLACK, 0.05 * 255)};
mixer[kColorSearchConversionButtonShadow2] = {
SkColorSetA(SK_ColorBLACK, 0.1 * 255)};
}

} // namespace
Expand Down Expand Up @@ -361,6 +381,7 @@ void AddBraveLightThemeColorMixer(ui::ColorProvider* provider,
PickColorContrastingToToolbar(key, mixer, SkColorSetRGB(0x49, 0x50, 0x57),
SkColorSetRGB(0xFF, 0xFF, 0xFF))};
mixer[kColorMenuItemSubText] = {SkColorSetRGB(0x86, 0x8E, 0x96)};

// It's "Themeable/Blue/10" but leo/color.h doesn't have it.
mixer[kColorSearchConversionBannerTypeBackground] = {
SkColorSetRGB(0xEA, 0xF1, 0xFF)};
Expand Down
21 changes: 21 additions & 0 deletions browser/ui/views/location_bar/brave_location_bar_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@
#include "brave/browser/ui/tabs/features.h"
#include "brave/browser/ui/views/brave_actions/brave_actions_container.h"
#include "brave/browser/ui/views/brave_news/brave_news_action_icon_view.h"
#include "brave/browser/ui/views/location_bar/brave_search_conversion/promotion_button_controller.h"
#include "brave/browser/ui/views/location_bar/brave_search_conversion/promotion_button_view.h"
#include "brave/browser/ui/views/playlist/playlist_action_icon_view.h"
#include "brave/browser/ui/views/toolbar/brave_toolbar_view.h"
#include "brave/components/brave_search_conversion/features.h"
#include "brave/components/commander/common/buildflags/buildflags.h"
#include "brave/components/l10n/common/localization_util.h"
#include "brave/grit/brave_theme_resources.h"
Expand Down Expand Up @@ -125,6 +128,13 @@ void BraveLocationBarView::Init() {
AddChildView(std::make_unique<OnionLocationView>(browser_->profile()));
#endif

if (base::FeatureList::IsEnabled(
brave_search_conversion::features::kOmniboxPromotionButton)) {
promotion_button_ = AddChildView(std::make_unique<PromotionButtonView>());
promotion_controller_ = std::make_unique<PromotionButtonController>(
promotion_button_, omnibox_view_, browser());
}

// brave action buttons
brave_actions_ = AddChildView(
std::make_unique<BraveActionsContainer>(browser_, profile()));
Expand Down Expand Up @@ -206,6 +216,13 @@ void BraveLocationBarView::OnChanged() {
brave_news_action_icon_view_->Update();
}

if (promotion_controller_) {
const bool show_button =
promotion_controller_->ShouldShowSearchPromotionButton() &&
!ShouldChipOverrideLocationIcon() && !ShouldShowKeywordBubble();
promotion_controller_->Show(show_button);
}

// OnChanged calls Layout
LocationBarView::OnChanged();
}
Expand Down Expand Up @@ -234,6 +251,10 @@ std::vector<views::View*> BraveLocationBarView::GetLeftMostTrailingViews() {
return views;
}

views::View* BraveLocationBarView::GetSearchPromotionButton() const {
return promotion_button_;
}

void BraveLocationBarView::RefreshBackground() {
LocationBarView::RefreshBackground();

Expand Down
5 changes: 5 additions & 0 deletions browser/ui/views/location_bar/brave_location_bar_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

class BraveActionsContainer;
class BraveActionsContainerTest;
class PromotionButtonController;
class PromotionButtonView;
class PlaylistActionIconView;
class RewardsBrowserTest;
class SkPath;
Expand Down Expand Up @@ -70,6 +72,7 @@ class BraveLocationBarView : public LocationBarView {
std::vector<views::View*> GetRightMostTrailingViews() override;
// Views that locates at left side of upstream's trailing views.
std::vector<views::View*> GetLeftMostTrailingViews() override;
views::View* GetSearchPromotionButton() const override;
void RefreshBackground() override;
void OnOmniboxBlurred() override;

Expand Down Expand Up @@ -113,6 +116,8 @@ class BraveLocationBarView : public LocationBarView {
std::unique_ptr<ViewShadow> shadow_;
raw_ptr<BraveActionsContainer> brave_actions_ = nullptr;
raw_ptr<BraveNewsActionIconView> brave_news_action_icon_view_ = nullptr;
std::unique_ptr<PromotionButtonController> promotion_controller_;
raw_ptr<PromotionButtonView> promotion_button_ = nullptr;
#if BUILDFLAG(ENABLE_TOR)
raw_ptr<OnionLocationView> onion_location_view_ = nullptr;
#endif
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
/* Copyright (c) 2024 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */

#include "brave/browser/ui/views/location_bar/brave_search_conversion/promotion_button_controller.h"

#include "base/functional/bind.h"
#include "brave/browser/ui/views/location_bar/brave_search_conversion/promotion_button_view.h"
#include "brave/components/ai_chat/core/common/buildflags/buildflags.h"
#include "brave/components/brave_search_conversion/pref_names.h"
#include "brave/components/brave_search_conversion/utils.h"
#include "brave/components/omnibox/browser/leo_provider.h"
#include "brave/components/omnibox/browser/promotion_utils.h"
#include "brave/components/search_engines/brave_prepopulated_engines.h"
#include "chrome/browser/image_fetcher/image_fetcher_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_key.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/views/omnibox/omnibox_view_views.h"
#include "components/image_fetcher/core/image_fetcher.h"
#include "components/image_fetcher/core/image_fetcher_service.h"
#include "components/omnibox/browser/autocomplete_match.h"
#include "components/omnibox/browser/omnibox_edit_model.h"
#include "components/omnibox/browser/omnibox_view.h"
#include "components/search_engines/template_url_data_util.h"
#include "components/search_engines/template_url_service.h"
#include "ui/base/page_transition_types.h"
#include "url/gurl.h"

namespace {

constexpr char kImageFetcherUmaClientName[] = "SearchPromotionButtonFavicon";

constexpr net::NetworkTrafficAnnotationTag
kSearchPromotionButtonTrafficAnnotation =
net::DefineNetworkTrafficAnnotation("search_promotion", R"(
semantics {
sender: "PromotionButtonController"
description:
"Fetches favicon for current search provider"
trigger:
"When current search provider is changed"
data: "URL of the favicon image to be fetched."
destination: WEBSITE
}
policy {
cookies_allowed: NO
setting: "Disabled when the user dismissed."
})");

} // namespace

PromotionButtonController::PromotionButtonController(
PromotionButtonView* button,
OmniboxViewViews* omnibox_view,
Browser* browser)
: button_(button),
omnibox_view_(omnibox_view),
prefs_(*browser->profile()->GetPrefs()),
browser_(*browser) {
CHECK(button_ && omnibox_view);
button_->SetDismissedCallback(base::BindOnce(
&PromotionButtonController::Dismissed, weak_factory_.GetWeakPtr()));
button_->SetMakeDefaultCallback(base::BindOnce(
&PromotionButtonController::SetDefaultAndLoadBraveSearchWithCurrentInput,
weak_factory_.GetWeakPtr()));
template_url_service_ =
TemplateURLServiceFactory::GetForProfile(browser_->profile());
is_brave_search_default_ = IsBraveSearchDefault();
view_observation_.AddObservation(button_);
view_observation_.AddObservation(omnibox_view_);
UpdateButtonUI();
template_url_service_observation_.Observe(template_url_service_);
}

PromotionButtonController::~PromotionButtonController() {
button_ = nullptr;
omnibox_view_ = nullptr;
}

void PromotionButtonController::Show(bool show) {
button_->SetVisible(show);

// For now, animation is triggered only once before chaning search provider.
// Showing animation whenever this button is visible is too much.
// TODO(simonhong): adjust how frequently this animation is used.
if (use_animation_ && show) {
button_->AnimateExpand();
use_animation_ = false;
}
}

bool PromotionButtonController::ShouldShowSearchPromotionButton() {
if (!button_ || !omnibox_view_) {
return false;
}

if (is_brave_search_default_) {
return false;
}

if (prefs_->GetBoolean(brave_search_conversion::prefs::kDismissed)) {
return false;
}

if (!omnibox_view_->model()->PopupIsOpen() ||
GURL(omnibox_view_->GetText()).is_valid()) {
return false;
}

const AutocompleteMatch match = omnibox_view_->model()->CurrentMatch(nullptr);
return !IsBraveSearchPromotionMatch(match) &&
#if BUILDFLAG(ENABLE_AI_CHAT)
!LeoProvider::IsMatchFromLeoProvider(match) &&
#endif
AutocompleteMatch::IsSearchType(match.type);
}

void PromotionButtonController::OnViewIsDeleting(views::View* observed_view) {
// If any observed view among butto or omnibox is destroying,
// this controller will not do anything after that.
view_observation_.RemoveAllObservations();
button_ = nullptr;
omnibox_view_ = nullptr;
}

void PromotionButtonController::OnTemplateURLServiceChanged() {
use_animation_ = true;
is_brave_search_default_ = IsBraveSearchDefault();
if (is_brave_search_default_) {
return;
}

UpdateButtonUI();
}

void PromotionButtonController::OnTemplateURLServiceShuttingDown() {
template_url_service_observation_.Reset();
}

void PromotionButtonController::SetDefaultAndLoadBraveSearchWithCurrentInput() {
CHECK(omnibox_view_);

// Set brave search as default.
auto provider_data = TemplateURLDataFromPrepopulatedEngine(
TemplateURLPrepopulateData::brave_search);
TemplateURL template_url(*provider_data);
template_url_service_->SetUserSelectedDefaultSearchProvider(&template_url);

// Load brave search with current input.
const auto url =
template_url_service_->GenerateSearchURLForDefaultSearchProvider(
omnibox_view_->GetText());

NavigateParams params(&*browser_, url, ui::PAGE_TRANSITION_TYPED);
params.disposition = WindowOpenDisposition::CURRENT_TAB;
Navigate(&params);
}

void PromotionButtonController::Dismissed() {
button_->SetVisible(false);
brave_search_conversion::SetDismissed(&*prefs_);

// After dismissed, we don't need to monitor search provider changes.
template_url_service_observation_.Reset();
}

void PromotionButtonController::UpdateButtonUI() {
if (!template_url_service_->loaded()) {
return;
}

const auto* template_url = template_url_service_->GetDefaultSearchProvider();
auto* service = ImageFetcherServiceFactory::GetForKey(
browser_->profile()->GetProfileKey());
CHECK(service);
auto* fetcher = service->GetImageFetcher(
image_fetcher::ImageFetcherConfig::kDiskCacheOnly);
image_fetcher::ImageFetcherParams params(
kSearchPromotionButtonTrafficAnnotation, kImageFetcherUmaClientName);
fetcher->FetchImage(
template_url->favicon_url(),
base::BindOnce(&PromotionButtonController::OnGetFaviconImage,
weak_factory_.GetWeakPtr()),
params);
}

bool PromotionButtonController::IsBraveSearchDefault() {
const auto* template_url = template_url_service_->GetDefaultSearchProvider();
if (template_url->prepopulate_id() ==
TemplateURLPrepopulateData::PREPOPULATED_ENGINE_ID_BRAVE ||
template_url->prepopulate_id() ==
TemplateURLPrepopulateData::PREPOPULATED_ENGINE_ID_BRAVE_TOR) {
return true;
}

return false;
}

void PromotionButtonController::OnGetFaviconImage(
const gfx::Image& image,
const image_fetcher::RequestMetadata& request_metadata) {
if (!image.IsEmpty()) {
button_->UpdateTargetProviderImage(image);
}
}
Loading

0 comments on commit cad4c85

Please sign in to comment.