[Customize Chrome] Add Brave Rewards to toolbar customization panel in new "Url bar" category (#30227)

This commit extends the toolbar customization feature to support 
Brave Rewards placement in the url bar by introducing a new "Url bar" category 
and implementing the necessary infrastructure.

Key changes:
- Add new "Url bar" category (CategoryId::kUrlBar) to organize url bar-specific actions
- Implement kShowReward action for toggling Brave Rewards visibility
- Integrate Brave Rewards with existing preference system (brave_rewards::prefs::kShowLocationBarButton)
- Add dynamic category management that only shows "Url bar" category when 
Brave Rewards is supported for the current profile

Technical implementation:
- Extended customize_toolbar.mojom with new ActionId::kShowReward and 
  CategoryId::kUrlBar enums
- Implemented AppendBraveSpecificCategories() function to conditionally 
  add Url bar category based on Brave Rewards availability
- Enhanced list action modifiers to handle URL bar actions alongside existing 
  navigation actions
- Added comprehensive unit tests covering both enabled and disabled states
   for Brave Rewards

<!-- Add brave-browser issue below that this PR will resolve -->
Resolves https://github.com/brave/brave-browser/issues/47820

<img width="332" height="189" alt="image" src="https://github.com/user-attachments/assets/af8b7b9b-03e2-4451-8a34-df6ae797cce6" />
This commit is contained in:
Sangwoo Ko
2025-07-29 07:26:53 +09:00
committed by GitHub
parent e97c0742ea
commit df7a753942
9 changed files with 190 additions and 23 deletions
@@ -14,14 +14,17 @@ source_set("customize_chrome") {
deps = [
"//base",
"//brave/browser/brave_rewards:util",
"//brave/components/ai_chat/core/browser",
"//brave/components/ai_chat/core/common",
"//brave/components/brave_rewards/core",
"//brave/components/brave_vpn/common/buildflags",
"//brave/components/brave_wallet/browser:pref_names",
"//brave/components/brave_wallet/common",
"//brave/components/constants",
"//brave/components/resources:strings_grit",
"//brave/components/vector_icons",
"//chrome/browser/profiles:profile",
"//chrome/browser/ui/webui/side_panel/customize_chrome:mojo_bindings",
"//chrome/browser/ui/webui/util",
"//components/prefs",
@@ -61,8 +64,10 @@ source_set("unit_tests") {
deps = [
":customize_chrome",
"//base",
"//brave/browser/brave_rewards:util",
"//brave/components/ai_chat/core/browser",
"//brave/components/ai_chat/core/common",
"//brave/components/brave_rewards/core",
"//brave/components/brave_vpn/common/buildflags",
"//brave/components/brave_wallet/common",
"//brave/components/vector_icons",
@@ -8,6 +8,7 @@
#include "base/containers/fixed_flat_map.h"
#include "brave/components/ai_chat/core/common/pref_names.h"
#include "brave/components/brave_rewards/core/pref_names.h"
#include "brave/components/brave_vpn/common/buildflags/buildflags.h"
#include "brave/components/brave_wallet/browser/pref_names.h"
#include "brave/components/constants/pref_names.h"
@@ -70,6 +71,15 @@ inline constexpr BraveAction kShowVPNAction = {
.icon = kLeoProductVpnIcon};
#endif // BUILDFLAG(ENABLE_BRAVE_VPN)
inline constexpr BraveAction kShowReward = {
.id = side_panel::customize_chrome::mojom::ActionId::kShowReward,
.display_name_resource_id = IDS_CUSTOMIZE_TOOLBAR_TOGGLE_REWARD,
.anchor = side_panel::customize_chrome::mojom::ActionId::
kShowReward, // assign id of itself to append to the end of the list
.category = side_panel::customize_chrome::mojom::CategoryId::kAddressBar,
.pref_name = brave_rewards::prefs::kShowLocationBarButton,
.icon = kLeoProductBatOutlineIcon};
inline constexpr auto kBraveActions =
base::MakeFixedFlatMap<side_panel::customize_chrome::mojom::ActionId,
const BraveAction*>({
@@ -79,6 +89,7 @@ inline constexpr auto kBraveActions =
#if BUILDFLAG(ENABLE_BRAVE_VPN)
{kShowVPNAction.id, &kShowVPNAction},
#endif // BUILDFLAG(ENABLE_BRAVE_VPN)
{kShowReward.id, &kShowReward},
});
} // namespace customize_chrome
@@ -12,10 +12,12 @@
#include "base/containers/contains.h"
#include "base/containers/fixed_flat_set.h"
#include "base/strings/utf_string_conversions.h"
#include "brave/browser/brave_rewards/rewards_util.h"
#include "brave/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/brave_action.h"
#include "brave/components/ai_chat/core/browser/utils.h"
#include "brave/components/brave_vpn/common/buildflags/buildflags.h"
#include "brave/components/brave_wallet/common/common_utils.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/util/image_util.h"
#include "components/prefs/pref_service.h"
#include "components/user_prefs/user_prefs.h"
@@ -32,8 +34,42 @@
namespace customize_chrome {
namespace {
void AddActionsForAddressBarCategory(Profile* profile,
std::vector<BraveAction>& brave_actions) {
if (brave_rewards::IsSupportedForProfile(profile)) {
brave_actions.push_back(kShowReward);
}
}
} // namespace
using side_panel::customize_chrome::mojom::ActionId;
using side_panel::customize_chrome::mojom::ActionPtr;
using side_panel::customize_chrome::mojom::Category;
using side_panel::customize_chrome::mojom::CategoryId;
using side_panel::customize_chrome::mojom::CategoryPtr;
std::vector<CategoryPtr> AppendBraveSpecificCategories(
content::WebContents& web_contents,
std::vector<CategoryPtr> categories) {
// Add a new "Address bar" category.
std::vector<BraveAction> brave_actions;
AddActionsForAddressBarCategory(
Profile::FromBrowserContext(web_contents.GetBrowserContext()),
brave_actions);
if (brave_actions.empty()) {
// In case we don't have any Brave actions for Address bar category, we
// don't need to add the category.
return categories;
}
categories.push_back(Category::New(
CategoryId::kAddressBar,
l10n_util::GetStringUTF8(IDS_CUSTOMIZE_TOOLBAR_CATEGORY_ADDRESS_BAR)));
return categories;
}
std::vector<ActionPtr> FilterUnsupportedChromiumActions(
std::vector<ActionPtr> actions) {
@@ -109,6 +145,8 @@ std::vector<ActionPtr> ApplyBraveSpecificModifications(
// kShowWallet,
// kShowAIChat,
// kShowVPN,
// Address bar
// kShowReward
auto* prefs = user_prefs::UserPrefs::Get(web_contents.GetBrowserContext());
CHECK(prefs) << "Browser context does not have prefs";
@@ -131,12 +169,15 @@ std::vector<ActionPtr> ApplyBraveSpecificModifications(
brave_actions.push_back(kShowWalletAction);
}
AddActionsForAddressBarCategory(
Profile::FromBrowserContext(web_contents.GetBrowserContext()),
brave_actions);
for (const auto& brave_action : brave_actions) {
// Find the anchor action.
// Find the anchor action. If anchor action is not found, just append to the
// end of the list.
auto anchor_it =
std::ranges::find(actions, brave_action.anchor, get_action_id);
CHECK(anchor_it != actions.end()) << "action to anchor not found: "
<< static_cast<int>(brave_action.anchor);
// Create the new action.
auto new_action = Action::New(
@@ -147,8 +188,9 @@ std::vector<ActionPtr> ApplyBraveSpecificModifications(
/*has_enterprise_controlled_pinned_state=*/false, brave_action.category,
get_icon_url(brave_action.icon));
// Insert the new action after the anchor.
actions.insert(anchor_it + 1, std::move(new_action));
// Insert the new action after the anchor or end of the list.
actions.insert(anchor_it == actions.end() ? actions.end() : anchor_it + 1,
std::move(new_action));
}
return actions;
@@ -16,6 +16,14 @@ class WebContents;
namespace customize_chrome {
// Append Brave-specific categories to the list of categories.
// * We have our own "Address bar" category that contains actions like
// `kShowReward`.
std::vector<side_panel::customize_chrome::mojom::CategoryPtr>
AppendBraveSpecificCategories(
content::WebContents& web_contents,
std::vector<side_panel::customize_chrome::mojom::CategoryPtr> categories);
// Removes unsupported Chromium actions from the list of actions.
std::vector<side_panel::customize_chrome::mojom::ActionPtr>
FilterUnsupportedChromiumActions(
@@ -32,6 +40,8 @@ FilterUnsupportedChromiumActions(
// 3. Adds Brave-specific actions.
// e.g. In 'Navigation' category:
// `kShowSidePanel`, `kShowWallet`, `kShowAIChat`, `kShowVPN`.
// In 'Address bar' category:
// `kShowReward`.
std::vector<side_panel::customize_chrome::mojom::ActionPtr>
ApplyBraveSpecificModifications(
content::WebContents& web_contents,
@@ -9,8 +9,10 @@
#include "base/containers/contains.h"
#include "base/containers/fixed_flat_set.h"
#include "brave/browser/brave_rewards/rewards_util.h"
#include "brave/components/ai_chat/core/browser/utils.h"
#include "brave/components/ai_chat/core/common/pref_names.h"
#include "brave/components/brave_rewards/core/pref_names.h"
#include "brave/components/brave_vpn/common/buildflags/buildflags.h"
#include "brave/components/brave_wallet/common/common_utils.h"
#include "brave/components/brave_wallet/common/features.h"
@@ -72,6 +74,12 @@ class ListActionModifiersUnitTest : public testing::Test {
side_panel::customize_chrome::mojom::CategoryId::kTools;
actions.push_back(std::move(tab_search_action));
auto dev_tools_action = side_panel::customize_chrome::mojom::Action::New();
dev_tools_action->id = ActionId::kDevTools;
dev_tools_action->category =
side_panel::customize_chrome::mojom::CategoryId::kTools;
actions.push_back(std::move(dev_tools_action));
return actions;
}
@@ -275,6 +283,33 @@ TEST_F(ListActionModifiersUnitTest,
EXPECT_EQ(wallet_action_it, modified_actions.end());
}
TEST_F(ListActionModifiersUnitTest,
ApplyBraveSpecificModifications_RewardsShouldNotBeAddedWhenDisabled) {
// Rewards should be added by default(Rewards enabled by default)
ASSERT_TRUE(brave_rewards::IsSupportedForProfile(
Profile::FromBrowserContext(web_contents_->GetBrowserContext())));
auto modified_actions = customize_chrome::ApplyBraveSpecificModifications(
*web_contents_, GetBasicActions());
auto rewards_action_it =
std::ranges::find(modified_actions, ActionId::kShowReward,
&side_panel::customize_chrome::mojom::Action::id);
ASSERT_NE(rewards_action_it, modified_actions.end());
// Disable Rewards using managed pref
prefs()->SetManagedPref(brave_rewards::prefs::kDisabledByPolicy,
base::Value(true));
ASSERT_TRUE(
prefs()->IsManagedPreference(brave_rewards::prefs::kDisabledByPolicy));
modified_actions = customize_chrome::ApplyBraveSpecificModifications(
*web_contents_, GetBasicActions());
rewards_action_it =
std::ranges::find(modified_actions, ActionId::kShowReward,
&side_panel::customize_chrome::mojom::Action::id);
// Show Rewards action should not be present
EXPECT_EQ(rewards_action_it, modified_actions.end());
}
TEST_F(ListActionModifiersUnitTest,
ApplyBraveSpecificModifications_ComprehensiveOrderTest) {
#if BUILDFLAG(ENABLE_BRAVE_VPN)
@@ -282,6 +317,8 @@ TEST_F(ListActionModifiersUnitTest,
#endif // BUILDFLAG(ENABLE_BRAVE_VPN)
ASSERT_TRUE(ai_chat::IsAIChatEnabled(prefs()));
ASSERT_TRUE(brave_wallet::IsNativeWalletEnabled());
ASSERT_TRUE(brave_rewards::IsSupportedForProfile(
Profile::FromBrowserContext(web_contents_->GetBrowserContext())));
auto modified_actions = customize_chrome::ApplyBraveSpecificModifications(
*web_contents_, GetBasicActions());
@@ -289,10 +326,43 @@ TEST_F(ListActionModifiersUnitTest,
testing::ElementsAre(
EqId(ActionId::kNewIncognitoWindow),
EqId(ActionId::kShowSidePanel), EqId(ActionId::kTabSearch),
EqId(ActionId::kShowWallet), EqId(ActionId::kShowAIChat)
EqId(ActionId::kShowWallet), EqId(ActionId::kShowAIChat),
#if BUILDFLAG(ENABLE_BRAVE_VPN)
,
EqId(ActionId::kShowVPN)
EqId(ActionId::kShowVPN),
#endif // BUILDFLAG(ENABLE_BRAVE_VPN)
));
EqId(ActionId::kDevTools), EqId(ActionId::kShowReward)));
}
TEST_F(ListActionModifiersUnitTest, AppendBraveSpecificCategories) {
// Create a vector of categories
std::vector<side_panel::customize_chrome::mojom::CategoryPtr> categories;
// Append Brave specific categories
categories = customize_chrome::AppendBraveSpecificCategories(
*web_contents_, std::move(categories));
// Verify "Address bar" category is added with expected actions
ASSERT_TRUE(brave_rewards::IsSupportedForProfile(
Profile::FromBrowserContext(web_contents_->GetBrowserContext())));
auto it = std::ranges::find(
categories, side_panel::customize_chrome::mojom::CategoryId::kAddressBar,
&side_panel::customize_chrome::mojom::Category::id);
EXPECT_NE(it, categories.end());
// When Brave Rewards isn't supported, the Address bar category should not be
// added
prefs()->SetManagedPref(brave_rewards::prefs::kDisabledByPolicy,
base::Value(true));
ASSERT_TRUE(
prefs()->IsManagedPreference(brave_rewards::prefs::kDisabledByPolicy));
ASSERT_FALSE(brave_rewards::IsSupportedForProfile(
Profile::FromBrowserContext(web_contents_->GetBrowserContext())));
categories.clear();
categories = customize_chrome::AppendBraveSpecificCategories(
*web_contents_, std::move(categories));
it = std::ranges::find(
categories, side_panel::customize_chrome::mojom::CategoryId::kAddressBar,
&side_panel::customize_chrome::mojom::Category::id);
EXPECT_EQ(it, categories.end());
}
@@ -7,8 +7,17 @@ module side_panel.customize_chrome.mojom;
[BraveExtend]
enum ActionId {
// Actions in the "Navigation" category.
kShowWallet,
kShowAIChat,
kShowVPN,
kShowSidePanel,
// Actions in the "Address bar" category.
kShowReward,
};
[BraveExtend]
enum CategoryId {
kAddressBar,
};
@@ -14,8 +14,9 @@
#include "chrome/grit/generated_resources.h"
#include "components/grit/brave_components_strings.h"
#define ListActions ListActionsChromium
#define PinAction PinActionChromium
#define ListCategories ListCategories_ChromiumImpl
#define ListActions ListActions_ChromiumImpl
#define PinAction PinAction_ChromiumImpl
// pref_change_registrar_.Init() in constructor
#define Init(...) \
@@ -35,9 +36,18 @@
#undef Init
#undef PinAction
#undef ListActions
#undef ListCategories
void CustomizeToolbarHandler::ListCategories(ListCategoriesCallback callback) {
ListCategories_ChromiumImpl(
base::BindOnce(
&customize_chrome::AppendBraveSpecificCategories,
base::Unretained(base::raw_ref<content::WebContents>(*web_contents_)))
.Then(std::move(callback)));
}
void CustomizeToolbarHandler::ListActions(ListActionsCallback callback) {
ListActionsChromium(
ListActions_ChromiumImpl(
base::BindOnce(&customize_chrome::FilterUnsupportedChromiumActions)
.Then(base::BindOnce(
&customize_chrome::ApplyBraveSpecificModifications,
@@ -57,7 +67,7 @@ void CustomizeToolbarHandler::PinAction(
return;
}
PinActionChromium(action_id, pin);
PinAction_ChromiumImpl(action_id, pin);
}
void CustomizeToolbarHandler::ObserveBraveActions() {
@@ -8,21 +8,25 @@
#include "chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar.mojom.h"
#define ListActions \
ListActionsChromium(ListActionsCallback callback); \
void ListActions
#define ListCategories(...) \
ListCategories_ChromiumImpl(__VA_ARGS__); \
void ListCategories(__VA_ARGS__)
#define PinAction \
PinActionChromium(side_panel::customize_chrome::mojom::ActionId action_id, \
bool pin); \
void ObserveBraveActions(); \
void OnBraveActionPinnedChanged( \
side_panel::customize_chrome::mojom::ActionId action_id); \
void PinAction
#define ListActions(...) \
ListActions_ChromiumImpl(__VA_ARGS__); \
void ListActions(__VA_ARGS__)
#define PinAction(...) \
PinAction_ChromiumImpl(__VA_ARGS__); \
void ObserveBraveActions(); \
void OnBraveActionPinnedChanged( \
side_panel::customize_chrome::mojom::ActionId action_id); \
void PinAction(__VA_ARGS__)
#include <chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler.h> // IWYU pragma: export
#undef PinAction
#undef ListActions
#undef ListCategories
#endif // BRAVE_CHROMIUM_SRC_CHROME_BROWSER_UI_WEBUI_SIDE_PANEL_CUSTOMIZE_CHROME_CUSTOMIZE_TOOLBAR_CUSTOMIZE_TOOLBAR_HANDLER_H_
@@ -15,4 +15,10 @@
<message name="IDS_CUSTOMIZE_TOOLBAR_CATEGORY_TOOLBAR" desc="Title for the toolbar category in the customize toolbar page">
Toolbar
</message>
<message name="IDS_CUSTOMIZE_TOOLBAR_CATEGORY_ADDRESS_BAR" desc="Title for the address bar category in the customize toolbar page">
Address bar
</message>
<message name="IDS_CUSTOMIZE_TOOLBAR_TOGGLE_REWARD" desc="Title for a toggle button to show or hide rewards">
Rewards
</message>
</grit-part>