[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:
@@ -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 {
|
||||
|
||||
+88
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+240
-9
@@ -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();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user