diff --git a/android/brave_java_sources.gni b/android/brave_java_sources.gni index 30312b42196..4ebaa65b946 100644 --- a/android/brave_java_sources.gni +++ b/android/brave_java_sources.gni @@ -98,6 +98,7 @@ brave_java_sources = [ "../../brave/android/java/org/chromium/chrome/browser/crash/BravePureJavaExceptionReporter.java", "../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/AssetRatioServiceFactory.java", "../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/BlockchainRegistryFactory.java", + "../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/BraveWalletPolicy.java", "../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/BraveWalletProviderDelegateImplHelper.java", "../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/BraveWalletServiceFactory.java", "../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/SwapServiceFactory.java", diff --git a/android/java/apk_for_test.flags b/android/java/apk_for_test.flags index af910f45c76..8ff675c3d02 100644 --- a/android/java/apk_for_test.flags +++ b/android/java/apk_for_test.flags @@ -351,6 +351,7 @@ } -keep class org.chromium.chrome.browser.site_settings.ChromeSiteSettingsDelegate { + *** mProfile; public (...); } diff --git a/android/java/org/chromium/chrome/browser/app/BraveActivity.java b/android/java/org/chromium/chrome/browser/app/BraveActivity.java index 3db33fa1efd..1ae7b1f6d96 100644 --- a/android/java/org/chromium/chrome/browser/app/BraveActivity.java +++ b/android/java/org/chromium/chrome/browser/app/BraveActivity.java @@ -130,6 +130,7 @@ import org.chromium.chrome.browser.browsing_data.TimePeriod; import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChrome; import org.chromium.chrome.browser.crypto_wallet.AssetRatioServiceFactory; import org.chromium.chrome.browser.crypto_wallet.BlockchainRegistryFactory; +import org.chromium.chrome.browser.crypto_wallet.BraveWalletPolicy; import org.chromium.chrome.browser.crypto_wallet.BraveWalletServiceFactory; import org.chromium.chrome.browser.crypto_wallet.SwapServiceFactory; import org.chromium.chrome.browser.crypto_wallet.activities.AddAccountActivity; @@ -770,13 +771,16 @@ public abstract class BraveActivity extends ChromeActivity public void showWalletPanel( final boolean showPendingTransactions, final boolean ignoreWeb3NotificationPreference) { + // Don't show wallet panel if disabled by policy or services not initialized + if (mKeyringService == null) { + return; + } final BraveToolbarLayoutImpl layout = getBraveToolbarLayout(); layout.showWalletIcon(true); if (!ignoreWeb3NotificationPreference && !BraveWalletPreferences.getPrefWeb3NotificationsEnabled()) { return; } - assert mKeyringService != null; mKeyringService.isLocked( locked -> { if (locked) { @@ -2052,6 +2056,10 @@ public abstract class BraveActivity extends ChromeActivity } public void setupWalletModel() { + // Don't setup wallet model if disabled by policy + if (BraveWalletPolicy.isDisabledByPolicy(mTabModelProfileSupplier.get())) { + return; + } PostTask.postTask( TaskTraits.UI_DEFAULT, () -> { @@ -2088,93 +2096,145 @@ public abstract class BraveActivity extends ChromeActivity @MainThread private void setupObservers() { ThreadUtils.assertOnUiThread(); + if (mWalletModel == null) { + return; + } clearObservers(); - mWalletModel.getCryptoModel().getPendingTxHelper().mSelectedPendingRequest.observe( - this, transactionInfo -> { - if (transactionInfo == null) { - return; - } - // don't show dapps panel if the wallet is locked and requests are being - // processed by the approve dialog already - mKeyringService.isLocked(locked -> { - if (locked) { - return; - } + mWalletModel + .getCryptoModel() + .getPendingTxHelper() + .mSelectedPendingRequest + .observe( + this, + transactionInfo -> { + if (transactionInfo == null) { + return; + } + // don't show dapps panel if the wallet is locked and requests are being + // processed by the approve dialog already + mKeyringService.isLocked( + locked -> { + if (locked) { + return; + } - if (!mIsProcessingPendingDappsTxRequest) { - mIsProcessingPendingDappsTxRequest = true; - openBraveWalletDAppsActivity( - BraveWalletDAppsActivity.ActivityType.CONFIRM_TRANSACTION); - } + if (!mIsProcessingPendingDappsTxRequest) { + mIsProcessingPendingDappsTxRequest = true; + openBraveWalletDAppsActivity( + BraveWalletDAppsActivity.ActivityType + .CONFIRM_TRANSACTION); + } - // update badge if there's a pending tx - updateWalletBadgeVisibility(); - }); - }); + // update badge if there's a pending tx + updateWalletBadgeVisibility(); + }); + }); - mWalletModel.getDappsModel().mWalletIconNotificationVisible.observe( - this, this::setWalletBadgeVisibility); + mWalletModel + .getDappsModel() + .mWalletIconNotificationVisible + .observe(this, this::setWalletBadgeVisibility); - mWalletModel.getDappsModel().mPendingWalletAccountCreationRequest.observe(this, request -> { - if (request == null) return; - mWalletModel.getKeyringModel().isWalletLocked(isLocked -> { - if (!BraveWalletPreferences.getPrefWeb3NotificationsEnabled()) return; - if (isLocked) { - Tab tab = getActivityTab(); - if (tab != null) { - walletInteractionDetected(tab.getWebContents()); - } - showWalletPanel(false); - return; - } - for (CryptoAccountTypeInfo info : - mWalletModel.getCryptoModel().getSupportedCryptoAccountTypes()) { - if (info.getCoinType() == request.getCoinType()) { - Intent intent = AddAccountActivity.createIntentToAddAccount( - this, info.getCoinType()); - startActivity(intent); - mWalletModel.getDappsModel().removeProcessedAccountCreationRequest(request); - break; - } - } - }); - }); - - mWalletModel.getCryptoModel().getNetworkModel().mNeedToCreateAccountForNetwork.observe( - this, networkInfo -> { - if (networkInfo == null) return; - - MaterialAlertDialogBuilder builder = - new MaterialAlertDialogBuilder( - this, R.style.BraveWalletAlertDialogTheme) - .setMessage(getString( - R.string.brave_wallet_create_account_description, - networkInfo.symbolName)) - .setPositiveButton(R.string.brave_action_yes, - (dialog, which) -> { - mWalletModel.createAccountAndSetDefaultNetwork( - networkInfo); - }) - .setNegativeButton( - R.string.brave_action_no, (dialog, which) -> { - mWalletModel.getCryptoModel() - .getNetworkModel() - .clearCreateAccountState(); - dialog.dismiss(); + mWalletModel + .getDappsModel() + .mPendingWalletAccountCreationRequest + .observe( + this, + request -> { + if (request == null) return; + mWalletModel + .getKeyringModel() + .isWalletLocked( + isLocked -> { + if (!BraveWalletPreferences + .getPrefWeb3NotificationsEnabled()) { + return; + } + if (isLocked) { + Tab tab = getActivityTab(); + if (tab != null) { + walletInteractionDetected( + tab.getWebContents()); + } + showWalletPanel(false); + return; + } + for (CryptoAccountTypeInfo info : + mWalletModel + .getCryptoModel() + .getSupportedCryptoAccountTypes()) { + if (info.getCoinType() + == request.getCoinType()) { + Intent intent = + AddAccountActivity + .createIntentToAddAccount( + this, + info.getCoinType()); + startActivity(intent); + mWalletModel + .getDappsModel() + .removeProcessedAccountCreationRequest( // presubmit: ignore-long-line + request); + break; + } + } }); - builder.show(); - }); + }); + + mWalletModel + .getCryptoModel() + .getNetworkModel() + .mNeedToCreateAccountForNetwork + .observe( + this, + networkInfo -> { + if (networkInfo == null) return; + + MaterialAlertDialogBuilder builder = + new MaterialAlertDialogBuilder( + this, R.style.BraveWalletAlertDialogTheme) + .setMessage( + getString( + R.string + .brave_wallet_create_account_description, // presubmit: ignore-long-line + networkInfo.symbolName)) + .setPositiveButton( + R.string.brave_action_yes, + (dialog, which) -> { + mWalletModel + .createAccountAndSetDefaultNetwork( + networkInfo); + }) + .setNegativeButton( + R.string.brave_action_no, + (dialog, which) -> { + mWalletModel + .getCryptoModel() + .getNetworkModel() + .clearCreateAccountState(); + dialog.dismiss(); + }); + builder.show(); + }); } @MainThread private void clearObservers() { ThreadUtils.assertOnUiThread(); - mWalletModel.getCryptoModel().getPendingTxHelper().mSelectedPendingRequest.removeObservers( - this); + if (mWalletModel == null) { + return; + } + mWalletModel + .getCryptoModel() + .getPendingTxHelper() + .mSelectedPendingRequest + .removeObservers(this); mWalletModel.getDappsModel().mWalletIconNotificationVisible.removeObservers(this); - mWalletModel.getCryptoModel() + mWalletModel + .getCryptoModel() .getNetworkModel() - .mNeedToCreateAccountForNetwork.removeObservers(this); + .mNeedToCreateAccountForNetwork + .removeObservers(this); } private void showBraveRateDialog() { @@ -2483,6 +2543,10 @@ public abstract class BraveActivity extends ChromeActivity } private void initWalletNativeServices() { + // Don't initialize wallet services if disabled by policy + if (BraveWalletPolicy.isDisabledByPolicy(mTabModelProfileSupplier.get())) { + return; + } initBlockchainRegistry(); initTxService(); initEthTxManagerProxy(); diff --git a/android/java/org/chromium/chrome/browser/crypto_wallet/BraveWalletPolicy.java b/android/java/org/chromium/chrome/browser/crypto_wallet/BraveWalletPolicy.java new file mode 100644 index 00000000000..9d1491aa267 --- /dev/null +++ b/android/java/org/chromium/chrome/browser/crypto_wallet/BraveWalletPolicy.java @@ -0,0 +1,27 @@ +/* Copyright (c) 2026 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/. */ + +package org.chromium.chrome.browser.crypto_wallet; + +import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; +import org.chromium.chrome.browser.preferences.BravePref; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.components.prefs.PrefService; +import org.chromium.components.user_prefs.UserPrefs; + +/** Provides policy state for Brave Wallet. */ +@NullMarked +public class BraveWalletPolicy { + /** Returns true if Wallet is disabled by policy for the given profile. */ + public static boolean isDisabledByPolicy(@Nullable Profile profile) { + if (profile == null) { + return false; + } + PrefService prefService = UserPrefs.get(profile); + return prefService.isManagedPreference(BravePref.BRAVE_WALLET_DISABLED_BY_POLICY) + && prefService.getBoolean(BravePref.BRAVE_WALLET_DISABLED_BY_POLICY); + } +} diff --git a/android/java/org/chromium/chrome/browser/privacy/settings/BravePrivacySettings.java b/android/java/org/chromium/chrome/browser/privacy/settings/BravePrivacySettings.java index c5e96fd8fd8..b0b3dbbf45f 100644 --- a/android/java/org/chromium/chrome/browser/privacy/settings/BravePrivacySettings.java +++ b/android/java/org/chromium/chrome/browser/privacy/settings/BravePrivacySettings.java @@ -26,6 +26,7 @@ import org.chromium.chrome.browser.BraveFeatureUtil; import org.chromium.chrome.browser.BraveLocalState; import org.chromium.chrome.browser.BraveRelaunchUtils; import org.chromium.chrome.browser.browsing_data.BraveClearBrowsingDataFragment; +import org.chromium.chrome.browser.crypto_wallet.BraveWalletPolicy; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.metrics.ChangeMetricsReportingStateCalledFrom; import org.chromium.chrome.browser.metrics.UmaSessionStats; @@ -473,6 +474,13 @@ public class BravePrivacySettings extends PrivacySettings { removePreferenceIfPresent(PREF_PRIVACY_GUIDE); removePreferenceIfPresent(PREF_PASSWORD_LEAK_DETECTION); + // Hide decentralized DNS settings when wallet is disabled by policy + if (BraveWalletPolicy.isDisabledByPolicy(getProfile())) { + removePreferenceIfPresent(PREF_UNSTOPPABLE_DOMAINS); + removePreferenceIfPresent(PREF_ENS); + removePreferenceIfPresent(PREF_SNS); + } + if (!ChromeFeatureList.isEnabled(BraveFeatureList.BRAVE_ANDROID_SAFE_BROWSING)) { removePreferenceIfPresent(PREF_SAFE_BROWSING); } else { diff --git a/android/java/org/chromium/chrome/browser/settings/BraveMainPreferencesBase.java b/android/java/org/chromium/chrome/browser/settings/BraveMainPreferencesBase.java index a5228b6fe75..cd6cc818607 100644 --- a/android/java/org/chromium/chrome/browser/settings/BraveMainPreferencesBase.java +++ b/android/java/org/chromium/chrome/browser/settings/BraveMainPreferencesBase.java @@ -28,6 +28,7 @@ import org.chromium.chrome.browser.brave_leo.BraveLeoPrefUtils; import org.chromium.chrome.browser.brave_news.BraveNewsPolicy; import org.chromium.chrome.browser.brave_origin.BraveOriginPlansActivity; import org.chromium.chrome.browser.brave_origin.BraveOriginSubscriptionPrefs; +import org.chromium.chrome.browser.crypto_wallet.BraveWalletPolicy; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.homepage.settings.BraveHomepageSettings; import org.chromium.chrome.browser.notifications.BraveNotificationWarningDialog; @@ -149,6 +150,7 @@ public abstract class BraveMainPreferencesBase extends BravePreferenceFragment checkLeoPolicyAndUpdatePreference(); checkNewsPolicyAndUpdatePreference(); checkVpnPolicyAndUpdatePreference(); + checkWalletPolicyAndUpdatePreference(); if (mNotificationClicked && BraveNotificationWarningDialog.shouldShowNotificationWarningDialog(getActivity()) @@ -630,4 +632,11 @@ public abstract class BraveMainPreferencesBase extends BravePreferenceFragment removePreferenceIfPresent(PREF_BRAVE_VPN_CALLOUT); } } + + /** Checks if Brave Wallet is disabled by policy and removes the preference if so. */ + private void checkWalletPolicyAndUpdatePreference() { + if (BraveWalletPolicy.isDisabledByPolicy(getProfile())) { + removePreferenceIfPresent(PREF_BRAVE_WALLET); + } + } } diff --git a/android/java/org/chromium/chrome/browser/site_settings/BraveSiteSettingsDelegate.java b/android/java/org/chromium/chrome/browser/site_settings/BraveSiteSettingsDelegate.java index 60f11816779..94f80a69dcf 100644 --- a/android/java/org/chromium/chrome/browser/site_settings/BraveSiteSettingsDelegate.java +++ b/android/java/org/chromium/chrome/browser/site_settings/BraveSiteSettingsDelegate.java @@ -9,15 +9,30 @@ import android.content.Context; import android.graphics.drawable.Drawable; import org.chromium.base.Callback; +import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; +import org.chromium.chrome.browser.crypto_wallet.BraveWalletPolicy; import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.components.browser_ui.site_settings.BraveWalletSiteSettingsDelegate; import org.chromium.components.browser_ui.site_settings.SiteSettingsCategory; import org.chromium.url.GURL; -public class BraveSiteSettingsDelegate extends ChromeSiteSettingsDelegate { +@NullMarked +public class BraveSiteSettingsDelegate extends ChromeSiteSettingsDelegate + implements BraveWalletSiteSettingsDelegate { + // Will be deleted in bytecode, value from the parent class will be used instead. + @Nullable private Profile mProfile; + public BraveSiteSettingsDelegate(Context context, Profile profile) { super(context, profile); } + @Override + public boolean isWalletDisabledByPolicy() { + return BraveWalletPolicy.isDisabledByPolicy(mProfile); + } + + @SuppressWarnings("NullAway") @Override public void getFaviconImageForURL(GURL faviconUrl, Callback callback) { if (!faviconUrl.isValid()) { diff --git a/android/java/org/chromium/chrome/browser/tabbed_mode/BraveTabbedAppMenuPropertiesDelegate.java b/android/java/org/chromium/chrome/browser/tabbed_mode/BraveTabbedAppMenuPropertiesDelegate.java index ef44f5b00c6..c2e0c84c7a2 100644 --- a/android/java/org/chromium/chrome/browser/tabbed_mode/BraveTabbedAppMenuPropertiesDelegate.java +++ b/android/java/org/chromium/chrome/browser/tabbed_mode/BraveTabbedAppMenuPropertiesDelegate.java @@ -38,6 +38,7 @@ 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_news.BraveNewsPolicy; +import org.chromium.chrome.browser.crypto_wallet.BraveWalletPolicy; import org.chromium.chrome.browser.feed.webfeed.WebFeedSnackbarController; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.homepage.HomepageManager; @@ -136,6 +137,16 @@ public class BraveTabbedAppMenuPropertiesDelegate extends TabbedAppMenuPropertie */ private List getPolicyControlledMenuItems() { return Arrays.asList( + new PolicyControlledMenuItem( + R.id.brave_wallet_id, + this::buildBraveWalletItem, + () -> ChromeFeatureList.isEnabled(BraveFeatureList.NATIVE_BRAVE_WALLET), + () -> { + Tab tab = mActivityTabProvider.get(); + return tab != null + && BraveWalletPolicy.isDisabledByPolicy(tab.getProfile()); + }, + Arrays.asList(R.id.brave_leo_id, R.id.all_bookmarks_menu_id)), new PolicyControlledMenuItem( R.id.brave_leo_id, this::buildBraveLeoItem, @@ -636,10 +647,7 @@ public class BraveTabbedAppMenuPropertiesDelegate extends TabbedAppMenuPropertie buildModelForStandardMenuItem( R.id.recent_tabs_menu_id, R.string.menu_recent_tabs, 0))); - // Add Brave specific items. - if (ChromeFeatureList.isEnabled(BraveFeatureList.NATIVE_BRAVE_WALLET)) { - modelList.add(buildBraveWalletItem()); - } + // Add Brave specific items (Wallet is handled by policy-controlled mechanism). if (ChromeFeatureList.isEnabled(BraveFeatureList.BRAVE_PLAYLIST)) { modelList.add(buildBravePlaylistItem()); modelList.add(buildBraveAddToPlaylistItem()); @@ -903,11 +911,7 @@ public class BraveTabbedAppMenuPropertiesDelegate extends TabbedAppMenuPropertie } } - // Add Brave specific items. - if (ChromeFeatureList.isEnabled(BraveFeatureList.NATIVE_BRAVE_WALLET)) { - addMenuItemAfter( - modelList, buildBraveWalletItem(), Arrays.asList(R.id.all_bookmarks_menu_id)); - } + // Add Brave specific items (Wallet is handled by policy-controlled mechanism). if (ChromeFeatureList.isEnabled(BraveFeatureList.BRAVE_PLAYLIST) && ChromeSharedPreferences.getInstance() .readBoolean(BravePreferenceKeys.PREF_ENABLE_PLAYLIST, true)) { diff --git a/android/java/org/chromium/chrome/browser/toolbar/top/BraveToolbarLayoutImpl.java b/android/java/org/chromium/chrome/browser/toolbar/top/BraveToolbarLayoutImpl.java index a11a8a55ffb..eecdb5223cf 100644 --- a/android/java/org/chromium/chrome/browser/toolbar/top/BraveToolbarLayoutImpl.java +++ b/android/java/org/chromium/chrome/browser/toolbar/top/BraveToolbarLayoutImpl.java @@ -58,6 +58,7 @@ import org.chromium.chrome.browser.BraveRewardsObserver; import org.chromium.chrome.browser.BraveRewardsPolicy; import org.chromium.chrome.browser.app.BraveActivity; import org.chromium.chrome.browser.brave_stats.BraveStatsUtil; +import org.chromium.chrome.browser.crypto_wallet.BraveWalletPolicy; import org.chromium.chrome.browser.crypto_wallet.controller.DAppsWalletController; import org.chromium.chrome.browser.custom_layout.popup_window_tooltip.PopupWindowTooltip; import org.chromium.chrome.browser.customtabs.FullScreenCustomTabActivity; @@ -1125,7 +1126,7 @@ public abstract class BraveToolbarLayoutImpl extends ToolbarLayout return; } } - if (show) { + if (show && !BraveWalletPolicy.isDisabledByPolicy(currentTab.getProfile())) { mWalletLayout.setVisibility(View.VISIBLE); mTabsWithWalletIcon.add(currentTab.getId()); } else { diff --git a/android/javatests/org/chromium/chrome/browser/BytecodeTest.java b/android/javatests/org/chromium/chrome/browser/BytecodeTest.java index 9c972a73e30..8f2771bbb05 100644 --- a/android/javatests/org/chromium/chrome/browser/BytecodeTest.java +++ b/android/javatests/org/chromium/chrome/browser/BytecodeTest.java @@ -2439,6 +2439,10 @@ public class BytecodeTest { "mSite", true, Website.class)); + Assert.assertTrue( + fieldExists( + "org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate", + "mProfile")); Assert.assertTrue( fieldExists( "org/chromium/components/variations/firstrun/VariationsSeedFetcher", diff --git a/android/junit/src/org/chromium/chrome/browser/tabbed_mode/BraveTabbedAppMenuPropertiesDelegateUnitTest.java b/android/junit/src/org/chromium/chrome/browser/tabbed_mode/BraveTabbedAppMenuPropertiesDelegateUnitTest.java index e4139d50e2e..82199dc75db 100644 --- a/android/junit/src/org/chromium/chrome/browser/tabbed_mode/BraveTabbedAppMenuPropertiesDelegateUnitTest.java +++ b/android/junit/src/org/chromium/chrome/browser/tabbed_mode/BraveTabbedAppMenuPropertiesDelegateUnitTest.java @@ -411,6 +411,10 @@ public class BraveTabbedAppMenuPropertiesDelegateUnitTest { when(mPrefService.isManagedPreference(BravePref.MANAGED_BRAVE_VPN_DISABLED)) .thenReturn(true); when(mPrefService.getBoolean(BravePref.MANAGED_BRAVE_VPN_DISABLED)).thenReturn(true); + // Wallet: BRAVE_WALLET_DISABLED_BY_POLICY = true means disabled + when(mPrefService.isManagedPreference(BravePref.BRAVE_WALLET_DISABLED_BY_POLICY)) + .thenReturn(true); + when(mPrefService.getBoolean(BravePref.BRAVE_WALLET_DISABLED_BY_POLICY)).thenReturn(true); assertEquals(MenuGroup.PAGE_MENU, mTabbedAppMenuPropertiesDelegate.getMenuGroup()); MVCListAdapter.ModelList modelList = mTabbedAppMenuPropertiesDelegate.getMenuItems(); @@ -424,7 +428,7 @@ public class BraveTabbedAppMenuPropertiesDelegateUnitTest { R.id.open_history_menu_id, R.id.downloads_menu_id, R.id.all_bookmarks_menu_id, - R.id.brave_wallet_id, + // R.id.brave_wallet_id is NOT included - disabled by policy // R.id.brave_leo_id is NOT included - disabled by policy // R.id.brave_rewards_id is NOT included - disabled by policy R.id.recent_tabs_menu_id, diff --git a/browser/android/preferences/BUILD.gn b/browser/android/preferences/BUILD.gn index a0c223fb9ae..1c7b408023f 100644 --- a/browser/android/preferences/BUILD.gn +++ b/browser/android/preferences/BUILD.gn @@ -43,6 +43,7 @@ java_cpp_strings("java_pref_names_srcjar") { "//brave/components/brave_rewards/core/pref_names.h", "//brave/components/brave_shields/core/common/pref_names.h", "//brave/components/brave_vpn/common/pref_names.h", + "//brave/components/brave_wallet/browser/pref_names.h", "//brave/components/constants/pref_names.h", "//brave/components/de_amp/common/pref_names.cc", "//brave/components/de_amp/common/pref_names.h", diff --git a/browser/net/decentralized_dns_network_delegate_helper_unittest.cc b/browser/net/decentralized_dns_network_delegate_helper_unittest.cc index 5664c65b917..b22338d8aaf 100644 --- a/browser/net/decentralized_dns_network_delegate_helper_unittest.cc +++ b/browser/net/decentralized_dns_network_delegate_helper_unittest.cc @@ -471,16 +471,18 @@ TEST_F(DecentralizedDnsNetworkDelegateHelperTest, int result = OnBeforeURLRequest_DecentralizedDnsPreRedirectWork( base::DoNothing(), brave_request_info); -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) - // On desktop platforms, policy is enforced, so wallet is disabled +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ + BUILDFLAG(IS_ANDROID) + // On desktop and Android platforms, policy is enforced, so wallet is disabled // Should return OK immediately (not pending) because wallet is disabled EXPECT_EQ(net::OK, result); EXPECT_TRUE(brave_request_info->new_url_spec.empty()); #else - // On mobile platforms, policy is not enforced, so wallet is always enabled + // On other platforms, policy is not enforced, so wallet is always enabled // Should return ERR_IO_PENDING because it will try to resolve the domain EXPECT_EQ(net::ERR_IO_PENDING, result); -#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) +#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || + // BUILDFLAG(IS_ANDROID) } // Test that decentralized DNS works when BraveWalletDisabled policy is false diff --git a/build/android/bytecode/java/org/brave/bytecode/BraveSiteSettingsDelegateClassAdapter.java b/build/android/bytecode/java/org/brave/bytecode/BraveSiteSettingsDelegateClassAdapter.java index 2e51913eb10..b7aab3f4580 100644 --- a/build/android/bytecode/java/org/brave/bytecode/BraveSiteSettingsDelegateClassAdapter.java +++ b/build/android/bytecode/java/org/brave/bytecode/BraveSiteSettingsDelegateClassAdapter.java @@ -9,12 +9,18 @@ import org.objectweb.asm.ClassVisitor; public class BraveSiteSettingsDelegateClassAdapter extends BraveClassVisitor { - static String sChromeSiteSettingsDelegateClassName = "org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate"; - static String sBraveSiteSettingsDelegateClassName = "org/chromium/chrome/browser/site_settings/BraveSiteSettingsDelegate"; + static String sChromeSiteSettingsDelegateClassName = + "org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate"; + static String sBraveSiteSettingsDelegateClassName = + "org/chromium/chrome/browser/site_settings/BraveSiteSettingsDelegate"; public BraveSiteSettingsDelegateClassAdapter(ClassVisitor visitor) { super(visitor); - redirectConstructor(sChromeSiteSettingsDelegateClassName, sBraveSiteSettingsDelegateClassName); + redirectConstructor( + sChromeSiteSettingsDelegateClassName, sBraveSiteSettingsDelegateClassName); + + deleteField(sBraveSiteSettingsDelegateClassName, "mProfile"); + makeProtectedField(sChromeSiteSettingsDelegateClassName, "mProfile"); } } diff --git a/components/brave_wallet/browser/brave_wallet_utils.cc b/components/brave_wallet/browser/brave_wallet_utils.cc index bf6f7f26e16..081e5173b63 100644 --- a/components/brave_wallet/browser/brave_wallet_utils.cc +++ b/components/brave_wallet/browser/brave_wallet_utils.cc @@ -49,13 +49,9 @@ namespace { constexpr size_t kCardanoScriptHashSize = 28u; bool IsDisabledByPolicy(PrefService* prefs) { -#if BUILDFLAG(IS_ANDROID) - return false; -#else DCHECK(prefs); return prefs->IsManagedPreference(kBraveWalletDisabledByPolicy) && prefs->GetBoolean(kBraveWalletDisabledByPolicy); -#endif } constexpr const char kEnsRegistryContractAddress[] = diff --git a/components/brave_wallet/browser/brave_wallet_utils_unittest.cc b/components/brave_wallet/browser/brave_wallet_utils_unittest.cc index 9d2d42f35eb..3d8739507ea 100644 --- a/components/brave_wallet/browser/brave_wallet_utils_unittest.cc +++ b/components/brave_wallet/browser/brave_wallet_utils_unittest.cc @@ -1016,13 +1016,8 @@ TEST_F(BraveWalletPolicyTest, PolicyDisablesWallet) { // Test that the policy preference is set correctly EXPECT_TRUE(prefs_.GetBoolean(kBraveWalletDisabledByPolicy)); -#if BUILDFLAG(IS_ANDROID) - // On android the policy is not enforced - EXPECT_TRUE(IsAllowed(&prefs_)); -#else - // On other platforms, policy should be enforced + // Policy should be enforced EXPECT_FALSE(IsAllowed(&prefs_)); -#endif // BUILDFLAG(IS_ANDROID) } TEST_F(BraveWalletPolicyTest, PolicyEnablesWallet) { diff --git a/components/browser_ui/site_settings/android/BUILD.gn b/components/browser_ui/site_settings/android/BUILD.gn index 25d8dd93705..c076e7cc694 100644 --- a/components/browser_ui/site_settings/android/BUILD.gn +++ b/components/browser_ui/site_settings/android/BUILD.gn @@ -12,6 +12,7 @@ android_library("java") { "java/src/org/chromium/components/browser_ui/site_settings/BraveSingleWebsiteSettings.java", "java/src/org/chromium/components/browser_ui/site_settings/BraveSiteSettingsCategory.java", "java/src/org/chromium/components/browser_ui/site_settings/BraveSiteSettingsPreferencesBase.java", + "java/src/org/chromium/components/browser_ui/site_settings/BraveWalletSiteSettingsDelegate.java", "java/src/org/chromium/components/browser_ui/site_settings/BraveWebsite.java", "java/src/org/chromium/components/browser_ui/site_settings/BraveWebsitePermissionsFetcher.java", ] diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/BraveSiteSettingsPreferencesBase.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/BraveSiteSettingsPreferencesBase.java index c2aaa550de7..3a2583d2e71 100644 --- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/BraveSiteSettingsPreferencesBase.java +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/BraveSiteSettingsPreferencesBase.java @@ -19,6 +19,7 @@ public class BraveSiteSettingsPreferencesBase extends BaseSiteSettingsFragment { private static final String IDLE_DETECTION = "idle_detection"; private static final String DIVIDER_KEY = "divider"; private static final String PERMISSION_AUTOREVOCATION_KEY = "permission_autorevocation"; + private static final String ETHEREUM_CONNECTED_SITES_KEY = "ethereum_connected_sites"; private static final String SOLANA_CONNECTED_SITES_KEY = "solana_connected_sites"; private final HashMap mRemovedPreferences = new HashMap<>(); @@ -67,6 +68,12 @@ public class BraveSiteSettingsPreferencesBase extends BaseSiteSettingsFragment { removePreferenceIfPresent(ADS_KEY); removePreferenceIfPresent(BACKGROUND_SYNC_KEY); + // Hide Ethereum and Solana connected sites when wallet is disabled by policy. + if (isWalletDisabledByPolicy()) { + removePreferenceIfPresent(ETHEREUM_CONNECTED_SITES_KEY); + removePreferenceIfPresent(SOLANA_CONNECTED_SITES_KEY); + } + // We want to place these Settings at the bottom. // See https://github.com/brave/brave-browser/issues/46547 // for the context @@ -78,11 +85,23 @@ public class BraveSiteSettingsPreferencesBase extends BaseSiteSettingsFragment { if (prefDivider != null && prefPermissionAutorevocation != null) { Preference prefSolanaConnectedSites = getPreferenceScreen().findPreference(SOLANA_CONNECTED_SITES_KEY); - assert prefSolanaConnectedSites != null - : "Adjust if needed for the last pref in the site settings screen"; - int solanaConnectedSitesOrder = prefSolanaConnectedSites.getOrder(); - prefDivider.setOrder(solanaConnectedSitesOrder + 1); - prefPermissionAutorevocation.setOrder(solanaConnectedSitesOrder + 2); + // Solana preference may be removed if wallet is disabled by policy. + if (prefSolanaConnectedSites != null) { + int solanaConnectedSitesOrder = prefSolanaConnectedSites.getOrder(); + prefDivider.setOrder(solanaConnectedSitesOrder + 1); + prefPermissionAutorevocation.setOrder(solanaConnectedSitesOrder + 2); + } } } + + private boolean isWalletDisabledByPolicy() { + if (!hasSiteSettingsDelegate()) { + return false; + } + SiteSettingsDelegate delegate = getSiteSettingsDelegate(); + if (delegate instanceof BraveWalletSiteSettingsDelegate) { + return ((BraveWalletSiteSettingsDelegate) delegate).isWalletDisabledByPolicy(); + } + return false; + } } diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/BraveWalletSiteSettingsDelegate.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/BraveWalletSiteSettingsDelegate.java new file mode 100644 index 00000000000..e5df433731e --- /dev/null +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/BraveWalletSiteSettingsDelegate.java @@ -0,0 +1,19 @@ +/* Copyright (c) 2026 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/. */ + +package org.chromium.components.browser_ui.site_settings; + +import org.chromium.build.annotations.NullMarked; + +/** + * Interface for wallet-related site settings delegate methods. Implemented by + * BraveSiteSettingsDelegate to provide wallet policy information to components-level code without + * creating layering violations. + */ +@NullMarked +public interface BraveWalletSiteSettingsDelegate { + /** Returns true if Brave Wallet is disabled by enterprise policy. */ + boolean isWalletDisabledByPolicy(); +}