[Android] Hide Brave Rewards UI elements when disabled by policy (#33116)

[Android] Hide Brave Rewards UI elements when disabled by policy

Implements policy-based visibility control for Brave Rewards across
Android UI. When BRAVE_REWARDS_DISABLED policy is active via Brave
Origin subscription settings, all rewards-related UI elements are
now properly hidden.

Resolves: https://github.com/brave/brave-browser/issues/51826
This commit is contained in:
Serg
2026-01-12 20:24:01 +00:00
committed by GitHub
parent 5298973e3b
commit 0a7ac78d6e
6 changed files with 472 additions and 42 deletions
@@ -464,17 +464,22 @@ public abstract class BraveActivity extends ChromeActivity
final BraveTabbedAppMenuPropertiesDelegate braveTabbedAppMenuPropertiesDelegate =
(BraveTabbedAppMenuPropertiesDelegate) delegate;
final Bundle bundle =
CustomizeBraveMenu.populateBundle(
getResources(),
new Bundle(),
braveTabbedAppMenuPropertiesDelegate.buildMainMenuModelList(),
braveTabbedAppMenuPropertiesDelegate.buildPageActionsModelList());
SettingsNavigation settingsNavigation =
SettingsNavigationFactory.createSettingsNavigation();
// Follow upstream code and pass null as fragment to show
// that defaults to main settings screen.
settingsNavigation.startSettings(this, null, bundle);
// Use async version to ensure policy values are checked before building menu
braveTabbedAppMenuPropertiesDelegate.buildMainMenuModelListAsync(
(mainMenuList) -> {
final Bundle bundle =
CustomizeBraveMenu.populateBundle(
getResources(),
new Bundle(),
mainMenuList,
braveTabbedAppMenuPropertiesDelegate
.buildPageActionsModelList());
SettingsNavigation settingsNavigation =
SettingsNavigationFactory.createSettingsNavigation();
// Follow upstream code and pass null as fragment to show
// that defaults to main settings screen.
settingsNavigation.startSettings(BraveActivity.this, null, bundle);
});
return true;
}
@@ -537,11 +542,15 @@ public abstract class BraveActivity extends ChromeActivity
assert delegate instanceof BraveTabbedAppMenuPropertiesDelegate;
final BraveTabbedAppMenuPropertiesDelegate braveTabbedAppMenuPropertiesDelegate =
(BraveTabbedAppMenuPropertiesDelegate) delegate;
// Get full menu items and pass them to settings.
CustomizeBraveMenu.openCustomizeMenuSettings(
this,
braveTabbedAppMenuPropertiesDelegate.buildMainMenuModelList(),
braveTabbedAppMenuPropertiesDelegate.buildPageActionsModelList());
// Use async version to ensure policy values are checked before building menu
braveTabbedAppMenuPropertiesDelegate.buildMainMenuModelListAsync(
(mainMenuList) -> {
// Get full menu items and pass them to settings.
CustomizeBraveMenu.openCustomizeMenuSettings(
BraveActivity.this,
mainMenuList,
braveTabbedAppMenuPropertiesDelegate.buildPageActionsModelList());
});
} else if (id == R.id.brave_shred_id) {
shredData(currentTab);
} else {
@@ -11,16 +11,21 @@ import android.util.Base64;
import org.json.JSONException;
import org.json.JSONObject;
import org.chromium.base.BraveFeatureList;
import org.chromium.base.Callback;
import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
import org.chromium.base.task.PostTask;
import org.chromium.base.task.TaskTraits;
import org.chromium.brave.browser.brave_origin.BraveOriginServiceFactory;
import org.chromium.brave.browser.skus.SkusServiceFactory;
import org.chromium.brave.browser.util.BraveDomainsUtils;
import org.chromium.brave.browser.util.ServicesEnvironment;
import org.chromium.brave_origin.mojom.BraveOriginSettingsHandler;
import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.policy.BravePolicyConstants;
import org.chromium.chrome.browser.preferences.BravePref;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.settings.BraveOriginPreferences;
@@ -402,4 +407,87 @@ public class BraveOriginSubscriptionPrefs {
SettingsNavigationFactory.createSettingsNavigation()
.startSettings(activity, BraveOriginPreferences.class);
}
/**
* Checks if a policy value should be inverted when mapping to/from UI state. DISABLED policies
* need inversion (true = disabled = unchecked in UI). ENABLED policies don't need inversion
* (true = enabled = checked in UI).
*
* @param policyKey The policy key to check
* @return true if the policy value should be inverted, false otherwise
*/
public static boolean isPolicyInverted(@Nullable String policyKey) {
if (policyKey == null) {
return false;
}
switch (policyKey) {
case BravePolicyConstants.BRAVE_REWARDS_DISABLED:
case BravePolicyConstants.BRAVE_NEWS_DISABLED:
case BravePolicyConstants.BRAVE_V_P_N_DISABLED:
case BravePolicyConstants.BRAVE_WALLET_DISABLED:
return true;
default:
return false;
}
}
/**
* Generic method to check if a feature is disabled by policy asynchronously. This method checks
* subscription status first, then checks the policy value.
*
* @param profile The profile to use for the operation
* @param policyKey The policy key to check (e.g., BravePolicyConstants.BRAVE_REWARDS_DISABLED)
* @param callback Called with the policy value (true if disabled, false if not disabled)
*/
public static void checkPolicyAsync(
@Nullable Profile profile, String policyKey, @Nullable Callback<Boolean> callback) {
if (callback == null) {
return;
}
// If Brave Origin feature is not enabled, policies are not applicable
if (!ChromeFeatureList.isEnabled(BraveFeatureList.BRAVE_ORIGIN)) {
callback.onResult(false);
return;
}
if (profile == null) {
callback.onResult(false);
return;
}
// Check subscription status first - if not active, policies don't apply (feature enabled)
requestCredentialSummary(
profile,
(isSubscriptionActive) -> {
// If subscription is not active, return false (feature not disabled = enabled)
if (!isSubscriptionActive) {
callback.onResult(false);
return;
}
// Subscription is active, proceed with policy check
BraveOriginServiceFactory factory = BraveOriginServiceFactory.getInstance();
BraveOriginSettingsHandler handler =
factory.getBraveOriginSettingsHandler(profile, null);
if (handler == null) {
callback.onResult(false);
return;
}
handler.getPolicyValue(
policyKey,
(value) -> {
// For "DISABLED" policies (inverted): true = disabled, null/false =
// enabled
// For "ENABLED" policies: true = enabled, null/false = disabled
boolean isDisabled =
isPolicyInverted(policyKey)
? (value != null && value)
: (value == null || !value);
callback.onResult(isDisabled);
handler.close();
});
});
}
}
@@ -20,12 +20,14 @@ import org.chromium.chrome.browser.BraveRelaunchUtils;
import org.chromium.chrome.browser.BraveRewardsNativeWorker;
import org.chromium.chrome.browser.BraveRewardsObserver;
import org.chromium.chrome.browser.appearance.settings.AppearanceSettingsFragment;
import org.chromium.chrome.browser.brave_origin.BraveOriginSubscriptionPrefs;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.multiwindow.BraveMultiWindowDialogFragment;
import org.chromium.chrome.browser.multiwindow.BraveMultiWindowUtils;
import org.chromium.chrome.browser.multiwindow.MultiInstanceManager.PersistedInstanceType;
import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
import org.chromium.chrome.browser.ntp.NtpUtil;
import org.chromium.chrome.browser.policy.BravePolicyConstants;
import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
import org.chromium.chrome.browser.tasks.tab_management.BraveTabUiFeatureUtilities;
import org.chromium.chrome.browser.toolbar.ToolbarPositionController;
@@ -175,6 +177,9 @@ public class AppearancePreferences extends AppearanceSettingsFragment
}
super.onStart();
// Check if Brave Rewards is disabled by policy and hide the icon preference if so
checkRewardsPolicyAndUpdatePreference();
if (ToolbarPositionController.isToolbarPositionCustomizationEnabled(getContext(), false)) {
updatePreferenceTitle(
PREF_ADDRESS_BAR, AddressBarSettingsFragment.getTitle(getContext()));
@@ -346,4 +351,23 @@ public class AppearancePreferences extends AppearanceSettingsFragment
preference.setOrder(order);
}
}
/**
* Checks if Brave Rewards is disabled by policy via Brave Origin and removes related
* preferences if so. This ensures that when Brave Rewards is disabled, users cannot toggle
* rewards-related settings in the appearance settings.
*/
private void checkRewardsPolicyAndUpdatePreference() {
BraveOriginSubscriptionPrefs.checkPolicyAsync(
getProfile(),
BravePolicyConstants.BRAVE_REWARDS_DISABLED,
(isDisabled) -> {
if (getActivity() == null || getActivity().isFinishing() || !isDisabled) {
return;
}
// Policy disables Brave Rewards - remove rewards-related preferences
removePreferenceIfPresent(PREF_SHOW_BRAVE_REWARDS_ICON);
removePreferenceIfPresent(PREF_ADS_SWITCH);
});
}
}
@@ -21,6 +21,7 @@ import org.chromium.brave_origin.mojom.BraveOriginSettingsHandler;
import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.brave_origin.BraveOriginSubscriptionPrefs;
import org.chromium.chrome.browser.policy.BravePolicyConstants;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
@@ -126,9 +127,13 @@ public class BraveOriginPreferences extends BravePreferenceFragment
if (policyKey == null || mBraveOriginSettingsHandler == null) {
return false;
}
// For DISABLED policies, invert the value (checked = enabled = false policy value)
// For ENABLED policies, use the value as-is (checked = enabled = true policy value)
boolean policyValue =
BraveOriginSubscriptionPrefs.isPolicyInverted(policyKey) ? !isEnabled : isEnabled;
mBraveOriginSettingsHandler.setPolicyValue(
policyKey,
isEnabled,
policyValue,
(success) -> {
if (!success) {
Log.e(TAG, "Failed to set policy value for " + policyKey);
@@ -170,8 +175,14 @@ public class BraveOriginPreferences extends BravePreferenceFragment
policyKey,
(value) -> {
if (value != null) {
preference.setChecked(value);
updateToggleDescription(preference, value);
// For DISABLED policies, invert the value (!value)
// For ENABLED policies, use the value as-is
boolean checkedValue =
BraveOriginSubscriptionPrefs.isPolicyInverted(policyKey)
? !value
: value;
preference.setChecked(checkedValue);
updateToggleDescription(preference, checkedValue);
}
});
}
@@ -23,7 +23,9 @@ import com.google.android.material.button.MaterialButton;
import org.chromium.base.BraveFeatureList;
import org.chromium.base.BravePreferenceKeys;
import org.chromium.base.BraveUrlConstants;
import org.chromium.base.Callback;
import org.chromium.base.DeviceInfo;
import org.chromium.base.library_loader.LibraryLoader;
import org.chromium.base.supplier.ObservableSupplier;
import org.chromium.base.supplier.OneshotSupplier;
import org.chromium.brave.browser.customize_menu.CustomizeBraveMenu;
@@ -35,6 +37,7 @@ import org.chromium.chrome.browser.BraveRewardsNativeWorker;
import org.chromium.chrome.browser.app.appmenu.AppMenuIconRowFooter;
import org.chromium.chrome.browser.bookmarks.BookmarkModel;
import org.chromium.chrome.browser.brave_leo.BraveLeoPrefUtils;
import org.chromium.chrome.browser.brave_origin.BraveOriginSubscriptionPrefs;
import org.chromium.chrome.browser.feed.webfeed.WebFeedSnackbarController;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.homepage.HomepageManager;
@@ -44,7 +47,9 @@ import org.chromium.chrome.browser.layouts.LayoutStateProvider;
import org.chromium.chrome.browser.multiwindow.BraveMultiWindowUtils;
import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcher;
import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
import org.chromium.chrome.browser.policy.BravePolicyConstants;
import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.readaloud.ReadAloudController;
import org.chromium.chrome.browser.set_default_browser.BraveSetDefaultBrowserUtils;
import org.chromium.chrome.browser.tab.Tab;
@@ -73,7 +78,9 @@ import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.url.GURL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
/** Brave's extension for TabbedAppMenuPropertiesDelegate */
@@ -84,6 +91,60 @@ public class BraveTabbedAppMenuPropertiesDelegate extends TabbedAppMenuPropertie
private boolean mJunitIsTesting;
private final Context mBraveContext;
/**
* Represents a menu item that can be controlled by policy.
*
* <p>To add a new policy-controlled menu item, add a new entry to {@link
* #getPolicyControlledMenuItems()} with: - menuItemId: The resource ID of the menu item (e.g.,
* R.id.brave_news_id) - policyKey: The policy constant (e.g.,
* BravePolicyConstants.BRAVE_NEWS_DISABLED) - itemBuilder: Method reference to build the menu
* item (e.g., this::buildBraveNewsItem) - isSupportedChecker: Lambda to check if feature is
* supported (e.g., () -> true) - insertBeforeItemId: Menu item ID to insert before (e.g.,
* R.id.brave_customize_id)
*
* <p>The item will automatically be hidden/shown in the app menu based on policy ({@link
* #updateMenuItemsBasedOnPolicy}) and hidden/shown in the settings screen menu based on policy
* ({@link #buildMainMenuModelListAsync}).
*/
private static class PolicyControlledMenuItem {
final int mMenuItemId;
final String mPolicyKey;
final Supplier<MVCListAdapter.ListItem> mItemBuilder;
final Supplier<Boolean> mIsSupportedChecker;
final int mInsertBeforeItemId;
PolicyControlledMenuItem(
int menuItemId,
String policyKey,
Supplier<MVCListAdapter.ListItem> itemBuilder,
Supplier<Boolean> isSupportedChecker,
int insertBeforeItemId) {
mMenuItemId = menuItemId;
mPolicyKey = policyKey;
mItemBuilder = itemBuilder;
mIsSupportedChecker = isSupportedChecker;
mInsertBeforeItemId = insertBeforeItemId;
}
}
/**
* Configuration list of all policy-controlled menu items. To add a new feature, simply add an
* entry here.
*/
private List<PolicyControlledMenuItem> getPolicyControlledMenuItems() {
return Arrays.asList(
new PolicyControlledMenuItem(
R.id.brave_rewards_id,
BravePolicyConstants.BRAVE_REWARDS_DISABLED,
this::buildBraveRewardsItem,
() -> {
BraveRewardsNativeWorker worker =
BraveRewardsNativeWorker.getInstance();
return worker != null && worker.isSupported();
},
R.id.brave_news_id));
}
public BraveTabbedAppMenuPropertiesDelegate(
Context context,
ActivityTabProvider activityTabProvider,
@@ -124,6 +185,116 @@ public class BraveTabbedAppMenuPropertiesDelegate extends TabbedAppMenuPropertie
mBraveContext = context;
}
/**
* Helper method to get the current profile from the activity tab provider. Used for policy
* checks that require a profile.
*
* @return The profile, or null if not available
*/
@Nullable
private Profile getCurrentProfile() {
Tab currentTab = mActivityTabProvider.get();
if (currentTab == null) {
return null;
}
// Check if native library is loaded before calling native method
// In unit tests (Robolectric), native methods are not available
if (!LibraryLoader.getInstance().isInitialized()) {
return null;
}
return Profile.fromWebContents(currentTab.getWebContents());
}
/**
* Checks if a menu item is present in the menu list.
*
* @param modelList The menu model list to search
* @param menuItemId The menu item ID to look for
* @return true if the item is present, false otherwise
*/
private boolean isMenuItemPresent(MVCListAdapter.ModelList modelList, int menuItemId) {
for (int i = 0; i < modelList.size(); i++) {
MVCListAdapter.ListItem item = modelList.get(i);
if (item.model.get(AppMenuItemProperties.MENU_ITEM_ID) == menuItemId) {
return true;
}
}
return false;
}
/**
* Removes a menu item by ID from the menu list.
*
* @param modelList The menu model list to modify
* @param menuItemId The menu item ID to remove
*/
private void removeMenuItemById(MVCListAdapter.ModelList modelList, int menuItemId) {
for (int i = 0; i < modelList.size(); i++) {
MVCListAdapter.ListItem item = modelList.get(i);
if (item.model.get(AppMenuItemProperties.MENU_ITEM_ID) == menuItemId) {
modelList.removeAt(i);
break;
}
}
}
/**
* Inserts a menu item before a specified item in the menu list.
*
* @param modelList The menu model list to modify
* @param itemToInsert The menu item to insert
* @param beforeItemId The menu item ID to insert before
*/
private void insertMenuItemBefore(
MVCListAdapter.ModelList modelList,
MVCListAdapter.ListItem itemToInsert,
int beforeItemId) {
int insertIndex = modelList.size() - 1; // Default to end if beforeItemId not found
for (int i = 0; i < modelList.size(); i++) {
MVCListAdapter.ListItem item = modelList.get(i);
if (item.model.get(AppMenuItemProperties.MENU_ITEM_ID) == beforeItemId) {
insertIndex = i;
break;
}
}
modelList.add(insertIndex, itemToInsert);
}
/**
* Updates menu items based on policy checks for all configured policy-controlled items. This
* method checks policies asynchronously and adds/removes menu items accordingly.
*
* @param modelList The menu model list to update
*/
private void updateMenuItemsBasedOnPolicy(MVCListAdapter.ModelList modelList) {
Profile profile = getCurrentProfile();
if (profile == null) {
// Profile not available (e.g., in tests) - skip policy check
return;
}
for (PolicyControlledMenuItem item : getPolicyControlledMenuItems()) {
BraveOriginSubscriptionPrefs.checkPolicyAsync(
profile,
item.mPolicyKey,
(isDisabled) -> {
if (isDisabled) {
// Policy disables the feature - remove item if present
removeMenuItemById(modelList, item.mMenuItemId);
} else {
// Policy allows the feature - add item if not present and supported
if (!isMenuItemPresent(modelList, item.mMenuItemId)) {
if (item.mIsSupportedChecker.get()) {
insertMenuItemBefore(
modelList,
item.mItemBuilder.get(),
item.mInsertBeforeItemId);
}
}
}
});
}
}
private void onFooterViewInflated(AppMenuHandler appMenuHandler, View view) {
// If it's still null, just hide the whole view
if (mBookmarkModelSupplier.get() == null) {
@@ -272,6 +443,54 @@ public class BraveTabbedAppMenuPropertiesDelegate extends TabbedAppMenuPropertie
&& super.shouldShowMoveToOtherWindow();
}
/**
* Builds the complete list of main menu items for the Customize menu settings screen
* asynchronously, ensuring policy values are checked before building.
*
* <p>This method checks all policy-controlled menu items asynchronously, then builds the menu
* list with the correct policy state. Use this method instead of {@link
* #buildMainMenuModelList()} when you need to ensure policy values are up-to-date.
*
* @param callback Called with the built menu model list once all policy checks complete
*/
public void buildMainMenuModelListAsync(Callback<MVCListAdapter.ModelList> callback) {
// Always check policy fresh (no caching) before building menu
// Check all policy-controlled items, then build menu with policy states
Profile profile = getCurrentProfile();
List<PolicyControlledMenuItem> policyItems = getPolicyControlledMenuItems();
if (profile == null || policyItems.isEmpty()) {
// Profile not available (e.g., in tests) or no policy items - build menu without policy
// checks
MVCListAdapter.ModelList menuList = buildMainMenuModelList(new HashMap<>());
callback.onResult(menuList);
return;
}
// Map to store policy states: menuItemId -> isDisabled
Map<Integer, Boolean> policyStates = new HashMap<>();
final int[] pendingChecks = {
policyItems.size()
}; // Use array to allow modification in lambda
for (PolicyControlledMenuItem item : policyItems) {
BraveOriginSubscriptionPrefs.checkPolicyAsync(
profile,
item.mPolicyKey,
(isDisabled) -> {
policyStates.put(item.mMenuItemId, isDisabled);
pendingChecks[0]--;
// When all policy checks are complete, build the menu
if (pendingChecks[0] == 0) {
MVCListAdapter.ModelList menuList =
buildMainMenuModelList(policyStates);
callback.onResult(menuList);
}
});
}
}
/**
* Builds the complete list of main menu items for the Customize menu settings screen.
*
@@ -279,15 +498,21 @@ public class BraveTabbedAppMenuPropertiesDelegate extends TabbedAppMenuPropertie
* customize through the menu settings. The list includes items like "New Tab", "History",
* "Downloads", "Brave Wallet", etc., based on feature availability and device configuration.
*
* <p><strong>Note:</strong> This synchronous version defaults to showing all menu items since
* it cannot check policy asynchronously. For accurate policy-based filtering, use {@link
* #buildMainMenuModelListAsync(Callback)} instead.
*
* <p><strong>Note on Icons:</strong> The returned menu items do not include drawable icons
* because {@link android.graphics.drawable.Drawable} objects cannot be parceled across activity
* boundaries. Instead, the settings screen uses {@link
* CustomizeBraveMenu#getDrawableResFromMenuItemId(int)} to map menu item IDs to their
* corresponding drawable resource IDs for display.
*
* @param policyStates Map of menu item IDs to their disabled-by-policy state (true = disabled,
* false/not present = enabled)
* @return a ModelList containing all customizable main menu items with their IDs and titles
*/
public MVCListAdapter.ModelList buildMainMenuModelList() {
private MVCListAdapter.ModelList buildMainMenuModelList(Map<Integer, Boolean> policyStates) {
MVCListAdapter.ModelList modelList = new MVCListAdapter.ModelList();
// New Tab
@@ -420,9 +645,13 @@ public class BraveTabbedAppMenuPropertiesDelegate extends TabbedAppMenuPropertie
modelList.add(buildBraveVpnLocationIconItem());
}
}
BraveRewardsNativeWorker braveRewardsNativeWorker = BraveRewardsNativeWorker.getInstance();
if (braveRewardsNativeWorker != null && braveRewardsNativeWorker.isSupported()) {
modelList.add(buildBraveRewardsItem());
// Add policy-controlled items based on policy states
for (PolicyControlledMenuItem item : getPolicyControlledMenuItems()) {
// Check if item is disabled by policy (default to false/not disabled if not in map)
boolean isDisabled = policyStates.getOrDefault(item.mMenuItemId, false);
if (!isDisabled && item.mIsSupportedChecker.get()) {
modelList.add(item.mItemBuilder.get());
}
}
modelList.add(buildBraveNewsItem());
@@ -629,7 +858,11 @@ public class BraveTabbedAppMenuPropertiesDelegate extends TabbedAppMenuPropertie
int menuGroup = getMenuGroup();
if (menuGroup == MenuGroup.PAGE_MENU) {
// Build menu without policy-controlled items initially (safer default)
// Policy-controlled items will be added/removed asynchronously based on policy checks
populateBravePageModeMenu(modelList);
// Check policies and update menu dynamically for all configured policy-controlled items
updateMenuItemsBasedOnPolicy(modelList);
}
// Apply Brave icons.
maybeReplaceIcons(modelList);
@@ -721,12 +954,10 @@ public class BraveTabbedAppMenuPropertiesDelegate extends TabbedAppMenuPropertie
modelList.add(buildBraveVpnLocationIconItem());
}
}
BraveRewardsNativeWorker braveRewardsNativeWorker =
BraveRewardsNativeWorker.getInstance();
if (braveRewardsNativeWorker != null && braveRewardsNativeWorker.isSupported()) {
modelList.add(buildBraveRewardsItem());
}
}
// Policy-controlled items (like Rewards) are handled by updateMenuItemsBasedOnPolicy()
// They are not added here to avoid showing them if policy disables them
// The async policy check will add them if policy allows
modelList.add(buildBraveNewsItem());
modelList.add(buildCustomMenuItem());
modelList.add(buildExitItem());
@@ -56,6 +56,7 @@ import org.chromium.chrome.browser.BraveRewardsHelper;
import org.chromium.chrome.browser.BraveRewardsNativeWorker;
import org.chromium.chrome.browser.BraveRewardsObserver;
import org.chromium.chrome.browser.app.BraveActivity;
import org.chromium.chrome.browser.brave_origin.BraveOriginSubscriptionPrefs;
import org.chromium.chrome.browser.brave_stats.BraveStatsUtil;
import org.chromium.chrome.browser.crypto_wallet.controller.DAppsWalletController;
import org.chromium.chrome.browser.custom_layout.popup_window_tooltip.PopupWindowTooltip;
@@ -76,6 +77,7 @@ import org.chromium.chrome.browser.onboarding.v2.HighlightView;
import org.chromium.chrome.browser.playlist.PlaylistServiceFactoryAndroid;
import org.chromium.chrome.browser.playlist.PlaylistServiceObserverImpl;
import org.chromium.chrome.browser.playlist.PlaylistServiceObserverImpl.PlaylistServiceObserverImplDelegate;
import org.chromium.chrome.browser.policy.BravePolicyConstants;
import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
import org.chromium.chrome.browser.preferences.website.BraveShieldsContentSettings;
import org.chromium.chrome.browser.preferences.website.BraveShieldsContentSettingsObserver;
@@ -481,18 +483,12 @@ public abstract class BraveToolbarLayoutImpl extends ToolbarLayout
&& mBraveRewardsNativeWorker.isSupported()
&& NtpUtil.shouldShowRewardsIcon()
&& mRewardsLayout != null) {
mRewardsLayout.setVisibility(View.VISIBLE);
}
maybeShowTermsOfServiceUpdateRequiredBadge();
if (mShieldsLayout != null) {
updateShieldsLayoutBackground(
!(mRewardsLayout != null && mRewardsLayout.getVisibility() == View.VISIBLE));
mShieldsLayout.setVisibility(View.VISIBLE);
}
if (mBraveRewardsNativeWorker != null) {
mBraveRewardsNativeWorker.addObserver(this);
mBraveRewardsNativeWorker.addPublisherObserver(this);
mBraveRewardsNativeWorker.getAllNotifications();
// Check if Brave Rewards is disabled by policy before showing
checkRewardsPolicyAndUpdateToolbarButton();
} else {
// Rewards not supported or user disabled it - complete initialization without policy
// check
completeRewardsInitialization();
}
}
@@ -1375,8 +1371,28 @@ public abstract class BraveToolbarLayoutImpl extends ToolbarLayout
&& mBraveRewardsNativeWorker != null
&& mBraveRewardsNativeWorker.isSupported()
&& NtpUtil.shouldShowRewardsIcon()) {
mRewardsLayout.setVisibility(View.VISIBLE);
updateShieldsLayoutBackground(false);
// Check policy before showing rewards icon
Profile profile = tab != null ? Profile.fromWebContents(tab.getWebContents()) : null;
BraveOriginSubscriptionPrefs.checkPolicyAsync(
profile,
BravePolicyConstants.BRAVE_REWARDS_DISABLED,
(isDisabled) -> {
Context context = getContext();
if ((context instanceof Activity
&& (((Activity) context).isFinishing()
|| ((Activity) context).isDestroyed()))
|| mRewardsLayout == null) {
return;
}
if (!isDisabled) {
mRewardsLayout.setVisibility(View.VISIBLE);
updateShieldsLayoutBackground(false);
} else {
mRewardsLayout.setVisibility(View.GONE);
updateShieldsLayoutBackground(true);
}
});
}
}
@@ -1759,4 +1775,55 @@ public abstract class BraveToolbarLayoutImpl extends ToolbarLayout
showOrHideRewardsBadge(true);
}
}
/**
* Completes rewards-related initialization that should happen after policy check. This includes
* updating shields layout background and setting up rewards observers.
*/
private void completeRewardsInitialization() {
maybeShowTermsOfServiceUpdateRequiredBadge();
if (mShieldsLayout != null) {
updateShieldsLayoutBackground(
!(mRewardsLayout != null && mRewardsLayout.getVisibility() == View.VISIBLE));
mShieldsLayout.setVisibility(View.VISIBLE);
}
if (mBraveRewardsNativeWorker != null) {
mBraveRewardsNativeWorker.addObserver(this);
mBraveRewardsNativeWorker.addPublisherObserver(this);
mBraveRewardsNativeWorker.getAllNotifications();
}
}
/**
* Checks if Brave Rewards is disabled by policy via Brave Origin and updates the toolbar
* rewards button visibility accordingly. This ensures that when Brave Rewards is disabled by
* policy, the rewards icon in the toolbar is force-hidden regardless of user preference.
*/
private void checkRewardsPolicyAndUpdateToolbarButton() {
Tab currentTab = getToolbarDataProvider().getTab();
Profile profile =
currentTab != null ? Profile.fromWebContents(currentTab.getWebContents()) : null;
BraveOriginSubscriptionPrefs.checkPolicyAsync(
profile,
BravePolicyConstants.BRAVE_REWARDS_DISABLED,
(isDisabled) -> {
Context context = getContext();
if ((context instanceof Activity
&& (((Activity) context).isFinishing()
|| ((Activity) context).isDestroyed()))
|| mRewardsLayout == null) {
return;
}
// Only show if policy allows (not disabled)
if (!isDisabled) {
mRewardsLayout.setVisibility(View.VISIBLE);
}
// If policy disables rewards, keep it hidden (default is GONE)
// Complete the rest of initialization after policy check
completeRewardsInitialization();
});
}
}