[Android] Android origin policies

Creates origin policies constants for Android
Adds BraveOriginServiceFactory and connect preferences with BraveOriginSettingsHandler
Resolves https://github.com/brave/brave-browser/issues/51333
This commit is contained in:
Serg
2025-12-10 07:14:19 +09:00
committed by GitHub
parent 82c9e16ccb
commit 7a06a92381
12 changed files with 397 additions and 39 deletions
+29
View File
@@ -4,6 +4,8 @@
# You can obtain one at https://mozilla.org/MPL/2.0/.
import("//brave/components/brave_wallet/common/buildflags/buildflags.gni")
import(
"//brave/components/policy/resources/templates/policy_definitions/brave_policies.gni")
import("//brave/components/web_discovery/buildflags/buildflags.gni")
import("//brave/components/webcompat_reporter/buildflags/buildflags.gni")
import("//build/config/android/rules.gni")
@@ -29,6 +31,33 @@ java_cpp_template("brave_config_java") {
]
}
# Generate Java constants from policy YAML files
# This target generates a srcjar that is consumed by chrome_java via srcjar_deps
# Using action_with_pydeps like upstream does
action_with_pydeps("brave_policy_constants_java_srcjar") {
script = "//brave/tools/generate_policy_constants_java.py"
# Collect all YAML policy files as inputs (excluding .group.details.yaml)
_policy_yaml_inputs = []
foreach(policy_file, brave_policies) {
if (policy_file != "BraveSoftware/.group.details.yaml") {
_policy_yaml_inputs += [ "//brave/components/policy/resources/templates/policy_definitions/$policy_file" ]
}
}
# List files explicitly so GN tracks them for incremental builds
inputs = _policy_yaml_inputs
outputs = [ "$target_gen_dir/$target_name.srcjar" ]
args = [
"--policy-dir",
rebase_path(
"//brave/components/policy/resources/templates/policy_definitions/BraveSoftware",
root_build_dir),
"--output-srcjar",
rebase_path("$target_gen_dir/$target_name.srcjar", root_build_dir),
]
}
android_library("qrreader_java") {
sources = [
"java/org/chromium/chrome/browser/qrreader/BarcodeTracker.java",
@@ -13,11 +13,16 @@ import androidx.appcompat.content.res.AppCompatResources;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import org.chromium.base.Log;
import org.chromium.base.supplier.ObservableSupplier;
import org.chromium.base.supplier.ObservableSupplierImpl;
import org.chromium.brave.browser.brave_origin.BraveOriginServiceFactory;
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.policy.BravePolicyConstants;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
import org.chromium.components.browser_ui.settings.SettingsUtils;
@@ -25,7 +30,7 @@ import org.chromium.components.browser_ui.settings.SettingsUtils;
@NullMarked
public class BraveOriginPreferences extends BravePreferenceFragment
implements Preference.OnPreferenceChangeListener {
private static final String TAG = "BraveOriginPreferences";
private static final String TAG = "BraveOriginPrefs";
// Preference keys
private static final String PREF_REWARDS_SWITCH = "rewards_switch";
@@ -49,12 +54,21 @@ public class BraveOriginPreferences extends BravePreferenceFragment
private static final String PREF_LINK_SUBSCRIPTION = "link_subscription";
private final ObservableSupplierImpl<String> mPageTitle = new ObservableSupplierImpl<>();
@Nullable private BraveOriginSettingsHandler mBraveOriginSettingsHandler;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
SettingsUtils.addPreferencesFromResource(this, R.xml.brave_origin_preferences);
mPageTitle.set(getString(R.string.menu_origin));
// Initialize BraveOriginSettingsHandler
Profile profile = getProfile();
if (profile != null) {
mBraveOriginSettingsHandler =
BraveOriginServiceFactory.getInstance()
.getBraveOriginSettingsHandler(profile, null);
}
// Set up toggle preferences
setupTogglePreference(PREF_REWARDS_SWITCH);
setupTogglePreference(PREF_CRASH_REPORTS_SWITCH);
@@ -108,38 +122,19 @@ public class BraveOriginPreferences extends BravePreferenceFragment
boolean isEnabled = (Boolean) newValue;
updateToggleDescription(preference, isEnabled);
if (PREF_REWARDS_SWITCH.equals(key)) {
// TODO: Handle rewards toggle change
return true;
} else if (PREF_CRASH_REPORTS_SWITCH.equals(key)) {
// TODO: Handle crash reports toggle change
return true;
} else if (PREF_PRIVACY_PRESERVING_ANALYTICS_SWITCH.equals(key)) {
// TODO: Handle privacy preserving analytics toggle change
return true;
} else if (PREF_EMAIL_ALIASES_SWITCH.equals(key)) {
// TODO: Handle email aliases toggle change
return true;
} else if (PREF_LEO_AI_SWITCH.equals(key)) {
// TODO: Handle Leo AI toggle change
return true;
} else if (PREF_NEWS_SWITCH.equals(key)) {
// TODO: Handle news toggle change
return true;
} else if (PREF_STATISTICS_REPORTING_SWITCH.equals(key)) {
// TODO: Handle statistics reporting toggle change
return true;
} else if (PREF_VPN_SWITCH.equals(key)) {
// TODO: Handle VPN toggle change
return true;
} else if (PREF_WALLET_SWITCH.equals(key)) {
// TODO: Handle wallet toggle change
return true;
} else if (PREF_WEB_DISCOVERY_PROJECT_SWITCH.equals(key)) {
// TODO: Handle web discovery project toggle change
return true;
String policyKey = getPolicyKeyForPreference(key);
if (policyKey == null || mBraveOriginSettingsHandler == null) {
return false;
}
return false;
mBraveOriginSettingsHandler.setPolicyValue(
policyKey,
isEnabled,
(success) -> {
if (!success) {
Log.e(TAG, "Failed to set policy value for " + policyKey);
}
});
return true;
}
@Override
@@ -152,16 +147,65 @@ public class BraveOriginPreferences extends BravePreferenceFragment
}
/**
* Sets up a toggle preference with listener and initial state.
* Sets up a toggle preference with listener and initial state. Also initializes the preference
* value from the policy service if available.
*
* @param key The preference key
*/
private void setupTogglePreference(String key) {
ChromeSwitchPreference preference = (ChromeSwitchPreference) findPreference(key);
if (preference != null) {
preference.setOnPreferenceChangeListener(this);
updateToggleDescription(preference, preference.isChecked());
if (preference == null) {
assert false : "Preference not found for key: " + key;
return;
}
preference.setOnPreferenceChangeListener(this);
updateToggleDescription(preference, preference.isChecked());
// Initialize from policy service if available
String policyKey = getPolicyKeyForPreference(key);
if (policyKey == null || mBraveOriginSettingsHandler == null) {
return;
}
mBraveOriginSettingsHandler.getPolicyValue(
policyKey,
(value) -> {
if (value != null) {
preference.setChecked(value);
updateToggleDescription(preference, value);
}
});
}
/**
* Gets the policy key for a given preference key.
*
* @param preferenceKey The preference key
* @return The policy key, or null if not mapped
*/
@Nullable
private String getPolicyKeyForPreference(String preferenceKey) {
// Map preference keys to policy keys
if (PREF_REWARDS_SWITCH.equals(preferenceKey)) {
return BravePolicyConstants.BRAVE_REWARDS_DISABLED;
} else if (PREF_PRIVACY_PRESERVING_ANALYTICS_SWITCH.equals(preferenceKey)) {
return BravePolicyConstants.BRAVE_P3_A_ENABLED;
} else if (PREF_LEO_AI_SWITCH.equals(preferenceKey)) {
return BravePolicyConstants.BRAVE_A_I_CHAT_ENABLED;
} else if (PREF_NEWS_SWITCH.equals(preferenceKey)) {
return BravePolicyConstants.BRAVE_NEWS_DISABLED;
} else if (PREF_STATISTICS_REPORTING_SWITCH.equals(preferenceKey)) {
return BravePolicyConstants.BRAVE_STATS_PING_ENABLED;
} else if (PREF_VPN_SWITCH.equals(preferenceKey)) {
return BravePolicyConstants.BRAVE_V_P_N_DISABLED;
} else if (PREF_WALLET_SWITCH.equals(preferenceKey)) {
return BravePolicyConstants.BRAVE_WALLET_DISABLED;
} else if (PREF_WEB_DISCOVERY_PROJECT_SWITCH.equals(preferenceKey)) {
return BravePolicyConstants.BRAVE_WEB_DISCOVERY_ENABLED;
}
// TODO: Add mappings for other preferences as they are implemented
// PREF_CRASH_REPORTS_SWITCH - no policy mapping found
// PREF_EMAIL_ALIASES_SWITCH - no policy mapping found
return null;
}
/**
@@ -236,4 +280,13 @@ public class BraveOriginPreferences extends BravePreferenceFragment
// Set the tinted icon back to the preference
preference.setIcon(icon);
}
@Override
public void onDestroy() {
super.onDestroy();
if (mBraveOriginSettingsHandler != null) {
mBraveOriginSettingsHandler.close();
mBraveOriginSettingsHandler = null;
}
}
}
+1
View File
@@ -24,6 +24,7 @@ source_set("android_browser_process") {
"//brave/browser/android/preferences",
"//brave/browser/android/safe_browsing",
"//brave/browser/brave_ads/android:jni_headers",
"//brave/browser/brave_origin/android:jni_headers",
"//brave/browser/skus/android:jni_headers",
"//brave/build/android:jni_headers",
"//brave/components/brave_ads/browser",
+5
View File
@@ -41,6 +41,11 @@ source_set("brave_origin") {
"//components/policy/core/common",
]
if (is_android) {
sources += [ "android/brave_origin_service_factory_android.cc" ]
deps += [ "//brave/browser/brave_origin/android:jni_headers" ]
}
if (enable_ai_chat) {
deps += [ "//brave/components/ai_chat/core/common" ]
}
+27
View File
@@ -0,0 +1,27 @@
# 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/.
import("//build/config/android/rules.gni")
import("//third_party/jni_zero/jni_zero.gni")
android_library("java") {
sources = [ "java/src/org/chromium/brave/browser/brave_origin/BraveOriginServiceFactory.java" ]
deps = [
"//base:base_java",
"//brave/components/brave_origin/common/mojom:mojom_java",
"//chrome/browser/profiles/android:java",
"//mojo/public/java:bindings_java",
"//mojo/public/java:system_java",
"//mojo/public/java/system:system_impl_java",
"//third_party/jni_zero:jni_zero_java",
]
srcjar_deps = [ ":jni_headers" ]
}
generate_jni("jni_headers") {
sources = [ "java/src/org/chromium/brave/browser/brave_origin/BraveOriginServiceFactory.java" ]
}
@@ -0,0 +1,40 @@
/* 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/browser/brave_origin/brave_origin_service_factory.h"
#include "base/android/jni_android.h"
#include "brave/browser/brave_origin/android/jni_headers/BraveOriginServiceFactory_jni.h"
#include "brave/components/brave_origin/brave_origin_handler.h"
#include "chrome/browser/profiles/profile.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
namespace brave {
namespace android {
static jlong
JNI_BraveOriginServiceFactory_GetInterfaceToBraveOriginSettingsHandler(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& profile_android) {
auto* profile = Profile::FromJavaObject(profile_android);
mojo::PendingRemote<brave_origin::mojom::BraveOriginSettingsHandler> pending;
if (profile) {
auto* brave_origin_service =
brave_origin::BraveOriginServiceFactory::GetForProfile(profile);
if (brave_origin_service) {
auto handler =
std::make_unique<brave_origin::BraveOriginSettingsHandlerImpl>(
brave_origin_service);
mojo::PendingReceiver<brave_origin::mojom::BraveOriginSettingsHandler>
receiver = pending.InitWithNewPipeAndPassReceiver();
mojo::MakeSelfOwnedReceiver(std::move(handler), std::move(receiver));
}
}
return static_cast<jlong>(pending.PassPipe().release().value());
}
} // namespace android
} // namespace brave
@@ -0,0 +1,61 @@
/* 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/. */
package org.chromium.brave.browser.brave_origin;
import org.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods;
import org.chromium.brave_origin.mojom.BraveOriginSettingsHandler;
import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.mojo.bindings.ConnectionErrorHandler;
import org.chromium.mojo.bindings.Interface;
import org.chromium.mojo.bindings.Interface.Proxy.Handler;
import org.chromium.mojo.system.MessagePipeHandle;
import org.chromium.mojo.system.impl.CoreImpl;
@NullMarked
@JNINamespace("brave::android")
public class BraveOriginServiceFactory {
private static class LazyHolder {
static final BraveOriginServiceFactory INSTANCE = new BraveOriginServiceFactory();
}
public static BraveOriginServiceFactory getInstance() {
return LazyHolder.INSTANCE;
}
private BraveOriginServiceFactory() {}
public @Nullable BraveOriginSettingsHandler getBraveOriginSettingsHandler(
Profile profile, @Nullable ConnectionErrorHandler connectionErrorHandler) {
long nativeHandle =
BraveOriginServiceFactoryJni.get()
.getInterfaceToBraveOriginSettingsHandler(profile);
MessagePipeHandle handle = wrapNativeHandle(nativeHandle);
if (!handle.isValid()) {
return null;
}
BraveOriginSettingsHandler braveOriginHandler =
BraveOriginSettingsHandler.MANAGER.attachProxy(handle, 0);
if (connectionErrorHandler != null && braveOriginHandler != null) {
Handler handler = ((Interface.Proxy) braveOriginHandler).getProxyHandler();
handler.setErrorHandler(connectionErrorHandler);
}
return braveOriginHandler;
}
private MessagePipeHandle wrapNativeHandle(long nativeHandle) {
return CoreImpl.getInstance().acquireNativeHandle(nativeHandle).toMessagePipeHandle();
}
@NativeMethods
interface Natives {
long getInterfaceToBraveOriginSettingsHandler(Profile profile);
}
}
+3
View File
@@ -25,6 +25,7 @@ brave_chrome_java_deps = [
"//brave/android:qrreader_java",
"//brave/android/java/org/chromium/chrome/browser/search_engines:java",
"//brave/brave_domains/android:java",
"//brave/browser/brave_origin/android:java",
"//brave/browser/customize_menu/android:java",
"//brave/browser/download/android:java",
"//brave/browser/notifications/android:brave_java",
@@ -42,6 +43,7 @@ brave_chrome_java_deps = [
"//brave/components/brave_account/mojom:mojom_java",
"//brave/components/brave_ads/core/mojom:mojom_java",
"//brave/components/brave_news/common:mojom_java",
"//brave/components/brave_origin/common/mojom:mojom_java",
"//brave/components/brave_rewards/core/mojom:mojom_java",
"//brave/components/brave_shields/core/common:mojom_java",
"//brave/components/brave_vpn/common/mojom:mojom_java",
@@ -101,6 +103,7 @@ brave_java_cpp_enum_filter =
brave_chrome_java_srcjar_deps = [
"//brave/android:brave_android_java_enums_srcjar",
"//brave/android:brave_config_java",
"//brave/android:brave_policy_constants_java_srcjar",
"//brave/browser/android/preferences:java_pref_names_srcjar",
"//brave/components/web_discovery/browser/android:java_pref_names_srcjar",
]
@@ -9,6 +9,7 @@ mojom_component("mojom") {
output_prefix = "brave_origin_mojom"
macro_prefix = "BRAVE_ORIGIN_MOJOM"
generate_java = true
generate_legacy_js_bindings = true
webui_module_path = "/"
@@ -3,7 +3,8 @@
# 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/.
_brave_policies = [
# Public list of Brave policy YAML files
brave_policies = [
"BraveSoftware/.group.details.yaml",
"BraveSoftware/BraveAIChatEnabled.yaml",
"BraveSoftware/BraveDeAmpEnabled.yaml",
@@ -40,7 +41,7 @@ _brave_policies_sync_config_path =
# List Brave's policy files as inputs for policy_templates.py to trigger a
# rebuild if changes are detected.
brave_generate_policy_templates_inputs =
get_path_info(_brave_policies, "abspath") +
get_path_info(brave_policies, "abspath") +
[ _brave_policies_sync_config_path ]
# Generate a policy list to copy into Chromium policy_definitions directory.
@@ -51,7 +52,7 @@ if (current_toolchain == default_toolchain) {
write_file(
_brave_policies_sync_config_path,
{
policies = _brave_policies
policies = brave_policies
copy_from = rebase_path(
"//brave/components/policy/resources/templates/policy_definitions",
root_build_dir)
+134
View File
@@ -0,0 +1,134 @@
#!/usr/bin/env python3
# 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/.
"""Generates Java constants file from Brave policy YAML definitions."""
import argparse
import os
import re
import sys
import zipfile
def extract_policy_name_from_filename(filename):
"""Extract policy name from YAML filename.
Example: 'BraveWebDiscoveryEnabled.yaml' -> 'BraveWebDiscoveryEnabled'
"""
basename = os.path.basename(filename)
if basename.endswith('.yaml'):
return basename[:-5] # Remove .yaml extension
return basename
def find_policy_yaml_files(policy_dir):
"""Find all YAML policy definition files."""
yaml_files = []
if not os.path.isdir(policy_dir):
print(f"Error: Policy directory not found: {policy_dir}",
file=sys.stderr)
return yaml_files
for filename in os.listdir(policy_dir):
if filename.endswith('.yaml') and filename != '.group.details.yaml':
yaml_files.append(os.path.join(policy_dir, filename))
return sorted(yaml_files)
def generate_java_constant_name(policy_name):
"""Convert policy name to Java constant name.
Example: 'BraveWebDiscoveryEnabled' -> 'BRAVE_WEB_DISCOVERY_ENABLED'
"""
# Insert underscore before capital letters (except the first one)
# and convert to uppercase
result = re.sub(r'(?<!^)(?=[A-Z])', '_', policy_name).upper()
return result
def generate_java_content(policy_names):
"""Generate Java file content with policy constants."""
java_content = (
"""/* 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/. */
package org.chromium.chrome.browser.policy;
/**
* Policy key constants for Brave policies.
*
* <p>This file is auto-generated from policy YAML definitions.
* Do not edit manually.
*/
public final class BravePolicyConstants {
private BravePolicyConstants() {
// Prevent instantiation
}
""")
# Generate constants for each policy
for policy_name in sorted(policy_names):
constant_name = generate_java_constant_name(policy_name)
java_content += (f' public static final String {constant_name} = '
f'"{policy_name}";\n')
java_content += "}\n"
return java_content
def generate_srcjar(policy_names, output_srcjar):
"""Generate srcjar (zip file) with Java constants."""
java_content = generate_java_content(policy_names)
# Create srcjar (zip file) with the Java file at the correct path
java_path = "org/chromium/chrome/browser/policy/BravePolicyConstants.java"
os.makedirs(os.path.dirname(output_srcjar), exist_ok=True)
with zipfile.ZipFile(output_srcjar, 'w', zipfile.ZIP_DEFLATED) as zf:
zf.writestr(java_path, java_content.encode('utf-8'))
print(f"Generated {len(policy_names)} policy constants in srcjar "
f"{output_srcjar}")
def main():
parser = argparse.ArgumentParser(
description='Generate Java constants from Brave policy YAML files')
parser.add_argument('--policy-dir',
required=True,
help='Directory containing policy YAML files')
parser.add_argument('--output-srcjar',
required=True,
help='Output srcjar file path')
args = parser.parse_args()
# Find all YAML policy files
yaml_files = find_policy_yaml_files(args.policy_dir)
if not yaml_files:
print(f"Warning: No YAML policy files found in {args.policy_dir}",
file=sys.stderr)
sys.exit(1)
# Extract policy names from filenames
policy_names = []
for yaml_file in yaml_files:
policy_name = extract_policy_name_from_filename(yaml_file)
if policy_name:
policy_names.append(policy_name)
# Generate srcjar output
generate_srcjar(policy_names, args.output_srcjar)
return 0
if __name__ == '__main__':
sys.exit(main())
@@ -0,0 +1,3 @@
# Generated by running:
# build/print_python_deps.py --root brave/tools --output brave/tools/generate_policy_constants_java.pydeps brave/tools/generate_policy_constants_java.py
generate_policy_constants_java.py