Files
cromite/build/patches/User-agent-customization.patch

1333 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
---
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 | 5 +-
.../init/ChromeBrowserInitializer.java | 3 +
.../PrivacyPreferencesManagerImpl.java | 42 ++++
.../settings/UserAgentPreferences.java | 189 ++++++++++++++++++
.../chromium/chrome/browser/tab/TabImpl.java | 64 +++++-
.../chromium/chrome/browser/tab/TabUtils.java | 8 +-
.../browser/android/content/content_utils.cc | 29 +++
.../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 ++
.../desktop_site/DesktopSiteUtils.java | 1 +
.../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 | 17 +-
content/renderer/render_thread_impl.cc | 1 -
34 files changed, 805 insertions(+), 24 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/base/base_switches.h b/base/base_switches.h
--- a/base/base_switches.h
+++ b/base/base_switches.h
@@ -193,6 +193,8 @@ inline constexpr char kPackageName[] = "package-name";
inline constexpr char kPackageVersionName[] = "package-version-name";
#endif
+inline constexpr 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/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
@@ -676,6 +676,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
@@ -982,6 +982,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
@@ -148,6 +148,11 @@ found in the LICENSE file.
android:key="content_settings"
android:order="27"
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
@@ -2901,7 +2901,10 @@ public abstract class ChromeActivity extends AsyncInitializationActivity
profile, currentTab.getUrl(), usingDesktopUserAgent);
// Use TabUtils.switchUserAgent() instead of Tab.reload(). Because we need to reload
// with LoadOriginalRequestURL. See http://crbug/1418587 for details.
- TabUtils.switchUserAgent(currentTab, usingDesktopUserAgent);
+ TabUtils.switchUserAgent(
+ currentTab,
+ usingDesktopUserAgent,
+ /* forcedByUser= */ true);
TrackerFactory.getTrackerForProfile(profile)
.notifyEvent(EventConstants.APP_MENU_DESKTOP_SITE_EXCEPTION_ADDED);
RequestDesktopUtils.recordUserChangeUserAgent(usingDesktopUserAgent, getActivityTab());
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
@@ -230,6 +230,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();
@@ -237,5 +272,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/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;
@@ -128,6 +131,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.
@@ -2381,9 +2387,6 @@ class TabImpl implements Tab {
}
if (mWebContents != null) {
- // Invoke switchUserAgentIfNeeded() from restoreIfNeeded() instead of loadIfNeeded()
- // to avoid reload without explicit user intent.
- switchUserAgentIfNeeded();
mWebContents.getNavigationController().loadIfNecessary();
}
mIsBeingRestored = true;
@@ -2783,6 +2786,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 =
DesktopSiteUtils.shouldOverrideDesktopSite(mProfile, url, getContext());
@@ -2814,7 +2822,7 @@ class TabImpl implements Tab {
}
boolean usingDesktopUserAgent =
getWebContents().getNavigationController().getUseDesktopUserAgent();
- TabUtils.switchUserAgent(this, /* switchToDesktop= */ !usingDesktopUserAgent);
+ TabUtils.switchUserAgent(this, /* switchToDesktop= */ !usingDesktopUserAgent, /* forcedByUser= */ false);
}
/** Sets the TabLaunchType for tabs launched with an unset launch type. */
@@ -3009,6 +3017,54 @@ class TabImpl implements Tab {
return mImportance;
}
+ 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(), /*skipOnInitialNavigation*/ false);
+ }
+ 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
@@ -112,12 +112,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) {
- final boolean reloadOnChange = !tab.isNativePage();
- assumeNonNull(tab.getWebContents())
- .getNavigationController()
- .setUseDesktopUserAgent(
- switchToDesktop, reloadOnChange, /* skipOnInitialNavigation= */ true);
+ public static void switchUserAgent(Tab tab, boolean switchToDesktop, boolean forcedByUser) {
+ 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
@@ -9,9 +9,22 @@
#include "third_party/blink/public/common/features.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::JavaRef;
+using base::android::ScopedJavaGlobalRef;
+using base::android::ScopedJavaLocalRef;
+
static std::string JNI_ContentUtils_GetBrowserUserAgent(JNIEnv* env) {
return embedder_support::GetUserAgent();
}
@@ -20,6 +33,22 @@ static void JNI_ContentUtils_SetUserAgentOverride(
JNIEnv* env,
const base::android::JavaRef<jobject>& jweb_contents,
bool 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
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,34 @@
#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::JavaRef;
+using base::android::ScopedJavaGlobalRef;
+using base::android::ScopedJavaLocalRef;
+
static bool JNI_PrivacyPreferencesManagerImpl_IsMetricsReportingEnabled(
JNIEnv* env) {
PrefService* local_state = g_browser_process->local_state();
@@ -37,4 +62,105 @@ JNI_PrivacyPreferencesManagerImpl_IsMetricsReportingDisabledByPolicy(
!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(),
+ ChromeContentBrowserClient().GetCpuPerformanceTier(),
+ 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 JavaRef<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();
+}
+
DEFINE_JNI(PrivacyPreferencesManagerImpl)
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
@@ -18,6 +18,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"
@@ -47,6 +48,7 @@ RequestDesktopSiteWebContentsObserverAndroid::
host_content_settings_map_ =
HostContentSettingsMapFactory::GetForProfile(profile);
pref_service_ = profile->GetPrefs();
+ tab_android_ = TabAndroid::FromWebContents(contents);
}
RequestDesktopSiteWebContentsObserverAndroid::
@@ -61,6 +63,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
@@ -1278,8 +1278,6 @@ public final class ChromePreferenceKeys {
SIGNIN_PROMO_NTP_FIRST_SHOWN_TIME,
SIGNIN_PROMO_NTP_LAST_SHOWN_TIME,
SYNC_PROMO_TOTAL_SHOW_COUNT,
- 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
@@ -347,6 +347,8 @@ public interface Tab extends TabLifecycle {
/** Goes to the navigation entry after the current one. */
void goForward();
+ void SetOverrideUserAgent(boolean usingDesktopUserAgent, boolean forcedByUser);
+
/** Returns true if the {@link Tab} is a custom tab, including CCTs, TWAs and WebAPKs. */
boolean isCustomTab();
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
@@ -193,6 +193,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
@@ -478,6 +478,24 @@ public class TabWindowManagerImpl implements TabWindowManager {
return null;
}
+ @Override
+ public void SetOverrideUserAgentForAllTabs(boolean usingDesktopUserAgent) {
+ for (Map.Entry<@WindowId Integer, TabModelSelector> entry : mWindowIdToSelectors.entrySet()) {
+ TabModelSelector selector = entry.getValue();
+ 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/desktop_site/java/src/org/chromium/chrome/browser/desktop_site/DesktopSiteUtils.java b/chrome/browser/ui/android/desktop_site/java/src/org/chromium/chrome/browser/desktop_site/DesktopSiteUtils.java
--- a/chrome/browser/ui/android/desktop_site/java/src/org/chromium/chrome/browser/desktop_site/DesktopSiteUtils.java
+++ b/chrome/browser/ui/android/desktop_site/java/src/org/chromium/chrome/browser/desktop_site/DesktopSiteUtils.java
@@ -66,6 +66,7 @@ public class DesktopSiteUtils {
*/
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/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
@@ -259,6 +259,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
@@ -1380,6 +1380,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
@@ -229,6 +229,7 @@ base::android::ScopedJavaLocalRef<jobject> NavigationControllerAndroid::LoadUrl(
bool can_load_local_resources,
bool is_renderer_initiated,
bool should_replace_current_entry,
+ jint user_agent_override_option,
const JavaRef<jobject>& j_initiator_origin,
bool has_user_gesture,
bool should_clear_history_list,
@@ -333,6 +334,9 @@ base::android::ScopedJavaLocalRef<jobject> NavigationControllerAndroid::LoadUrl(
ConvertJavaStringToUTF8(env, internal_scroll_to_text_fragment);
}
+ 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
@@ -69,6 +69,7 @@ class CONTENT_EXPORT NavigationControllerAndroid {
bool can_load_local_resources,
bool is_renderer_initiated,
bool should_replace_current_entry,
+ jint user_agent_override_option,
const base::android::JavaRef<jobject>& j_initiator_origin,
bool has_user_gesture,
bool 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
@@ -3889,6 +3889,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/flat_set.h"
@@ -2425,8 +2426,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;
@@ -3880,6 +3879,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
@@ -231,6 +231,7 @@ import java.util.Map;
params.getCanLoadLocalResources(),
params.getIsRendererInitiated(),
params.getShouldReplaceCurrentEntry(),
+ params.getUserAgentOverrideOption(),
params.getInitiatorOrigin(),
params.getHasUserGesture(),
params.getShouldClearHistoryList(),
@@ -299,13 +300,13 @@ import java.util.Map;
public void setUseDesktopUserAgent(
boolean override, boolean reloadOnChange, boolean skipOnInitialNavigation) {
if (mNativeNavigationControllerAndroid != 0) {
- Log.i(
- TAG,
- "Thread dump for debugging, override: "
- + override
- + " reloadOnChange: "
- + reloadOnChange);
- Thread.dumpStack();
+ // Log.i(
+ // TAG,
+ // "Thread dump for debugging, override: "
+ // + override
+ // + " reloadOnChange: "
+ // + reloadOnChange);
+ // Thread.dumpStack();
NavigationControllerImplJni.get()
.setUseDesktopUserAgent(
@@ -480,7 +481,7 @@ import java.util.Map;
@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
@@ -832,7 +832,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);
--