diff --git a/build/cromite_patches_list.txt b/build/cromite_patches_list.txt index 8b76d8c0..d6461da6 100644 --- a/build/cromite_patches_list.txt +++ b/build/cromite_patches_list.txt @@ -274,6 +274,7 @@ Timezone-customization.patch 00Add-PartialLowEndModeOnMidRangeDevices-flag.patch 00Use-list-mode-for-tab-switcher.patch 00Chrome-web-store-protection.patch +00Enable-search-engine-settings-desktop-ui.patch 00Temp-PerformanceNavigationTiming-privacy-fix.patch 00Temp-disable-predictive-back-gesture.patch diff --git a/build/patches/00Enable-search-engine-settings-desktop-ui.patch b/build/patches/00Enable-search-engine-settings-desktop-ui.patch new file mode 100644 index 00000000..66381007 --- /dev/null +++ b/build/patches/00Enable-search-engine-settings-desktop-ui.patch @@ -0,0 +1,2206 @@ +From: uazo +Date: Thu, 4 Jan 2024 13:00:12 +0000 +Subject: Enable search engine settings desktop ui + +Activates the ability to use the desktop ui for search engine management. +The desktop ui is accessible via a button in the android ui. +--- + .../settings/SettingsLauncherImpl.java | 10 + + chrome/app/generated_resources.grd | 7 +- + chrome/app/settings_strings.grdp | 3 + + chrome/app/settings_strings_android.grdp | 257 ++++++++++++++++++ + chrome/browser/BUILD.gn | 3 + + chrome/browser/resources/BUILD.gn | 6 + + chrome/browser/resources/settings/BUILD.gn | 2 +- + .../resources/settings/page_visibility.ts | 30 +- + .../search_engine_edit_dialog.html | 6 + + .../search_engine_edit_dialog.ts | 5 +- + .../search_engines_browser_proxy.ts | 8 +- + .../search_engines_page.html | 9 +- + .../settings/search_page/search_page.html | 6 +- + .../browser/resources/settings/settings.gni | 2 +- + .../browser/resources/settings/settings.html | 8 +- + .../settings/settings_ui/settings_ui.html | 6 + + .../resources/settings_shared/BUILD.gn | 2 +- + .../browser/search_engines/android/BUILD.gn | 1 + + .../java/res/layout/search_engine_layout.xml | 25 ++ + .../settings/SearchEngineSettings.java | 19 ++ + chrome/browser/ui/BUILD.gn | 12 + + .../edit_search_engine_controller.cc | 8 +- + .../edit_search_engine_controller.h | 6 +- + .../keyword_editor_controller.cc | 13 +- + .../keyword_editor_controller.h | 6 +- + .../template_url_table_model.cc | 9 +- + .../search_engines/template_url_table_model.h | 6 +- + .../webui/chrome_web_ui_controller_factory.cc | 6 + + chrome/browser/ui/webui/favicon_source.cc | 20 ++ + chrome/browser/ui/webui/favicon_source.h | 2 + + .../webui/settings/search_engines_handler.cc | 28 +- + .../webui/settings/search_engines_handler.h | 3 +- + .../settings_localized_strings_provider.cc | 2 + + ...ings_localized_strings_provider_android.cc | 196 +++++++++++++ + ...tings_localized_strings_provider_android.h | 19 ++ + .../ui/webui/settings/settings_ui_android.cc | 135 +++++++++ + .../ui/webui/settings/settings_ui_android.h | 127 +++++++++ + chrome/browser/ui/webui/webui_util.cc | 5 + + chrome/chrome_paks.gni | 11 + + .../browser_ui/settings/SettingsLauncher.java | 2 + + .../search_engine_desktop_ui.grdp | 6 + + .../android/template_url_service_android.cc | 2 +- + .../search_engines/template_url_service.cc | 8 +- + .../search_engines/template_url_service.h | 6 +- + content/browser/webui/web_ui_impl.cc | 11 +- + content/browser/webui/web_ui_impl.h | 3 + + content/public/browser/web_ui.h | 1 + + ui/base/template_expressions.cc | 21 +- + ui/webui/BUILD.gn | 8 + + ui/webui/resources/BUILD.gn | 10 + + .../customize_color_scheme_mode/BUILD.gn | 2 +- + .../cr_components/customize_themes/BUILD.gn | 2 +- + .../cr_components/help_bubble/BUILD.gn | 2 +- + .../cr_components/theme_color_picker/BUILD.gn | 2 +- + .../cr_elements/cr_dialog/cr_dialog.html | 2 +- + .../resources/cr_elements/cr_shared_vars.css | 4 + + ui/webui/resources/css/BUILD.gn | 2 +- + ui/webui/resources/images/BUILD.gn | 2 +- + ui/webui/resources/include_polymer.gni | 2 +- + ui/webui/resources/js/BUILD.gn | 2 +- + ui/webui/resources/js/load_time_data.ts | 17 +- + 61 files changed, 1088 insertions(+), 58 deletions(-) + create mode 100644 chrome/app/settings_strings_android.grdp + create mode 100644 chrome/browser/search_engines/android/java/res/layout/search_engine_layout.xml + create mode 100644 chrome/browser/ui/webui/settings/settings_localized_strings_provider_android.cc + create mode 100644 chrome/browser/ui/webui/settings/settings_localized_strings_provider_android.h + create mode 100644 chrome/browser/ui/webui/settings/settings_ui_android.cc + create mode 100644 chrome/browser/ui/webui/settings/settings_ui_android.h + create mode 100644 components/browser_ui/strings/bromite_content_settings/search_engine_desktop_ui.grdp + +diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsLauncherImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsLauncherImpl.java +--- a/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsLauncherImpl.java ++++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsLauncherImpl.java +@@ -12,6 +12,9 @@ import android.os.Bundle; + import androidx.annotation.Nullable; + import androidx.fragment.app.Fragment; + ++import org.chromium.base.ContextUtils; ++import org.chromium.chrome.browser.customtabs.CustomTabActivity; ++ + import org.chromium.base.IntentUtils; + import org.chromium.chrome.browser.autofill.settings.AutofillPaymentMethodsFragment; + import org.chromium.chrome.browser.browsing_data.ClearBrowsingDataFragment; +@@ -27,6 +30,13 @@ import org.chromium.components.browser_ui.site_settings.SiteSettings; + public class SettingsLauncherImpl implements SettingsLauncher { + public SettingsLauncherImpl() {} + ++ @Override ++ public void launchUrlInCustomTab(Context context, String url) { ++ CustomTabActivity.showInfoPage( ++ ContextUtils.activityFromContext(context), ++ url); ++ } ++ + @Override + public void launchSettingsActivity(Context context) { + launchSettingsActivity(context, SettingsFragment.MAIN); +diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd +--- a/chrome/app/generated_resources.grd ++++ b/chrome/app/generated_resources.grd +@@ -311,6 +311,11 @@ are declared in tools/grit/grit_rule.gni. + + + ++ ++ ++ ++ ++ + + + +@@ -486,7 +491,7 @@ are declared in tools/grit/grit_rule.gni. + Disable + + +- ++ + + Search cleared + +diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp +--- a/chrome/app/settings_strings.grdp ++++ b/chrome/app/settings_strings.grdp +@@ -2509,6 +2509,9 @@ + + URL with %s in place of query + ++ ++ Suggestion URL (with %s in place of query) ++ + + Make default + +diff --git a/chrome/app/settings_strings_android.grdp b/chrome/app/settings_strings_android.grdp +new file mode 100644 +--- /dev/null ++++ b/chrome/app/settings_strings_android.grdp +@@ -0,0 +1,257 @@ ++ ++ ++ ++ ++ ++ ++ Advanced ++ ++ ++ Basic ++ ++ ++ Main menu ++ ++ ++ Opens in a new tab ++ ++ ++ Search settings ++ ++ ++ Go to <a target="_blank" href="$1">Google Chrome help</a> if you can't find what you're looking for ++ ++ ++ Settings ++ ++ ++ Settings - $1About Chromium ++ ++ ++ Subpage button ++ ++ ++ Relaunch ++ ++ ++ $1Adblocker plusplus is controlling this setting ++ ++ ++ Clear ++ ++ ++ Delete ++ ++ ++ Edit ++ ++ ++ End time $15:00 AM ++ ++ ++ Not valid ++ ++ ++ Not a valid web address ++ ++ ++ Origin must be secure ++ ++ ++ Retry ++ ++ ++ Slider: $1Slowest to $2Fastest ++ ++ ++ Start time $19:06 PM ++ ++ ++ ++ ++ Search engine ++ ++ ++ Search engine used in the address bar. ++ ++ ++ Learn more about default search engines ++ ++ ++ Manage search engines ++ ++ ++ Manage search engines and site search ++ ++ ++ Create shortcuts for searching sites and manage your search engine ++ ++ ++ ++ ++ Search Engines ++ ++ ++ You can use shortcuts in the address bar to quickly search a specific site or to use a different search engine ++ ++ ++ Search ++ ++ ++ Add search engine ++ ++ ++ Edit search engine ++ ++ ++ Delete search engine ++ ++ ++ Are you sure you want to delete this search engine? ++ ++ ++ Search engines ++ ++ ++ To use a search engine other than the default, type its shortcut in the address bar followed by your preferred keyboard shortcut. You can also change your default search engine here. ++ ++ ++ Site search ++ ++ ++ To search a specific site or part of Chrome, type its shortcut in the address bar, followed by your preferred keyboard shortcut. ++ ++ ++ To search a specific site or part of Chrome, type its shortcut in the address bar, followed by your preferred keyboard shortcut. For example, to search only Bookmarks, type "@bookmarks", then press Tab or Space. ++ ++ ++ No sites added ++ ++ ++ Inactive shortcuts ++ ++ ++ Other saved search engines will appear here ++ ++ ++ Extensions ++ ++ ++ Some extensions can add search engines to Chrome ++ ++ ++ Search engine ++ ++ ++ Site or page ++ ++ ++ Shortcut ++ ++ ++ Query URL ++ ++ ++ URL with %s in place of query ++ ++ ++ Suggestion URL (with %s in place of query) ++ ++ ++ Make default ++ ++ ++ Activate ++ ++ ++ Deactivate ++ ++ ++ Manage ++ ++ ++ Keyboard shortcut ++ ++ ++ In the address bar, use this keyboard shortcut with shortcuts for search engines and site search ++ ++ ++ In the address bar, enter the shortcut for the site you want to search, such as "@bookmarks". Then, press your preferred keyboard shortcut, and enter your search term. ++ ++ ++ Space or Tab ++ ++ ++ Tab ++ ++ ++ Additional sites ++ ++ ++ Additional inactive sites ++ ++ ++ ++ ++ Add ++ ++ ++ Cancel ++ ++ ++ Close ++ ++ ++ Done ++ ++ ++ Learn more ++ ++ ++ Menu ++ ++ ++ ++ No thanks ++ ++ ++ OK ++ ++ ++ Remove ++ ++ ++ Save ++ ++ ++ ++ ++ Back ++ ++ ++ ++ Manage ++ ++ ++ Fonts ++ ++ ++ ++ ++ Continue ++ ++ ++ More actions ++ ++ ++ Send feedback button ++ ++ ++ Custom ++ ++ ++ Opens in new tab ++ ++ ++ ++ +diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn +--- a/chrome/browser/BUILD.gn ++++ b/chrome/browser/BUILD.gn +@@ -3736,6 +3736,9 @@ static_library("browser") { + "//components/user_scripts/android", + ] + } ++ deps += [ ++ "//ui/webui/resources/cr_components/help_bubble:mojo_bindings", ++ ] + } else { + #!is_android + sources += [ +diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn +--- a/chrome/browser/resources/BUILD.gn ++++ b/chrome/browser/resources/BUILD.gn +@@ -22,6 +22,12 @@ assert(!is_ios, "Chromium/iOS shouldn't use anything in //chrome") + group("resources") { + public_deps = [ "segmentation_internals:resources" ] + ++ if (is_android) { ++ public_deps += [ ++ "settings:resources", ++ "settings_shared:resources", ++ ] ++ } + if (!is_android) { + public_deps += [ + ":app_icon_resources", +diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn +--- a/chrome/browser/resources/settings/BUILD.gn ++++ b/chrome/browser/resources/settings/BUILD.gn +@@ -8,7 +8,7 @@ import("//crypto/features.gni") + import("//ui/webui/resources/tools/build_webui.gni") + import("./settings.gni") + +-assert(!is_android, "Android does not use these settings") ++#assert(!is_android, "Android does not use these settings") + + build_webui("build") { + grd_prefix = "settings" +diff --git a/chrome/browser/resources/settings/page_visibility.ts b/chrome/browser/resources/settings/page_visibility.ts +--- a/chrome/browser/resources/settings/page_visibility.ts ++++ b/chrome/browser/resources/settings/page_visibility.ts +@@ -47,7 +47,35 @@ export interface PrivacyPageVisibility { + */ + export let pageVisibility: PageVisibility; + +-if (loadTimeData.getBoolean('isGuest')) { ++const isAndroid = (loadTimeData.getString('chromeAndroid') !== ""); ++if (isAndroid) { ++ // @ts-expect-error ++ chrome.autofillPrivate = {}; ++ ++ // @ts-expect-error ++ chrome.languageSettingsPrivate = {}; ++ ++ // @ts-expect-error ++ chrome.metricsPrivate = { ++ recordSparseValueWithPersistentHash: function() {} ++ }; ++ ++ // @ts-expect-error ++ chrome.settingsPrivate_ = { ++ onPrefsChanged: { ++ addListener: function() {} ++ }, ++ getAllPrefs: function() { ++ var obj = {}; ++ (obj as any).then = function() {}; ++ return obj; ++ } ++ } ++ // @ts-expect-error ++ chrome.settingsPrivate = chrome.settingsPrivate_; ++} ++ ++if (loadTimeData.getBoolean('isGuest') || isAndroid) { + // "if not chromeos" and "if chromeos" in two completely separate blocks + // to work around closure compiler. + // +diff --git a/chrome/browser/resources/settings/search_engines_page/search_engine_edit_dialog.html b/chrome/browser/resources/settings/search_engines_page/search_engine_edit_dialog.html +--- a/chrome/browser/resources/settings/search_engines_page/search_engine_edit_dialog.html ++++ b/chrome/browser/resources/settings/search_engines_page/search_engine_edit_dialog.html +@@ -20,6 +20,12 @@ + value="{{queryUrl_}}" on-focus="validate_" on-input="validate_" + disabled$="[[model.urlLocked]]"> + ++ ++ + +
+ +diff --git a/chrome/browser/resources/settings/search_engines_page/search_engine_edit_dialog.ts b/chrome/browser/resources/settings/search_engines_page/search_engine_edit_dialog.ts +--- a/chrome/browser/resources/settings/search_engines_page/search_engine_edit_dialog.ts ++++ b/chrome/browser/resources/settings/search_engines_page/search_engine_edit_dialog.ts +@@ -63,6 +63,7 @@ export class SettingsSearchEngineEditDialogElement extends + searchEngine_: String, + keyword_: String, + queryUrl_: String, ++ suggestionUrl_: String, + dialogTitle_: String, + actionButtonText_: String, + }; +@@ -72,6 +73,7 @@ export class SettingsSearchEngineEditDialogElement extends + private searchEngine_: string; + private keyword_: string; + private queryUrl_: string; ++ private suggestionUrl_: string; + private dialogTitle_: string; + private actionButtonText_: string; + private browserProxy_: SearchEnginesBrowserProxy = +@@ -89,6 +91,7 @@ export class SettingsSearchEngineEditDialogElement extends + this.searchEngine_ = this.model.name; + this.keyword_ = this.model.keyword; + this.queryUrl_ = this.model.url; ++ this.suggestionUrl_ = this.model.suggestionurl; + } else { + this.dialogTitle_ = + loadTimeData.getString('searchEnginesAddSearchEngine'); +@@ -134,7 +137,7 @@ export class SettingsSearchEngineEditDialogElement extends + + private onActionButtonClick_() { + this.browserProxy_.searchEngineEditCompleted( +- this.searchEngine_, this.keyword_, this.queryUrl_); ++ this.searchEngine_, this.keyword_, this.queryUrl_, this.suggestionUrl_); + this.$.dialog.close(); + } + +diff --git a/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.ts b/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.ts +--- a/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.ts ++++ b/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.ts +@@ -32,6 +32,7 @@ export interface SearchEngine { + name: string; + shouldConfirmDeletion: boolean; + url: string; ++ suggestionurl: string; + urlLocked: boolean; + } + +@@ -94,7 +95,7 @@ export interface SearchEnginesBrowserProxy { + searchEngineEditCancelled(): void; + + searchEngineEditCompleted( +- searchEngine: string, keyword: string, queryUrl: string): void; ++ searchEngine: string, keyword: string, queryUrl: string, suggestionUrl: string): void; + + getSearchEnginesList(): Promise; + +@@ -136,11 +137,12 @@ export class SearchEnginesBrowserProxyImpl implements + } + + searchEngineEditCompleted( +- searchEngine: string, keyword: string, queryUrl: string) { ++ searchEngine: string, keyword: string, queryUrl: string, suggestionUrl: string) { + chrome.send('searchEngineEditCompleted', [ + searchEngine, + keyword, + queryUrl, ++ suggestionUrl + ]); + } + +@@ -153,7 +155,7 @@ export class SearchEnginesBrowserProxyImpl implements + } + + recordSearchEnginesPageHistogram(interaction: SearchEnginesInteractions) { +- chrome.metricsPrivate.recordEnumerationValue( ++ chrome.metricsPrivate?.recordEnumerationValue( + 'Settings.SearchEngines.Interactions', interaction, + SearchEnginesInteractions.COUNT); + } +diff --git a/chrome/browser/resources/settings/search_engines_page/search_engines_page.html b/chrome/browser/resources/settings/search_engines_page/search_engines_page.html +--- a/chrome/browser/resources/settings/search_engines_page/search_engines_page.html ++++ b/chrome/browser/resources/settings/search_engines_page/search_engines_page.html +@@ -3,6 +3,7 @@ + border-top: var(--cr-separator-line); + } + ++ +
+
$i18n{searchEnginesPageExplanation}
+
+@@ -34,10 +35,14 @@ + + +
+- ++
+
+
+-

$i18n{searchEnginesSearchEngines}

++

++ style="padding-top:0px" ++ ++ >$i18n{searchEnginesSearchEngines}

+
+ $i18n{searchEnginesSearchEnginesExplanation} +
+diff --git a/chrome/browser/resources/settings/search_page/search_page.html b/chrome/browser/resources/settings/search_page/search_page.html +--- a/chrome/browser/resources/settings/search_page/search_page.html ++++ b/chrome/browser/resources/settings/search_page/search_page.html +@@ -121,7 +121,11 @@ + associated-control="[[$$('#enginesSubpageTrigger')]]" + page-title="$i18n{searchEnginesManageSiteSearch}" + search-label="$i18n{searchEnginesSearch}" +- search-term="{{searchEnginesFilter_}}"> ++ search-term="{{searchEnginesFilter_}}" ++ ++ hide-close-button="true" ++ ++ style="max-width: calc(100vw)"> + + +diff --git a/chrome/browser/resources/settings/settings.gni b/chrome/browser/resources/settings/settings.gni +--- a/chrome/browser/resources/settings/settings.gni ++++ b/chrome/browser/resources/settings/settings.gni +@@ -4,7 +4,7 @@ + + import("//third_party/closure_compiler/compile_js.gni") + +-assert(!is_android, "Android does not use these settings") ++#assert(!is_android, "Android does not use these settings") + + settings_closure_flags = + default_closure_args + [ +diff --git a/chrome/browser/resources/settings/settings.html b/chrome/browser/resources/settings/settings.html +--- a/chrome/browser/resources/settings/settings.html ++++ b/chrome/browser/resources/settings/settings.html +@@ -1,9 +1,15 @@ + + ++ $i18n{chromeRefresh2023Attribute} ++ ++ $i18n{chromeAndroid} ++> + + + ++ ++ ++ + $i18n{settings} + + +diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.html b/chrome/browser/resources/settings/settings_ui/settings_ui.html +--- a/chrome/browser/resources/settings/settings_ui/settings_ui.html ++++ b/chrome/browser/resources/settings/settings_ui/settings_ui.html +@@ -44,6 +44,9 @@ + display: flex; + flex: 1; + overflow: overlay; ++ ++ overflow-x: hidden; ++ + position: relative; + } + +@@ -84,6 +87,9 @@ + + + ++ style="display:none" ++ + page-name="$i18n{settings}" + clear-label="$i18n{clearSearch}" + autofocus +diff --git a/chrome/browser/resources/settings_shared/BUILD.gn b/chrome/browser/resources/settings_shared/BUILD.gn +--- a/chrome/browser/resources/settings_shared/BUILD.gn ++++ b/chrome/browser/resources/settings_shared/BUILD.gn +@@ -4,7 +4,7 @@ + + import("//ui/webui/resources/tools/build_webui.gni") + +-assert(!is_android) ++#assert(!is_android) + + build_webui("build") { + grd_prefix = "settings_shared" +diff --git a/chrome/browser/search_engines/android/BUILD.gn b/chrome/browser/search_engines/android/BUILD.gn +--- a/chrome/browser/search_engines/android/BUILD.gn ++++ b/chrome/browser/search_engines/android/BUILD.gn +@@ -75,6 +75,7 @@ android_resources("java_resources") { + sources = [ + "java/res/drawable/search_sogou.xml", + "java/res/layout/search_engine.xml", ++ "java/res/layout/search_engine_layout.xml", + "java/res/layout/search_engine_choice_item.xml", + "java/res/layout/search_engine_choice_view.xml", + "java/res/layout/search_engine_recent_title.xml", +diff --git a/chrome/browser/search_engines/android/java/res/layout/search_engine_layout.xml b/chrome/browser/search_engines/android/java/res/layout/search_engine_layout.xml +new file mode 100644 +--- /dev/null ++++ b/chrome/browser/search_engines/android/java/res/layout/search_engine_layout.xml +@@ -0,0 +1,25 @@ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/SearchEngineSettings.java b/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/SearchEngineSettings.java +--- a/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/SearchEngineSettings.java ++++ b/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/SearchEngineSettings.java +@@ -8,6 +8,10 @@ import android.os.Bundle; + import android.view.View; + import android.widget.ListView; + ++import android.view.LayoutInflater; ++import android.view.ViewGroup; ++import android.widget.TextView; ++ + import androidx.fragment.app.ListFragment; + + import org.chromium.chrome.browser.profiles.Profile; +@@ -25,6 +29,7 @@ import org.chromium.components.browser_ui.settings.SettingsLauncher; + public class SearchEngineSettings extends ListFragment implements ProfileDependentSetting { + private SearchEngineAdapter mSearchEngineAdapter; + private Profile mProfile; ++ private SettingsLauncher mSettingsLauncher; + + String getValueForTesting() { + return mSearchEngineAdapter.getValueForTesting(); +@@ -46,6 +51,19 @@ public class SearchEngineSettings extends ListFragment implements ProfileDepende + setListAdapter(mSearchEngineAdapter); + } + ++ @Override ++ public View onCreateView(LayoutInflater inflater, ViewGroup container, ++ Bundle savedInstanceState) { ++ View v = inflater.inflate(R.layout.search_engine_layout, null); ++ ++ TextView selectButton = (TextView) v.findViewById(R.id.open_desktop_ui); ++ selectButton.setOnClickListener(view -> { ++ mSettingsLauncher.launchUrlInCustomTab(getContext(), ++ "chrome://settings/searchEngines"); ++ }); ++ return v; ++ } ++ + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); +@@ -81,6 +99,7 @@ public class SearchEngineSettings extends ListFragment implements ProfileDepende + * @param settingsLauncher The SettingsLauncher that is injected. + */ + public void setSettingsLauncher(SettingsLauncher settingsLauncher) { ++ mSettingsLauncher = settingsLauncher; + createAdapterIfNecessary(); + mSearchEngineAdapter.setSettingsLauncher(settingsLauncher); + } +diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn +--- a/chrome/browser/ui/BUILD.gn ++++ b/chrome/browser/ui/BUILD.gn +@@ -1019,6 +1019,18 @@ static_library("ui") { + "//ui/android", + "//url", + ] ++ sources += [ ++ "webui/settings/settings_ui_android.cc", ++ "webui/settings/settings_ui_android.h", ++ "webui/settings/search_engines_handler.cc", ++ "webui/settings/search_engines_handler.h", ++ "webui/settings/settings_page_ui_handler.cc", ++ "webui/settings/settings_page_ui_handler.h", ++ "webui/settings/settings_localized_strings_provider_android.cc", ++ "webui/settings/settings_localized_strings_provider_android.h", ++ "webui/favicon_source.cc", ++ "webui/favicon_source.h", ++ ] + } else { + # !is_android + sources += [ +diff --git a/chrome/browser/ui/search_engines/edit_search_engine_controller.cc b/chrome/browser/ui/search_engines/edit_search_engine_controller.cc +--- a/chrome/browser/ui/search_engines/edit_search_engine_controller.cc ++++ b/chrome/browser/ui/search_engines/edit_search_engine_controller.cc +@@ -89,9 +89,11 @@ bool EditSearchEngineController::IsKeywordValid( + void EditSearchEngineController::AcceptAddOrEdit( + const std::u16string& title_input, + const std::u16string& keyword_input, +- const std::string& url_input) { ++ const std::string& url_input, ++ const std::string& url_suggestion_input) { + DCHECK(!keyword_input.empty()); + std::string url_string = GetFixedUpURL(url_input); ++ std::string url_suggestion = GetFixedUpURL(url_suggestion_input); + DCHECK(!url_string.empty()); + + TemplateURLService* template_url_service = +@@ -115,12 +117,12 @@ void EditSearchEngineController::AcceptAddOrEdit( + DCHECK(template_url_); + template_url_service->AddWithOverrides( + base::WrapUnique(template_url_.get()), title_input, keyword_input, +- url_string); ++ url_string, url_suggestion); + base::RecordAction(UserMetricsAction("KeywordEditor_AddKeywordJS")); + } else { + // Adding or modifying an entry via the Delegate. + edit_keyword_delegate_->OnEditedKeyword(template_url_, title_input, +- keyword_input, url_string); ++ keyword_input, url_string, url_suggestion); + } + } + +diff --git a/chrome/browser/ui/search_engines/edit_search_engine_controller.h b/chrome/browser/ui/search_engines/edit_search_engine_controller.h +--- a/chrome/browser/ui/search_engines/edit_search_engine_controller.h ++++ b/chrome/browser/ui/search_engines/edit_search_engine_controller.h +@@ -23,7 +23,8 @@ class EditSearchEngineControllerDelegate { + virtual void OnEditedKeyword(TemplateURL* template_url, + const std::u16string& title, + const std::u16string& keyword, +- const std::string& url) = 0; ++ const std::string& url, ++ const std::string& suggestion_url) = 0; + + protected: + virtual ~EditSearchEngineControllerDelegate() {} +@@ -62,7 +63,8 @@ class EditSearchEngineController { + // Completes the add or edit of a search engine. + void AcceptAddOrEdit(const std::u16string& title_input, + const std::u16string& keyword_input, +- const std::string& url_input); ++ const std::string& url_input, ++ const std::string& url_suggestion); + + // Deletes an unused TemplateURL, if its add was cancelled and it's not + // already owned by the TemplateURLService. +diff --git a/chrome/browser/ui/search_engines/keyword_editor_controller.cc b/chrome/browser/ui/search_engines/keyword_editor_controller.cc +--- a/chrome/browser/ui/search_engines/keyword_editor_controller.cc ++++ b/chrome/browser/ui/search_engines/keyword_editor_controller.cc +@@ -23,13 +23,14 @@ KeywordEditorController::~KeywordEditorController() { + + int KeywordEditorController::AddTemplateURL(const std::u16string& title, + const std::u16string& keyword, +- const std::string& url) { ++ const std::string& url, ++ const std::string& suggestion_url) { + DCHECK(!url.empty()); + + base::RecordAction(UserMetricsAction("KeywordEditor_AddKeyword")); + + const int new_index = table_model_->last_other_engine_index(); +- table_model_->Add(new_index, title, keyword, url); ++ table_model_->Add(new_index, title, keyword, url, suggestion_url); + + return new_index; + } +@@ -37,7 +38,8 @@ int KeywordEditorController::AddTemplateURL(const std::u16string& title, + void KeywordEditorController::ModifyTemplateURL(TemplateURL* template_url, + const std::u16string& title, + const std::u16string& keyword, +- const std::string& url) { ++ const std::string& url, ++ const std::string& suggestion_url) { + DCHECK(!url.empty()); + const absl::optional index = + table_model_->IndexOfTemplateURL(template_url); +@@ -49,10 +51,11 @@ void KeywordEditorController::ModifyTemplateURL(TemplateURL* template_url, + + // Don't do anything if the entry didn't change. + if ((template_url->short_name() == title) && +- (template_url->keyword() == keyword) && (template_url->url() == url)) ++ (template_url->keyword() == keyword) && (template_url->url() == url) && ++ (template_url->data().suggestions_url == suggestion_url)) + return; + +- table_model_->ModifyTemplateURL(index.value(), title, keyword, url); ++ table_model_->ModifyTemplateURL(index.value(), title, keyword, url, suggestion_url); + + base::RecordAction(UserMetricsAction("KeywordEditor_ModifiedKeyword")); + } +diff --git a/chrome/browser/ui/search_engines/keyword_editor_controller.h b/chrome/browser/ui/search_engines/keyword_editor_controller.h +--- a/chrome/browser/ui/search_engines/keyword_editor_controller.h ++++ b/chrome/browser/ui/search_engines/keyword_editor_controller.h +@@ -29,14 +29,16 @@ class KeywordEditorController { + // model. Returns the index of the added URL. + int AddTemplateURL(const std::u16string& title, + const std::u16string& keyword, +- const std::string& url); ++ const std::string& url, ++ const std::string& suggestion_url); + + // Invoked when the user modifies a TemplateURL. Updates the + // TemplateURLService and table model appropriately. + void ModifyTemplateURL(TemplateURL* template_url, + const std::u16string& title, + const std::u16string& keyword, +- const std::string& url); ++ const std::string& url, ++ const std::string& suggestion_url); + + // Return true if the given |url| can be edited. + bool CanEdit(const TemplateURL* url) const; +diff --git a/chrome/browser/ui/search_engines/template_url_table_model.cc b/chrome/browser/ui/search_engines/template_url_table_model.cc +--- a/chrome/browser/ui/search_engines/template_url_table_model.cc ++++ b/chrome/browser/ui/search_engines/template_url_table_model.cc +@@ -105,7 +105,8 @@ void TemplateURLTableModel::Remove(size_t index) { + void TemplateURLTableModel::Add(size_t index, + const std::u16string& short_name, + const std::u16string& keyword, +- const std::string& url) { ++ const std::string& url, ++ const std::string& suggestion_url) { + DCHECK(index <= RowCount()); + DCHECK(!url.empty()); + TemplateURLData data; +@@ -113,13 +114,15 @@ void TemplateURLTableModel::Add(size_t index, + data.SetKeyword(keyword); + data.SetURL(url); + data.is_active = TemplateURLData::ActiveStatus::kTrue; ++ data.suggestions_url = suggestion_url; + template_url_service_->Add(std::make_unique(data)); + } + + void TemplateURLTableModel::ModifyTemplateURL(size_t index, + const std::u16string& title, + const std::u16string& keyword, +- const std::string& url) { ++ const std::string& url, ++ const std::string& suggestion_url) { + DCHECK(index <= RowCount()); + DCHECK(!url.empty()); + TemplateURL* template_url = GetTemplateURL(index); +@@ -128,7 +131,7 @@ void TemplateURLTableModel::ModifyTemplateURL(size_t index, + DCHECK(template_url_service_->GetDefaultSearchProvider() != template_url || + template_url->SupportsReplacement( + template_url_service_->search_terms_data())); +- template_url_service_->ResetTemplateURL(template_url, title, keyword, url); ++ template_url_service_->ResetTemplateURL(template_url, title, keyword, url, suggestion_url); + } + + TemplateURL* TemplateURLTableModel::GetTemplateURL(size_t index) { +diff --git a/chrome/browser/ui/search_engines/template_url_table_model.h b/chrome/browser/ui/search_engines/template_url_table_model.h +--- a/chrome/browser/ui/search_engines/template_url_table_model.h ++++ b/chrome/browser/ui/search_engines/template_url_table_model.h +@@ -54,13 +54,15 @@ class TemplateURLTableModel : public ui::TableModel, + void Add(size_t index, + const std::u16string& short_name, + const std::u16string& keyword, +- const std::string& url); ++ const std::string& url, ++ const std::string& suggestion_url); + + // Update the entry at the specified index. + void ModifyTemplateURL(size_t index, + const std::u16string& title, + const std::u16string& keyword, +- const std::string& url); ++ const std::string& url, ++ const std::string& suggestion_url); + + // Reloads the icon at the specified index. + void ReloadIcon(size_t index); +diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc +--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc ++++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc +@@ -138,6 +138,8 @@ + #include "chrome/browser/ui/webui/webapks/webapks_ui.h" + #include "components/feed/buildflags.h" + #include "components/feed/feed_feature_list.h" ++#include "chrome/browser/ui/webui/settings/settings_ui.h" ++#include "chrome/browser/ui/webui/settings/settings_utils.h" + #else // BUILDFLAG(IS_ANDROID) + #include "chrome/browser/media/router/discovery/access_code/access_code_cast_feature.h" + #include "chrome/browser/media/router/media_router_feature.h" +@@ -673,6 +675,10 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui, + return &NewWebUI; + } + #endif // !BUILDFLAG(IS_ANDROID) ++#if BUILDFLAG(IS_ANDROID) ++ if (url.host_piece() == chrome::kChromeUISettingsHost) ++ return &NewWebUI; ++#endif // BUILDFLAG(IS_ANDROID) + #if BUILDFLAG(IS_WIN) + if (url.host_piece() == chrome::kChromeUIConflictsHost) + return &NewWebUI; +diff --git a/chrome/browser/ui/webui/favicon_source.cc b/chrome/browser/ui/webui/favicon_source.cc +--- a/chrome/browser/ui/webui/favicon_source.cc ++++ b/chrome/browser/ui/webui/favicon_source.cc +@@ -15,7 +15,9 @@ + #include "chrome/browser/favicon/history_ui_favicon_request_handler_factory.h" + #include "chrome/browser/history/top_sites_factory.h" + #include "chrome/browser/profiles/profile.h" ++#if !BUILDFLAG(IS_ANDROID) + #include "chrome/browser/search/instant_service.h" ++#endif + #include "chrome/browser/ui/webui/webui_util.h" + #include "chrome/common/url_constants.h" + #include "chrome/common/webui_url_constants.h" +@@ -24,9 +26,11 @@ + #include "components/history/core/browser/top_sites.h" + #include "content/public/browser/browser_thread.h" + #include "content/public/browser/web_contents.h" ++#if !BUILDFLAG(IS_ANDROID) + #include "extensions/browser/extension_registry.h" + #include "extensions/common/constants.h" + #include "extensions/common/manifest.h" ++#endif + #include "third_party/skia/include/core/SkBitmap.h" + #include "ui/base/resource/resource_bundle.h" + #include "ui/base/resource/resource_scale_factor.h" +@@ -122,6 +126,7 @@ void FaviconSource::StartDataRequest( + return; + } + ++#if !BUILDFLAG(IS_ANDROID) + if (url_format_ == chrome::FaviconUrlFormat::kFaviconLegacy) { + const extensions::Extension* extension = + extensions::ExtensionRegistry::Get(profile_) +@@ -133,6 +138,7 @@ void FaviconSource::StartDataRequest( + extensions::Manifest::NUM_LOAD_TYPES); + } + } ++#endif + + if (parsed.page_url.empty()) { + // Request by icon url. +@@ -220,18 +226,22 @@ bool FaviconSource::ShouldServiceRequest( + const GURL& url, + content::BrowserContext* browser_context, + int render_process_id) { ++#if !BUILDFLAG(IS_ANDROID) + if (url.SchemeIs(chrome::kChromeSearchScheme)) { + return InstantService::ShouldServiceRequest(url, browser_context, + render_process_id); + } ++#endif + return URLDataSource::ShouldServiceRequest(url, browser_context, + render_process_id); + } + ++#if !BUILDFLAG(IS_ANDROID) + ui::NativeTheme* FaviconSource::GetNativeTheme( + const content::WebContents::Getter& wc_getter) { + return webui::GetNativeTheme(wc_getter.Run()); + } ++#endif + + void FaviconSource::OnFaviconDataAvailable( + content::URLDataSource::GotDataCallback callback, +@@ -255,7 +265,11 @@ void FaviconSource::SendDefaultResponse( + parsed.device_scale_factor, + parsed.force_light_mode + ? false ++#if !BUILDFLAG(IS_ANDROID) + : GetNativeTheme(wc_getter)->ShouldUseDarkColors()); ++#else ++ : false); ++#endif + return; + } + int icon_size = std::ceil(parsed.size_in_dip * parsed.device_scale_factor); +@@ -274,7 +288,11 @@ void FaviconSource::SendDefaultResponse( + SendDefaultResponse(std::move(callback), 16, 1.0f, + force_light_mode + ? false ++#if !BUILDFLAG(IS_ANDROID) + : GetNativeTheme(wc_getter)->ShouldUseDarkColors()); ++#else ++ : false); ++#endif + } + + void FaviconSource::SendDefaultResponse( +@@ -284,6 +302,7 @@ void FaviconSource::SendDefaultResponse( + bool dark_mode) { + int resource_id; + switch (size_in_dip) { ++#if !BUILDFLAG(IS_ANDROID) + case 64: + resource_id = + dark_mode ? IDR_DEFAULT_FAVICON_DARK_64 : IDR_DEFAULT_FAVICON_64; +@@ -292,6 +311,7 @@ void FaviconSource::SendDefaultResponse( + resource_id = + dark_mode ? IDR_DEFAULT_FAVICON_DARK_32 : IDR_DEFAULT_FAVICON_32; + break; ++#endif + default: + resource_id = dark_mode ? IDR_DEFAULT_FAVICON_DARK : IDR_DEFAULT_FAVICON; + break; +diff --git a/chrome/browser/ui/webui/favicon_source.h b/chrome/browser/ui/webui/favicon_source.h +--- a/chrome/browser/ui/webui/favicon_source.h ++++ b/chrome/browser/ui/webui/favicon_source.h +@@ -60,9 +60,11 @@ class FaviconSource : public content::URLDataSource { + int render_process_id) override; + + protected: ++#if !BUILDFLAG(IS_ANDROID) + // Exposed for testing. + virtual ui::NativeTheme* GetNativeTheme( + const content::WebContents::Getter& wc_getter); ++#endif + virtual base::RefCountedMemory* LoadIconBytes(float scale_factor, + int resource_id); + +diff --git a/chrome/browser/ui/webui/settings/search_engines_handler.cc b/chrome/browser/ui/webui/settings/search_engines_handler.cc +--- a/chrome/browser/ui/webui/settings/search_engines_handler.cc ++++ b/chrome/browser/ui/webui/settings/search_engines_handler.cc +@@ -31,10 +31,12 @@ + #include "components/search_engines/template_url_service.h" + #include "components/signin/public/base/signin_switches.h" + #include "content/public/browser/web_ui.h" ++#if !BUILDFLAG(IS_ANDROID) + #include "extensions/browser/extension_registry.h" + #include "extensions/browser/extension_system.h" + #include "extensions/browser/management_policy.h" + #include "extensions/common/extension.h" ++#endif + + #if BUILDFLAG(IS_CHROMEOS_ASH) + #include "ash/public/cpp/new_window_delegate.h" +@@ -46,6 +48,7 @@ namespace { + const char kSearchEngineField[] = "searchEngine"; + const char kKeywordField[] = "keyword"; + const char kQueryUrlField[] = "queryUrl"; ++const char kSuggestionUrlField[] = "suggestionUrl"; + + // Dummy number used for indicating that a new search engine is added. + const int kNewSearchEngineIndex = -1; +@@ -218,15 +221,17 @@ base::Value::Dict SearchEnginesHandler::CreateDictionaryForEngine( + IDS_SEARCH_ENGINES_EDITOR_DESCRIPTION_COLUMN)); + dict.Set("keyword", table_model->GetText( + index, IDS_SEARCH_ENGINES_EDITOR_KEYWORD_COLUMN)); +- Profile* profile = Profile::FromWebUI(web_ui()); + dict.Set("url", + template_url->url_ref().DisplayURL(UIThreadSearchTermsData())); ++ dict.Set("suggestionurl", ++ template_url->suggestions_url_ref().DisplayURL(UIThreadSearchTermsData())); + dict.Set("urlLocked", ((template_url->prepopulate_id() > 0) || + (template_url->starter_pack_id() > 0))); + GURL icon_url = template_url->favicon_url(); + if (icon_url.is_valid()) + dict.Set("iconURL", icon_url.spec()); + ++#if !BUILDFLAG(IS_ANDROID) + const bool is_search_engine_choice_settings_ui = + base::FeatureList::IsEnabled(switches::kSearchEngineChoiceSettingsUi) && + search_engines::IsChoiceScreenFlagEnabled( +@@ -237,6 +242,7 @@ base::Value::Dict SearchEnginesHandler::CreateDictionaryForEngine( + template_url->keyword(), /*parent_directory_path=*/u"images/"); + dict.Set("iconPath", icon_path); + } ++#endif + + dict.Set("modelIndex", base::checked_cast(index)); + +@@ -250,8 +256,10 @@ base::Value::Dict SearchEnginesHandler::CreateDictionaryForEngine( + list_controller_.ShouldConfirmDeletion(template_url)); + TemplateURL::Type type = template_url->type(); + dict.Set("isOmniboxExtension", type == TemplateURL::OMNIBOX_API_EXTENSION); ++#if !BUILDFLAG(IS_ANDROID) + if (type == TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION || + type == TemplateURL::OMNIBOX_API_EXTENSION) { ++ Profile* profile = Profile::FromWebUI(web_ui()); + const extensions::Extension* extension = + extensions::ExtensionRegistry::Get(profile)->GetExtensionById( + template_url->GetExtensionId(), +@@ -266,6 +274,7 @@ base::Value::Dict SearchEnginesHandler::CreateDictionaryForEngine( + dict.Set("extension", std::move(ext_info)); + } + } ++#endif + return dict; + } + +@@ -357,12 +366,13 @@ void SearchEnginesHandler::HandleSearchEngineEditStarted( + void SearchEnginesHandler::OnEditedKeyword(TemplateURL* template_url, + const std::u16string& title, + const std::u16string& keyword, +- const std::string& url) { ++ const std::string& url, ++ const std::string& suggestion_url) { + DCHECK(!url.empty()); + if (template_url) +- list_controller_.ModifyTemplateURL(template_url, title, keyword, url); ++ list_controller_.ModifyTemplateURL(template_url, title, keyword, url, suggestion_url); + else +- list_controller_.AddTemplateURL(title, keyword, url); ++ list_controller_.AddTemplateURL(title, keyword, url, suggestion_url); + + edit_controller_.reset(); + } +@@ -390,6 +400,8 @@ bool SearchEnginesHandler::CheckFieldValidity(const std::string& field_name, + is_valid = edit_controller_->IsKeywordValid(base::UTF8ToUTF16(field_value)); + else if (field_name.compare(kQueryUrlField) == 0) + is_valid = edit_controller_->IsURLValid(field_value); ++ else if (field_name.compare(kSuggestionUrlField) == 0) ++ is_valid = edit_controller_->IsURLValid(field_value); + else + NOTREACHED(); + +@@ -409,18 +421,20 @@ void SearchEnginesHandler::HandleSearchEngineEditCompleted( + if (!edit_controller_.get()) + return; + +- CHECK_EQ(3U, args.size()); ++ CHECK_EQ(4U, args.size()); + const std::string& search_engine = args[0].GetString(); + const std::string& keyword = args[1].GetString(); + const std::string& query_url = args[2].GetString(); ++ const std::string& suggestion_url = args[3].GetString(); + + // Recheck validity. It's possible to get here with invalid input if e.g. the + // user calls the right JS functions directly from the web inspector. + if (CheckFieldValidity(kSearchEngineField, search_engine) && + CheckFieldValidity(kKeywordField, keyword) && +- CheckFieldValidity(kQueryUrlField, query_url)) { ++ CheckFieldValidity(kQueryUrlField, query_url) && ++ CheckFieldValidity(kSuggestionUrlField, suggestion_url)) { + edit_controller_->AcceptAddOrEdit(base::UTF8ToUTF16(search_engine), +- base::UTF8ToUTF16(keyword), query_url); ++ base::UTF8ToUTF16(keyword), query_url, suggestion_url); + } + } + +diff --git a/chrome/browser/ui/webui/settings/search_engines_handler.h b/chrome/browser/ui/webui/settings/search_engines_handler.h +--- a/chrome/browser/ui/webui/settings/search_engines_handler.h ++++ b/chrome/browser/ui/webui/settings/search_engines_handler.h +@@ -41,7 +41,8 @@ class SearchEnginesHandler : public SettingsPageUIHandler, + void OnEditedKeyword(TemplateURL* template_url, + const std::u16string& title, + const std::u16string& keyword, +- const std::string& url) override; ++ const std::string& url, ++ const std::string& suggestion_url) override; + + // SettingsPageUIHandler implementation. + void RegisterMessages() override; +diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc ++++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +@@ -2493,6 +2493,8 @@ void AddSearchEnginesStrings(content::WebUIDataSource* html_source) { + {"searchEnginesQueryURL", IDS_SETTINGS_SEARCH_ENGINES_QUERY_URL}, + {"searchEnginesQueryURLExplanation", + IDS_SETTINGS_SEARCH_ENGINES_QUERY_URL_EXPLANATION}, ++ {"searchEnginesSuggestionURLExplanation", ++ IDS_SETTINGS_SEARCH_ENGINES_SUGGESTION_URL_EXPLANATION}, + {"searchEnginesMakeDefault", IDS_SETTINGS_SEARCH_ENGINES_MAKE_DEFAULT}, + {"searchEnginesActivate", IDS_SETTINGS_SEARCH_ENGINES_ACTIVATE}, + {"searchEnginesDeactivate", IDS_SETTINGS_SEARCH_ENGINES_DEACTIVATE}, +diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider_android.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider_android.cc +new file mode 100644 +--- /dev/null ++++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider_android.cc +@@ -0,0 +1,196 @@ ++#include "chrome/browser/ui/webui/settings/settings_localized_strings_provider.h" ++ ++#include ++ ++#include "base/command_line.h" ++#include "base/feature_list.h" ++#include "base/i18n/message_formatter.h" ++#include "base/i18n/number_formatting.h" ++#include "base/strings/escape.h" ++#include "base/strings/string_number_conversions.h" ++#include "base/strings/utf_string_conversions.h" ++#include "base/json/json_writer.h" ++#include "build/branding_buildflags.h" ++#include "build/build_config.h" ++#include "build/buildflag.h" ++#include "build/chromeos_buildflags.h" ++#include "chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.h" ++#include "chrome/browser/ui/webui/version/version_ui.h" ++#include "chrome/grit/branded_strings.h" ++#include "chrome/grit/generated_resources.h" ++#include "chrome/grit/locale_settings.h" ++#include "ui/base/l10n/l10n_util.h" ++#include "ui/strings/grit/ui_strings.h" ++ ++namespace settings { ++namespace { ++ ++inline constexpr char16_t kSettingsSearchHelpURL[] = ++ u"https://nourl"; ++ ++void AddCommonStrings(content::WebUIDataSource* html_source, Profile* profile) { ++ static constexpr webui::LocalizedString kLocalizedStrings[] = { ++ {"add", IDS_ADD2}, ++ {"advancedPageTitle", IDS_SETTINGS_ADVANCED}, ++ {"back", IDS_ACCNAME_BACK2}, ++ {"basicPageTitle", IDS_SETTINGS_BASIC}, ++ {"cancel", IDS_CANCEL2}, ++ {"clear", IDS_SETTINGS_CLEAR}, ++ {"close", IDS_CLOSE2}, ++ {"confirm", IDS_CONFIRM}, ++ {"continue", IDS_SETTINGS_CONTINUE}, ++ {"controlledByExtension", IDS_SETTINGS_CONTROLLED_BY_EXTENSION}, ++ {"custom", IDS_SETTINGS_CUSTOM}, ++ {"delete", IDS_SETTINGS_DELETE}, ++ {"disable", IDS_DISABLE}, ++ {"done", IDS_DONE2}, ++ {"edit", IDS_SETTINGS_EDIT}, ++ {"extensionsLinkTooltip", IDS_SETTINGS_MENU_EXTENSIONS_LINK_TOOLTIP}, ++ {"fonts", IDS_SETTINGS_FONTS}, ++ {"learnMore", IDS_LEARN_MORE2}, ++ {"manage", IDS_SETTINGS_MANAGE}, ++ {"menu", IDS_MENU2}, ++ {"menuButtonLabel", IDS_SETTINGS_MENU_BUTTON_LABEL}, ++ {"moreActions", IDS_SETTINGS_MORE_ACTIONS}, ++ {"noThanks", IDS_NO_THANKS2}, ++ {"ok", IDS_OK2}, ++ {"opensInNewTab", IDS_SETTINGS_OPENS_IN_NEW_TAB}, ++ {"sendFeedbackButton", IDS_SETTINGS_SEND_FEEDBACK_ROLE_DESCRIPTION}, ++ //{"relaunchConfirmationDialogTitle", IDS_RELAUNCH_CONFIRMATION_DIALOG_TITLE}, ++ {"remove", IDS_REMOVE2}, ++ {"restart", IDS_SETTINGS_RESTART}, ++ //{"restartToApplyChanges", IDS_SETTINGS_RESTART_TO_APPLY_CHANGES}, ++ {"retry", IDS_SETTINGS_RETRY}, ++ {"save", IDS_SAVE2}, ++ //{"searchResultBubbleText", IDS_SEARCH_RESULT_BUBBLE_TEXT}, ++ //{"searchResultsBubbleText", IDS_SEARCH_RESULTS_BUBBLE_TEXT}, ++ {"sentenceEnd", IDS_SENTENCE_END}, ++ {"settings", IDS_SETTINGS_SETTINGS}, ++ {"settingsAltPageTitle", IDS_SETTINGS_ALT_PAGE_TITLE}, ++ {"subpageArrowRoleDescription", IDS_SETTINGS_SUBPAGE_BUTTON}, ++ {"subpageBackButtonAriaLabel", IDS_SETTINGS_SUBPAGE_BACK_BUTTON_ARIA_LABEL}, ++ {"subpageBackButtonAriaRoleDescription", ++ IDS_SETTINGS_SUBPAGE_BACK_BUTTON_ARIA_ROLE_DESCRIPTION}, ++ {"subpageLearnMoreAriaLabel", IDS_SETTINGS_SUBPAGE_LEARN_MORE_ARIA_LABEL}, ++ {"notValid", IDS_SETTINGS_NOT_VALID}, ++ {"notValidWebAddress", IDS_SETTINGS_NOT_VALID_WEB_ADDRESS}, ++ {"notValidWebAddressForContentType", ++ IDS_SETTINGS_NOT_VALID_WEB_ADDRESS_FOR_CONTENT_TYPE}, ++ }; ++ html_source->AddLocalizedStrings(kLocalizedStrings); ++ ++ html_source->AddBoolean( ++ "isGuest", false); ++ ++ html_source->AddBoolean("isChildAccount", false); ++ ++ html_source->AddBoolean( ++ "clearingCookiesKeepsSupervisedUsersSignedIn", ++ false); ++ ++ html_source->AddBoolean("allowQtTheme", false); ++} ++ ++void AddSearchEnginesStrings(content::WebUIDataSource* html_source) { ++ static constexpr webui::LocalizedString kLocalizedStrings[] = { ++ {"searchEnginesPageExplanation", ++ IDS_SETTINGS_SEARCH_ENGINES_PAGE_EXPLANATION}, ++ {"searchEnginesAddSearchEngine", ++ IDS_SETTINGS_SEARCH_ENGINES_ADD_SEARCH_ENGINE}, ++ {"searchEnginesEditSearchEngine", ++ IDS_SETTINGS_SEARCH_ENGINES_EDIT_SEARCH_ENGINE}, ++ {"searchEnginesDeleteConfirmationTitle", ++ IDS_SETTINGS_SEARCH_ENGINES_DELETE_CONFIRMATION_TITLE}, ++ {"searchEnginesDeleteConfirmationDescription", ++ IDS_SETTINGS_SEARCH_ENGINES_DELETE_CONFIRMATION_DESCRIPTION}, ++ {"searchEngines", IDS_SETTINGS_SEARCH_ENGINES}, ++ {"searchEnginesSearchEngines", ++ IDS_SETTINGS_SEARCH_ENGINES_SEARCH_ENGINES}, ++ {"searchEnginesSearchEnginesExplanation", ++ IDS_SETTINGS_SEARCH_ENGINES_SEARCH_ENGINES_EXPLANATION}, ++ {"searchEnginesSiteSearch", IDS_SETTINGS_SEARCH_ENGINES_SITE_SEARCH}, ++ {"searchEnginesSiteSearchExplanation", ++ IDS_SETTINGS_SEARCH_ENGINES_SITE_SEARCH_EXPLANATION}, ++ {"searchEnginesNoSitesAdded", IDS_SETTINGS_SEARCH_ENGINES_NO_SITES_ADDED}, ++ {"searchEnginesInactiveShortcuts", ++ IDS_SETTINGS_SEARCH_ENGINES_INACTIVE_SHORTCUTS}, ++ {"searchEnginesNoOtherEngines", ++ IDS_SETTINGS_SEARCH_ENGINES_NO_OTHER_ENGINES}, ++ {"searchEnginesExtension", IDS_SETTINGS_SEARCH_ENGINES_EXTENSION_ENGINES}, ++ {"searchEnginesExtensionExplanation", ++ IDS_SETTINGS_SEARCH_ENGINES_EXTENSION_ENGINES_EXPLANATION}, ++ {"searchEnginesSearch", IDS_SETTINGS_SEARCH_ENGINES_SEARCH}, ++ {"searchEnginesSearchEngine", IDS_SETTINGS_SEARCH_ENGINES_SEARCH_ENGINE}, ++ {"searchEnginesSiteOrPage", IDS_SETTINGS_SEARCH_ENGINES_SITE_OR_PAGE}, ++ {"searchEnginesShortcut", IDS_SETTINGS_SEARCH_ENGINES_SHORTCUT}, ++ {"searchEnginesQueryURL", IDS_SETTINGS_SEARCH_ENGINES_QUERY_URL}, ++ {"searchEnginesQueryURLExplanation", ++ IDS_SETTINGS_SEARCH_ENGINES_QUERY_URL_EXPLANATION}, ++ {"searchEnginesSuggestionURLExplanation", ++ IDS_SETTINGS_SEARCH_ENGINES_SUGGESTION_URL_EXPLANATION}, ++ {"searchEnginesMakeDefault", IDS_SETTINGS_SEARCH_ENGINES_MAKE_DEFAULT}, ++ {"searchEnginesActivate", IDS_SETTINGS_SEARCH_ENGINES_ACTIVATE}, ++ {"searchEnginesDeactivate", IDS_SETTINGS_SEARCH_ENGINES_DEACTIVATE}, ++ {"searchEnginesManageExtension", ++ IDS_SETTINGS_SEARCH_ENGINES_MANAGE_EXTENSION}, ++ {"searchEnginesKeyboardShortcutsTitle", ++ IDS_SETTINGS_SEARCH_ENGINES_KEYBOARD_SHORTCUTS_TITLE}, ++ {"searchEnginesKeyboardShortcutsDescription", ++ IDS_SETTINGS_SEARCH_ENGINES_KEYBOARD_SHORTCUTS_DESCRIPTION}, ++ {"searchEnginesKeyboardShortcutsSpaceOrTab", ++ IDS_SETTINGS_SEARCH_ENGINES_KEYBOARD_SHORTCUTS_SPACE_OR_TAB}, ++ {"searchEnginesKeyboardShortcutsTab", ++ IDS_SETTINGS_SEARCH_ENGINES_KEYBOARD_SHORTCUTS_TAB}, ++ {"searchEnginesAdditionalSites", ++ IDS_SETTINGS_SEARCH_ENGINES_ADDITIONAL_SITES}, ++ {"searchEnginesAdditionalInactiveSites", ++ IDS_SETTINGS_SEARCH_ENGINES_ADDITIONAL_INACTIVE_SITES}, ++ }; ++ html_source->AddLocalizedStrings(kLocalizedStrings); ++} ++ ++void AddSearchStrings(content::WebUIDataSource* html_source) { ++ static constexpr webui::LocalizedString kLocalizedStrings[] = { ++ {"searchEnginesManage", IDS_SETTINGS_SEARCH_MANAGE_SEARCH_ENGINES}, ++ {"searchEnginesManageSiteSearch", ++ IDS_SETTINGS_SEARCH_MANAGE_SEARCH_ENGINES_AND_SITE_SEARCH}, ++ {"searchPageTitle", IDS_SETTINGS_SEARCH}, ++ {"searchExplanation", IDS_SETTINGS_SEARCH_EXPLANATION}, ++ {"searchExplanationLearnMoreA11yLabel", ++ IDS_SETTINGS_SEARCH_EXPLANATION_ACCESSIBILITY_LABEL}, ++ }; ++ html_source->AddLocalizedStrings(kLocalizedStrings); ++ ++ html_source->AddString("searchExplanationLearnMoreURL", ++ ""); ++} ++ ++void AddSearchInSettingsStrings(content::WebUIDataSource* html_source) { ++ static constexpr webui::LocalizedString kLocalizedStrings[] = { ++ {"searchPrompt", IDS_SETTINGS_SEARCH_PROMPT}, ++ {"searchNoResults", IDS_SEARCH_NO_RESULTS}, ++ {"searchResults", IDS_SEARCH_RESULTS}, ++ {"clearSearch", IDS_CLEAR_SEARCH}, ++ }; ++ html_source->AddLocalizedStrings(kLocalizedStrings); ++ ++ std::u16string help_text = l10n_util::GetStringFUTF16( ++ IDS_SETTINGS_SEARCH_NO_RESULTS_HELP, kSettingsSearchHelpURL); ++ html_source->AddString("searchNoResultsHelp", help_text); ++} ++ ++} // namespace ++ ++void AddLocalizedStringsAndroid(content::WebUIDataSource* html_source, ++ Profile* profile, ++ content::WebContents* web_contents) { ++ AddCommonStrings(html_source, profile); ++ AddSearchStrings(html_source); ++ AddSearchEnginesStrings(html_source); ++ AddSearchInSettingsStrings(html_source); ++ html_source->AddString("check_notfound", "false"); ++ html_source->AddInteger("br_cs_count", 0); ++ html_source->UseStringsJs(); ++} ++ ++} // namespace settings +diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider_android.h b/chrome/browser/ui/webui/settings/settings_localized_strings_provider_android.h +new file mode 100644 +--- /dev/null ++++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider_android.h +@@ -0,0 +1,19 @@ ++#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_LOCALIZED_STRINGS_PROVIDER_ANDROID_H_ ++#define CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_LOCALIZED_STRINGS_PROVIDER_ANDROID_H_ ++ ++class Profile; ++ ++namespace content { ++class WebUIDataSource; ++class WebContents; ++} ++ ++namespace settings { ++ ++void AddLocalizedStringsAndroid(content::WebUIDataSource* html_source, ++ Profile* profile, ++ content::WebContents* web_contents); ++ ++} // namespace settings ++ ++#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_LOCALIZED_STRINGS_PROVIDER_ANDROID_H_ +diff --git a/chrome/browser/ui/webui/settings/settings_ui_android.cc b/chrome/browser/ui/webui/settings/settings_ui_android.cc +new file mode 100644 +--- /dev/null ++++ b/chrome/browser/ui/webui/settings/settings_ui_android.cc +@@ -0,0 +1,135 @@ ++// Copyright 2015 The Chromium Authors ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#include "chrome/browser/ui/webui/settings/settings_ui.h" ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "base/feature_list.h" ++#include "base/memory/ptr_util.h" ++#include "build/branding_buildflags.h" ++#include "build/build_config.h" ++#include "build/chromeos_buildflags.h" ++#include "chrome/browser/profiles/profile.h" ++#include "chrome/browser/ui/ui_features.h" ++#include "chrome/browser/ui/webui/favicon_source.h" ++#include "chrome/browser/ui/webui/settings/search_engines_handler.h" ++#include "chrome/common/chrome_features.h" ++#include "chrome/common/pref_names.h" ++#include "chrome/common/url_constants.h" ++#include "chrome/grit/branded_strings.h" ++#include "chrome/grit/generated_resources.h" ++#include "chrome/grit/settings_resources.h" ++#include "chrome/grit/settings_resources_map.h" ++#include "components/favicon_base/favicon_url_parser.h" ++#include "components/permissions/features.h" ++#include "components/pref_registry/pref_registry_syncable.h" ++#include "components/prefs/pref_service.h" ++#include "content/public/browser/url_data_source.h" ++#include "content/public/browser/web_contents.h" ++#include "content/public/browser/web_ui.h" ++#include "content/public/browser/web_ui_data_source.h" ++#include "crypto/crypto_buildflags.h" ++#include "services/network/public/cpp/features.h" ++#include "third_party/blink/public/common/features.h" ++#include "ui/base/interaction/element_identifier.h" ++ ++#include "chrome/browser/ui/webui/webui_util.h" ++#include "chrome/browser/ui/webui/theme_handler.h" ++#include "chrome/browser/ui/webui/cr_components/customize_color_scheme_mode/customize_color_scheme_mode_handler.h" ++#include "chrome/browser/ui/webui/customize_themes/chrome_customize_themes_handler.h" ++#include "chrome/browser/ui/webui/settings/settings_localized_strings_provider_android.h" ++ ++#if !BUILDFLAG(OPTIMIZE_WEBUI) ++#include "chrome/grit/settings_shared_resources.h" ++#include "chrome/grit/settings_shared_resources_map.h" ++#endif ++ ++#include "chrome/browser/ui/webui/cr_components/theme_color_picker/theme_color_picker_handler.h" ++#include "chrome/browser/ui/webui/settings/captions_handler.h" ++#include "chrome/browser/ui/webui/settings/settings_default_browser_handler.h" ++#include "chrome/browser/ui/webui/settings/settings_manage_profile_handler.h" ++#include "chrome/browser/ui/webui/settings/system_handler.h" ++ ++namespace settings { ++ ++SettingsUI::SettingsUI(content::WebUI* web_ui) ++ : ui::MojoWebUIController(web_ui, /*enable_chrome_send=*/true) { ++ Profile* profile = Profile::FromWebUI(web_ui); ++ content::WebUIDataSource* html_source = ++ content::WebUIDataSource::CreateAndAdd( ++ web_ui->GetWebContents()->GetBrowserContext(), ++ chrome::kChromeUISettingsHost); ++ html_source->OverrideContentSecurityPolicy( ++ network::mojom::CSPDirectiveName::WorkerSrc, ++ "worker-src blob: chrome://resources 'self';"); ++ ++ AddSettingsPageUIHandler(std::make_unique(profile)); ++ web_ui->DoNotCrashOnUnhandledMessage(); ++ ++ webui::SetupWebUIDataSource( ++ html_source, base::make_span(kSettingsResources, kSettingsResourcesSize), ++ IDR_SETTINGS_SETTINGS_HTML); ++ ++ html_source->AddBoolean( ++ "enablePageContentSetting", ++ false); ++ ++#if !BUILDFLAG(OPTIMIZE_WEBUI) ++ html_source->AddResourcePaths( ++ base::make_span(kSettingsSharedResources, kSettingsSharedResourcesSize)); ++#endif ++ ++ webui::SetupChromeRefresh2023(html_source); ++ AddLocalizedStringsAndroid(html_source, profile, web_ui->GetWebContents()); ++ ++ content::URLDataSource::Add( ++ profile, std::make_unique( ++ profile, chrome::FaviconUrlFormat::kFavicon2)); ++} ++ ++SettingsUI::~SettingsUI() = default; ++ ++void SettingsUI::AddSettingsPageUIHandler( ++ std::unique_ptr handler) { ++ DCHECK(handler); ++ web_ui()->AddMessageHandler(std::move(handler)); ++} ++ ++void SettingsUI::CreateCustomizeThemesHandler( ++ mojo::PendingRemote ++ pending_client, ++ mojo::PendingReceiver ++ pending_handler) { ++} ++ ++void SettingsUI::CreateThemeColorPickerHandler( ++ mojo::PendingReceiver ++ handler, ++ mojo::PendingRemote ++ client) { ++} ++ ++void SettingsUI::CreateHelpBubbleHandler( ++ mojo::PendingRemote client, ++ mojo::PendingReceiver handler) { ++} ++ ++void SettingsUI::CreateCustomizeColorSchemeModeHandler( ++ mojo::PendingRemote< ++ customize_color_scheme_mode::mojom::CustomizeColorSchemeModeClient> ++ client, ++ mojo::PendingReceiver< ++ customize_color_scheme_mode::mojom::CustomizeColorSchemeModeHandler> ++ handler) { ++} ++ ++WEB_UI_CONTROLLER_TYPE_IMPL(SettingsUI) ++ ++} // namespace settings +diff --git a/chrome/browser/ui/webui/settings/settings_ui_android.h b/chrome/browser/ui/webui/settings/settings_ui_android.h +new file mode 100644 +--- /dev/null ++++ b/chrome/browser/ui/webui/settings/settings_ui_android.h +@@ -0,0 +1,127 @@ ++#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_UI_ANDROID_H_ ++#define CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_UI_ANDROID_H_ ++ ++#include "build/build_config.h" ++#include "build/chromeos_buildflags.h" ++#include "chrome/browser/profiles/profile.h" ++#include "components/user_education/webui/help_bubble_handler.h" ++#include "content/public/browser/web_ui_controller.h" ++#include "mojo/public/cpp/bindings/pending_receiver.h" ++#include "mojo/public/cpp/bindings/pending_remote.h" ++#include "mojo/public/cpp/bindings/receiver.h" ++#include "ui/webui/mojo_web_ui_controller.h" ++#include "ui/webui/resources/cr_components/customize_color_scheme_mode/customize_color_scheme_mode.mojom.h" ++#include "ui/webui/resources/cr_components/help_bubble/help_bubble.mojom.h" ++ ++#if !BUILDFLAG(IS_CHROMEOS_ASH) ++#include "ui/webui/resources/cr_components/customize_themes/customize_themes.mojom.h" ++#include "ui/webui/resources/cr_components/theme_color_picker/theme_color_picker.mojom.h" ++#endif // !BUILDFLAG(IS_CHROMEOS_ASH) ++ ++namespace content { ++class WebUIMessageHandler; ++} // namespace content ++ ++namespace user_prefs { ++class PrefRegistrySyncable; ++} ++ ++#if !BUILDFLAG(IS_CHROMEOS_ASH) ++class ChromeCustomizeThemesHandler; ++class ThemeColorPickerHandler; ++#endif // !BUILDFLAG(IS_CHROMEOS_ASH) ++ ++class CustomizeColorSchemeModeHandler; ++namespace settings { ++ ++// The WebUI handler for chrome://settings. ++class SettingsUI ++ : public ui::MojoWebUIController, ++ public help_bubble::mojom::HelpBubbleHandlerFactory ++ // public customize_color_scheme_mode::mojom::CustomizeColorSchemeModeHandlerFactory ++#if !BUILDFLAG(IS_CHROMEOS_ASH) ++ // chrome://settings/manageProfile which only exists on !OS_CHROMEOS ++ // requires mojo bindings. ++ , ++ public customize_themes::mojom::CustomizeThemesHandlerFactory, ++ public theme_color_picker::mojom::ThemeColorPickerHandlerFactory ++#endif // BUILDFLAG(IS_CHROMEOS_ASH) ++{ ++ public: ++ static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); ++ ++ explicit SettingsUI(content::WebUI* web_ui); ++ ++ SettingsUI(const SettingsUI&) = delete; ++ SettingsUI& operator=(const SettingsUI&) = delete; ++ ++ ~SettingsUI() override; ++ ++#if !BUILDFLAG(IS_CHROMEOS_ASH) ++ // Instantiates the implementor of the ++ // customize_themes::mojom::CustomizeThemesHandlerFactory mojo interface ++ // passing the pending receiver that will be internally bound. ++ void BindInterface(mojo::PendingReceiver< ++ customize_themes::mojom::CustomizeThemesHandlerFactory> ++ pending_receiver); ++ ++ // Instantiates the implementor of the ++ // theme_color_picker::mojom::ThemeColorPickerHandlerFactory mojo interface ++ // passing the pending receiver that will be internally bound. ++ void BindInterface(mojo::PendingReceiver< ++ theme_color_picker::mojom::ThemeColorPickerHandlerFactory> ++ pending_receiver); ++#endif // !BUILDFLAG(IS_CHROMEOS_ASH) ++ ++ // Implements support for help bubbles (IPH, tutorials, etc.) in settings ++ // pages. ++ void BindInterface( ++ mojo::PendingReceiver ++ pending_receiver); ++ ++ void BindInterface( ++ mojo::PendingReceiver ++ pending_receiver); ++ ++ private: ++ void AddSettingsPageUIHandler( ++ std::unique_ptr handler); ++ ++#if !BUILDFLAG(IS_CHROMEOS_ASH) ++ // customize_themes::mojom::CustomizeThemesHandlerFactory: ++ void CreateCustomizeThemesHandler( ++ mojo::PendingRemote ++ pending_client, ++ mojo::PendingReceiver ++ pending_handler) override; ++ ++ // theme_color_picker::mojom::ThemeColorPickerHandlerFactory: ++ void CreateThemeColorPickerHandler( ++ mojo::PendingReceiver ++ handler, ++ mojo::PendingRemote ++ client) override; ++ ++#endif // !BUILDFLAG(IS_CHROMEOS_ASH) ++ ++ // help_bubble::mojom::HelpBubbleHandlerFactory: ++ void CreateHelpBubbleHandler( ++ mojo::PendingRemote client, ++ mojo::PendingReceiver handler) ++ override; ++ ++ void CreateCustomizeColorSchemeModeHandler( ++ mojo::PendingRemote< ++ customize_color_scheme_mode::mojom::CustomizeColorSchemeModeClient> ++ client, ++ mojo::PendingReceiver< ++ customize_color_scheme_mode::mojom::CustomizeColorSchemeModeHandler> ++ handler) override; ++ ++ WEB_UI_CONTROLLER_TYPE_DECL(); ++}; ++ ++} // namespace settings ++ ++#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_UI_ANDROID_H_ +diff --git a/chrome/browser/ui/webui/webui_util.cc b/chrome/browser/ui/webui/webui_util.cc +--- a/chrome/browser/ui/webui/webui_util.cc ++++ b/chrome/browser/ui/webui/webui_util.cc +@@ -94,6 +94,11 @@ void SetupChromeRefresh2023(content::WebUIDataSource* source) { + source->AddString( + "chromeRefresh2023Attribute", + features::IsChromeWebuiRefresh2023() ? "chrome-refresh-2023" : ""); ++#if BUILDFLAG(IS_ANDROID) ++ source->AddString("chromeAndroid", "chrome-android"); ++#else ++ source->AddString("chromeAndroid", ""); ++#endif + } + + #if defined(TOOLKIT_VIEWS) +diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni +--- a/chrome/chrome_paks.gni ++++ b/chrome/chrome_paks.gni +@@ -149,6 +149,17 @@ template("chrome_extra_paks") { + sources += invoker.additional_paks + } + ++ if (is_android) { ++ sources += [ ++ "$root_gen_dir/chrome/settings_resources.pak", ++ ] ++ if (!optimize_webui) { ++ # Only add when optimize_webui=false, since in other cases the same ++ # resources are already bundled within the UIs that use them. ++ sources += [ "$root_gen_dir/chrome/settings_shared_resources.pak" ] ++ deps += [ "//chrome/browser/resources/settings_shared:resources" ] ++ } ++ } + if (!is_android) { + # New paks should be added here by default. + sources += [ +diff --git a/components/browser_ui/settings/android/java/src/org/chromium/components/browser_ui/settings/SettingsLauncher.java b/components/browser_ui/settings/android/java/src/org/chromium/components/browser_ui/settings/SettingsLauncher.java +--- a/components/browser_ui/settings/android/java/src/org/chromium/components/browser_ui/settings/SettingsLauncher.java ++++ b/components/browser_ui/settings/android/java/src/org/chromium/components/browser_ui/settings/SettingsLauncher.java +@@ -40,6 +40,8 @@ public interface SettingsLauncher { + int ACCESSIBILITY = 6; + } + ++ void launchUrlInCustomTab(Context context, String url); ++ + /** + * Launches a Settings Activity with the default (top-level) fragment. + * +diff --git a/components/browser_ui/strings/bromite_content_settings/search_engine_desktop_ui.grdp b/components/browser_ui/strings/bromite_content_settings/search_engine_desktop_ui.grdp +new file mode 100644 +--- /dev/null ++++ b/components/browser_ui/strings/bromite_content_settings/search_engine_desktop_ui.grdp +@@ -0,0 +1,6 @@ ++ ++ ++ ++ Edit search engines ++ ++ +diff --git a/components/search_engines/android/template_url_service_android.cc b/components/search_engines/android/template_url_service_android.cc +--- a/components/search_engines/android/template_url_service_android.cc ++++ b/components/search_engines/android/template_url_service_android.cc +@@ -336,7 +336,7 @@ jboolean TemplateUrlServiceAndroid::SetPlayAPISearchEngine( + TemplateURL* turl = *existing_play_api_turl; + if (turl->safe_for_autoreplace()) { + template_url_service_->ResetTemplateURL(turl, turl->short_name(), +- turl->keyword(), turl->url()); ++ turl->keyword(), turl->url(), /*suggestion_url*/ ""); + } + return false; + } +diff --git a/components/search_engines/template_url_service.cc b/components/search_engines/template_url_service.cc +--- a/components/search_engines/template_url_service.cc ++++ b/components/search_engines/template_url_service.cc +@@ -444,13 +444,15 @@ TemplateURL* TemplateURLService::AddWithOverrides( + std::unique_ptr template_url, + const std::u16string& short_name, + const std::u16string& keyword, +- const std::string& url) { ++ const std::string& url, ++ const std::string& suggestions_url) { + DCHECK(!short_name.empty()); + DCHECK(!keyword.empty()); + DCHECK(!url.empty()); + template_url->data_.SetShortName(short_name); + template_url->data_.SetKeyword(keyword); + template_url->SetURL(url); ++ template_url->data_.suggestions_url = suggestions_url; + return Add(std::move(template_url)); + } + +@@ -628,7 +630,8 @@ void TemplateURLService::IncrementUsageCount(TemplateURL* url) { + void TemplateURLService::ResetTemplateURL(TemplateURL* url, + const std::u16string& title, + const std::u16string& keyword, +- const std::string& search_url) { ++ const std::string& search_url, ++ const std::string& suggestion_url) { + DCHECK(!IsCreatedByExtension(url)); + DCHECK(!keyword.empty()); + DCHECK(!search_url.empty()); +@@ -640,6 +643,7 @@ void TemplateURLService::ResetTemplateURL(TemplateURL* url, + // The urls have changed, reset the favicon url. + data.favicon_url = GURL(); + } ++ data.suggestions_url = suggestion_url; + data.safe_for_autoreplace = false; + data.last_modified = clock_->Now(); + data.is_active = TemplateURLData::ActiveStatus::kTrue; +diff --git a/components/search_engines/template_url_service.h b/components/search_engines/template_url_service.h +--- a/components/search_engines/template_url_service.h ++++ b/components/search_engines/template_url_service.h +@@ -193,7 +193,8 @@ class TemplateURLService : public WebDataServiceConsumer, + TemplateURL* AddWithOverrides(std::unique_ptr template_url, + const std::u16string& short_name, + const std::u16string& keyword, +- const std::string& url); ++ const std::string& url, ++ const std::string& suggestion_url); + + // Removes the keyword from the model. This deletes the supplied TemplateURL. + // This fails if the supplied template_url is the default search provider. +@@ -246,7 +247,8 @@ class TemplateURLService : public WebDataServiceConsumer, + void ResetTemplateURL(TemplateURL* url, + const std::u16string& title, + const std::u16string& keyword, +- const std::string& search_url); ++ const std::string& search_url, ++ const std::string& suggestion_url); + + // Sets the `is_active` field of the specified TemplateURL to `kTrue` or + // `kFalse`. Called when a user explicitly activates/deactivates the search +diff --git a/content/browser/webui/web_ui_impl.cc b/content/browser/webui/web_ui_impl.cc +--- a/content/browser/webui/web_ui_impl.cc ++++ b/content/browser/webui/web_ui_impl.cc +@@ -255,6 +255,10 @@ void WebUIImpl::RegisterMessageCallback(base::StringPiece message, + message_callbacks_.emplace(message, std::move(callback)); + } + ++void WebUIImpl::DoNotCrashOnUnhandledMessage() { ++ do_not_crash_on_unhandled_message_ = true; ++} ++ + void WebUIImpl::ProcessWebUIMessage(const GURL& source_url, + const std::string& message, + base::Value::List args) { +@@ -268,8 +272,13 @@ void WebUIImpl::ProcessWebUIMessage(const GURL& source_url, + return; + } + +- NOTREACHED() << "Unhandled chrome.send(\"" << message << "\", " << args ++ if (!do_not_crash_on_unhandled_message_) { ++ NOTREACHED() << "Unhandled chrome.send(\"" << message << "\", " << args ++ << "); from " << source_url; ++ } else { ++ DLOG(INFO) << "---Unhandled chrome.send(\"" << message << "\", " << args + << "); from " << source_url; ++ } + } + + std::vector>* +diff --git a/content/browser/webui/web_ui_impl.h b/content/browser/webui/web_ui_impl.h +--- a/content/browser/webui/web_ui_impl.h ++++ b/content/browser/webui/web_ui_impl.h +@@ -84,6 +84,7 @@ class CONTENT_EXPORT WebUIImpl : public WebUI, + void ProcessWebUIMessage(const GURL& source_url, + const std::string& message, + base::Value::List args) override; ++ void DoNotCrashOnUnhandledMessage() override; + bool CanCallJavascript() override; + void CallJavascriptFunctionUnsafe(base::StringPiece function_name) override; + void CallJavascriptFunctionUnsafe( +@@ -155,6 +156,8 @@ class CONTENT_EXPORT WebUIImpl : public WebUI, + + std::unique_ptr controller_; + ++ bool do_not_crash_on_unhandled_message_ = false; ++ + mojo::AssociatedRemote remote_; + mojo::AssociatedReceiver receiver_{this}; + }; +diff --git a/content/public/browser/web_ui.h b/content/public/browser/web_ui.h +--- a/content/public/browser/web_ui.h ++++ b/content/public/browser/web_ui.h +@@ -83,6 +83,7 @@ class CONTENT_EXPORT WebUI { + + virtual void AddMessageHandler( + std::unique_ptr handler) = 0; ++ virtual void DoNotCrashOnUnhandledMessage() = 0; + + // Used by WebUIMessageHandlers. If the given message is already registered, + // the call has no effect. +diff --git a/ui/base/template_expressions.cc b/ui/base/template_expressions.cc +--- a/ui/base/template_expressions.cc ++++ b/ui/base/template_expressions.cc +@@ -13,6 +13,7 @@ + #include "base/strings/escape.h" + #include "base/strings/string_piece.h" + #include "base/values.h" ++#include "base/logging.h" + #include "build/chromeos_buildflags.h" + #include "third_party/abseil-cpp/absl/types/optional.h" + +@@ -165,11 +166,25 @@ bool ReplaceTemplateExpressionsInternal( + std::string key(source.substr(current_pos, key_end - current_pos)); + CHECK(!key.empty()); + ++ std::string replacement; + auto value = replacements.find(key); +- CHECK(value != replacements.end()) << "$i18n replacement key \"" << key +- << "\" not found"; ++ if (value == replacements.end()) { ++ bool check_notfound = ++ replacements.find("check_notfound") == replacements.end(); ++ if (check_notfound) { ++ CHECK(false) << "$i18n replacement key \"" << key ++ << "\" not found"; ++ } ++ DLOG(INFO) << "---$i18n replacement key \"" << key ++ << "\" not found" ++ << " replacements=" << replacements.size() ++ << " is_javascript=" << is_javascript; ++ //<< " source=" << source; ++ replacement = key; ++ } else { ++ replacement = value->second; ++ } + +- std::string replacement = value->second; + if (is_javascript) { + // Run JS escaping first. + absl::optional last = formatted->empty() +diff --git a/ui/webui/BUILD.gn b/ui/webui/BUILD.gn +--- a/ui/webui/BUILD.gn ++++ b/ui/webui/BUILD.gn +@@ -32,6 +32,14 @@ static_library("webui") { + "//ui/webui/resources/js/metrics_reporter:mojo_bindings", + ] + ++ if (is_android) { ++ public_deps += [ ++ "//ui/webui/resources/cr_components/customize_color_scheme_mode:mojom", ++ "//ui/webui/resources/cr_components/customize_themes:mojom", ++ "//ui/webui/resources/cr_components/theme_color_picker:mojom", ++ ] ++ } ++ + if (!is_android && !is_ios) { + public_deps += [ + "//ui/webui/resources/cr_components/color_change_listener:mojom", +diff --git a/ui/webui/resources/BUILD.gn b/ui/webui/resources/BUILD.gn +--- a/ui/webui/resources/BUILD.gn ++++ b/ui/webui/resources/BUILD.gn +@@ -73,6 +73,16 @@ generate_grd("build_grd") { + "$target_gen_dir/cr_components/most_visited/resources.grdp", + "$target_gen_dir/cr_components/settings_prefs/resources.grdp", + ] ++ if (is_android) { ++ public_deps -= [ ++ "cr_components/app_management:build_grdp", ++ "cr_components/most_visited:build_grdp", ++ ] ++ grdp_files -= [ ++ "$target_gen_dir/cr_components/app_management/resources.grdp", ++ "$target_gen_dir/cr_components/most_visited/resources.grdp", ++ ] ++ } + + if (use_nss_certs) { + public_deps += [ "cr_components/certificate_manager:build_grdp" ] +diff --git a/ui/webui/resources/cr_components/customize_color_scheme_mode/BUILD.gn b/ui/webui/resources/cr_components/customize_color_scheme_mode/BUILD.gn +--- a/ui/webui/resources/cr_components/customize_color_scheme_mode/BUILD.gn ++++ b/ui/webui/resources/cr_components/customize_color_scheme_mode/BUILD.gn +@@ -5,7 +5,7 @@ + import("//mojo/public/tools/bindings/mojom.gni") + import("//ui/webui/resources/tools/build_webui.gni") + +-assert(!is_android && !is_ios) ++assert(!is_ios) + + mojom("mojom") { + sources = [ "customize_color_scheme_mode.mojom" ] +diff --git a/ui/webui/resources/cr_components/customize_themes/BUILD.gn b/ui/webui/resources/cr_components/customize_themes/BUILD.gn +--- a/ui/webui/resources/cr_components/customize_themes/BUILD.gn ++++ b/ui/webui/resources/cr_components/customize_themes/BUILD.gn +@@ -5,7 +5,7 @@ + import("//mojo/public/tools/bindings/mojom.gni") + import("//ui/webui/resources/tools/build_webui.gni") + +-assert(!is_android && !is_ios) ++assert(!is_ios) + + mojom("mojom") { + sources = [ "customize_themes.mojom" ] +diff --git a/ui/webui/resources/cr_components/help_bubble/BUILD.gn b/ui/webui/resources/cr_components/help_bubble/BUILD.gn +--- a/ui/webui/resources/cr_components/help_bubble/BUILD.gn ++++ b/ui/webui/resources/cr_components/help_bubble/BUILD.gn +@@ -5,7 +5,7 @@ + import("//mojo/public/tools/bindings/mojom.gni") + import("//ui/webui/resources/tools/build_webui.gni") + +-assert(!is_android && !is_ios) ++assert(!is_ios) + + mojom("mojo_bindings") { + sources = [ "help_bubble.mojom" ] +diff --git a/ui/webui/resources/cr_components/theme_color_picker/BUILD.gn b/ui/webui/resources/cr_components/theme_color_picker/BUILD.gn +--- a/ui/webui/resources/cr_components/theme_color_picker/BUILD.gn ++++ b/ui/webui/resources/cr_components/theme_color_picker/BUILD.gn +@@ -5,7 +5,7 @@ + import("//mojo/public/tools/bindings/mojom.gni") + import("//ui/webui/resources/tools/build_webui.gni") + +-assert(!is_android && !is_ios) ++assert(!is_ios) + + mojom("mojom") { + sources = [ "theme_color_picker.mojom" ] +diff --git a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html +--- a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html ++++ b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html +@@ -10,7 +10,7 @@ + 0 16px 16px rgba(0, 0, 0, 0.24); + color: inherit; + max-height: initial; +- max-width: initial; ++ max-width: 95%; + overflow-y: hidden; + padding: 0; + position: absolute; +diff --git a/ui/webui/resources/cr_elements/cr_shared_vars.css b/ui/webui/resources/cr_elements/cr_shared_vars.css +--- a/ui/webui/resources/cr_elements/cr_shared_vars.css ++++ b/ui/webui/resources/cr_elements/cr_shared_vars.css +@@ -246,6 +246,10 @@ html { + --cr-form-field-label-line-height: 1; + } + ++html[chrome-android] { ++ --cr-section-indent-width: 0px; ++} ++ + html[chrome-refresh-2023] { + /* Colors: These variables should never be overridden and should only be used + as fallback values for shared cr_elements or in UIs that do not have +diff --git a/ui/webui/resources/css/BUILD.gn b/ui/webui/resources/css/BUILD.gn +--- a/ui/webui/resources/css/BUILD.gn ++++ b/ui/webui/resources/css/BUILD.gn +@@ -5,7 +5,7 @@ + import("//tools/grit/preprocess_if_expr.gni") + import("//ui/webui/resources/tools/generate_grd.gni") + +-include_polymer = !is_android && !is_ios ++include_polymer = !is_ios + + preprocess_manifest = "preprocessed_manifest.json" + +diff --git a/ui/webui/resources/images/BUILD.gn b/ui/webui/resources/images/BUILD.gn +--- a/ui/webui/resources/images/BUILD.gn ++++ b/ui/webui/resources/images/BUILD.gn +@@ -45,7 +45,7 @@ generate_grd("build_grdp") { + "2x/select.png", + ] + +- if (!is_android && !is_ios) { ++ if (!is_ios) { + input_files += [ + "arrow_down.svg", + "arrow_right.svg", +diff --git a/ui/webui/resources/include_polymer.gni b/ui/webui/resources/include_polymer.gni +--- a/ui/webui/resources/include_polymer.gni ++++ b/ui/webui/resources/include_polymer.gni +@@ -2,4 +2,4 @@ + # Use of this source code is governed by a BSD-style license that can be + # found in the LICENSE file. + +-include_polymer = !is_android && !is_ios ++include_polymer = !is_ios +diff --git a/ui/webui/resources/js/BUILD.gn b/ui/webui/resources/js/BUILD.gn +--- a/ui/webui/resources/js/BUILD.gn ++++ b/ui/webui/resources/js/BUILD.gn +@@ -5,7 +5,7 @@ + import("//build/config/chromeos/ui_mode.gni") + import("../tools/build_webui.gni") + +-include_polymer = !is_android && !is_ios ++include_polymer = !is_ios + + build_webui("build") { + grd_prefix = "webui_js" +diff --git a/ui/webui/resources/js/load_time_data.ts b/ui/webui/resources/js/load_time_data.ts +--- a/ui/webui/resources/js/load_time_data.ts ++++ b/ui/webui/resources/js/load_time_data.ts +@@ -22,6 +22,7 @@ interface LoadTimeDataRaw { + + class LoadTimeData { + private data_: LoadTimeDataRaw|null = null; ++ private is_android_: boolean = false; + + /** + * Sets the backing object. +@@ -33,6 +34,8 @@ class LoadTimeData { + set data(value: LoadTimeDataRaw) { + assert(!this.data_, 'Re-setting data.'); + this.data_ = value; ++ if (this.getValue("chromeAndroid") != "") ++ this.is_android_ = true; + } + + /** +@@ -52,7 +55,12 @@ class LoadTimeData { + getValue(id: string): any { + assert(this.data_, 'No data. Did you remember to include strings.js?'); + const value = this.data_[id]; +- assert(typeof value !== 'undefined', 'Could not find value for ' + id); ++ if (!this.is_android_) ++ assert(typeof value !== 'undefined', 'Could not find value for ' + id); ++ if(typeof value === 'undefined') { ++ //console.log('Could not find value for ' + id); ++ return id; ++ } + return value; + } + +@@ -152,7 +160,12 @@ class LoadTimeData { + */ + getBoolean(id: string): boolean { + const value = this.getValue(id); +- assert(typeof value === 'boolean', `[${value}] (${id}) is not a boolean`); ++ if (!this.is_android_) ++ assert(typeof value === 'boolean', `[${value}] (${id}) is not a boolean`); ++ if(typeof value !== 'boolean') { ++ //console.log(`[${value}] (${id}) is not a boolean`); ++ return false; ++ } + return value; + } + +-- +2.25.1 diff --git a/build/patches/00Eyeo-Adblock-Remove-Privacy-Issues.patch b/build/patches/00Eyeo-Adblock-Remove-Privacy-Issues.patch index 9c583acc..3bd344f5 100644 --- a/build/patches/00Eyeo-Adblock-Remove-Privacy-Issues.patch +++ b/build/patches/00Eyeo-Adblock-Remove-Privacy-Issues.patch @@ -789,7 +789,7 @@ new file mode 100644 + this.subscriptions = [] + this.customSubscriptions = []; + -+ chrome.adblockPrivate.getBuiltInSubscriptions(list => { ++ chrome.adblockPrivate?.getBuiltInSubscriptions(list => { + chrome.adblockPrivate.getInstalledSubscriptions(activelist => { + let new_subscriptions: Subscription[] = []; + let custom_subscriptions: Subscription[] = []; @@ -842,7 +842,7 @@ new file mode 100644 + this.additionalMessageIcon = ""; + this.countEnabled = 0; + -+ chrome.adblockPrivate.isEnabled(enabled => { ++ chrome.adblockPrivate?.isEnabled(enabled => { + if (!enabled) return; + + let c = 0; @@ -858,13 +858,13 @@ new file mode 100644 + } + }); + -+ chrome.adblockPrivate.isPrivilegedFiltersEnabled(enabled => { ++ chrome.adblockPrivate?.isPrivilegedFiltersEnabled(enabled => { + this.isEnablePrivilegedFiltersToggle_ = enabled; + }); + } + + private syncCustomFilters() { -+ chrome.adblockPrivate.getCustomFilters(domain => { ++ chrome.adblockPrivate?.getCustomFilters(domain => { + this.customFilters = []; + domain.forEach(value => { + this.customFilters.push(value); @@ -875,7 +875,7 @@ new file mode 100644 + + private syncAllowedDomains() { + this.allowedDomainsCount = 0; -+ chrome.adblockPrivate.getAllowedDomains(domain => { ++ chrome.adblockPrivate?.getAllowedDomains(domain => { + this.allowedDomains = []; + domain.forEach(value => { + this.allowedDomains.push(value);