User-agent-customization.patch 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275
  1. From: uazo <uazo@users.noreply.github.com>
  2. Date: Mon, 26 Oct 2020 16:50:15 +0000
  3. Subject: User agent customization
  4. Add flag to always view the desktop site for all websites
  5. Add possibility to define a custom User agent for mobile and desktop mode.
  6. Add possibility to reactivate the metatag view for desktop mode, allowing users to choose
  7. to use the flag in the hamburger menu to navigate with a custom useragent leaving the standard navigation unchanged.
  8. ---
  9. base/base_switches.cc | 2 +
  10. base/base_switches.h | 2 +
  11. chrome/android/chrome_java_resources.gni | 2 +
  12. chrome/android/chrome_java_sources.gni | 1 +
  13. .../layout/custom_useragent_preferences.xml | 108 ++++++++++
  14. .../android/java/res/xml/main_preferences.xml | 5 +
  15. .../java/res/xml/useragent_preferences.xml | 31 +++
  16. .../chrome/browser/app/ChromeActivity.java | 21 +-
  17. .../init/ChromeBrowserInitializer.java | 3 +
  18. .../PrivacyPreferencesManagerImpl.java | 42 ++++
  19. .../settings/UserAgentPreferences.java | 185 ++++++++++++++++++
  20. .../chromium/chrome/browser/tab/TabImpl.java | 83 +++++++-
  21. .../browser/android/content/content_utils.cc | 28 +++
  22. .../preferences/browser_prefs_android.cc | 7 +
  23. .../privacy_preferences_manager_impl.cc | 114 +++++++++++
  24. chrome/browser/android/tab_android.cc | 5 +-
  25. chrome/browser/android/tab_android.h | 3 +-
  26. .../browser/chrome_content_browser_client.cc | 8 +
  27. .../preferences/ChromePreferenceKeys.java | 7 +-
  28. .../settings/PrivacyPreferencesManager.java | 8 +
  29. .../org/chromium/chrome/browser/tab/Tab.java | 2 +
  30. .../browser/tabmodel/TabWindowManager.java | 8 +
  31. .../tabmodel/TabWindowManagerImpl.java | 18 ++
  32. .../strings/android_chrome_strings.grd | 35 ++++
  33. chrome/common/pref_names.cc | 13 ++
  34. chrome/common/pref_names.h | 8 +
  35. .../widget/RadioButtonWithEditText.java | 11 ++
  36. .../navigation_controller_android.cc | 6 +-
  37. .../navigation_controller_android.h | 3 +-
  38. .../renderer_host/render_process_host_impl.cc | 1 +
  39. .../browser/web_contents/web_contents_impl.cc | 4 +-
  40. .../framehost/NavigationControllerImpl.java | 6 +-
  41. content/renderer/render_thread_impl.cc | 1 -
  42. 33 files changed, 767 insertions(+), 14 deletions(-)
  43. create mode 100644 chrome/android/java/res/layout/custom_useragent_preferences.xml
  44. create mode 100644 chrome/android/java/res/xml/useragent_preferences.xml
  45. create mode 100644 chrome/android/java/src/org/chromium/chrome/browser/settings/UserAgentPreferences.java
  46. diff --git a/base/base_switches.cc b/base/base_switches.cc
  47. --- a/base/base_switches.cc
  48. +++ b/base/base_switches.cc
  49. @@ -164,6 +164,8 @@ const char kForceFieldTrialParams[] = "force-fieldtrial-params";
  50. const char kEnableThreadInstructionCount[] = "enable-thread-instruction-count";
  51. #endif
  52. +const char kDesktopModeViewportMetaEnabled[] = "dm-viewport-meta-enabled";
  53. +
  54. #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
  55. // Override the default scheduling boosting value for urgent tasks.
  56. // This can be adjusted if a specific chromeos device shows better perf/power
  57. diff --git a/base/base_switches.h b/base/base_switches.h
  58. --- a/base/base_switches.h
  59. +++ b/base/base_switches.h
  60. @@ -66,6 +66,8 @@ extern const char kEnableThreadInstructionCount[];
  61. extern const char kSchedulerBoostUrgent[];
  62. #endif
  63. +extern const char kDesktopModeViewportMetaEnabled[];
  64. +
  65. } // namespace switches
  66. #endif // BASE_BASE_SWITCHES_H_
  67. diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni
  68. --- a/chrome/android/chrome_java_resources.gni
  69. +++ b/chrome/android/chrome_java_resources.gni
  70. @@ -998,4 +998,6 @@ chrome_java_resources = [
  71. "java/res/xml/sync_and_services_preferences.xml",
  72. "java/res/xml/theme_preferences.xml",
  73. "java/res/xml/tracing_preferences.xml",
  74. + "java/res/xml/useragent_preferences.xml",
  75. + "java/res/layout/custom_useragent_preferences.xml",
  76. ]
  77. diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
  78. --- a/chrome/android/chrome_java_sources.gni
  79. +++ b/chrome/android/chrome_java_sources.gni
  80. @@ -1155,6 +1155,7 @@ chrome_java_sources = [
  81. "java/src/org/chromium/chrome/browser/payments/ui/DimmingDialog.java",
  82. "java/src/org/chromium/chrome/browser/payments/ui/LineItem.java",
  83. "java/src/org/chromium/chrome/browser/payments/ui/PaymentAppComparator.java",
  84. + "java/src/org/chromium/chrome/browser/settings/UserAgentPreferences.java",
  85. "java/src/org/chromium/chrome/browser/payments/ui/PaymentInformation.java",
  86. "java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestBottomBar.java",
  87. "java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestHeader.java",
  88. diff --git a/chrome/android/java/res/layout/custom_useragent_preferences.xml b/chrome/android/java/res/layout/custom_useragent_preferences.xml
  89. new file mode 100644
  90. --- /dev/null
  91. +++ b/chrome/android/java/res/layout/custom_useragent_preferences.xml
  92. @@ -0,0 +1,108 @@
  93. +<?xml version="1.0" encoding="utf-8"?>
  94. +<!--
  95. + This file is part of Bromite.
  96. +
  97. + Bromite is free software: you can redistribute it and/or modify
  98. + it under the terms of the GNU General Public License as published by
  99. + the Free Software Foundation, either version 3 of the License, or
  100. + (at your option) any later version.
  101. +
  102. + Bromite is distributed in the hope that it will be useful,
  103. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  104. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  105. + GNU General Public License for more details.
  106. +
  107. + You should have received a copy of the GNU General Public License
  108. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  109. +-->
  110. +
  111. +<!-- Layout used by the UserAgentPreferences. -->
  112. +
  113. +<ScrollView
  114. + xmlns:android="http://schemas.android.com/apk/res/android"
  115. + xmlns:app="http://schemas.android.com/apk/res-auto"
  116. + android:layout_weight="0"
  117. + android:gravity="top"
  118. + android:layout_width="match_parent"
  119. + android:layout_height="wrap_content">
  120. +
  121. + <LinearLayout
  122. + android:layout_width="match_parent"
  123. + android:layout_height="wrap_content"
  124. + android:focusable="false"
  125. + android:orientation="vertical"
  126. + android:divider="?android:dividerHorizontal">
  127. +
  128. + <TextView
  129. + android:layout_width="match_parent"
  130. + android:layout_height="wrap_content"
  131. + android:textAppearance="@style/TextAppearance.AccessibilityTextPreference"
  132. + android:background="@color/default_bg_color_secondary"
  133. + android:padding="16dp"
  134. + android:text="@string/custom_ua_text"/>
  135. +
  136. + <org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionLayout
  137. + android:id="@+id/ua_radio_button_layout"
  138. + android:layout_width="match_parent"
  139. + android:layout_height="wrap_content">
  140. +
  141. + <org.chromium.components.browser_ui.widget.RadioButtonWithDescription
  142. + android:id="@+id/default_ua_switch"
  143. + android:layout_width="match_parent"
  144. + android:layout_height="wrap_content"
  145. + android:paddingStart="?android:attr/listPreferredItemPaddingStart"
  146. + app:primaryText="@string/custom_ua_flag_off" />
  147. +
  148. + <org.chromium.components.browser_ui.widget.RadioButtonWithEditText
  149. + android:id="@+id/custom_ua_switch"
  150. + android:layout_width="match_parent"
  151. + android:layout_height="wrap_content"
  152. + android:paddingStart="?android:attr/listPreferredItemPaddingStart"
  153. + android:inputType="text"
  154. + android:hint="@string/custom_ua_placeholder"
  155. + app:descriptionText="@string/custom_ua_flag_on" />
  156. +
  157. + </org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionLayout>
  158. +
  159. + <TextView
  160. + android:layout_width="match_parent"
  161. + android:layout_height="wrap_content"
  162. + android:textAppearance="@style/TextAppearance.AccessibilityTextPreference"
  163. + android:background="@color/default_bg_color_secondary"
  164. + android:padding="16dp"
  165. + android:text="@string/custom_desktop_ua_text"/>
  166. +
  167. + <org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionLayout
  168. + android:id="@+id/ua_radio_button_layout_dm"
  169. + android:layout_width="match_parent"
  170. + android:layout_height="wrap_content">
  171. +
  172. + <org.chromium.components.browser_ui.widget.RadioButtonWithDescription
  173. + android:id="@+id/default_ua_switch_dm"
  174. + android:layout_width="match_parent"
  175. + android:layout_height="wrap_content"
  176. + android:paddingStart="?android:attr/listPreferredItemPaddingStart"
  177. + app:primaryText="@string/custom_ua_flag_off" />
  178. +
  179. + <org.chromium.components.browser_ui.widget.RadioButtonWithEditText
  180. + android:id="@+id/custom_ua_switch_dm"
  181. + android:layout_width="match_parent"
  182. + android:layout_height="wrap_content"
  183. + android:paddingStart="?android:attr/listPreferredItemPaddingStart"
  184. + android:inputType="text"
  185. + android:hint="@string/custom_ua_placeholder"
  186. + app:descriptionText="@string/custom_ua_flag_on" />
  187. +
  188. + </org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionLayout>
  189. +
  190. + <CheckBox
  191. + android:id="@+id/desktop_mode_viewportmeta"
  192. + android:layout_width="wrap_content"
  193. + android:layout_height="wrap_content"
  194. + android:layout_centerVertical="true"
  195. + android:layout_marginLeft="?android:attr/listPreferredItemPaddingStart"
  196. + android:text="@string/desktop_mode_viewportmeta_checkbox" />
  197. +
  198. + </LinearLayout>
  199. +
  200. +</ScrollView>
  201. diff --git a/chrome/android/java/res/xml/main_preferences.xml b/chrome/android/java/res/xml/main_preferences.xml
  202. --- a/chrome/android/java/res/xml/main_preferences.xml
  203. +++ b/chrome/android/java/res/xml/main_preferences.xml
  204. @@ -101,6 +101,11 @@
  205. android:key="content_settings"
  206. android:order="19"
  207. android:title="@string/prefs_site_settings"/>
  208. + <Preference
  209. + android:fragment="org.chromium.chrome.browser.settings.UserAgentPreferences"
  210. + android:key="useragent_settings"
  211. + android:order="20"
  212. + android:title="@string/prefs_useragent_settings"/>
  213. <Preference
  214. android:fragment="org.chromium.chrome.browser.language.settings.LanguageSettings"
  215. android:key="languages"
  216. diff --git a/chrome/android/java/res/xml/useragent_preferences.xml b/chrome/android/java/res/xml/useragent_preferences.xml
  217. new file mode 100644
  218. --- /dev/null
  219. +++ b/chrome/android/java/res/xml/useragent_preferences.xml
  220. @@ -0,0 +1,31 @@
  221. +<?xml version="1.0" encoding="utf-8"?>
  222. +<!--
  223. + This file is part of Bromite.
  224. +
  225. + Bromite is free software: you can redistribute it and/or modify
  226. + it under the terms of the GNU General Public License as published by
  227. + the Free Software Foundation, either version 3 of the License, or
  228. + (at your option) any later version.
  229. +
  230. + Bromite is distributed in the hope that it will be useful,
  231. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  232. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  233. + GNU General Public License for more details.
  234. +
  235. + You should have received a copy of the GNU General Public License
  236. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  237. +-->
  238. +
  239. +<!-- Layout used by the UserAgentPreferences. -->
  240. +
  241. +<PreferenceScreen
  242. + xmlns:android="http://schemas.android.com/apk/res/android"
  243. + xmlns:app="http://schemas.android.com/apk/res-auto">
  244. +
  245. + <org.chromium.components.browser_ui.settings.ChromeSwitchPreference
  246. + android:key="desktop_mode_switch"
  247. + android:title="@string/option_desktop_flag"
  248. + android:summaryOn="@string/option_desktop_flag_on"
  249. + android:summaryOff="@string/option_desktop_flag_off" />
  250. +
  251. +</PreferenceScreen>
  252. 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
  253. --- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
  254. +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
  255. @@ -72,6 +72,7 @@ import org.chromium.chrome.browser.app.flags.ChromeCachedFlags;
  256. import org.chromium.chrome.browser.app.tab_activity_glue.ReparentingDelegateFactory;
  257. import org.chromium.chrome.browser.app.tab_activity_glue.TabReparentingController;
  258. import org.chromium.chrome.browser.app.tabmodel.AsyncTabParamsManagerSingleton;
  259. +import org.chromium.chrome.browser.app.tabmodel.TabWindowManagerSingleton;
  260. import org.chromium.chrome.browser.bookmarks.BookmarkBridge;
  261. import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkItem;
  262. import org.chromium.chrome.browser.bookmarks.BookmarkModel;
  263. @@ -209,6 +210,13 @@ import org.chromium.ui.widget.Toast;
  264. import org.chromium.url.GURL;
  265. import org.chromium.url.Origin;
  266. import org.chromium.webapk.lib.client.WebApkNavigationClient;
  267. +import org.chromium.chrome.browser.tabmodel.TabWindowManager;
  268. +import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
  269. +import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
  270. +
  271. +import org.chromium.chrome.browser.tabmodel.TabWindowManager;
  272. +import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
  273. +import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
  274. import org.chromium.url.GURL;
  275. @@ -2102,11 +2110,18 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
  276. } else if (id == R.id.view_source_id) {
  277. currentTab.getWebContents().getNavigationController().loadUrl(new LoadUrlParams("view-source:"+currentTab.getUrlString()));
  278. } else if (id == R.id.request_desktop_site_id || id == R.id.request_desktop_site_check_id) {
  279. - final boolean reloadOnChange = !currentTab.isNativePage();
  280. final boolean usingDesktopUserAgent =
  281. currentTab.getWebContents().getNavigationController().getUseDesktopUserAgent();
  282. - currentTab.getWebContents().getNavigationController().setUseDesktopUserAgent(
  283. - !usingDesktopUserAgent, reloadOnChange);
  284. + SharedPreferencesManager.getInstance().writeBoolean(
  285. + ChromePreferenceKeys.USERAGENT_ALWAYS_DESKTOP_MODE, !usingDesktopUserAgent);
  286. +
  287. + final boolean stickyDesktopModeEnabled = SharedPreferencesManager.getInstance().readBoolean(
  288. + ChromePreferenceKeys.USERAGENT_STICKY_DESKTOP_MODE, false);
  289. + if (stickyDesktopModeEnabled) {
  290. + TabWindowManagerSingleton.getInstance().SetOverrideUserAgentForAllTabs(!usingDesktopUserAgent);
  291. + } else {
  292. + currentTab.SetOverrideUserAgent(!usingDesktopUserAgent);
  293. + }
  294. RecordUserAction.record("MobileMenuRequestDesktopSite");
  295. } else if (id == R.id.reader_mode_prefs_id) {
  296. DomDistillerUIUtils.openSettings(currentTab.getWebContents());
  297. 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
  298. --- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
  299. +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
  300. @@ -47,6 +47,7 @@ import org.chromium.content_public.browser.SpeechRecognition;
  301. import org.chromium.content_public.browser.UiThreadTaskTraits;
  302. import org.chromium.net.NetworkChangeNotifier;
  303. import org.chromium.ui.resources.ResourceExtractor;
  304. +import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManagerImpl;
  305. import java.io.File;
  306. import java.util.ArrayList;
  307. @@ -322,11 +323,13 @@ public class ChromeBrowserInitializer {
  308. @Override
  309. public void onSuccess() {
  310. + PrivacyPreferencesManagerImpl.getInstance().updateOverrideUserAgent();
  311. tasks.start(false);
  312. }
  313. });
  314. } else {
  315. startChromeBrowserProcessesSync();
  316. + PrivacyPreferencesManagerImpl.getInstance().updateOverrideUserAgent();
  317. tasks.start(true);
  318. }
  319. }
  320. 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
  321. --- a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacyPreferencesManagerImpl.java
  322. +++ b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacyPreferencesManagerImpl.java
  323. @@ -162,6 +162,41 @@ public class PrivacyPreferencesManagerImpl implements PrivacyPreferencesManager
  324. return PrivacyPreferencesManagerImplJni.get().getNetworkPredictionManaged();
  325. }
  326. + @Override
  327. + public void updateOverrideUserAgent() {
  328. + PrivacyPreferencesManagerImplJni.get().updateOverrideUserAgent();
  329. + }
  330. +
  331. + @Override
  332. + public boolean isOverrideUserAgentEnabled(boolean desktopMode) {
  333. + return PrivacyPreferencesManagerImplJni.get().isOverrideUserAgentEnabled(desktopMode);
  334. + }
  335. +
  336. + @Override
  337. + public void setOverrideUserAgentEnabled(boolean enabled, boolean desktopMode) {
  338. + PrivacyPreferencesManagerImplJni.get().setOverrideUserAgentEnabled(enabled, desktopMode);
  339. + }
  340. +
  341. + @Override
  342. + public String getOverrideUserAgentValue(boolean desktopMode) {
  343. + return PrivacyPreferencesManagerImplJni.get().getOverrideUserAgentValue(desktopMode);
  344. + }
  345. +
  346. + @Override
  347. + public void setOverrideUserAgentValue(String user_agent, boolean desktopMode) {
  348. + PrivacyPreferencesManagerImplJni.get().setOverrideUserAgentValue(user_agent, desktopMode);
  349. + }
  350. +
  351. + @Override
  352. + public boolean isDesktopModeViewportMetaEnabled() {
  353. + return PrivacyPreferencesManagerImplJni.get().isDesktopModeViewportMetaEnabled();
  354. + }
  355. +
  356. + @Override
  357. + public void setDesktopModeViewportMetaEnabled(boolean enabled) {
  358. + PrivacyPreferencesManagerImplJni.get().setDesktopModeViewportMetaEnabled(enabled);
  359. + }
  360. +
  361. @NativeMethods
  362. public interface Natives {
  363. boolean canPrefetchAndPrerender();
  364. @@ -171,5 +206,12 @@ public class PrivacyPreferencesManagerImpl implements PrivacyPreferencesManager
  365. boolean isMetricsReportingEnabled();
  366. void setMetricsReportingEnabled(boolean enabled);
  367. boolean isMetricsReportingManaged();
  368. + void updateOverrideUserAgent();
  369. + boolean isOverrideUserAgentEnabled(boolean desktopMode);
  370. + void setOverrideUserAgentEnabled(boolean enabled, boolean desktopMode);
  371. + String getOverrideUserAgentValue(boolean desktopMode);
  372. + void setOverrideUserAgentValue(String timezone, boolean desktopMode);
  373. + boolean isDesktopModeViewportMetaEnabled();
  374. + void setDesktopModeViewportMetaEnabled(boolean enabled);
  375. }
  376. }
  377. 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
  378. new file mode 100644
  379. --- /dev/null
  380. +++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/UserAgentPreferences.java
  381. @@ -0,0 +1,185 @@
  382. +/*
  383. + This file is part of Bromite.
  384. +
  385. + Bromite is free software: you can redistribute it and/or modify
  386. + it under the terms of the GNU General Public License as published by
  387. + the Free Software Foundation, either version 3 of the License, or
  388. + (at your option) any later version.
  389. +
  390. + Bromite is distributed in the hope that it will be useful,
  391. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  392. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  393. + GNU General Public License for more details.
  394. +
  395. + You should have received a copy of the GNU General Public License
  396. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  397. +*/
  398. +
  399. +package org.chromium.chrome.browser.settings;
  400. +
  401. +import android.os.Bundle;
  402. +import androidx.preference.Preference;
  403. +import androidx.preference.PreferenceFragmentCompat;
  404. +import androidx.preference.PreferenceViewHolder;
  405. +import androidx.annotation.NonNull;
  406. +import androidx.annotation.Nullable;
  407. +import android.view.LayoutInflater;
  408. +import android.widget.RadioGroup;
  409. +import android.content.Context;
  410. +import android.util.AttributeSet;
  411. +import android.view.View;
  412. +import android.view.ViewGroup;
  413. +import android.widget.LinearLayout;
  414. +import android.widget.ScrollView;
  415. +import android.widget.CheckBox;
  416. +import android.widget.CompoundButton;
  417. +import androidx.recyclerview.widget.RecyclerView;
  418. +
  419. +import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
  420. +import org.chromium.components.browser_ui.widget.RadioButtonWithDescription;
  421. +import org.chromium.components.browser_ui.widget.RadioButtonWithEditText;
  422. +import org.chromium.components.browser_ui.settings.SettingsUtils;
  423. +
  424. +import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
  425. +import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
  426. +
  427. +import org.chromium.chrome.browser.app.tabmodel.TabWindowManagerSingleton;
  428. +import org.chromium.chrome.browser.tabmodel.TabWindowManager;
  429. +import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManagerImpl;
  430. +import org.chromium.chrome.R;
  431. +
  432. +/**
  433. + * Fragment that allows the user to configure User Agent related preferences.
  434. + */
  435. +public class UserAgentPreferences
  436. + extends PreferenceFragmentCompat implements RadioGroup.OnCheckedChangeListener {
  437. +
  438. + private static final String PREF_STICK_DESKTOP_MODE_SWITCH = "desktop_mode_switch";
  439. + private RadioButtonWithDescription useDefaultAgentSwitch;
  440. + private RadioButtonWithEditText useCustomAgentSwitch;
  441. + private RadioButtonWithDescription useDefaultAgentSwitchDesktopMode;
  442. + private RadioButtonWithEditText useCustomAgentSwitchDesktopMode;
  443. + private RadioGroup mRadioGroup;
  444. + private RadioGroup mRadioGroupDesktopMode;
  445. + private CheckBox mDesktopModeViewportmeta;
  446. +
  447. + @Override
  448. + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
  449. + getActivity().setTitle(R.string.useragent_settings_title);
  450. + SettingsUtils.addPreferencesFromResource(this, R.xml.useragent_preferences);
  451. +
  452. + ChromeSwitchPreference alwaysDesktopModeSwitch =
  453. + (ChromeSwitchPreference) findPreference(PREF_STICK_DESKTOP_MODE_SWITCH);
  454. + boolean enabled = SharedPreferencesManager.getInstance().readBoolean(
  455. + ChromePreferenceKeys.USERAGENT_STICKY_DESKTOP_MODE, false);
  456. + alwaysDesktopModeSwitch.setChecked(enabled);
  457. + alwaysDesktopModeSwitch.setOnPreferenceChangeListener((preference, newValue) -> {
  458. + SharedPreferencesManager.getInstance().writeBoolean(
  459. + ChromePreferenceKeys.USERAGENT_STICKY_DESKTOP_MODE, (boolean) newValue);
  460. + UpdateAllTabs();
  461. + return true;
  462. + });
  463. + }
  464. +
  465. + @Override
  466. + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
  467. + @Nullable Bundle savedInstanceState) {
  468. + LinearLayout viewGroup = (LinearLayout) super.onCreateView(inflater, container, savedInstanceState);
  469. + ScrollView view = (ScrollView) inflater.inflate(R.layout.custom_useragent_preferences, viewGroup, false);
  470. + viewGroup.addView(view);
  471. +
  472. + boolean enabledCustomUA = PrivacyPreferencesManagerImpl.getInstance().isOverrideUserAgentEnabled(false);
  473. + boolean enabledCustomUADesktopMode = PrivacyPreferencesManagerImpl.getInstance().isOverrideUserAgentEnabled(true);
  474. + boolean enabledDesktopModeViewportmeta = PrivacyPreferencesManagerImpl.getInstance().isDesktopModeViewportMetaEnabled();
  475. +
  476. + useDefaultAgentSwitch =
  477. + (RadioButtonWithDescription) view.findViewById(R.id.default_ua_switch);
  478. + useCustomAgentSwitch =
  479. + (RadioButtonWithEditText) view.findViewById(R.id.custom_ua_switch);
  480. + useDefaultAgentSwitchDesktopMode =
  481. + (RadioButtonWithDescription) view.findViewById(R.id.default_ua_switch_dm);
  482. + useCustomAgentSwitchDesktopMode =
  483. + (RadioButtonWithEditText) view.findViewById(R.id.custom_ua_switch_dm);
  484. +
  485. + mRadioGroup = (RadioGroup) view.findViewById(R.id.ua_radio_button_layout);
  486. + mRadioGroup.setOnCheckedChangeListener(this);
  487. +
  488. + mRadioGroupDesktopMode = (RadioGroup) view.findViewById(R.id.ua_radio_button_layout_dm);
  489. + mRadioGroupDesktopMode.setOnCheckedChangeListener(this);
  490. +
  491. + mDesktopModeViewportmeta = (CheckBox) view.findViewById(R.id.desktop_mode_viewportmeta);
  492. + mDesktopModeViewportmeta.setChecked(enabledDesktopModeViewportmeta);
  493. + mDesktopModeViewportmeta.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
  494. + @Override
  495. + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
  496. + PrivacyPreferencesManagerImpl.getInstance().setDesktopModeViewportMetaEnabled(
  497. + mDesktopModeViewportmeta.isChecked());
  498. + }
  499. + });
  500. +
  501. + useDefaultAgentSwitch.setChecked(!enabledCustomUA);
  502. + useCustomAgentSwitch.setChecked(enabledCustomUA);
  503. +
  504. + useDefaultAgentSwitchDesktopMode.setChecked(!enabledCustomUADesktopMode);
  505. + useCustomAgentSwitchDesktopMode.setChecked(enabledCustomUADesktopMode);
  506. +
  507. + useCustomAgentSwitch.setPrimaryText(
  508. + PrivacyPreferencesManagerImpl.getInstance().getOverrideUserAgentValue(false));
  509. + useCustomAgentSwitch.addTextChangeListener(new RadioButtonWithEditText.OnTextChangeListener() {
  510. + @Override
  511. + public void onTextChanged(CharSequence newText) {
  512. + PrivacyPreferencesManagerImpl.getInstance().setOverrideUserAgentValue(
  513. + newText.toString(), false);
  514. + }
  515. + });
  516. + useCustomAgentSwitch.setFocusChangeListener( hasFocus -> {
  517. + if( hasFocus )
  518. + PrivacyPreferencesManagerImpl.getInstance().setOverrideUserAgentEnabled(true, false);
  519. + });
  520. +
  521. + useCustomAgentSwitchDesktopMode.setPrimaryText(
  522. + PrivacyPreferencesManagerImpl.getInstance().getOverrideUserAgentValue(true));
  523. + useCustomAgentSwitchDesktopMode.addTextChangeListener(new RadioButtonWithEditText.OnTextChangeListener() {
  524. + @Override
  525. + public void onTextChanged(CharSequence newText) {
  526. + PrivacyPreferencesManagerImpl.getInstance().setOverrideUserAgentValue(
  527. + newText.toString(), true);
  528. + }
  529. + });
  530. + useCustomAgentSwitchDesktopMode.setFocusChangeListener( hasFocus -> {
  531. + if( hasFocus )
  532. + PrivacyPreferencesManagerImpl.getInstance().setOverrideUserAgentEnabled(true, true);
  533. + });
  534. +
  535. + return viewGroup;
  536. + }
  537. +
  538. + private void UpdateAllTabs() {
  539. + final boolean alwaysDesktopModeEnabled = SharedPreferencesManager.getInstance().readBoolean(
  540. + ChromePreferenceKeys.USERAGENT_ALWAYS_DESKTOP_MODE, false);
  541. + TabWindowManagerSingleton.getInstance().SetOverrideUserAgentForAllTabs(alwaysDesktopModeEnabled);
  542. + }
  543. +
  544. + @Override
  545. + public void onCheckedChanged(RadioGroup group, int checkedId) {
  546. + if (useDefaultAgentSwitch.isChecked()) {
  547. + PrivacyPreferencesManagerImpl.getInstance().setOverrideUserAgentEnabled(false, false);
  548. + } else if (useCustomAgentSwitch.isChecked()) {
  549. + PrivacyPreferencesManagerImpl.getInstance().setOverrideUserAgentEnabled(true, false);
  550. + }
  551. +
  552. + if (useDefaultAgentSwitchDesktopMode.isChecked()) {
  553. + PrivacyPreferencesManagerImpl.getInstance().setOverrideUserAgentEnabled(false, true);
  554. + } else if (useCustomAgentSwitchDesktopMode.isChecked()) {
  555. + PrivacyPreferencesManagerImpl.getInstance().setOverrideUserAgentEnabled(true, true);
  556. + }
  557. +
  558. + UpdateAllTabs();
  559. + }
  560. +
  561. + @Override
  562. + public void onStop() {
  563. + super.onStop();
  564. + UpdateAllTabs();
  565. + }
  566. +}
  567. 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
  568. --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
  569. +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
  570. @@ -61,6 +61,18 @@ import org.chromium.ui.base.WindowAndroid;
  571. import org.chromium.ui.util.ColorUtils;
  572. import org.chromium.url.GURL;
  573. import org.chromium.url.Origin;
  574. +import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
  575. +import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
  576. +import org.chromium.content_public.browser.navigation_controller.UserAgentOverrideOption;
  577. +import org.chromium.content_public.browser.NavigationController;
  578. +import org.chromium.components.embedder_support.util.UrlUtilities;
  579. +import org.chromium.components.url_formatter.UrlFormatter;
  580. +import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
  581. +import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
  582. +import org.chromium.content_public.browser.navigation_controller.UserAgentOverrideOption;
  583. +import org.chromium.content_public.browser.NavigationController;
  584. +import org.chromium.components.embedder_support.util.UrlUtilities;
  585. +import org.chromium.components.url_formatter.UrlFormatter;
  586. /**
  587. * Implementation of the interface {@link Tab}. Contains and manages a {@link ContentView}.
  588. @@ -481,6 +493,31 @@ public class TabImpl implements Tab, TabObscuringHandler.Observer {
  589. throw new RuntimeException("Tab.loadUrl called when no native side exists");
  590. }
  591. + final boolean stickyDesktopModeEnabled = SharedPreferencesManager.getInstance().readBoolean(
  592. + ChromePreferenceKeys.USERAGENT_STICKY_DESKTOP_MODE, false);
  593. + if (stickyDesktopModeEnabled) {
  594. + boolean alwaysDesktopModeEnabled = SharedPreferencesManager.getInstance().readBoolean(
  595. + ChromePreferenceKeys.USERAGENT_ALWAYS_DESKTOP_MODE, false);
  596. +
  597. + if (UrlUtilities.isInternalScheme(UrlFormatter.fixupUrl(params.getUrl()))) {
  598. + alwaysDesktopModeEnabled = false;
  599. + }
  600. +
  601. + WebContents webContents = this.getWebContents();
  602. + if (webContents != null) {
  603. + NavigationController navigationController = webContents.getNavigationController();
  604. + boolean currentUseDesktopUserAgent = navigationController.getUseDesktopUserAgent();
  605. + if (currentUseDesktopUserAgent != alwaysDesktopModeEnabled)
  606. + navigationController.setUseDesktopUserAgent(alwaysDesktopModeEnabled, false);
  607. + }
  608. +
  609. + if (alwaysDesktopModeEnabled) {
  610. + params.setOverrideUserAgent((int)UserAgentOverrideOption.TRUE);
  611. + } else {
  612. + params.setOverrideUserAgent((int)UserAgentOverrideOption.FALSE);
  613. + }
  614. + }
  615. +
  616. // We load the URL from the tab rather than directly from the ContentView so the tab has
  617. // a chance of using a prerenderer page is any.
  618. int loadType = TabImplJni.get().loadUrl(mNativeTabAndroid, params.getUrl(),
  619. @@ -493,7 +530,8 @@ public class TabImpl implements Tab, TabObscuringHandler.Observer {
  620. params.getReferrer() != null ? params.getReferrer().getPolicy() : 0,
  621. params.getIsRendererInitiated(), params.getShouldReplaceCurrentEntry(),
  622. params.getHasUserGesture(), params.getShouldClearHistoryList(),
  623. - params.getInputStartTimestamp(), params.getIntentReceivedTimestamp());
  624. + params.getInputStartTimestamp(), params.getIntentReceivedTimestamp(),
  625. + params.getUserAgentOverrideOption());
  626. for (TabObserver observer : mObservers) {
  627. observer.onLoadUrl(this, params, loadType);
  628. @@ -1477,6 +1515,10 @@ public class TabImpl implements Tab, TabObscuringHandler.Observer {
  629. if (mWebContents != null) mWebContents.getNavigationController().loadIfNecessary();
  630. mIsBeingRestored = true;
  631. for (TabObserver observer : mObservers) observer.onRestoreStarted(this);
  632. +
  633. + if(overrideUserAgentWhenUnFrozen != UserAgentOverrideOption.INHERIT) {
  634. + SetOverrideUserAgent(overrideUserAgentWhenUnFrozen == (int)UserAgentOverrideOption.TRUE ? true : false);
  635. + }
  636. } finally {
  637. TraceEvent.end("Tab.restoreIfNeeded");
  638. }
  639. @@ -1596,6 +1638,42 @@ public class TabImpl implements Tab, TabObscuringHandler.Observer {
  640. }
  641. }
  642. + int overrideUserAgentWhenUnFrozen = (int)UserAgentOverrideOption.INHERIT;
  643. +
  644. + public void SetOverrideUserAgent(boolean usingDesktopUserAgent) {
  645. + WebContents webContents = this.getWebContents();
  646. + overrideUserAgentWhenUnFrozen = UserAgentOverrideOption.INHERIT;
  647. +
  648. + if (usingDesktopUserAgent) {
  649. + GURL url = this.getUrl();
  650. + if (webContents == null && this.getPendingLoadParams() != null) {
  651. + url = UrlFormatter.fixupUrl(this.getPendingLoadParams().getUrl());
  652. + }
  653. + if (UrlUtilities.isInternalScheme(url) == true)
  654. + usingDesktopUserAgent = false;
  655. + }
  656. +
  657. + if (webContents != null) {
  658. + ContentUtils.setUserAgentOverride(webContents);
  659. +
  660. + NavigationController navigationController = webContents.getNavigationController();
  661. + navigationController.setUseDesktopUserAgent(
  662. + usingDesktopUserAgent, !this.isNativePage());
  663. + }
  664. + else if (this.getPendingLoadParams() != null) {
  665. + if (usingDesktopUserAgent) {
  666. + this.getPendingLoadParams().setOverrideUserAgent((int)UserAgentOverrideOption.TRUE);
  667. + }
  668. + else {
  669. + this.getPendingLoadParams().setOverrideUserAgent((int)UserAgentOverrideOption.FALSE);
  670. + }
  671. + }
  672. + else {
  673. + overrideUserAgentWhenUnFrozen = usingDesktopUserAgent ? UserAgentOverrideOption.TRUE :
  674. + UserAgentOverrideOption.FALSE;
  675. + }
  676. + }
  677. +
  678. @NativeMethods
  679. interface Natives {
  680. TabImpl fromWebContents(WebContents webContents);
  681. @@ -1615,7 +1693,8 @@ public class TabImpl implements Tab, TabObscuringHandler.Observer {
  682. ResourceRequestBody postData, int transition, String referrerUrl,
  683. int referrerPolicy, boolean isRendererInitiated, boolean shoulReplaceCurrentEntry,
  684. boolean hasUserGesture, boolean shouldClearHistoryList, long inputStartTimestamp,
  685. - long intentReceivedTimestamp);
  686. + long intentReceivedTimestamp,
  687. + int userAgentOverrideOption);
  688. void setActiveNavigationEntryTitleForUrl(long nativeTabAndroid, String url, String title);
  689. void loadOriginalImage(long nativeTabAndroid);
  690. void setAddApi2TransitionToFutureNavigations(long nativeTabAndroid, boolean shouldAdd);
  691. diff --git a/chrome/browser/android/content/content_utils.cc b/chrome/browser/android/content/content_utils.cc
  692. --- a/chrome/browser/android/content/content_utils.cc
  693. +++ b/chrome/browser/android/content/content_utils.cc
  694. @@ -8,6 +8,20 @@
  695. #include "components/embedder_support/android/util/user_agent_utils.h"
  696. #include "components/version_info/version_info.h"
  697. +#include "base/android/jni_android.h"
  698. +#include "base/android/scoped_java_ref.h"
  699. +#include "chrome/browser/browser_process.h"
  700. +#include "components/prefs/pref_service.h"
  701. +#include "chrome/common/pref_names.h"
  702. +
  703. +using base::android::ConvertJavaStringToUTF8;
  704. +using base::android::ConvertUTF16ToJavaString;
  705. +using base::android::ConvertUTF8ToJavaString;
  706. +using base::android::JavaParamRef;
  707. +using base::android::JavaRef;
  708. +using base::android::ScopedJavaGlobalRef;
  709. +using base::android::ScopedJavaLocalRef;
  710. +
  711. static base::android::ScopedJavaLocalRef<jstring>
  712. JNI_ContentUtils_GetBrowserUserAgent(JNIEnv* env) {
  713. return base::android::ConvertUTF8ToJavaString(env, GetUserAgent());
  714. @@ -16,6 +30,20 @@ JNI_ContentUtils_GetBrowserUserAgent(JNIEnv* env) {
  715. static void JNI_ContentUtils_SetUserAgentOverride(
  716. JNIEnv* env,
  717. const base::android::JavaParamRef<jobject>& jweb_contents) {
  718. + bool enabled =
  719. + g_browser_process->local_state()->GetBoolean(prefs::kOverrideUserAgentDesktopModeEnabled);
  720. +
  721. + if (enabled == true) {
  722. + std::string ua = g_browser_process->local_state()->GetString(prefs::kOverrideUserAgentDesktopMode);
  723. + blink::UserAgentOverride spoofed_ua;
  724. + spoofed_ua.ua_string_override = ua;
  725. +
  726. + content::WebContents* web_contents =
  727. + content::WebContents::FromJavaWebContents(jweb_contents);
  728. + web_contents->SetUserAgentOverride(spoofed_ua, false);
  729. + return;
  730. + }
  731. +
  732. content::WebContents* web_contents =
  733. content::WebContents::FromJavaWebContents(jweb_contents);
  734. embedder_support::SetDesktopUserAgentOverride(web_contents,
  735. diff --git a/chrome/browser/android/preferences/browser_prefs_android.cc b/chrome/browser/android/preferences/browser_prefs_android.cc
  736. --- a/chrome/browser/android/preferences/browser_prefs_android.cc
  737. +++ b/chrome/browser/android/preferences/browser_prefs_android.cc
  738. @@ -10,11 +10,18 @@
  739. #include "chrome/browser/notifications/notification_platform_bridge_android.h"
  740. #include "components/pref_registry/pref_registry_syncable.h"
  741. #include "components/prefs/pref_registry_simple.h"
  742. +#include "chrome/common/pref_names.h"
  743. namespace android {
  744. void RegisterPrefs(PrefRegistrySimple* registry) {
  745. RegisterClipboardAndroidPrefs(registry);
  746. +
  747. + registry->RegisterBooleanPref(prefs::kOverrideUserAgentEnabled, false);
  748. + registry->RegisterStringPref(prefs::kOverrideUserAgent, "");
  749. + registry->RegisterBooleanPref(prefs::kOverrideUserAgentDesktopModeEnabled, false);
  750. + registry->RegisterStringPref(prefs::kOverrideUserAgentDesktopMode, "");
  751. + registry->RegisterBooleanPref(prefs::kDesktopModeViewportMetaEnabled, false);
  752. }
  753. void RegisterUserProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
  754. diff --git a/chrome/browser/android/preferences/privacy_preferences_manager_impl.cc b/chrome/browser/android/preferences/privacy_preferences_manager_impl.cc
  755. --- a/chrome/browser/android/preferences/privacy_preferences_manager_impl.cc
  756. +++ b/chrome/browser/android/preferences/privacy_preferences_manager_impl.cc
  757. @@ -12,6 +12,26 @@
  758. #include "components/metrics/metrics_pref_names.h"
  759. #include "components/prefs/pref_service.h"
  760. +#include "base/command_line.h"
  761. +#include "base/base_switches.h"
  762. +#include "chrome/common/chrome_switches.h"
  763. +#include "content/browser/renderer_host/render_process_host_impl.h"
  764. +#include "content/common/renderer.mojom.h"
  765. +#include "chrome/browser/chrome_content_browser_client.h"
  766. +
  767. +#include "base/android/jni_android.h"
  768. +#include "base/android/jni_array.h"
  769. +#include "base/android/jni_string.h"
  770. +#include "base/android/scoped_java_ref.h"
  771. +
  772. +using base::android::ConvertJavaStringToUTF8;
  773. +using base::android::ConvertUTF16ToJavaString;
  774. +using base::android::ConvertUTF8ToJavaString;
  775. +using base::android::JavaParamRef;
  776. +using base::android::JavaRef;
  777. +using base::android::ScopedJavaGlobalRef;
  778. +using base::android::ScopedJavaLocalRef;
  779. +
  780. namespace {
  781. PrefService* GetPrefService() {
  782. @@ -67,3 +87,97 @@ static void JNI_PrivacyPreferencesManagerImpl_SetNetworkPredictionEnabled(
  783. enabled ? chrome_browser_net::NETWORK_PREDICTION_WIFI_ONLY
  784. : chrome_browser_net::NETWORK_PREDICTION_NEVER);
  785. }
  786. +
  787. +static void UpdateOverrideUserAgent() {
  788. + bool overrideUserAgentEnabled =
  789. + g_browser_process->local_state()->GetBoolean(prefs::kOverrideUserAgentEnabled);
  790. + std::string ua = g_browser_process->local_state()->GetString(prefs::kOverrideUserAgent);
  791. + if (ua.empty()) {
  792. + ua = ChromeContentBrowserClient().GetUserAgent();
  793. + }
  794. +
  795. + base::CommandLine* parsed_command_line =
  796. + base::CommandLine::ForCurrentProcess();
  797. + parsed_command_line->RemoveSwitch(switches::kUserAgent);
  798. + if (!ua.empty()) {
  799. + if (overrideUserAgentEnabled) {
  800. + parsed_command_line->AppendSwitchASCII(switches::kUserAgent, ua);
  801. + }
  802. +
  803. + for (auto iter = content::RenderProcessHost::AllHostsIterator(); !iter.IsAtEnd();
  804. + iter.Advance()) {
  805. + if (iter.GetCurrentValue()->IsInitializedAndNotDead()) {
  806. + iter.GetCurrentValue()->GetRendererInterface()->SetUserAgent(ua);
  807. + }
  808. + }
  809. + }
  810. +
  811. + parsed_command_line->RemoveSwitch(switches::kDesktopModeViewportMetaEnabled);
  812. + if (g_browser_process->local_state()->GetBoolean(prefs::kDesktopModeViewportMetaEnabled))
  813. + parsed_command_line->AppendSwitch(switches::kDesktopModeViewportMetaEnabled);
  814. +}
  815. +
  816. +static void JNI_PrivacyPreferencesManagerImpl_UpdateOverrideUserAgent(
  817. + JNIEnv* env) {
  818. + UpdateOverrideUserAgent();
  819. +}
  820. +
  821. +static jboolean JNI_PrivacyPreferencesManagerImpl_IsOverrideUserAgentEnabled(
  822. + JNIEnv* env, jboolean desktopMode) {
  823. + if (desktopMode == false)
  824. + return g_browser_process->local_state()->GetBoolean(prefs::kOverrideUserAgentEnabled);
  825. + else
  826. + return g_browser_process->local_state()->GetBoolean(prefs::kOverrideUserAgentDesktopModeEnabled);
  827. +}
  828. +
  829. +static void JNI_PrivacyPreferencesManagerImpl_SetOverrideUserAgentEnabled(
  830. + JNIEnv* env,
  831. + jboolean enabled, jboolean desktopMode) {
  832. + if (desktopMode == false) {
  833. + g_browser_process->local_state()->SetBoolean(prefs::kOverrideUserAgentEnabled,
  834. + enabled);
  835. + UpdateOverrideUserAgent();
  836. + } else {
  837. + g_browser_process->local_state()->SetBoolean(prefs::kOverrideUserAgentDesktopModeEnabled,
  838. + enabled);
  839. + }
  840. +}
  841. +
  842. +static void JNI_PrivacyPreferencesManagerImpl_SetOverrideUserAgentValue(
  843. + JNIEnv* env,
  844. + const JavaParamRef<jstring>& ua, jboolean desktopMode) {
  845. + std::string new_ua = ConvertJavaStringToUTF8(env, ua);
  846. + if (desktopMode == false) {
  847. + g_browser_process->local_state()->SetString(prefs::kOverrideUserAgent,
  848. + new_ua);
  849. + UpdateOverrideUserAgent();
  850. + } else {
  851. + g_browser_process->local_state()->SetString(prefs::kOverrideUserAgentDesktopMode,
  852. + new_ua);
  853. + }
  854. +}
  855. +
  856. +static base::android::ScopedJavaLocalRef<jstring>
  857. + JNI_PrivacyPreferencesManagerImpl_GetOverrideUserAgentValue(
  858. + JNIEnv* env, jboolean desktopMode) {
  859. + if (desktopMode == false) {
  860. + std::string ua = g_browser_process->local_state()->GetString(prefs::kOverrideUserAgent);
  861. + return ConvertUTF8ToJavaString(env, ua);
  862. + } else {
  863. + std::string ua = g_browser_process->local_state()->GetString(prefs::kOverrideUserAgentDesktopMode);
  864. + return ConvertUTF8ToJavaString(env, ua);
  865. + }
  866. +}
  867. +
  868. +static jboolean JNI_PrivacyPreferencesManagerImpl_IsDesktopModeViewportMetaEnabled(
  869. + JNIEnv* env) {
  870. + return g_browser_process->local_state()->GetBoolean(prefs::kDesktopModeViewportMetaEnabled);
  871. +}
  872. +
  873. +static void JNI_PrivacyPreferencesManagerImpl_SetDesktopModeViewportMetaEnabled(
  874. + JNIEnv* env,
  875. + jboolean enabled) {
  876. + g_browser_process->local_state()->SetBoolean(prefs::kDesktopModeViewportMetaEnabled,
  877. + enabled);
  878. + UpdateOverrideUserAgent();
  879. +}
  880. \ No newline at end of file
  881. diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
  882. --- a/chrome/browser/android/tab_android.cc
  883. +++ b/chrome/browser/android/tab_android.cc
  884. @@ -373,7 +373,8 @@ TabAndroid::TabLoadStatus TabAndroid::LoadUrl(
  885. jboolean has_user_gesture,
  886. jboolean should_clear_history_list,
  887. jlong input_start_timestamp,
  888. - jlong intent_received_timestamp) {
  889. + jlong intent_received_timestamp,
  890. + jint user_agent_override_option) {
  891. if (!web_contents())
  892. return PAGE_LOAD_FAILED;
  893. @@ -430,6 +431,8 @@ TabAndroid::TabLoadStatus TabAndroid::LoadUrl(
  894. load_params.input_start =
  895. base::TimeTicks::FromUptimeMillis(intent_received_timestamp);
  896. }
  897. + load_params.override_user_agent = static_cast<NavigationController::UserAgentOverrideOption>(
  898. + user_agent_override_option);
  899. web_contents()->GetController().LoadURLWithParams(load_params);
  900. }
  901. return DEFAULT_PAGE_LOAD;
  902. diff --git a/chrome/browser/android/tab_android.h b/chrome/browser/android/tab_android.h
  903. --- a/chrome/browser/android/tab_android.h
  904. +++ b/chrome/browser/android/tab_android.h
  905. @@ -167,7 +167,8 @@ class TabAndroid : public base::SupportsUserData {
  906. jboolean has_user_gesture,
  907. jboolean should_clear_history_list,
  908. jlong omnibox_input_received_timestamp,
  909. - jlong intent_received_timestamp);
  910. + jlong intent_received_timestamp,
  911. + jint user_agent_override_option);
  912. void SetActiveNavigationEntryTitleForUrl(
  913. JNIEnv* env,
  914. const base::android::JavaParamRef<jstring>& jurl,
  915. diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
  916. --- a/chrome/browser/chrome_content_browser_client.cc
  917. +++ b/chrome/browser/chrome_content_browser_client.cc
  918. @@ -1286,6 +1286,13 @@ std::string GetPlatformForUAMetadata() {
  919. blink::UserAgentMetadata GetUserAgentMetadata() {
  920. blink::UserAgentMetadata metadata;
  921. + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
  922. + if (command_line->HasSwitch(switches::kUserAgent)) {
  923. + std::string ua = command_line->GetSwitchValueASCII(switches::kUserAgent);
  924. +
  925. + return metadata;
  926. + }
  927. +
  928. metadata.brand_version_list = GetBrandVersionList();
  929. metadata.full_version = version_info::GetVersionNumber();
  930. metadata.platform = GetPlatformForUAMetadata();
  931. @@ -2379,6 +2386,7 @@ void ChromeContentBrowserClient::AppendExtraCommandLineSwitches(
  932. switches::kDisableTargetBlankImpliesNoOpener);
  933. }
  934. +
  935. #if defined(OS_ANDROID)
  936. // Communicating to content/ for BackForwardCache.
  937. if (prefs->HasPrefPath(policy::policy_prefs::kBackForwardCacheEnabled) &&
  938. 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
  939. --- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
  940. +++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
  941. @@ -828,6 +828,9 @@ public final class ChromePreferenceKeys {
  942. public static final KeyPrefix KEY_ZERO_SUGGEST_HEADER_GROUP_COLLAPSED_BY_DEFAULT_PREFIX =
  943. new KeyPrefix("zero_suggest_header_group_collapsed_by_default*");
  944. + public static final String USERAGENT_STICKY_DESKTOP_MODE = "Chrome.UserAgent.StickyDesktopMode";
  945. + public static final String USERAGENT_ALWAYS_DESKTOP_MODE = "Chrome.UserAgent.AlwaysDesktopMode";
  946. +
  947. /**
  948. * These values are currently used as SharedPreferences keys, along with the keys in
  949. * {@link GrandfatheredChromePreferenceKeys#getKeysInUse()}. Add new SharedPreferences keys
  950. @@ -890,7 +893,9 @@ public final class ChromePreferenceKeys {
  951. SETTINGS_SAFETY_CHECK_RUN_COUNTER,
  952. SIGNIN_PROMO_IMPRESSIONS_COUNT_NTP,
  953. TWA_DISCLOSURE_SEEN_PACKAGES,
  954. - VIDEO_TUTORIALS_SHARE_URL_SET
  955. + VIDEO_TUTORIALS_SHARE_URL_SET,
  956. + USERAGENT_STICKY_DESKTOP_MODE,
  957. + USERAGENT_ALWAYS_DESKTOP_MODE
  958. );
  959. // clang-format on
  960. }
  961. 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
  962. --- a/chrome/browser/privacy/settings/java/src/org/chromium/chrome/browser/privacy/settings/PrivacyPreferencesManager.java
  963. +++ b/chrome/browser/privacy/settings/java/src/org/chromium/chrome/browser/privacy/settings/PrivacyPreferencesManager.java
  964. @@ -105,4 +105,12 @@ public interface PrivacyPreferencesManager extends CrashReportingPermissionManag
  965. * @return Whether Network Predictions is configured by policy.
  966. */
  967. boolean isNetworkPredictionManaged();
  968. +
  969. + void updateOverrideUserAgent();
  970. + boolean isOverrideUserAgentEnabled(boolean desktopMode);
  971. + void setOverrideUserAgentEnabled(boolean enabled, boolean desktopMode);
  972. + String getOverrideUserAgentValue(boolean desktopMode);
  973. + void setOverrideUserAgentValue(String timezone, boolean desktopMode);
  974. + boolean isDesktopModeViewportMetaEnabled();
  975. + void setDesktopModeViewportMetaEnabled(boolean enabled);
  976. }
  977. 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
  978. --- a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Tab.java
  979. +++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Tab.java
  980. @@ -279,6 +279,8 @@ public interface Tab extends TabLifecycle {
  981. */
  982. void setIsTabStateDirty(boolean isTabStateDirty);
  983. + void SetOverrideUserAgent(boolean usingDesktopUserAgent);
  984. +
  985. /**
  986. * If set to true, any future navigations in the tab automatically get
  987. * PageTransition.FROM_API_2 applied.
  988. diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabWindowManager.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabWindowManager.java
  989. --- a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabWindowManager.java
  990. +++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabWindowManager.java
  991. @@ -10,6 +10,11 @@ import org.chromium.chrome.browser.tab.Tab;
  992. import org.chromium.chrome.browser.tabmodel.NextTabPolicy.NextTabPolicySupplier;
  993. import org.chromium.ui.base.WindowAndroid;
  994. +import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
  995. +import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
  996. +
  997. +import java.util.List;
  998. +
  999. /**
  1000. * Manages multiple {@link TabModelSelector} instances, each owned by different {@link Activity}s.
  1001. *
  1002. @@ -76,4 +81,7 @@ public interface TabWindowManager {
  1003. * @return Specified {@link Tab} or {@code null} if the {@link Tab} is not found.
  1004. */
  1005. Tab getTabById(int tabId);
  1006. +
  1007. + void SetOverrideUserAgentForAllTabs(boolean usingDesktopUserAgent);
  1008. +
  1009. }
  1010. diff --git a/chrome/browser/tabmodel/internal/android/java/src/org/chromium/chrome/browser/tabmodel/TabWindowManagerImpl.java b/chrome/browser/tabmodel/internal/android/java/src/org/chromium/chrome/browser/tabmodel/TabWindowManagerImpl.java
  1011. --- a/chrome/browser/tabmodel/internal/android/java/src/org/chromium/chrome/browser/tabmodel/TabWindowManagerImpl.java
  1012. +++ b/chrome/browser/tabmodel/internal/android/java/src/org/chromium/chrome/browser/tabmodel/TabWindowManagerImpl.java
  1013. @@ -119,6 +119,24 @@ public class TabWindowManagerImpl implements ActivityStateListener, TabWindowMan
  1014. return null;
  1015. }
  1016. + @Override
  1017. + public void SetOverrideUserAgentForAllTabs(boolean usingDesktopUserAgent) {
  1018. + for (int selectorIndex = 0; selectorIndex < mSelectors.size(); selectorIndex++) {
  1019. + TabModelSelector selector = mSelectors.get(selectorIndex);
  1020. + if (selector != null) {
  1021. + List<TabModel> models = selector.getModels();
  1022. + for (int modelIndex = 0; modelIndex < models.size(); modelIndex++) {
  1023. + TabModel model = models.get(modelIndex);
  1024. +
  1025. + for (int tabIdex = 0; tabIdex < model.getCount(); tabIdex++) {
  1026. + Tab theTab = model.getTabAt(tabIdex);
  1027. + theTab.SetOverrideUserAgent(usingDesktopUserAgent);
  1028. + }
  1029. + }
  1030. + }
  1031. + }
  1032. + }
  1033. +
  1034. @Override
  1035. public Tab getTabById(int tabId) {
  1036. for (int i = 0; i < mSelectors.size(); i++) {
  1037. diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
  1038. --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
  1039. +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
  1040. @@ -228,6 +228,41 @@ CHAR-LIMIT guidelines:
  1041. Visit help page
  1042. </message>
  1043. + <!-- User Agent settings -->
  1044. + <message name="IDS_PREFS_USERAGENT_SETTINGS" desc="Title of the User Agent preference. [CHAR-LIMIT=32]">
  1045. + User Agent
  1046. + </message>
  1047. + <message name="IDS_USERAGENT_SETTINGS_TITLE" desc="Title of the User Agent screen. [CHAR-LIMIT=32]">
  1048. + Customize User Agent
  1049. + </message>
  1050. + <message name="IDS_OPTION_DESKTOP_FLAG" desc="The label of the option that allows users to sticky desktop mode view flag under hambuger menu.">
  1051. + Current behaviour for desktop mode toggle in hamburger menu
  1052. + </message>
  1053. + <message name="IDS_OPTION_DESKTOP_FLAG_ON" desc="The label of the option that allows users to sticky desktop mode view flag under hambuger menu. [CHAR-LIMIT=32]">
  1054. + Applies to all tabs (sticky mode)
  1055. + </message>
  1056. + <message name="IDS_OPTION_DESKTOP_FLAG_OFF" desc="The label of the option that revert the hambuger menu flag to actual behaviour. [CHAR-LIMIT=32]">
  1057. + Applies to current tab only
  1058. + </message>
  1059. + <message name="IDS_CUSTOM_UA_FLAG_ON" desc="The label of the option that allows users to define custom user agent.">
  1060. + Use custom user agent
  1061. + </message>
  1062. + <message name="IDS_CUSTOM_UA_FLAG_OFF" desc="The label of the option that revert the user agent to actual value.">
  1063. + Use standard user agent
  1064. + </message>
  1065. + <message name="IDS_CUSTOM_UA_PLACEHOLDER" desc="The label of the placeholder for user agent textbox.">
  1066. + Insert a valid user agent
  1067. + </message>
  1068. + <message name="IDS_CUSTOM_UA_TEXT" desc="The label of the placeholder for user agent textbox.">
  1069. + Mobile User Agent
  1070. + </message>
  1071. + <message name="IDS_CUSTOM_DESKTOP_UA_TEXT" desc="The label of the placeholder for user agent textbox.">
  1072. + Desktop Mode User Agent
  1073. + </message>
  1074. + <message name="IDS_DESKTOP_MODE_VIEWPORTMETA_CHECKBOX" desc="The label of the enable viewport meta checkbox for user desktop mode.">
  1075. + Enable processing of the viewport meta tag also for desktop mode
  1076. + </message>
  1077. +
  1078. <!-- Notification channels -->
  1079. <message name="IDS_NOTIFICATION_CATEGORY_GROUP_GENERAL" desc='Subheading for "General" section of a list of notification categories. [CHAR-LIMIT=32]'>
  1080. General
  1081. diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
  1082. --- a/chrome/common/pref_names.cc
  1083. +++ b/chrome/common/pref_names.cc
  1084. @@ -418,6 +418,19 @@ const char kAllowJavascriptAppleEvents[] =
  1085. #endif
  1086. +#if defined(OS_ANDROID)
  1087. +const char kOverrideUserAgentEnabled[] =
  1088. + "override_user_agent_enabled";
  1089. +const char kOverrideUserAgent[] =
  1090. + "override_user_agent";
  1091. +const char kOverrideUserAgentDesktopModeEnabled[] =
  1092. + "override_user_agent_dm_enabled";
  1093. +const char kOverrideUserAgentDesktopMode[] =
  1094. + "override_user_agent_dm";
  1095. +const char kDesktopModeViewportMetaEnabled[] =
  1096. + "dm-viewport-meta-enabled";
  1097. +#endif
  1098. +
  1099. // Boolean which specifies whether we should ask the user if we should download
  1100. // a file (true) or just download it automatically.
  1101. const char kPromptForDownload[] = "download.prompt_for_download";
  1102. diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
  1103. --- a/chrome/common/pref_names.h
  1104. +++ b/chrome/common/pref_names.h
  1105. @@ -1120,6 +1120,14 @@ extern const char kCartModuleWelcomeSurfaceShownTimes[];
  1106. extern const char kIncognitoTabHistoryEnabled[];
  1107. #endif
  1108. +#if defined(OS_ANDROID)
  1109. +extern const char kOverrideUserAgentEnabled[];
  1110. +extern const char kOverrideUserAgent[];
  1111. +extern const char kOverrideUserAgentDesktopModeEnabled[];
  1112. +extern const char kOverrideUserAgentDesktopMode[];
  1113. +extern const char kDesktopModeViewportMetaEnabled[];
  1114. +#endif
  1115. +
  1116. } // namespace prefs
  1117. #endif // CHROME_COMMON_PREF_NAMES_H_
  1118. 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
  1119. --- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonWithEditText.java
  1120. +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonWithEditText.java
  1121. @@ -167,6 +167,17 @@ public class RadioButtonWithEditText extends RadioButtonWithDescription {
  1122. mEditText.setCursorVisible(false);
  1123. KeyboardVisibilityDelegate.getInstance().hideKeyboard(mEditText);
  1124. }
  1125. + if (mRadioButtonWithEditTextFocusListener != null) {
  1126. + mRadioButtonWithEditTextFocusListener.onRadioButtonWithEditTextFocusChanged(hasFocus);
  1127. + }
  1128. + }
  1129. +
  1130. + public interface RadioButtonWithEditTextFocusListener {
  1131. + void onRadioButtonWithEditTextFocusChanged(boolean hasFocus);
  1132. + }
  1133. + private RadioButtonWithEditTextFocusListener mRadioButtonWithEditTextFocusListener;
  1134. + public void setFocusChangeListener(RadioButtonWithEditTextFocusListener listener) {
  1135. + mRadioButtonWithEditTextFocusListener = listener;
  1136. }
  1137. /**
  1138. diff --git a/content/browser/renderer_host/navigation_controller_android.cc b/content/browser/renderer_host/navigation_controller_android.cc
  1139. --- a/content/browser/renderer_host/navigation_controller_android.cc
  1140. +++ b/content/browser/renderer_host/navigation_controller_android.cc
  1141. @@ -237,7 +237,8 @@ void NavigationControllerAndroid::LoadUrl(
  1142. const JavaParamRef<jstring>& data_url_as_string,
  1143. jboolean can_load_local_resources,
  1144. jboolean is_renderer_initiated,
  1145. - jboolean should_replace_current_entry) {
  1146. + jboolean should_replace_current_entry,
  1147. + jint user_agent_override_option) {
  1148. DCHECK(url);
  1149. NavigationController::LoadURLParams params(
  1150. GURL(ConvertJavaStringToUTF8(env, url)));
  1151. @@ -291,6 +292,9 @@ void NavigationControllerAndroid::LoadUrl(
  1152. Referrer::ConvertToPolicy(referrer_policy));
  1153. }
  1154. + params.override_user_agent = static_cast<NavigationController::UserAgentOverrideOption>(
  1155. + user_agent_override_option);
  1156. +
  1157. navigation_controller_->LoadURLWithParams(params);
  1158. }
  1159. diff --git a/content/browser/renderer_host/navigation_controller_android.h b/content/browser/renderer_host/navigation_controller_android.h
  1160. --- a/content/browser/renderer_host/navigation_controller_android.h
  1161. +++ b/content/browser/renderer_host/navigation_controller_android.h
  1162. @@ -80,7 +80,8 @@ class CONTENT_EXPORT NavigationControllerAndroid {
  1163. const base::android::JavaParamRef<jstring>& data_url_as_string,
  1164. jboolean can_load_local_resources,
  1165. jboolean is_renderer_initiated,
  1166. - jboolean should_replace_current_entry);
  1167. + jboolean should_replace_current_entry,
  1168. + jint user_agent_override_option);
  1169. void ClearSslPreferences(
  1170. JNIEnv* env,
  1171. const base::android::JavaParamRef<jobject>& /* obj */);
  1172. diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
  1173. --- a/content/browser/renderer_host/render_process_host_impl.cc
  1174. +++ b/content/browser/renderer_host/render_process_host_impl.cc
  1175. @@ -3366,6 +3366,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
  1176. #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
  1177. switches::kSchedulerBoostUrgent,
  1178. #endif
  1179. + switches::kDesktopModeViewportMetaEnabled,
  1180. };
  1181. renderer_cmd->CopySwitchesFrom(browser_cmd, kSwitchNames,
  1182. base::size(kSwitchNames));
  1183. diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
  1184. --- a/content/browser/web_contents/web_contents_impl.cc
  1185. +++ b/content/browser/web_contents/web_contents_impl.cc
  1186. @@ -38,6 +38,7 @@
  1187. #include "base/strings/string_util.h"
  1188. #include "base/strings/utf_string_conversions.h"
  1189. #include "base/system/sys_info.h"
  1190. +#include "base/base_switches.h"
  1191. #include "base/threading/thread_task_runner_handle.h"
  1192. #include "base/time/time.h"
  1193. #include "base/trace_event/optional_trace_event.h"
  1194. @@ -2447,7 +2448,8 @@ const blink::web_pref::WebPreferences WebContentsImpl::ComputeWebPreferences() {
  1195. prefs.threaded_scrolling_enabled =
  1196. !command_line.HasSwitch(blink::switches::kDisableThreadedScrolling);
  1197. - if (IsOverridingUserAgent())
  1198. + if (IsOverridingUserAgent() &&
  1199. + !command_line.HasSwitch(switches::kDesktopModeViewportMetaEnabled))
  1200. prefs.viewport_meta_enabled = false;
  1201. prefs.main_frame_resizes_are_orientation_changes =
  1202. 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
  1203. --- a/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java
  1204. +++ b/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java
  1205. @@ -169,7 +169,8 @@ import org.chromium.url.GURL;
  1206. params.getUserAgentOverrideOption(), params.getExtraHeadersString(),
  1207. params.getPostData(), params.getBaseUrl(), params.getVirtualUrlForDataUrl(),
  1208. params.getDataUrlAsString(), params.getCanLoadLocalResources(),
  1209. - params.getIsRendererInitiated(), params.getShouldReplaceCurrentEntry());
  1210. + params.getIsRendererInitiated(), params.getShouldReplaceCurrentEntry(),
  1211. + params.getUserAgentOverrideOption());
  1212. }
  1213. }
  1214. @@ -348,7 +349,8 @@ import org.chromium.url.GURL;
  1215. int referrerPolicy, int uaOverrideOption, String extraHeaders,
  1216. ResourceRequestBody postData, String baseUrlForDataUrl, String virtualUrlForDataUrl,
  1217. String dataUrlAsString, boolean canLoadLocalResources, boolean isRendererInitiated,
  1218. - boolean shouldReplaceCurrentEntry);
  1219. + boolean shouldReplaceCurrentEntry,
  1220. + int userAgentOverrideOption);
  1221. void clearHistory(long nativeNavigationControllerAndroid, NavigationControllerImpl caller);
  1222. int getNavigationHistory(long nativeNavigationControllerAndroid,
  1223. NavigationControllerImpl caller, Object history);
  1224. diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
  1225. --- a/content/renderer/render_thread_impl.cc
  1226. +++ b/content/renderer/render_thread_impl.cc
  1227. @@ -1673,7 +1673,6 @@ void RenderThreadImpl::SetWebKitSharedTimersSuspended(bool suspend) {
  1228. }
  1229. void RenderThreadImpl::SetUserAgent(const std::string& user_agent) {
  1230. - DCHECK(user_agent_.IsNull());
  1231. user_agent_ = WebString::FromUTF8(user_agent);
  1232. GetContentClient()->renderer()->DidSetUserAgent(user_agent);
  1233. }
  1234. --
  1235. 2.17.1