Add Speedreader admin policy (#30017)

This commit is contained in:
Brian R. Bondy
2025-07-16 02:20:43 +02:00
committed by GitHub
parent e72a94aa67
commit df908077f0
14 changed files with 201 additions and 2 deletions
+1
View File
@@ -980,6 +980,7 @@ BraveContentBrowserClient::CreateURLLoaderThrottles(
auto* speedreader_service =
speedreader::SpeedreaderServiceFactory::GetForBrowserContext(
browser_context);
CHECK(speedreader_service);
auto producer =
speedreader::SpeedreaderDistilledPageProducer::MaybeCreate(
+9
View File
@@ -11,6 +11,7 @@
#include "brave/components/brave_vpn/common/buildflags/buildflags.h"
#include "brave/components/constants/pref_names.h"
#include "brave/components/ipfs/buildflags/buildflags.h"
#include "brave/components/speedreader/common/buildflags/buildflags.h"
#include "brave/components/tor/buildflags/buildflags.h"
#include "build/build_config.h"
#include "components/policy/core/browser/configuration_policy_handler.h"
@@ -34,6 +35,10 @@
#include "brave/components/ipfs/ipfs_prefs.h"
#endif // BUILDFLAG(DEPRECATE_IPFS)
#if BUILDFLAG(ENABLE_SPEEDREADER)
#include "brave/components/speedreader/speedreader_pref_names.h"
#endif
namespace policy {
inline constexpr PolicyToPreferenceMapEntry kBraveSimplePolicyMap[] = {
@@ -65,6 +70,10 @@ inline constexpr PolicyToPreferenceMapEntry kBraveSimplePolicyMap[] = {
brave_news::prefs::kBraveNewsDisabledByPolicy, base::Value::Type::BOOLEAN},
{policy::key::kBraveTalkDisabled, kBraveTalkDisabledByPolicy,
base::Value::Type::BOOLEAN},
#if BUILDFLAG(ENABLE_SPEEDREADER)
{policy::key::kBraveSpeedreaderDisabled,
speedreader::kSpeedreaderDisabledByPolicy, base::Value::Type::BOOLEAN},
#endif
#endif
#if BUILDFLAG(DEPRECATE_IPFS)
{policy::key::kIPFSEnabled, ipfs::prefs::kIPFSEnabledByPolicy,
@@ -76,7 +76,8 @@ function getPageVisibility () {
// </if>
content: alwaysTrueProxy,
playlist: loadTimeData.getBoolean('isPlaylistAllowed'),
speedreader: loadTimeData.getBoolean('isSpeedreaderFeatureEnabled'),
speedreader: loadTimeData.getBoolean('isSpeedreaderFeatureEnabled') &&
!loadTimeData.getBoolean('isSpeedreaderDisabledByPolicy'),
}
// Proxy so we can respond to any other property
return new Proxy(staticProps, {
@@ -13,6 +13,8 @@
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/profiles/incognito_helpers.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/user_prefs/user_prefs.h"
#include "content/public/browser/browser_context.h"
namespace speedreader {
@@ -49,6 +51,12 @@ SpeedreaderServiceFactory::BuildServiceInstanceForBrowserContext(
if (!features::IsSpeedreaderEnabled()) {
return {};
}
// Don't create service if disabled by policy
if (speedreader::IsDisabledByPolicy(user_prefs::UserPrefs::Get(context))) {
return {};
}
return std::make_unique<SpeedreaderService>(
context, g_browser_process->local_state(),
HostContentSettingsMapFactory::GetForProfile(context));
@@ -36,6 +36,8 @@
#include "components/dom_distiller/content/browser/distillable_page_utils.h"
#include "components/grit/brave_components_resources.h"
#include "components/grit/brave_components_strings.h"
#include "components/user_prefs/user_prefs.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/reload_type.h"
@@ -94,6 +96,14 @@ void SpeedreaderTabHelper::MaybeCreateForWebContents(
return;
}
// Check if speedreader is available (feature enabled and not disabled by
// policy)
auto* speedreader_service = SpeedreaderServiceFactory::GetForBrowserContext(
contents->GetBrowserContext());
if (!speedreader_service) {
return;
}
auto* rewriter_service =
g_brave_browser_process->speedreader_rewriter_service();
if (!rewriter_service) {
@@ -168,6 +178,10 @@ bool SpeedreaderTabHelper::MaybeUpdateCachedState(
return false;
}
auto* speedreader_service = GetSpeedreaderService();
if (!speedreader_service) {
SpeedreaderExtendedInfoHandler::ClearPersistedData(entry);
return false;
}
const DistillState state =
SpeedreaderExtendedInfoHandler::GetCachedMode(entry, speedreader_service);
+4
View File
@@ -67,6 +67,7 @@
#if BUILDFLAG(ENABLE_SPEEDREADER)
#include "brave/components/speedreader/common/features.h"
#include "brave/components/speedreader/speedreader_pref_names.h"
#endif
#if BUILDFLAG(ENABLE_BRAVE_VPN)
@@ -165,6 +166,9 @@ void BraveSettingsUI::AddResources(content::WebUIDataSource* html_source,
html_source->AddBoolean(
"isSpeedreaderFeatureEnabled",
base::FeatureList::IsEnabled(speedreader::kSpeedreaderFeature));
html_source->AddBoolean("isSpeedreaderDisabledByPolicy",
profile->GetPrefs()->GetBoolean(
speedreader::kSpeedreaderDisabledByPolicy));
#endif
html_source->AddBoolean(
"isNativeBraveWalletFeatureEnabled",
@@ -0,0 +1,36 @@
caption: Disable Speedreader
default: null
desc: |-
Disable Speedreader in Brave.
Speedreader is a feature that provides a clutter-free reading experience by automatically cleaning up articles and simplifying page layouts.
If this policy is set to true, Speedreader will always be disabled and all related UI elements will be hidden.
If this policy is set to false, Speedreader will always be enabled.
If you set this policy, users cannot change or override it.
If this policy is left unset, Speedreader will be enabled by default (subject to user preferences).
example_value: true
features:
can_be_mandatory: true
can_be_recommended: false
dynamic_refresh: false
per_profile: true
items:
- caption: Enable Speedreader
value: false
- caption: Disable Speedreader
value: true
- caption: Allow the user to decide
value: null
owners:
- bbondy@brave.com
- clifton@brave.com
schema:
type: boolean
supported_on:
- chrome.*:138-
tags: []
type: main
@@ -17,3 +17,12 @@ In a nutshell, the steps for adding a new policy in Brave look like this:
7. The group policy assets get output to `//out/<build_type_here>/brave_policy_templates.zip`. You can open this up and inspect the registry and adm/admx files. There is also a `policy_templates.zip` - that is the raw output before the script at `//brave/components/policy/pack_policy_templates.py` runs.
If rebuilding isn't picking up your policy, you can try to delete `//out/<build_type_here>/gen/components/policy/policy_constants.cc`. Rebuilding will trigger the rebuild for this file and your changes should be there.
## Troubleshooting
If you're getting an error similar to:
> ../../brave/browser/policy/brave_simple_policy_map.h:75:19: error: no member named 'kBraveSpeedreaderDisabled' in namespace 'policy::key'; did you mean 'kBraveRewardsDisabled'?
It might be that the minimum Chromium version is not yet in use by Brave via the YAML's `supported_on`. In that case you will need to temporarily specify a lower version until Brave updates to the newer version.
@@ -10,6 +10,7 @@ _brave_policies = [
"BraveSoftware/BraveRewardsDisabled.yaml",
"BraveSoftware/BraveShieldsDisabledForUrls.yaml",
"BraveSoftware/BraveShieldsEnabledForUrls.yaml",
"BraveSoftware/BraveSpeedreaderDisabled.yaml",
"BraveSoftware/BraveSyncUrl.yaml",
"BraveSoftware/BraveTalkDisabled.yaml",
"BraveSoftware/BraveVPNDisabled.yaml",
+1
View File
@@ -65,6 +65,7 @@ source_set("unit_tests") {
sources = [
"speedreader_metrics_unittest.cc",
"speedreader_rewriter_unittest.cc",
"speedreader_service_unittest.cc",
"speedreader_util_unittest.cc",
]
@@ -46,6 +46,10 @@ inline constexpr char kSpeedreaderPrefTtsSpeed[] =
inline constexpr char kSpeedreaderPageViewsStoragePref[] =
"brave.speedreader.page_views";
// Used to enable/disable Speedreader via a policy.
inline constexpr char kSpeedreaderDisabledByPolicy[] =
"brave.speedreader.disabled_by_policy";
} // namespace speedreader
#endif // BRAVE_COMPONENTS_SPEEDREADER_SPEEDREADER_PREF_NAMES_H_
@@ -44,6 +44,10 @@ bool IsSpeedreaderEnabled() {
} // namespace features
bool IsDisabledByPolicy(PrefService* prefs) {
return prefs->GetBoolean(kSpeedreaderDisabledByPolicy);
}
SpeedreaderService::SpeedreaderService(content::BrowserContext* browser_context,
PrefService* local_state,
HostContentSettingsMap* content_rules)
@@ -83,6 +87,7 @@ void SpeedreaderService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterStringPref(kSpeedreaderPrefTtsVoice, "");
registry->RegisterIntegerPref(kSpeedreaderPrefTtsSpeed,
static_cast<int>(PlaybackSpeed::k100));
registry->RegisterBooleanPref(kSpeedreaderDisabledByPolicy, false);
}
// static
@@ -99,7 +104,9 @@ void SpeedreaderService::RemoveObserver(Observer* observer) {
}
bool SpeedreaderService::IsEnabledForAllSites() {
return prefs_->GetBoolean(kSpeedreaderPrefEnabled);
bool disabled_by_policy = speedreader::IsDisabledByPolicy(prefs_);
bool enabled_pref = prefs_->GetBoolean(kSpeedreaderPrefEnabled);
return !disabled_by_policy && enabled_pref;
}
ContentSetting SpeedreaderService::GetEnabledForSiteSetting(const GURL& url) {
@@ -31,6 +31,9 @@ namespace features {
bool IsSpeedreaderEnabled();
}
// Returns true if Speedreader is disabled by policy.
bool IsDisabledByPolicy(PrefService* prefs);
class SpeedreaderService : public KeyedService {
public:
class Observer : public base::CheckedObserver {
@@ -0,0 +1,101 @@
// Copyright (c) 2025 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
#include "brave/components/speedreader/speedreader_service.h"
#include "base/test/task_environment.h"
#include "brave/components/speedreader/speedreader_pref_names.h"
#include "build/build_config.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace speedreader {
class SpeedreaderPolicyTest : public testing::Test {
public:
SpeedreaderPolicyTest() {
SpeedreaderService::RegisterProfilePrefs(pref_service_.registry());
}
protected:
void SetSpeedreaderDisabledByPolicy(bool value) {
pref_service_.SetManagedPref(kSpeedreaderDisabledByPolicy,
base::Value(value));
}
sync_preferences::TestingPrefServiceSyncable pref_service_;
};
TEST_F(SpeedreaderPolicyTest, PolicyDisablesSpeedreader) {
// Initially, policy should not be disabled
EXPECT_FALSE(pref_service_.GetBoolean(kSpeedreaderDisabledByPolicy));
EXPECT_FALSE(pref_service_.IsManagedPreference(kSpeedreaderDisabledByPolicy));
EXPECT_FALSE(IsDisabledByPolicy(&pref_service_));
// Set policy to disable Speedreader
SetSpeedreaderDisabledByPolicy(true);
// Test that the policy preference is set correctly
EXPECT_TRUE(pref_service_.FindPreference(kSpeedreaderDisabledByPolicy));
EXPECT_TRUE(pref_service_.IsManagedPreference(kSpeedreaderDisabledByPolicy));
EXPECT_TRUE(pref_service_.GetBoolean(kSpeedreaderDisabledByPolicy));
// Test that IsDisabledByPolicy function works
EXPECT_TRUE(IsDisabledByPolicy(&pref_service_));
}
TEST_F(SpeedreaderPolicyTest, PolicyEnablesSpeedreader) {
// Set policy to explicitly enable Speedreader (policy value false = not
// disabled)
SetSpeedreaderDisabledByPolicy(false);
// Test that the policy preference is set correctly
EXPECT_TRUE(pref_service_.FindPreference(kSpeedreaderDisabledByPolicy));
EXPECT_TRUE(pref_service_.IsManagedPreference(kSpeedreaderDisabledByPolicy));
EXPECT_FALSE(pref_service_.GetBoolean(kSpeedreaderDisabledByPolicy));
// Test that IsDisabledByPolicy function works
EXPECT_FALSE(IsDisabledByPolicy(&pref_service_));
}
TEST_F(SpeedreaderPolicyTest, DefaultValueWhenNotManaged) {
// When not managed by policy, should be false by default
EXPECT_FALSE(pref_service_.GetBoolean(kSpeedreaderDisabledByPolicy));
EXPECT_FALSE(pref_service_.IsManagedPreference(kSpeedreaderDisabledByPolicy));
EXPECT_FALSE(IsDisabledByPolicy(&pref_service_));
}
TEST_F(SpeedreaderPolicyTest, PolicyChangesAreReflected) {
// Start with policy allowing speedreader
SetSpeedreaderDisabledByPolicy(false);
EXPECT_FALSE(IsDisabledByPolicy(&pref_service_));
// Change policy to disable speedreader
SetSpeedreaderDisabledByPolicy(true);
EXPECT_TRUE(IsDisabledByPolicy(&pref_service_));
// Change back to allowing speedreader
SetSpeedreaderDisabledByPolicy(false);
EXPECT_FALSE(IsDisabledByPolicy(&pref_service_));
}
TEST_F(SpeedreaderPolicyTest, PolicyWorksWithDefaultsWrite) {
// This simulates the behavior when using "defaults write" command on macOS
// where the preference is set but not marked as managed
// Manually set the preference value without using SetManagedPref
pref_service_.SetBoolean(kSpeedreaderDisabledByPolicy, true);
// Verify the preference is set but not marked as managed
EXPECT_TRUE(pref_service_.GetBoolean(kSpeedreaderDisabledByPolicy));
EXPECT_FALSE(pref_service_.IsManagedPreference(kSpeedreaderDisabledByPolicy));
// IsDisabledByPolicy should still return true since we just check the
// preference value
EXPECT_TRUE(IsDisabledByPolicy(&pref_service_));
}
} // namespace speedreader