cromite/build/patches/User-agent-customization.patch
2025-11-22 16:25:29 +01:00

1342 lines
65 KiB
Diff

From: uazo <uazo@users.noreply.github.com>
Date: Fri, 9 Apr 2021 20:09:08 +0000
Subject: User agent customization
Add possibility to define a custom User agent for mobile and desktop mode.
Add possibility to reactivate the metatag view for desktop mode.
The menu item in the hamburger menu applies to the tab only,
whereas the content setting is intended for use in a specific site.
Original License: GPL-2.0-or-later - https://spdx.org/licenses/GPL-2.0-or-later.html
License: GPL-3.0-only - https://spdx.org/licenses/GPL-3.0-only.html
---
.../browser/aw_content_browser_client.cc | 2 +-
base/base_switches.cc | 2 +
base/base_switches.h | 2 +
chrome/android/chrome_java_resources.gni | 2 +
chrome/android/chrome_java_sources.gni | 1 +
.../layout/custom_useragent_preferences.xml | 106 ++++++++++
.../android/java/res/xml/main_preferences.xml | 5 +
.../java/res/xml/useragent_preferences.xml | 25 +++
.../chrome/browser/app/ChromeActivity.java | 1 +
.../init/ChromeBrowserInitializer.java | 3 +
.../PrivacyPreferencesManagerImpl.java | 42 ++++
.../settings/UserAgentPreferences.java | 189 ++++++++++++++++++
.../browser/tab/RequestDesktopUtils.java | 1 +
.../chromium/chrome/browser/tab/TabImpl.java | 64 +++++-
.../chromium/chrome/browser/tab/TabUtils.java | 7 +-
.../browser/android/content/content_utils.cc | 32 ++-
.../preferences/browser_prefs_android.cc | 7 +
.../privacy_preferences_manager_impl.cc | 126 ++++++++++++
...ktop_site_web_contents_observer_android.cc | 11 +
...sktop_site_web_contents_observer_android.h | 2 +
.../preferences/ChromePreferenceKeys.java | 2 -
.../settings/PrivacyPreferencesManager.java | 8 +
.../org/chromium/chrome/browser/tab/Tab.java | 2 +
.../browser/tabwindow/TabWindowManager.java | 2 +
.../tabwindow/TabWindowManagerImpl.java | 18 ++
.../strings/android_chrome_strings.grd | 26 +++
chrome/common/pref_names.h | 8 +
...omiteRequestDesktopSiteContentSetting.java | 76 +++++++
.../request_desktop_site.grdp | 18 ++
.../widget/RadioButtonWithEditText.java | 11 +
.../navigation_controller_android.cc | 4 +
.../navigation_controller_android.h | 1 +
.../renderer_host/render_process_host_impl.cc | 1 +
.../browser/web_contents/web_contents_impl.cc | 6 +-
.../framehost/NavigationControllerImpl.java | 3 +-
content/renderer/render_thread_impl.cc | 1 -
36 files changed, 800 insertions(+), 17 deletions(-)
create mode 100644 chrome/android/java/res/layout/custom_useragent_preferences.xml
create mode 100644 chrome/android/java/res/xml/useragent_preferences.xml
create mode 100644 chrome/android/java/src/org/chromium/chrome/browser/settings/UserAgentPreferences.java
create mode 100644 components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/impl/BromiteRequestDesktopSiteContentSetting.java
create mode 100644 components/browser_ui/strings/bromite_content_settings/request_desktop_site.grdp
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -201,7 +201,7 @@ base::WeakPtr<AsyncCheckTracker> GetAsyncCheckTracker(
} // anonymous namespace
std::string GetProduct() {
- return embedder_support::GetProductAndVersion();
+ return embedder_support::GetProductAndVersion(embedder_support::UserAgentReductionEnterprisePolicyState::kForceEnabled);
}
std::string GetUserAgent() {
diff --git a/base/base_switches.cc b/base/base_switches.cc
--- a/base/base_switches.cc
+++ b/base/base_switches.cc
@@ -185,6 +185,8 @@ const char kPackageName[] = "package-name";
const char kPackageVersionName[] = "package-version-name";
#endif
+const char kDesktopModeViewportMetaEnabled[] = "dm-viewport-meta-enabled";
+
#if BUILDFLAG(IS_CHROMEOS)
// Override the default scheduling boosting value for urgent tasks.
// This can be adjusted if a specific chromeos device shows better perf/power
diff --git a/base/base_switches.h b/base/base_switches.h
--- a/base/base_switches.h
+++ b/base/base_switches.h
@@ -65,6 +65,8 @@ extern const char kPackageVersionName[];
extern const char kSchedulerBoostUrgent[];
#endif
+extern const char kDesktopModeViewportMetaEnabled[];
+
} // namespace switches
#endif // BASE_BASE_SWITCHES_H_
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni
--- a/chrome/android/chrome_java_resources.gni
+++ b/chrome/android/chrome_java_resources.gni
@@ -665,6 +665,8 @@ chrome_java_resources = [
"java/res/xml/search_widget_info.xml",
"java/res/xml/tracing_preferences.xml",
"java/res/xml/unified_account_settings_preferences.xml",
+ "java/res/xml/useragent_preferences.xml",
+ "java/res/layout/custom_useragent_preferences.xml",
]
chrome_java_resources += [
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -919,6 +919,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/payments/ui/DimmingDialog.java",
"java/src/org/chromium/chrome/browser/payments/ui/LineItem.java",
"java/src/org/chromium/chrome/browser/payments/ui/PaymentAppComparator.java",
+ "java/src/org/chromium/chrome/browser/settings/UserAgentPreferences.java",
"java/src/org/chromium/chrome/browser/payments/ui/PaymentInformation.java",
"java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestBottomBar.java",
"java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestHeader.java",
diff --git a/chrome/android/java/res/layout/custom_useragent_preferences.xml b/chrome/android/java/res/layout/custom_useragent_preferences.xml
new file mode 100644
--- /dev/null
+++ b/chrome/android/java/res/layout/custom_useragent_preferences.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ This file is part of Bromite.
+
+ Bromite is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Bromite is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bromite. If not, see <https://www.gnu.org/licenses/>.
+-->
+
+<!-- Layout used by the UserAgentPreferences. -->
+
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:focusable="false"
+ android:orientation="vertical"
+ android:divider="?android:dividerHorizontal">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.TextLarge.Primary"
+ android:background="@color/default_bg_color_secondary"
+ android:padding="16dp"
+ android:text="@string/custom_ua_text"/>
+
+ <org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionLayout
+ android:id="@+id/ua_radio_button_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <org.chromium.components.browser_ui.widget.RadioButtonWithDescription
+ android:id="@+id/default_ua_switch"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ app:primaryText="@string/custom_ua_flag_off" />
+
+ <org.chromium.components.browser_ui.widget.RadioButtonWithEditText
+ android:id="@+id/custom_ua_switch"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:inputType="text"
+ android:hint="@string/custom_ua_placeholder"
+ app:descriptionText="@string/custom_ua_flag_on" />
+
+ </org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionLayout>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.TextLarge.Primary"
+ android:background="@color/default_bg_color_secondary"
+ android:padding="16dp"
+ android:text="@string/custom_desktop_ua_text"/>
+
+ <org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionLayout
+ android:id="@+id/ua_radio_button_layout_dm"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <org.chromium.components.browser_ui.widget.RadioButtonWithDescription
+ android:id="@+id/default_ua_switch_dm"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ app:primaryText="@string/custom_ua_flag_off" />
+
+ <org.chromium.components.browser_ui.widget.RadioButtonWithEditText
+ android:id="@+id/custom_ua_switch_dm"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:inputType="text"
+ android:hint="@string/custom_ua_placeholder"
+ app:descriptionText="@string/custom_ua_flag_on" />
+
+ </org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionLayout>
+
+ <CheckBox
+ android:id="@+id/desktop_mode_viewportmeta"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginLeft="?android:attr/listPreferredItemPaddingStart"
+ android:text="@string/desktop_mode_viewportmeta_checkbox" />
+
+ </LinearLayout>
+
+</ScrollView>
diff --git a/chrome/android/java/res/xml/main_preferences.xml b/chrome/android/java/res/xml/main_preferences.xml
--- a/chrome/android/java/res/xml/main_preferences.xml
+++ b/chrome/android/java/res/xml/main_preferences.xml
@@ -140,6 +140,11 @@ found in the LICENSE file.
android:key="content_settings"
android:order="26"
android:title="@string/prefs_site_settings"/>
+ <Preference
+ android:fragment="org.chromium.chrome.browser.settings.UserAgentPreferences"
+ android:key="useragent_settings"
+ android:order="20"
+ android:title="@string/prefs_useragent_settings"/>
<Preference
android:fragment="org.chromium.chrome.browser.language.settings.LanguageSettings"
android:key="languages"
diff --git a/chrome/android/java/res/xml/useragent_preferences.xml b/chrome/android/java/res/xml/useragent_preferences.xml
new file mode 100644
--- /dev/null
+++ b/chrome/android/java/res/xml/useragent_preferences.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ This file is part of Bromite.
+
+ Bromite is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Bromite is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bromite. If not, see <https://www.gnu.org/licenses/>.
+-->
+
+<!-- Layout used by the UserAgentPreferences. -->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+</PreferenceScreen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -2776,6 +2776,7 @@ public abstract class ChromeActivity extends AsyncInitializationActivity
TabUtils.switchUserAgent(
currentTab,
usingDesktopUserAgent,
+ /* forcedByUser= */ true,
UseDesktopUserAgentCaller.ON_MENU_OR_KEYBOARD_ACTION);
TrackerFactory.getTrackerForProfile(profile)
.notifyEvent(EventConstants.APP_MENU_DESKTOP_SITE_EXCEPTION_ADDED);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
@@ -24,6 +24,7 @@ import org.chromium.chrome.browser.signin.SigninCheckerProvider;
import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
import org.chromium.content_public.browser.BrowserStartupController;
import org.chromium.content_public.browser.BrowserStartupController.StartupMetrics;
+import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManagerImpl;
import java.util.ArrayList;
import java.util.List;
@@ -245,11 +246,13 @@ public class ChromeBrowserInitializer {
@Override
public void onSuccess(@Nullable StartupMetrics metrics) {
+ PrivacyPreferencesManagerImpl.getInstance().updateOverrideUserAgent();
tasks.start(false);
}
});
} else {
startChromeBrowserProcessesSync(delegate.shouldStartGpuProcess());
+ PrivacyPreferencesManagerImpl.getInstance().updateOverrideUserAgent();
tasks.start(true);
}
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacyPreferencesManagerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacyPreferencesManagerImpl.java
--- a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacyPreferencesManagerImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacyPreferencesManagerImpl.java
@@ -239,6 +239,41 @@ public class PrivacyPreferencesManagerImpl implements PrivacyPreferencesManager
return getCrashUploadPermittedSupplier();
}
+ @Override
+ public void updateOverrideUserAgent() {
+ PrivacyPreferencesManagerImplJni.get().updateOverrideUserAgent();
+ }
+
+ @Override
+ public boolean isOverrideUserAgentEnabled(boolean desktopMode) {
+ return PrivacyPreferencesManagerImplJni.get().isOverrideUserAgentEnabled(desktopMode);
+ }
+
+ @Override
+ public void setOverrideUserAgentEnabled(boolean enabled, boolean desktopMode) {
+ PrivacyPreferencesManagerImplJni.get().setOverrideUserAgentEnabled(enabled, desktopMode);
+ }
+
+ @Override
+ public String getOverrideUserAgentValue(boolean desktopMode) {
+ return PrivacyPreferencesManagerImplJni.get().getOverrideUserAgentValue(desktopMode);
+ }
+
+ @Override
+ public void setOverrideUserAgentValue(String user_agent, boolean desktopMode) {
+ PrivacyPreferencesManagerImplJni.get().setOverrideUserAgentValue(user_agent, desktopMode);
+ }
+
+ @Override
+ public boolean isDesktopModeViewportMetaEnabled() {
+ return PrivacyPreferencesManagerImplJni.get().isDesktopModeViewportMetaEnabled();
+ }
+
+ @Override
+ public void setDesktopModeViewportMetaEnabled(boolean enabled) {
+ PrivacyPreferencesManagerImplJni.get().setDesktopModeViewportMetaEnabled(enabled);
+ }
+
@NativeMethods
public interface Natives {
boolean isMetricsReportingEnabled();
@@ -246,5 +281,12 @@ public class PrivacyPreferencesManagerImpl implements PrivacyPreferencesManager
void setMetricsReportingEnabled(boolean enabled);
boolean isMetricsReportingDisabledByPolicy();
+ void updateOverrideUserAgent();
+ boolean isOverrideUserAgentEnabled(boolean desktopMode);
+ void setOverrideUserAgentEnabled(boolean enabled, boolean desktopMode);
+ String getOverrideUserAgentValue(boolean desktopMode);
+ void setOverrideUserAgentValue(String user_agent, boolean desktopMode);
+ boolean isDesktopModeViewportMetaEnabled();
+ void setDesktopModeViewportMetaEnabled(boolean enabled);
}
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/UserAgentPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/UserAgentPreferences.java
new file mode 100644
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/UserAgentPreferences.java
@@ -0,0 +1,189 @@
+/*
+ This file is part of Bromite.
+
+ Bromite is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Bromite is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bromite. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+package org.chromium.chrome.browser.settings;
+
+import android.os.Bundle;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceFragmentCompat;
+import androidx.preference.PreferenceViewHolder;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import android.view.LayoutInflater;
+import android.widget.RadioGroup;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import androidx.recyclerview.widget.RecyclerView;
+
+import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
+import org.chromium.components.browser_ui.widget.RadioButtonWithDescription;
+import org.chromium.components.browser_ui.widget.RadioButtonWithEditText;
+import org.chromium.components.browser_ui.settings.SettingsUtils;
+import org.chromium.components.content_settings.ContentSettingsType;
+import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridge;
+import org.chromium.components.browser_ui.settings.SettingsFragment;
+import org.chromium.chrome.browser.app.tabwindow.TabWindowManagerSingleton;
+import org.chromium.chrome.browser.tabwindow.TabWindowManager;
+import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManagerImpl;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.settings.ProfileDependentSetting;
+import org.chromium.chrome.R;
+
+/**
+ * Fragment that allows the user to configure User Agent related preferences.
+ */
+public class UserAgentPreferences
+ extends PreferenceFragmentCompat
+ implements RadioGroup.OnCheckedChangeListener, SettingsFragment,
+ ProfileDependentSetting {
+
+ private RadioButtonWithDescription useDefaultAgentSwitch;
+ private RadioButtonWithEditText useCustomAgentSwitch;
+ private RadioButtonWithDescription useDefaultAgentSwitchDesktopMode;
+ private RadioButtonWithEditText useCustomAgentSwitchDesktopMode;
+ private RadioGroup mRadioGroup;
+ private RadioGroup mRadioGroupDesktopMode;
+ private CheckBox mDesktopModeViewportmeta;
+ private Profile mProfile;
+
+ @Override
+ public @AnimationType int getAnimationType() {
+ return AnimationType.PROPERTY;
+ }
+
+ @Override
+ public void setProfile(Profile profile) {
+ mProfile = profile;
+ }
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ getActivity().setTitle(R.string.useragent_settings_title);
+ SettingsUtils.addPreferencesFromResource(this, R.xml.useragent_preferences);
+ }
+
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ LinearLayout viewGroup = (LinearLayout) super.onCreateView(inflater, container, savedInstanceState);
+ LinearLayout.LayoutParams params =
+ new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+ viewGroup.setLayoutParams(params);
+ ScrollView view = (ScrollView) inflater.inflate(R.layout.custom_useragent_preferences, viewGroup, false);
+ viewGroup.addView(view);
+
+ boolean enabledCustomUA = PrivacyPreferencesManagerImpl.getInstance().isOverrideUserAgentEnabled(false);
+ boolean enabledCustomUADesktopMode = PrivacyPreferencesManagerImpl.getInstance().isOverrideUserAgentEnabled(true);
+ boolean enabledDesktopModeViewportmeta = PrivacyPreferencesManagerImpl.getInstance().isDesktopModeViewportMetaEnabled();
+
+ useDefaultAgentSwitch =
+ (RadioButtonWithDescription) view.findViewById(R.id.default_ua_switch);
+ useCustomAgentSwitch =
+ (RadioButtonWithEditText) view.findViewById(R.id.custom_ua_switch);
+ useDefaultAgentSwitchDesktopMode =
+ (RadioButtonWithDescription) view.findViewById(R.id.default_ua_switch_dm);
+ useCustomAgentSwitchDesktopMode =
+ (RadioButtonWithEditText) view.findViewById(R.id.custom_ua_switch_dm);
+
+ mRadioGroup = (RadioGroup) view.findViewById(R.id.ua_radio_button_layout);
+ mRadioGroup.setOnCheckedChangeListener(this);
+
+ mRadioGroupDesktopMode = (RadioGroup) view.findViewById(R.id.ua_radio_button_layout_dm);
+ mRadioGroupDesktopMode.setOnCheckedChangeListener(this);
+
+ mDesktopModeViewportmeta = (CheckBox) view.findViewById(R.id.desktop_mode_viewportmeta);
+ mDesktopModeViewportmeta.setChecked(enabledDesktopModeViewportmeta);
+ mDesktopModeViewportmeta.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ PrivacyPreferencesManagerImpl.getInstance().setDesktopModeViewportMetaEnabled(
+ mDesktopModeViewportmeta.isChecked());
+ }
+ });
+
+ useDefaultAgentSwitch.setChecked(!enabledCustomUA);
+ useCustomAgentSwitch.setChecked(enabledCustomUA);
+
+ useDefaultAgentSwitchDesktopMode.setChecked(!enabledCustomUADesktopMode);
+ useCustomAgentSwitchDesktopMode.setChecked(enabledCustomUADesktopMode);
+
+ useCustomAgentSwitch.setPrimaryText(
+ PrivacyPreferencesManagerImpl.getInstance().getOverrideUserAgentValue(false));
+ useCustomAgentSwitch.addTextChangeListener(new RadioButtonWithEditText.OnTextChangeListener() {
+ @Override
+ public void onTextChanged(CharSequence newText) {
+ PrivacyPreferencesManagerImpl.getInstance().setOverrideUserAgentValue(
+ newText.toString(), false);
+ }
+ });
+ useCustomAgentSwitch.setFocusChangeListener( hasFocus -> {
+ if( hasFocus )
+ PrivacyPreferencesManagerImpl.getInstance().setOverrideUserAgentEnabled(true, false);
+ });
+
+ useCustomAgentSwitchDesktopMode.setPrimaryText(
+ PrivacyPreferencesManagerImpl.getInstance().getOverrideUserAgentValue(true));
+ useCustomAgentSwitchDesktopMode.addTextChangeListener(new RadioButtonWithEditText.OnTextChangeListener() {
+ @Override
+ public void onTextChanged(CharSequence newText) {
+ PrivacyPreferencesManagerImpl.getInstance().setOverrideUserAgentValue(
+ newText.toString(), true);
+ }
+ });
+ useCustomAgentSwitchDesktopMode.setFocusChangeListener( hasFocus -> {
+ if( hasFocus )
+ PrivacyPreferencesManagerImpl.getInstance().setOverrideUserAgentEnabled(true, true);
+ });
+
+ return viewGroup;
+ }
+
+ private void UpdateAllTabs() {
+ final boolean alwaysDesktopModeEnabled = WebsitePreferenceBridge.isCategoryEnabled(
+ mProfile, ContentSettingsType.REQUEST_DESKTOP_SITE);
+ TabWindowManagerSingleton.getInstance().SetOverrideUserAgentForAllTabs(alwaysDesktopModeEnabled);
+ }
+
+ @Override
+ public void onCheckedChanged(RadioGroup group, int checkedId) {
+ if (useDefaultAgentSwitch.isChecked()) {
+ PrivacyPreferencesManagerImpl.getInstance().setOverrideUserAgentEnabled(false, false);
+ } else if (useCustomAgentSwitch.isChecked()) {
+ PrivacyPreferencesManagerImpl.getInstance().setOverrideUserAgentEnabled(true, false);
+ }
+
+ if (useDefaultAgentSwitchDesktopMode.isChecked()) {
+ PrivacyPreferencesManagerImpl.getInstance().setOverrideUserAgentEnabled(false, true);
+ } else if (useCustomAgentSwitchDesktopMode.isChecked()) {
+ PrivacyPreferencesManagerImpl.getInstance().setOverrideUserAgentEnabled(true, true);
+ }
+
+ UpdateAllTabs();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ UpdateAllTabs();
+ }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java
@@ -142,6 +142,7 @@ public class RequestDesktopUtils {
*/
public static void setRequestDesktopSiteContentSettingsForUrl(
Profile profile, GURL url, boolean useDesktopUserAgent) {
+ if ((true)) return;
boolean isOffTheRecord = profile.isOffTheRecord();
String domainWildcardPattern =
WebsitePreferenceBridge.toDomainWildcardPattern(url.getSpec());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
@@ -82,6 +82,9 @@ import org.chromium.components.autofill.AutofillProvider;
import org.chromium.components.autofill.AutofillProviderUMA;
import org.chromium.components.autofill.AutofillSelectionActionMenuDelegate;
import org.chromium.components.autofill.AutofillSelectionMenuItemHelper;
+import org.chromium.components.content_settings.ContentSetting;
+import org.chromium.components.content_settings.ContentSettingsType;
+import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridge;
import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
import org.chromium.components.embedder_support.contextmenu.ContextMenuPopulatorFactory;
import org.chromium.components.embedder_support.util.UrlConstants;
@@ -127,6 +130,9 @@ import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.profiles.ProfileManager;
import org.chromium.components.user_prefs.UserPrefs;
+import org.chromium.content_public.browser.NavigationController;
+import org.chromium.components.embedder_support.util.UrlUtilities;
+
/**
* Implementation of the interface {@link Tab}. Contains and manages a {@link ContentView}. This
* class is not intended to be extended.
@@ -2318,9 +2324,6 @@ class TabImpl implements Tab {
}
if (mWebContents != null) {
- // Invoke switchUserAgentIfNeeded() from restoreIfNeeded() instead of loadIfNeeded()
- // to avoid reload without explicit user intent.
- switchUserAgentIfNeeded(UseDesktopUserAgentCaller.LOAD_IF_NEEDED + caller);
mWebContents.getNavigationController().loadIfNecessary();
}
mIsBeingRestored = true;
@@ -2720,6 +2723,11 @@ class TabImpl implements Tab {
url = webContents.getVisibleUrl();
}
+ if (mUserAgent == TabUserAgent.MOBILE)
+ return UserAgentOverrideOption.FALSE;
+ else if (mUserAgent == TabUserAgent.DESKTOP)
+ return UserAgentOverrideOption.TRUE;
+
boolean shouldRequestDesktopSite =
RequestDesktopUtils.shouldOverrideDesktopSite(mProfile, url, getContext());
@@ -2749,7 +2757,7 @@ class TabImpl implements Tab {
}
boolean usingDesktopUserAgent =
getWebContents().getNavigationController().getUseDesktopUserAgent();
- TabUtils.switchUserAgent(this, /* switchToDesktop= */ !usingDesktopUserAgent, caller);
+ TabUtils.switchUserAgent(this, /* switchToDesktop= */ !usingDesktopUserAgent, /* forcedByUser= */ false, caller);
}
/** Sets the TabLaunchType for tabs launched with an unset launch type. */
@@ -2899,6 +2907,54 @@ class TabImpl implements Tab {
/* allowDialog= */ false);
}
+ int overrideUserAgentWhenUnFrozen = (int)UserAgentOverrideOption.INHERIT;
+
+ public void SetOverrideUserAgent(boolean usingDesktopUserAgent, boolean forcedByUser) {
+ WebContents webContents = this.getWebContents();
+
+ GURL url = this.getUrl();
+ if (usingDesktopUserAgent) {
+ if (webContents == null && this.getPendingLoadParams() != null) {
+ url = UrlFormatter.fixupUrl(this.getPendingLoadParams().getUrl());
+ }
+ if (UrlUtilities.isInternalScheme(url) == true)
+ usingDesktopUserAgent = false;
+ }
+
+ if (forcedByUser) {
+ @TabUserAgent
+ int tabUserAgent = TabUserAgent.DEFAULT;
+ @ContentSetting
+ int contentSetting = WebsitePreferenceBridge.getContentSetting(
+ mProfile, ContentSettingsType.REQUEST_DESKTOP_SITE, url, url);
+ if (!usingDesktopUserAgent
+ && contentSetting != ContentSetting.BLOCK) {
+ tabUserAgent = TabUserAgent.MOBILE;
+ } else if (usingDesktopUserAgent
+ && contentSetting != ContentSetting.ALLOW) {
+ tabUserAgent = TabUserAgent.DESKTOP;
+ }
+
+ setUserAgent(tabUserAgent);
+ }
+
+ if (webContents != null) {
+ ContentUtils.setUserAgentOverride(webContents, /*forcedByUser*/ true);
+
+ NavigationController navigationController = webContents.getNavigationController();
+ navigationController.setUseDesktopUserAgent(
+ usingDesktopUserAgent, !this.isNativePage(), UseDesktopUserAgentCaller.OTHER);
+ }
+ else if (this.getPendingLoadParams() != null) {
+ if (usingDesktopUserAgent) {
+ this.getPendingLoadParams().setOverrideUserAgent((int)UserAgentOverrideOption.TRUE);
+ }
+ else {
+ this.getPendingLoadParams().setOverrideUserAgent((int)UserAgentOverrideOption.FALSE);
+ }
+ }
+ }
+
@NativeMethods
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
public interface Natives {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java
@@ -130,11 +130,8 @@ public class TabUtils {
* @param switchToDesktop Whether switching the user agent to desktop.
* @param caller The caller of this method.
*/
- public static void switchUserAgent(Tab tab, boolean switchToDesktop, int caller) {
- final boolean reloadOnChange = !tab.isNativePage();
- assumeNonNull(tab.getWebContents())
- .getNavigationController()
- .setUseDesktopUserAgent(switchToDesktop, reloadOnChange, caller);
+ public static void switchUserAgent(Tab tab, boolean switchToDesktop, boolean forcedByUser, int caller) {
+ tab.SetOverrideUserAgent(switchToDesktop, forcedByUser);
}
/**
diff --git a/chrome/browser/android/content/content_utils.cc b/chrome/browser/android/content/content_utils.cc
--- a/chrome/browser/android/content/content_utils.cc
+++ b/chrome/browser/android/content/content_utils.cc
@@ -8,9 +8,23 @@
#include "content/public/browser/web_contents.h"
#include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "chrome/browser/browser_process.h"
+#include "components/prefs/pref_service.h"
+#include "chrome/common/pref_names.h"
+
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "chrome/browser/android/content/jni_headers/ContentUtils_jni.h"
+using base::android::ConvertJavaStringToUTF8;
+using base::android::ConvertUTF16ToJavaString;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
+using base::android::JavaRef;
+using base::android::ScopedJavaGlobalRef;
+using base::android::ScopedJavaLocalRef;
+
static std::string JNI_ContentUtils_GetBrowserUserAgent(JNIEnv* env) {
return embedder_support::GetUserAgent();
}
@@ -19,6 +33,22 @@ static void JNI_ContentUtils_SetUserAgentOverride(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& jweb_contents,
jboolean j_override_in_new_tabs) {
+ bool enabled =
+ g_browser_process->local_state()->GetBoolean(prefs::kOverrideUserAgentDesktopModeEnabled);
+
+ if (enabled == true) {
+ std::string ua = g_browser_process->local_state()->GetString(prefs::kOverrideUserAgentDesktopMode);
+ blink::UserAgentOverride spoofed_ua;
+ spoofed_ua.ua_string_override = ua;
+ spoofed_ua.ua_metadata_override =
+ embedder_support::GetUserAgentMetadata(/*only_low_entropy_ch*/ true);
+
+ content::WebContents* web_contents =
+ content::WebContents::FromJavaWebContents(jweb_contents);
+ web_contents->SetUserAgentOverride(spoofed_ua, false);
+ return;
+ }
+
constexpr char kLinuxInfoStr[] = "X11; Linux x86_64";
// Note: Any updates to desktop overrides here should also be applied to
@@ -29,7 +59,7 @@ static void JNI_ContentUtils_SetUserAgentOverride(
blink::UserAgentOverride spoofed_ua;
spoofed_ua.ua_string_override =
embedder_support::BuildUserAgentFromOSAndProduct(
- kLinuxInfoStr, embedder_support::GetProductAndVersion());
+ kLinuxInfoStr, embedder_support::GetProductAndVersion(embedder_support::UserAgentReductionEnterprisePolicyState::kForceEnabled));
spoofed_ua.ua_metadata_override = metadata;
spoofed_ua.ua_metadata_override->platform = "Linux";
spoofed_ua.ua_metadata_override->platform_version =
diff --git a/chrome/browser/android/preferences/browser_prefs_android.cc b/chrome/browser/android/preferences/browser_prefs_android.cc
--- a/chrome/browser/android/preferences/browser_prefs_android.cc
+++ b/chrome/browser/android/preferences/browser_prefs_android.cc
@@ -12,6 +12,7 @@
#include "components/content_settings/core/common/pref_names.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_registry_simple.h"
+#include "chrome/common/pref_names.h"
namespace android {
@@ -19,6 +20,12 @@ void RegisterPrefs(PrefRegistrySimple* registry) {
RegisterClipboardAndroidPrefs(registry);
readaloud::RegisterLocalPrefs(registry);
webauthn::authenticator::RegisterLocalState(registry);
+
+ registry->RegisterBooleanPref(prefs::kOverrideUserAgentEnabled, false);
+ registry->RegisterStringPref(prefs::kOverrideUserAgent, "");
+ registry->RegisterBooleanPref(prefs::kOverrideUserAgentDesktopModeEnabled, false);
+ registry->RegisterStringPref(prefs::kOverrideUserAgentDesktopMode, "");
+ registry->RegisterBooleanPref(prefs::kDesktopModeViewportMetaEnabled, false);
}
void RegisterUserProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
diff --git a/chrome/browser/android/preferences/privacy_preferences_manager_impl.cc b/chrome/browser/android/preferences/privacy_preferences_manager_impl.cc
--- a/chrome/browser/android/preferences/privacy_preferences_manager_impl.cc
+++ b/chrome/browser/android/preferences/privacy_preferences_manager_impl.cc
@@ -12,9 +12,35 @@
#include "components/policy/core/common/features.h"
#include "components/prefs/pref_service.h"
+#include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+
+#include "base/command_line.h"
+#include "base/base_switches.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/browser/attribution_reporting/attribution_manager.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/common/renderer.mojom.h"
+#include "chrome/browser/chrome_content_browser_client.h"
+
+#include "components/embedder_support/content_settings_utils.h"
+#include "components/embedder_support/switches.h"
+#include "components/embedder_support/user_agent_utils.h"
+#include "components/embedder_support/origin_trials/origin_trials_settings_storage.h"
+
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "chrome/android/chrome_jni_headers/PrivacyPreferencesManagerImpl_jni.h"
+using base::android::ConvertJavaStringToUTF8;
+using base::android::ConvertUTF16ToJavaString;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
+using base::android::JavaRef;
+using base::android::ScopedJavaGlobalRef;
+using base::android::ScopedJavaLocalRef;
+
static jboolean JNI_PrivacyPreferencesManagerImpl_IsMetricsReportingEnabled(
JNIEnv* env) {
PrefService* local_state = g_browser_process->local_state();
@@ -36,3 +62,103 @@ JNI_PrivacyPreferencesManagerImpl_IsMetricsReportingDisabledByPolicy(
metrics::prefs::kMetricsReportingEnabled) &&
!local_state->GetBoolean(metrics::prefs::kMetricsReportingEnabled);
}
+
+static void UpdateOverrideUserAgent() {
+ bool overrideUserAgentEnabled =
+ g_browser_process->local_state()->GetBoolean(prefs::kOverrideUserAgentEnabled);
+ std::string ua = g_browser_process->local_state()->GetString(prefs::kOverrideUserAgent);
+ if (ua.empty()) {
+ ua = ChromeContentBrowserClient().GetUserAgent();
+ }
+
+ base::CommandLine* parsed_command_line =
+ base::CommandLine::ForCurrentProcess();
+ parsed_command_line->RemoveSwitch(embedder_support::kUserAgent);
+ if (!ua.empty()) {
+ if (overrideUserAgentEnabled) {
+ parsed_command_line->AppendSwitchASCII(embedder_support::kUserAgent, ua);
+ }
+
+ for (auto iter = content::RenderProcessHost::AllHostsIterator(); !iter.IsAtEnd();
+ iter.Advance()) {
+ if (iter.GetCurrentValue()->IsInitializedAndNotDead()) {
+ uint64_t trace_id = base::Token::CreateRandom().high();
+ std::vector<std::string> cors_exempt_header_list;
+ iter.GetCurrentValue()->GetRendererInterface()->InitializeRenderer(
+ /*user_agent*/ ua, /*metadata*/ blink::UserAgentMetadata(),
+ cors_exempt_header_list,
+ g_browser_process->GetOriginTrialsSettingsStorage()->GetSettings(),
+ trace_id);
+ }
+ }
+ }
+
+ parsed_command_line->RemoveSwitch(switches::kDesktopModeViewportMetaEnabled);
+ if (g_browser_process->local_state()->GetBoolean(prefs::kDesktopModeViewportMetaEnabled))
+ parsed_command_line->AppendSwitch(switches::kDesktopModeViewportMetaEnabled);
+}
+
+static void JNI_PrivacyPreferencesManagerImpl_UpdateOverrideUserAgent(
+ JNIEnv* env) {
+ UpdateOverrideUserAgent();
+}
+
+static jboolean JNI_PrivacyPreferencesManagerImpl_IsOverrideUserAgentEnabled(
+ JNIEnv* env, jboolean desktopMode) {
+ if (desktopMode == false)
+ return g_browser_process->local_state()->GetBoolean(prefs::kOverrideUserAgentEnabled);
+ else
+ return g_browser_process->local_state()->GetBoolean(prefs::kOverrideUserAgentDesktopModeEnabled);
+}
+
+static void JNI_PrivacyPreferencesManagerImpl_SetOverrideUserAgentEnabled(
+ JNIEnv* env,
+ jboolean enabled, jboolean desktopMode) {
+ if (desktopMode == false) {
+ g_browser_process->local_state()->SetBoolean(prefs::kOverrideUserAgentEnabled,
+ enabled);
+ UpdateOverrideUserAgent();
+ } else {
+ g_browser_process->local_state()->SetBoolean(prefs::kOverrideUserAgentDesktopModeEnabled,
+ enabled);
+ }
+}
+
+static void JNI_PrivacyPreferencesManagerImpl_SetOverrideUserAgentValue(
+ JNIEnv* env,
+ const JavaParamRef<jstring>& ua, jboolean desktopMode) {
+ std::string new_ua = ConvertJavaStringToUTF8(env, ua);
+ if (desktopMode == false) {
+ g_browser_process->local_state()->SetString(prefs::kOverrideUserAgent,
+ new_ua);
+ UpdateOverrideUserAgent();
+ } else {
+ g_browser_process->local_state()->SetString(prefs::kOverrideUserAgentDesktopMode,
+ new_ua);
+ }
+}
+
+static base::android::ScopedJavaLocalRef<jstring>
+ JNI_PrivacyPreferencesManagerImpl_GetOverrideUserAgentValue(
+ JNIEnv* env, jboolean desktopMode) {
+ if (desktopMode == false) {
+ std::string ua = g_browser_process->local_state()->GetString(prefs::kOverrideUserAgent);
+ return ConvertUTF8ToJavaString(env, ua);
+ } else {
+ std::string ua = g_browser_process->local_state()->GetString(prefs::kOverrideUserAgentDesktopMode);
+ return ConvertUTF8ToJavaString(env, ua);
+ }
+}
+
+static jboolean JNI_PrivacyPreferencesManagerImpl_IsDesktopModeViewportMetaEnabled(
+ JNIEnv* env) {
+ return g_browser_process->local_state()->GetBoolean(prefs::kDesktopModeViewportMetaEnabled);
+}
+
+static void JNI_PrivacyPreferencesManagerImpl_SetDesktopModeViewportMetaEnabled(
+ JNIEnv* env,
+ jboolean enabled) {
+ g_browser_process->local_state()->SetBoolean(prefs::kDesktopModeViewportMetaEnabled,
+ enabled);
+ UpdateOverrideUserAgent();
+}
diff --git a/chrome/browser/content_settings/request_desktop_site_web_contents_observer_android.cc b/chrome/browser/content_settings/request_desktop_site_web_contents_observer_android.cc
--- a/chrome/browser/content_settings/request_desktop_site_web_contents_observer_android.cc
+++ b/chrome/browser/content_settings/request_desktop_site_web_contents_observer_android.cc
@@ -16,6 +16,7 @@
#include "chrome/browser/flags/android/chrome_feature_list.h"
#include "chrome/browser/preferences/android/chrome_shared_preferences.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/android/tab_model/tab_model.h"
#include "chrome/common/chrome_switches.h"
#include "components/content_settings/core/common/content_settings_utils.h"
#include "components/content_settings/core/common/pref_names.h"
@@ -45,6 +46,7 @@ RequestDesktopSiteWebContentsObserverAndroid::
host_content_settings_map_ =
HostContentSettingsMapFactory::GetForProfile(profile);
pref_service_ = profile->GetPrefs();
+ tab_android_ = TabAndroid::FromWebContents(contents);
}
RequestDesktopSiteWebContentsObserverAndroid::
@@ -59,6 +61,15 @@ void RequestDesktopSiteWebContentsObserverAndroid::DidStartNavigation(
return;
}
+ // Stop UA override if there is a tab level setting.
+ TabModel::TabUserAgent tabSetting =
+ tab_android_
+ ? static_cast<TabModel::TabUserAgent>(tab_android_->GetUserAgent())
+ : TabModel::TabUserAgent::DEFAULT;
+ if (tabSetting != TabModel::TabUserAgent::DEFAULT) {
+ return;
+ }
+
const GURL& url = navigation_handle->GetParentFrameOrOuterDocument()
? navigation_handle->GetParentFrameOrOuterDocument()
->GetOutermostMainFrame()
diff --git a/chrome/browser/content_settings/request_desktop_site_web_contents_observer_android.h b/chrome/browser/content_settings/request_desktop_site_web_contents_observer_android.h
--- a/chrome/browser/content_settings/request_desktop_site_web_contents_observer_android.h
+++ b/chrome/browser/content_settings/request_desktop_site_web_contents_observer_android.h
@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_CONTENT_SETTINGS_REQUEST_DESKTOP_SITE_WEB_CONTENTS_OBSERVER_ANDROID_H_
#define CHROME_BROWSER_CONTENT_SETTINGS_REQUEST_DESKTOP_SITE_WEB_CONTENTS_OBSERVER_ANDROID_H_
+#include "chrome/browser/android/tab_android.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
@@ -40,6 +41,7 @@ class RequestDesktopSiteWebContentsObserverAndroid
bool ShouldAllowOnExternalDisplay(bool is_global_setting);
raw_ptr<HostContentSettingsMap> host_content_settings_map_;
raw_ptr<PrefService> pref_service_;
+ raw_ptr<TabAndroid> tab_android_ = nullptr;
// The display size threshold in inches for enabling desktop user agent on
// connected displays.
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -1243,8 +1243,6 @@ public final class ChromePreferenceKeys {
SIGNIN_PROMO_NTP_LAST_SHOWN_TIME,
SYNC_PROMO_TOTAL_SHOW_COUNT,
SEARCH_RESUMPTION_MODULE_COLLAPSE_ON_NTP,
- SWAA_TIMESTAMP,
- SWAA_STATUS,
TABBED_ACTIVITY_LAST_VISIBLE_TIME_MS,
TAB_DECLUTTER_ARCHIVE_DUPLICATE_TABS_ENABLED,
TAB_DECLUTTER_ARCHIVE_ENABLED,
diff --git a/chrome/browser/privacy/settings/java/src/org/chromium/chrome/browser/privacy/settings/PrivacyPreferencesManager.java b/chrome/browser/privacy/settings/java/src/org/chromium/chrome/browser/privacy/settings/PrivacyPreferencesManager.java
--- a/chrome/browser/privacy/settings/java/src/org/chromium/chrome/browser/privacy/settings/PrivacyPreferencesManager.java
+++ b/chrome/browser/privacy/settings/java/src/org/chromium/chrome/browser/privacy/settings/PrivacyPreferencesManager.java
@@ -102,6 +102,14 @@ public interface PrivacyPreferencesManager extends CrashReportingPermissionManag
*/
boolean isMetricsReportingEnabled();
+ void updateOverrideUserAgent();
+ boolean isOverrideUserAgentEnabled(boolean desktopMode);
+ void setOverrideUserAgentEnabled(boolean enabled, boolean desktopMode);
+ String getOverrideUserAgentValue(boolean desktopMode);
+ void setOverrideUserAgentValue(String user_agent, boolean desktopMode);
+ boolean isDesktopModeViewportMetaEnabled();
+ void setDesktopModeViewportMetaEnabled(boolean enabled);
+
/** Sets whether the usage and crash reporting pref should be enabled. */
void setMetricsReportingEnabled(boolean enabled);
diff --git a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Tab.java
--- a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -388,6 +388,8 @@ public interface Tab extends TabLifecycle {
/** Goes to the navigation entry after the current one. */
void goForward();
+ void SetOverrideUserAgent(boolean usingDesktopUserAgent, boolean forcedByUser);
+
/**
* @return true if the {@link Tab} is a custom tab, including CCTs, TWAs and WebAPKs.
*/
diff --git a/chrome/browser/tabwindow/android/java/src/org/chromium/chrome/browser/tabwindow/TabWindowManager.java b/chrome/browser/tabwindow/android/java/src/org/chromium/chrome/browser/tabwindow/TabWindowManager.java
--- a/chrome/browser/tabwindow/android/java/src/org/chromium/chrome/browser/tabwindow/TabWindowManager.java
+++ b/chrome/browser/tabwindow/android/java/src/org/chromium/chrome/browser/tabwindow/TabWindowManager.java
@@ -174,6 +174,8 @@ public interface TabWindowManager {
@Nullable List<Tab> getGroupedTabsByWindow(
@WindowId int windowId, Token tabGroupId, boolean isIncognito);
+ void SetOverrideUserAgentForAllTabs(boolean usingDesktopUserAgent);
+
/**
* Finds the {@link TabModelSelector} bound to an Activity instance of a given id.
*
diff --git a/chrome/browser/tabwindow/internal/android/java/src/org/chromium/chrome/browser/tabwindow/TabWindowManagerImpl.java b/chrome/browser/tabwindow/internal/android/java/src/org/chromium/chrome/browser/tabwindow/TabWindowManagerImpl.java
--- a/chrome/browser/tabwindow/internal/android/java/src/org/chromium/chrome/browser/tabwindow/TabWindowManagerImpl.java
+++ b/chrome/browser/tabwindow/internal/android/java/src/org/chromium/chrome/browser/tabwindow/TabWindowManagerImpl.java
@@ -499,6 +499,24 @@ public class TabWindowManagerImpl implements TabWindowManager {
return null;
}
+ @Override
+ public void SetOverrideUserAgentForAllTabs(boolean usingDesktopUserAgent) {
+ for (int selectorIndex : mWindowIdToSelectors.keySet()) {
+ TabModelSelector selector = mWindowIdToSelectors.get(selectorIndex);
+ if (selector != null) {
+ List<TabModel> models = selector.getModels();
+ for (int modelIndex = 0; modelIndex < models.size(); modelIndex++) {
+ TabModel model = models.get(modelIndex);
+
+ for (int tabIdex = 0; tabIdex < model.getCount(); tabIdex++) {
+ Tab theTab = model.getTabAt(tabIdex);
+ theTab.SetOverrideUserAgent(usingDesktopUserAgent, /*forcedByUser*/ false);
+ }
+ }
+ }
+ }
+ }
+
@Override
public @Nullable Tab getTabById(@TabId int tabId) {
for (TabModelSelector selector : getAllTabModelSelectors()) {
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -238,6 +238,32 @@ CHAR_LIMIT guidelines:
Visit help page
</message>
+ <!-- User Agent settings -->
+ <message name="IDS_PREFS_USERAGENT_SETTINGS" desc="Title of the User Agent preference. [CHAR-LIMIT=32]">
+ User Agent
+ </message>
+ <message name="IDS_USERAGENT_SETTINGS_TITLE" desc="Title of the User Agent screen. [CHAR-LIMIT=32]">
+ Customize User Agent
+ </message>
+ <message name="IDS_CUSTOM_UA_FLAG_ON" desc="The label of the option that allows users to define custom user agent.">
+ Use custom user agent
+ </message>
+ <message name="IDS_CUSTOM_UA_FLAG_OFF" desc="The label of the option that revert the user agent to actual value.">
+ Use standard user agent
+ </message>
+ <message name="IDS_CUSTOM_UA_PLACEHOLDER" desc="The label of the placeholder for user agent textbox.">
+ Insert a valid user agent
+ </message>
+ <message name="IDS_CUSTOM_UA_TEXT" desc="The label of the placeholder for user agent textbox.">
+ Mobile User Agent
+ </message>
+ <message name="IDS_CUSTOM_DESKTOP_UA_TEXT" desc="The label of the placeholder for user agent textbox.">
+ Desktop Mode User Agent
+ </message>
+ <message name="IDS_DESKTOP_MODE_VIEWPORTMETA_CHECKBOX" desc="The label of the enable viewport meta checkbox for user desktop mode.">
+ Enable processing of the viewport meta tag also for desktop mode
+ </message>
+
<!-- Notification channels -->
<message name="IDS_NOTIFICATION_CATEGORY_GROUP_GENERAL" desc='Subheading for "General" section of a list of notification categories. [CHAR_LIMIT=32]'>
General
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -1899,6 +1899,14 @@ inline constexpr char kNaviOnboardGroup[] = "browser.navi_onboard_group";
inline constexpr char kHadThreeConsecutiveNotificationPermissionDenies[] =
"profile.content_settings.had_three_consecutive_denies.notifications";
+#if BUILDFLAG(IS_ANDROID)
+inline constexpr char kOverrideUserAgentEnabled[] = "override_user_agent_enabled";
+inline constexpr char kOverrideUserAgent[] = "override_user_agent";
+inline constexpr char kOverrideUserAgentDesktopModeEnabled[] = "override_user_agent_dm_enabled";
+inline constexpr char kOverrideUserAgentDesktopMode[] = "override_user_agent_dm";
+inline constexpr char kDesktopModeViewportMetaEnabled[] = "dm-viewport-meta-enabled";
+#endif
+
// Boolean indicating whether support for Data URLs in SVGUseElement should be
// removed.
inline constexpr char kDataUrlInSvgUseEnabled[] =
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/impl/BromiteRequestDesktopSiteContentSetting.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/impl/BromiteRequestDesktopSiteContentSetting.java
new file mode 100644
--- /dev/null
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/impl/BromiteRequestDesktopSiteContentSetting.java
@@ -0,0 +1,76 @@
+/*
+ This file is part of Bromite.
+
+ Bromite is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Bromite is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bromite. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+package org.chromium.components.browser_ui.site_settings.impl;
+
+import org.chromium.components.browser_ui.site_settings.R;
+
+import org.chromium.components.browser_ui.site_settings.BromiteCustomContentSetting;
+import org.chromium.components.browser_ui.site_settings.ContentSettingsResources;
+import org.chromium.components.browser_ui.site_settings.SiteSettingsCategory;
+import org.chromium.components.content_settings.ContentSetting;
+import org.chromium.components.content_settings.ContentSettingsType;
+import org.chromium.content_public.browser.BrowserContextHandle;
+
+import androidx.annotation.Nullable;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import java.util.ArrayList;
+
+public class BromiteRequestDesktopSiteContentSetting extends BromiteCustomContentSetting {
+ public BromiteRequestDesktopSiteContentSetting() {
+ super(/*contentSettingsType*/ ContentSettingsType.REQUEST_DESKTOP_SITE,
+ /*defaultEnabledValue*/ ContentSetting.ALLOW,
+ /*defaultDisabledValue*/ ContentSetting.BLOCK,
+ /*allowException*/ true,
+ /*preferenceKey*/ "request_desktop_site",
+ /*profilePrefKey*/ "request_desktop_site_permission_list");
+ }
+
+ @Override
+ public ContentSettingsResources.ResourceItem getResourceItem() {
+ return null;
+ }
+
+ @Override
+ public int getCategorySummary(@Nullable @ContentSetting int value) {
+ switch (value) {
+ case ContentSetting.ALLOW:
+ return R.string.website_settings_category_request_desktop_site_enabled;
+ case ContentSetting.BLOCK:
+ return R.string.website_settings_category_request_desktop_site_disabled;
+ default:
+ return 0;
+ }
+ }
+
+ @Override
+ public int getCategoryDescription() {
+ return R.string.settings_site_settings_request_desktop_site_description;
+ }
+
+ @Override
+ public int getAddExceptionDialogMessage() {
+ return R.string.website_settings_category_request_desktop_site_enabled;
+ }
+
+ @Override
+ public @Nullable Boolean considerException(SiteSettingsCategory category, @ContentSetting int value) {
+ return value != ContentSetting.ALLOW;
+ }
+}
diff --git a/components/browser_ui/strings/bromite_content_settings/request_desktop_site.grdp b/components/browser_ui/strings/bromite_content_settings/request_desktop_site.grdp
new file mode 100644
--- /dev/null
+++ b/components/browser_ui/strings/bromite_content_settings/request_desktop_site.grdp
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<grit-part>
+ <message name="IDS_SITE_SETTINGS_TYPE_REQUEST_DESKTOP_SITE" desc="The label used for request desktop site site settings controls." formatter_data="android_java">
+ Request desktop site
+ </message>
+
+ <message name="IDS_SETTINGS_SITE_SETTINGS_REQUEST_DESKTOP_SITE_DESCRIPTION" desc="" formatter_data="android_java">
+ Request desktop site
+ </message>
+
+ <message name="IDS_WEBSITE_SETTINGS_CATEGORY_REQUEST_DESKTOP_SITE_ENABLED" desc="" formatter_data="android_java">
+ Request desktop site
+ </message>
+
+ <message name="IDS_WEBSITE_SETTINGS_CATEGORY_REQUEST_DESKTOP_SITE_DISABLED" desc="" formatter_data="android_java">
+ Request mobile site
+ </message>
+</grit-part>
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonWithEditText.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonWithEditText.java
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonWithEditText.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonWithEditText.java
@@ -171,6 +171,17 @@ public class RadioButtonWithEditText extends RadioButtonWithDescription {
mEditText.setCursorVisible(false);
KeyboardVisibilityDelegate.getInstance().hideKeyboard(mEditText);
}
+ if (mRadioButtonWithEditTextFocusListener != null) {
+ mRadioButtonWithEditTextFocusListener.onRadioButtonWithEditTextFocusChanged(hasFocus);
+ }
+ }
+
+ public interface RadioButtonWithEditTextFocusListener {
+ void onRadioButtonWithEditTextFocusChanged(boolean hasFocus);
+ }
+ private RadioButtonWithEditTextFocusListener mRadioButtonWithEditTextFocusListener;
+ public void setFocusChangeListener(RadioButtonWithEditTextFocusListener listener) {
+ mRadioButtonWithEditTextFocusListener = listener;
}
/**
diff --git a/content/browser/renderer_host/navigation_controller_android.cc b/content/browser/renderer_host/navigation_controller_android.cc
--- a/content/browser/renderer_host/navigation_controller_android.cc
+++ b/content/browser/renderer_host/navigation_controller_android.cc
@@ -225,6 +225,7 @@ base::android::ScopedJavaLocalRef<jobject> NavigationControllerAndroid::LoadUrl(
jboolean can_load_local_resources,
jboolean is_renderer_initiated,
jboolean should_replace_current_entry,
+ jint user_agent_override_option,
const JavaParamRef<jobject>& j_initiator_origin,
jboolean has_user_gesture,
jboolean should_clear_history_list,
@@ -320,6 +321,9 @@ base::android::ScopedJavaLocalRef<jobject> NavigationControllerAndroid::LoadUrl(
params.navigation_ui_data = std::move(navigation_ui_data);
+ params.override_user_agent = static_cast<NavigationController::UserAgentOverrideOption>(
+ user_agent_override_option);
+
base::WeakPtr<NavigationHandle> handle =
navigation_controller_->LoadURLWithParams(params);
diff --git a/content/browser/renderer_host/navigation_controller_android.h b/content/browser/renderer_host/navigation_controller_android.h
--- a/content/browser/renderer_host/navigation_controller_android.h
+++ b/content/browser/renderer_host/navigation_controller_android.h
@@ -73,6 +73,7 @@ class CONTENT_EXPORT NavigationControllerAndroid {
jboolean can_load_local_resources,
jboolean is_renderer_initiated,
jboolean should_replace_current_entry,
+ jint user_agent_override_option,
const base::android::JavaParamRef<jobject>& j_initiator_origin,
jboolean has_user_gesture,
jboolean should_clear_history_list,
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -3815,6 +3815,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
#if BUILDFLAG(IS_CHROMEOS)
switches::kSchedulerBoostUrgent,
#endif
+ switches::kDesktopModeViewportMetaEnabled,
};
renderer_cmd->CopySwitchesFrom(browser_cmd, kSwitchNames);
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -19,6 +19,7 @@
#include "base/auto_reset.h"
#include "base/base_switches.h"
+#include "base/base_switches.h"
#include "base/check_op.h"
#include "base/command_line.h"
#include "base/containers/contains.h"
@@ -2449,8 +2450,6 @@ void WebContentsImpl::SetUserAgentOverride(
OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::SetUserAgentOverride",
"ua_override", ua_override.ua_string_override,
"override_in_new_tabs", override_in_new_tabs);
- DCHECK(!ua_override.ua_metadata_override.has_value() ||
- !ua_override.ua_string_override.empty());
if (GetUserAgentOverride() == ua_override) {
return;
@@ -3818,6 +3817,9 @@ const blink::web_pref::WebPreferences WebContentsImpl::ComputeWebPreferences(
#else
prefs.viewport_meta_enabled = false;
#endif
+ if (!command_line.HasSwitch(switches::kDesktopModeViewportMetaEnabled)) {
+ prefs.viewport_meta_enabled = false;
+ }
}
prefs.spatial_navigation_enabled =
diff --git a/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java b/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java
--- a/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java
@@ -200,6 +200,7 @@ import org.chromium.url.Origin;
params.getCanLoadLocalResources(),
params.getIsRendererInitiated(),
params.getShouldReplaceCurrentEntry(),
+ params.getUserAgentOverrideOption(),
params.getInitiatorOrigin(),
params.getHasUserGesture(),
params.getShouldClearHistoryList(),
@@ -445,7 +446,7 @@ import org.chromium.url.Origin;
@Nullable String dataUrlAsString,
boolean canLoadLocalResources,
boolean isRendererInitiated,
- boolean shouldReplaceCurrentEntry,
+ boolean shouldReplaceCurrentEntry, int userAgentOverrideOption,
@Nullable Origin initiatorOrigin,
boolean hasUserGesture,
boolean shouldClearHistoryList,
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -850,7 +850,6 @@ void RenderThreadImpl::InitializeRenderer(
uint64_t trace_id) {
TRACE_EVENT("navigation", "RenderThreadImpl::InitializeRenderer",
perfetto::TerminatingFlow::Global(trace_id));
- DCHECK(user_agent_.IsNull());
user_agent_ = WebString::FromUTF8(user_agent);
GetContentClient()->renderer()->DidSetUserAgent(user_agent);
--