diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-07-16 11:45:35 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-07-17 08:59:23 +0000 |
commit | 552906b0f222c5d5dd11b9fd73829d510980461a (patch) | |
tree | 3a11e6ed0538a81dd83b20cf3a4783e297f26d91 /chromium/chrome/browser/ui/webui/settings | |
parent | 1b05827804eaf047779b597718c03e7d38344261 (diff) |
BASELINE: Update Chromium to 83.0.4103.122
Change-Id: Ie3a82f5bb0076eec2a7c6a6162326b4301ee291e
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/chrome/browser/ui/webui/settings')
104 files changed, 13049 insertions, 3825 deletions
diff --git a/chromium/chrome/browser/ui/webui/settings/OWNERS b/chromium/chrome/browser/ui/webui/settings/OWNERS index 93f7d799e7d..b19cbb7cc52 100644 --- a/chromium/chrome/browser/ui/webui/settings/OWNERS +++ b/chromium/chrome/browser/ui/webui/settings/OWNERS @@ -2,4 +2,9 @@ file://chrome/browser/resources/settings/OWNERS per-file people_handler*=tangltom@chromium.org +per-file safe_browsing_handler*=msramek@chromium.org +per-file safe_browsing_handler*=sauski@google.com +per-file site_settings_handler*=msramek@chromium.org +per-file site_settings_handler*=sauski@google.com + # COMPONENT: UI>Settings diff --git a/chromium/chrome/browser/ui/webui/settings/about_handler.cc b/chromium/chrome/browser/ui/webui/settings/about_handler.cc index 21c3de52e0d..bcc0134af2f 100644 --- a/chromium/chrome/browser/ui/webui/settings/about_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/about_handler.cc @@ -22,7 +22,9 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "base/system/sys_info.h" #include "base/task/post_task.h" +#include "base/task/thread_pool.h" #include "base/time/time.h" #include "base/values.h" #include "build/branding_buildflags.h" @@ -56,6 +58,7 @@ #if defined(OS_CHROMEOS) #include "base/i18n/time_formatting.h" +#include "chrome/browser/chromeos/arc/arc_util.h" #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h" #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" @@ -71,6 +74,7 @@ #include "chromeos/constants/chromeos_switches.h" #include "chromeos/dbus/power/power_manager_client.h" #include "chromeos/dbus/update_engine_client.h" +#include "chromeos/dbus/util/version_loader.h" #include "chromeos/network/network_state.h" #include "chromeos/network/network_state_handler.h" #include "chromeos/system/statistics_provider.h" @@ -227,6 +231,19 @@ std::string ReadRegulatoryLabelText(const base::FilePath& label_dir_path) { return std::string(); } +std::unique_ptr<base::DictionaryValue> GetVersionInfo() { + std::unique_ptr<base::DictionaryValue> version_info( + new base::DictionaryValue); + version_info->SetString("osVersion", + chromeos::version_loader::GetVersion( + chromeos::version_loader::VERSION_FULL)); + version_info->SetString("arcVersion", + chromeos::version_loader::GetARCVersion()); + version_info->SetString("osFirmware", + chromeos::version_loader::GetFirmware()); + return version_info; +} + #endif // defined(OS_CHROMEOS) std::string UpdateStatusToString(VersionUpdater::Status status) { @@ -335,16 +352,21 @@ AboutHandler* AboutHandler::Create(content::WebUIDataSource* html_source, base::string16 os_with_linux_license = l10n_util::GetStringFUTF16( IDS_ABOUT_CROS_WITH_LINUX_VERSION_LICENSE, base::ASCIIToUTF16(chrome::kChromeUIOSCreditsURL), - base::ASCIIToUTF16(chrome::kChromeUILinuxCreditsURL)); + base::ASCIIToUTF16(chrome::kChromeUICrostiniCreditsURL)); html_source->AddString("aboutProductOsWithLinuxLicense", os_with_linux_license); html_source->AddBoolean("aboutEnterpriseManaged", IsEnterpriseManaged()); - - html_source->AddString("endOfLifeMessage", l10n_util::GetStringFUTF16( - IDS_EOL_NOTIFICATION_EOL, - ui::GetChromeOSDeviceName())); - html_source->AddString("endOfLifeLearnMoreURL", - base::ASCIIToUTF16(chrome::kEolNotificationURL)); + html_source->AddBoolean("aboutIsArcEnabled", + arc::IsArcPlayStoreEnabledForProfile(profile)); + html_source->AddBoolean("aboutIsDeveloperMode", + base::CommandLine::ForCurrentProcess()->HasSwitch( + chromeos::switches::kSystemDevMode)); + + html_source->AddString("endOfLifeMessage", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_ABOUT_PAGE_LAST_UPDATE_MESSAGE, + ui::GetChromeOSDeviceName(), + base::ASCIIToUTF16(chrome::kEolNotificationURL))); #endif return new AboutHandler(); @@ -380,6 +402,9 @@ void AboutHandler::RegisterMessages() { base::BindRepeating(&AboutHandler::HandleRequestUpdateOverCellular, base::Unretained(this))); web_ui()->RegisterMessageCallback( + "getVersionInfo", base::BindRepeating(&AboutHandler::HandleGetVersionInfo, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( "getRegulatoryInfo", base::BindRepeating(&AboutHandler::HandleGetRegulatoryInfo, base::Unretained(this))); @@ -387,6 +412,10 @@ void AboutHandler::RegisterMessages() { "getChannelInfo", base::BindRepeating(&AboutHandler::HandleGetChannelInfo, base::Unretained(this))); web_ui()->RegisterMessageCallback( + "canChangeChannel", + base::BindRepeating(&AboutHandler::HandleCanChangeChannel, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( "refreshTPMFirmwareUpdateStatus", base::BindRepeating(&AboutHandler::HandleRefreshTPMFirmwareUpdateStatus, base::Unretained(this))); @@ -572,17 +601,33 @@ void AboutHandler::HandleSetChannel(const base::ListValue* args) { } } +void AboutHandler::HandleGetVersionInfo(const base::ListValue* args) { + CHECK_EQ(1U, args->GetSize()); + std::string callback_id; + CHECK(args->GetString(0, &callback_id)); + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, + base::BindOnce(&GetVersionInfo), + base::BindOnce(&AboutHandler::OnGetVersionInfoReady, + weak_factory_.GetWeakPtr(), callback_id)); +} + +void AboutHandler::OnGetVersionInfoReady( + std::string callback_id, + std::unique_ptr<base::DictionaryValue> version_info) { + ResolveJavascriptCallback(base::Value(callback_id), *version_info); +} + void AboutHandler::HandleGetRegulatoryInfo(const base::ListValue* args) { CHECK_EQ(1U, args->GetSize()); std::string callback_id; CHECK(args->GetString(0, &callback_id)); - base::PostTaskAndReplyWithResult( - FROM_HERE, - {base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE}, - base::Bind(&FindRegulatoryLabelDir), - base::Bind(&AboutHandler::OnRegulatoryLabelDirFound, - weak_factory_.GetWeakPtr(), callback_id)); + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, + base::BindOnce(&FindRegulatoryLabelDir), + base::BindOnce(&AboutHandler::OnRegulatoryLabelDirFound, + weak_factory_.GetWeakPtr(), callback_id)); } void AboutHandler::HandleGetChannelInfo(const base::ListValue* args) { @@ -595,6 +640,15 @@ void AboutHandler::HandleGetChannelInfo(const base::ListValue* args) { callback_id)); } +void AboutHandler::HandleCanChangeChannel(const base::ListValue* args) { + CHECK_EQ(1U, args->GetSize()); + std::string callback_id; + CHECK(args->GetString(0, &callback_id)); + ResolveJavascriptCallback( + base::Value(callback_id), + base::Value(CanChangeChannel(Profile::FromWebUI(web_ui())))); +} + void AboutHandler::OnGetCurrentChannel(std::string callback_id, const std::string& current_channel) { version_updater_->GetChannel( @@ -610,8 +664,6 @@ void AboutHandler::OnGetTargetChannel(std::string callback_id, new base::DictionaryValue); channel_info->SetString("currentChannel", current_channel); channel_info->SetString("targetChannel", target_channel); - channel_info->SetBoolean("canChangeChannel", - CanChangeChannel(Profile::FromWebUI(web_ui()))); ResolveJavascriptCallback(base::Value(callback_id), *channel_info); } @@ -672,10 +724,14 @@ void AboutHandler::OnGetEndOfLifeInfo( base::Value response(base::Value::Type::DICTIONARY); if (!eol_info.eol_date.is_null()) { response.SetBoolKey("hasEndOfLife", eol_info.eol_date <= base::Time::Now()); - response.SetStringKey("aboutPageEndOfLifeMessage", - l10n_util::GetStringFUTF16( - IDS_SETTINGS_ABOUT_PAGE_END_OF_LIFE_MESSAGE, - base::TimeFormatMonthAndYear(eol_info.eol_date))); + int eol_string_id = eol_info.eol_date <= base::Time::Now() + ? IDS_SETTINGS_ABOUT_PAGE_END_OF_LIFE_MESSAGE_PAST + : IDS_SETTINGS_ABOUT_PAGE_END_OF_LIFE_MESSAGE_FUTURE; + response.SetStringKey( + "aboutPageEndOfLifeMessage", + l10n_util::GetStringFUTF16( + eol_string_id, base::TimeFormatMonthAndYear(eol_info.eol_date), + base::ASCIIToUTF16(chrome::kEolNotificationURL))); } else { response.SetBoolKey("hasEndOfLife", false); response.SetStringKey("aboutPageEndOfLifeMessage", ""); @@ -765,12 +821,11 @@ void AboutHandler::OnRegulatoryLabelDirFound( return; } - base::PostTaskAndReplyWithResult( - FROM_HERE, - {base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE}, - base::Bind(&ReadRegulatoryLabelText, label_dir_path), - base::Bind(&AboutHandler::OnRegulatoryLabelTextRead, - weak_factory_.GetWeakPtr(), callback_id, label_dir_path)); + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, + base::BindOnce(&ReadRegulatoryLabelText, label_dir_path), + base::BindOnce(&AboutHandler::OnRegulatoryLabelTextRead, + weak_factory_.GetWeakPtr(), callback_id, label_dir_path)); } void AboutHandler::OnRegulatoryLabelTextRead( diff --git a/chromium/chrome/browser/ui/webui/settings/about_handler.h b/chromium/chrome/browser/ui/webui/settings/about_handler.h index 679bad2fa37..e69de9f2d82 100644 --- a/chromium/chrome/browser/ui/webui/settings/about_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/about_handler.h @@ -25,6 +25,7 @@ #endif // defined(OS_CHROMEOS) namespace base { +class DictionaryValue; class FilePath; class ListValue; } @@ -99,8 +100,18 @@ class AboutHandler : public settings::SettingsPageUIHandler, // Sets the release track version. void HandleSetChannel(const base::ListValue* args); - // Retrieves combined channel info. + // Retrieves OS, ARC and firmware versions. + void HandleGetVersionInfo(const base::ListValue* args); + void OnGetVersionInfoReady( + std::string callback_id, + std::unique_ptr<base::DictionaryValue> version_info); + + // Retrieves channel info. void HandleGetChannelInfo(const base::ListValue* args); + + // Checks whether we can change the current channel. + void HandleCanChangeChannel(const base::ListValue* args); + // Callbacks for version_updater_->GetChannel calls. void OnGetCurrentChannel(std::string callback_id, const std::string& current_channel); diff --git a/chromium/chrome/browser/ui/webui/settings/browser_lifetime_handler.cc b/chromium/chrome/browser/ui/webui/settings/browser_lifetime_handler.cc index 6c11c87a3f5..8a02491acd6 100644 --- a/chromium/chrome/browser/ui/webui/settings/browser_lifetime_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/browser_lifetime_handler.cc @@ -19,10 +19,6 @@ #include "components/user_manager/user_manager.h" #endif // defined(OS_CHROMEOS) -#if defined(OS_MACOSX) -#include "chrome/browser/first_run/upgrade_util_mac.h" -#endif - namespace settings { namespace { @@ -86,11 +82,6 @@ void BrowserLifetimeHandler::HandleRestart( void BrowserLifetimeHandler::HandleRelaunch( const base::ListValue* args) { -#if defined(OS_MACOSX) - if (!upgrade_util::ShouldContinueToRelaunchForUpgrade()) - return; -#endif // OS_MACOSX - chrome::AttemptRelaunch(); } diff --git a/chromium/chrome/browser/ui/webui/settings/change_password_handler.cc b/chromium/chrome/browser/ui/webui/settings/change_password_handler.cc deleted file mode 100644 index b34815f9c76..00000000000 --- a/chromium/chrome/browser/ui/webui/settings/change_password_handler.cc +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// 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/change_password_handler.h" - -#include "base/bind.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/safe_browsing/chrome_password_protection_service.h" -#include "components/prefs/pref_service.h" -#include "components/safe_browsing/password_protection/metrics_util.h" -#include "components/safe_browsing/proto/csd.pb.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_ui.h" - -namespace settings { - -using password_manager::metrics_util::PasswordType; -using safe_browsing::ChromePasswordProtectionService; -using safe_browsing::LoginReputationClientResponse; -using safe_browsing::RequestOutcome; - -ChangePasswordHandler::ChangePasswordHandler( - Profile* profile, - safe_browsing::ChromePasswordProtectionService* service) - : profile_(profile), service_(service) { - DCHECK(service_); -} - -ChangePasswordHandler::~ChangePasswordHandler() {} - -void ChangePasswordHandler::RegisterMessages() { - web_ui()->RegisterMessageCallback( - "initializeChangePasswordHandler", - base::BindRepeating(&ChangePasswordHandler::HandleInitialize, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "changePassword", - base::BindRepeating(&ChangePasswordHandler::HandleChangePassword, - base::Unretained(this))); -} - -void ChangePasswordHandler::OnJavascriptAllowed() { - pref_registrar_.Init(profile_->GetPrefs()); - pref_registrar_.Add( - prefs::kSafeBrowsingUnhandledGaiaPasswordReuses, - base::Bind(&ChangePasswordHandler::UpdateChangePasswordCardVisibility, - base::Unretained(this))); -} - -void ChangePasswordHandler::OnJavascriptDisallowed() { - pref_registrar_.RemoveAll(); -} - -void ChangePasswordHandler::HandleInitialize(const base::ListValue* args) { - AllowJavascript(); - UpdateChangePasswordCardVisibility(); -} - -void ChangePasswordHandler::HandleChangePassword(const base::ListValue* args) { - service_->OnUserAction( - web_ui()->GetWebContents(), - service_->reused_password_account_type_for_last_shown_warning(), - RequestOutcome::UNKNOWN, - LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED, "unused_token", - safe_browsing::WarningUIType::CHROME_SETTINGS, - safe_browsing::WarningAction::CHANGE_PASSWORD); -} - -void ChangePasswordHandler::UpdateChangePasswordCardVisibility() { - FireWebUIListener( - "change-password-visibility", - base::Value( - service_->IsWarningEnabled( - service_ - ->reused_password_account_type_for_last_shown_warning()) && - safe_browsing::ChromePasswordProtectionService:: - ShouldShowChangePasswordSettingUI(profile_))); -} - -} // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/change_password_handler.h b/chromium/chrome/browser/ui/webui/settings/change_password_handler.h deleted file mode 100644 index f1ea3806473..00000000000 --- a/chromium/chrome/browser/ui/webui/settings/change_password_handler.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHANGE_PASSWORD_HANDLER_H_ -#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHANGE_PASSWORD_HANDLER_H_ - -#include "base/macros.h" -#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" -#include "components/prefs/pref_change_registrar.h" - -class Profile; - -namespace safe_browsing { -class ChromePasswordProtectionService; -} - -namespace settings { - -// Chrome "Change Password" settings page UI handler. -class ChangePasswordHandler : public SettingsPageUIHandler { - public: - explicit ChangePasswordHandler( - Profile* profile, - safe_browsing::ChromePasswordProtectionService* service); - ~ChangePasswordHandler() override; - - // settings::SettingsPageUIHandler: - void RegisterMessages() override; - void OnJavascriptAllowed() override; - void OnJavascriptDisallowed() override; - - private: - void HandleInitialize(const base::ListValue* args); - - void HandleChangePassword(const base::ListValue* args); - - void UpdateChangePasswordCardVisibility(); - - Profile* profile_; - - PrefChangeRegistrar pref_registrar_; - - safe_browsing::ChromePasswordProtectionService* service_; - - DISALLOW_COPY_AND_ASSIGN(ChangePasswordHandler); -}; - -} // namespace settings - -#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHANGE_PASSWORD_HANDLER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/DEPS b/chromium/chrome/browser/ui/webui/settings/chromeos/DEPS new file mode 100644 index 00000000000..eb3c6b1fa0c --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/DEPS @@ -0,0 +1,4 @@ +include_rules = [ + "+chrome/services/local_search_service", + "+device/udev_linux/fake_udev_loader.h", # For keyboard unit test. +] diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/OWNERS b/chromium/chrome/browser/ui/webui/settings/chromeos/OWNERS index f42990c5d35..ff0d48d0403 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/OWNERS +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/OWNERS @@ -1,3 +1,5 @@ +file://chrome/browser/resources/settings/chromeos/OWNERS + per-file multidevice_handler*=file://chromeos/components/multidevice/OWNERS -# COMPONENT: UI>Settings +# COMPONENT: OS>Systems>Settings diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.cc index 34dbb5b6fac..e1d62743ff2 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.cc @@ -4,8 +4,10 @@ #include "chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h" +#include "ash/public/cpp/tablet_mode.h" #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/metrics/histogram_functions.h" #include "chrome/browser/chromeos/accessibility/accessibility_manager.h" #include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/profiles/profile.h" @@ -18,11 +20,24 @@ namespace chromeos { namespace settings { -AccessibilityHandler::AccessibilityHandler(content::WebUI* webui) - : profile_(Profile::FromWebUI(webui)) { +namespace { + +void RecordShowShelfNavigationButtonsValueChange(bool enabled) { + base::UmaHistogramBoolean( + "Accessibility.CrosShelfNavigationButtonsInTabletModeChanged." + "OsSettings", + enabled); } -AccessibilityHandler::~AccessibilityHandler() {} +} // namespace + +AccessibilityHandler::AccessibilityHandler(Profile* profile) + : profile_(profile) {} + +AccessibilityHandler::~AccessibilityHandler() { + if (a11y_nav_buttons_toggle_metrics_reporter_timer_.IsRunning()) + a11y_nav_buttons_toggle_metrics_reporter_timer_.FireNow(); +} void AccessibilityHandler::RegisterMessages() { web_ui()->RegisterMessageCallback( @@ -35,13 +50,21 @@ void AccessibilityHandler::RegisterMessages() { &AccessibilityHandler::HandleShowSelectToSpeakSettings, base::Unretained(this))); web_ui()->RegisterMessageCallback( - "getStartupSoundEnabled", - base::BindRepeating(&AccessibilityHandler::HandleGetStartupSoundEnabled, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( "setStartupSoundEnabled", base::BindRepeating(&AccessibilityHandler::HandleSetStartupSoundEnabled, base::Unretained(this))); + + web_ui()->RegisterMessageCallback( + "recordSelectedShowShelfNavigationButtonValue", + base::BindRepeating( + &AccessibilityHandler:: + HandleRecordSelectedShowShelfNavigationButtonsValue, + base::Unretained(this))); + + web_ui()->RegisterMessageCallback( + "manageA11yPageReady", + base::BindRepeating(&AccessibilityHandler::HandleManageA11yPageReady, + base::Unretained(this))); } void AccessibilityHandler::HandleShowChromeVoxSettings( @@ -54,20 +77,54 @@ void AccessibilityHandler::HandleShowSelectToSpeakSettings( OpenExtensionOptionsPage(extension_misc::kSelectToSpeakExtensionId); } -void AccessibilityHandler::HandleGetStartupSoundEnabled( +void AccessibilityHandler::HandleSetStartupSoundEnabled( const base::ListValue* args) { - AllowJavascript(); - FireWebUIListener( - "startup-sound-enabled-updated", - base::Value(AccessibilityManager::Get()->GetStartupSoundEnabled())); + DCHECK_EQ(1U, args->GetSize()); + bool enabled; + args->GetBoolean(0, &enabled); + AccessibilityManager::Get()->SetStartupSoundEnabled(enabled); } -void AccessibilityHandler::HandleSetStartupSoundEnabled( +void AccessibilityHandler::HandleRecordSelectedShowShelfNavigationButtonsValue( const base::ListValue* args) { DCHECK_EQ(1U, args->GetSize()); bool enabled; args->GetBoolean(0, &enabled); - AccessibilityManager::Get()->SetStartupSoundEnabled(enabled); + + a11y_nav_buttons_toggle_metrics_reporter_timer_.Start( + FROM_HERE, base::TimeDelta::FromSeconds(10), + base::BindOnce(&RecordShowShelfNavigationButtonsValueChange, enabled)); +} + +void AccessibilityHandler::HandleManageA11yPageReady( + const base::ListValue* args) { + AllowJavascript(); + + // When tablet mode is active we can return early since tablet mode + // is supported. + if (ash::TabletMode::Get()->InTabletMode()) { + FireWebUIListener( + "initial-data-ready", + base::Value(AccessibilityManager::Get()->GetStartupSoundEnabled()), + base::Value(true /* tablet_mode_supported */)); + return; + } + + PowerManagerClient::Get()->GetSwitchStates( + base::BindOnce(&AccessibilityHandler::OnReceivedSwitchStates, + weak_ptr_factory_.GetWeakPtr())); +} + +void AccessibilityHandler::OnReceivedSwitchStates( + base::Optional<PowerManagerClient::SwitchStates> switch_states) { + bool tablet_mode_supported = + switch_states.has_value() && + switch_states->tablet_mode != PowerManagerClient::TabletMode::UNSUPPORTED; + + FireWebUIListener( + "initial-data-ready", + base::Value(AccessibilityManager::Get()->GetStartupSoundEnabled()), + base::Value(tablet_mode_supported)); } void AccessibilityHandler::OpenExtensionOptionsPage(const char extension_id[]) { diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h b/chromium/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h index 80d735832cb..54290f81dd8 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h @@ -6,16 +6,14 @@ #define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_ACCESSIBILITY_HANDLER_H_ #include "base/macros.h" +#include "base/timer/timer.h" #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" +#include "chromeos/dbus/power/power_manager_client.h" namespace base { class ListValue; } -namespace content { -class WebUI; -} - class Profile; namespace chromeos { @@ -23,7 +21,7 @@ namespace settings { class AccessibilityHandler : public ::settings::SettingsPageUIHandler { public: - explicit AccessibilityHandler(content::WebUI* webui); + explicit AccessibilityHandler(Profile* profile); ~AccessibilityHandler() override; // SettingsPageUIHandler implementation. @@ -31,18 +29,36 @@ class AccessibilityHandler : public ::settings::SettingsPageUIHandler { void OnJavascriptAllowed() override {} void OnJavascriptDisallowed() override {} + // Callback which updates if startup sound is enabled and if tablet + // mode is supported. Visible for testing. + void HandleManageA11yPageReady(const base::ListValue* args); + private: // Callback for the messages to show settings for ChromeVox or // Select To Speak. void HandleShowChromeVoxSettings(const base::ListValue* args); void HandleShowSelectToSpeakSettings(const base::ListValue* args); - void HandleGetStartupSoundEnabled(const base::ListValue* args); void HandleSetStartupSoundEnabled(const base::ListValue* args); + void HandleRecordSelectedShowShelfNavigationButtonsValue( + const base::ListValue* args); + + // Callback which updates visibility for the shelf navigation buttons + // accessibility setting, depending on whether tablet mode is supported. + void OnReceivedSwitchStates( + base::Optional<chromeos::PowerManagerClient::SwitchStates> switch_states); void OpenExtensionOptionsPage(const char extension_id[]); Profile* profile_; // Weak pointer. + // Timer to record user changed value for the accessibility setting to turn + // shelf navigation buttons on in tablet mode. The metric is recorded with 10 + // second delay to avoid overreporting when the user keeps toggling the + // setting value in the screen UI. + base::OneShotTimer a11y_nav_buttons_toggle_metrics_reporter_timer_; + + base::WeakPtrFactory<AccessibilityHandler> weak_ptr_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(AccessibilityHandler); }; diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/accessibility_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/accessibility_handler_unittest.cc new file mode 100644 index 00000000000..8ee78caacd8 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/accessibility_handler_unittest.cc @@ -0,0 +1,103 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/chromeos/accessibility_handler.h" + +#include <memory> + +#include "ash/public/cpp/test/test_tablet_mode.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chromeos/dbus/power/fake_power_manager_client.h" +#include "content/public/test/test_web_ui.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace chromeos { +namespace settings { + +class TestingAccessibilityHandler : public AccessibilityHandler { + public: + explicit TestingAccessibilityHandler(content::WebUI* web_ui) + : AccessibilityHandler(/* profile */ nullptr) { + set_web_ui(web_ui); + } + + private: + DISALLOW_COPY_AND_ASSIGN(TestingAccessibilityHandler); +}; + +class AccessibilityHandlerTest : public ChromeRenderViewHostTestHarness { + public: + AccessibilityHandlerTest() = default; + AccessibilityHandlerTest(const AccessibilityHandlerTest&) = delete; + AccessibilityHandlerTest& operator=(const AccessibilityHandlerTest&) = delete; + + void SetUp() override { + ChromeRenderViewHostTestHarness::SetUp(); + PowerManagerClient::InitializeFake(); + test_tablet_mode_ = std::make_unique<ash::TestTabletMode>(); + handler_ = std::make_unique<TestingAccessibilityHandler>(&web_ui_); + } + + void TearDown() override { + handler_.reset(); + test_tablet_mode_.reset(); + PowerManagerClient::Shutdown(); + ChromeRenderViewHostTestHarness::TearDown(); + } + + content::TestWebUI web_ui_; + std::unique_ptr<ash::TestTabletMode> test_tablet_mode_; + std::unique_ptr<TestingAccessibilityHandler> handler_; +}; + +// Test that when tablet mode is supported, the correct data is returned by +// HandleManageA11yPageReady(). +TEST_F(AccessibilityHandlerTest, ManageA11yPageReadyTabletModeSupported) { + // Set tablet mode as supported. + chromeos::FakePowerManagerClient::Get()->SetTabletMode( + chromeos::PowerManagerClient::TabletMode::OFF, base::TimeTicks()); + + handler_->HandleManageA11yPageReady(/* args */ nullptr); + + // Wait for the AccessibilityHandler to receive data from PowerManagerClient. + base::RunLoop().RunUntilIdle(); + + const content::TestWebUI::CallData& call_data = *web_ui_.call_data().back(); + + // Ensure tablet mode is returned as supported. + EXPECT_TRUE(call_data.arg3()->GetBool()); +} + +// Test that when tablet mode is unsupported, the correct data is returned by +// HandleManageA11yPageReady(). +TEST_F(AccessibilityHandlerTest, ManageA11yPageReadyTabletModeUnsupported) { + // Set tablet mode as unsupported. + chromeos::FakePowerManagerClient::Get()->SetTabletMode( + chromeos::PowerManagerClient::TabletMode::UNSUPPORTED, base::TimeTicks()); + handler_->HandleManageA11yPageReady(/* args */ nullptr); + + // Wait for the AccessibilityHandler to receive data from PowerManagerClient. + base::RunLoop().RunUntilIdle(); + + const content::TestWebUI::CallData& call_data = *web_ui_.call_data().back(); + + // Ensure tablet mode is returned as unsupported. + EXPECT_FALSE(call_data.arg3()->GetBool()); +} + +// Test that when tablet mode is enabled, the correct data is returned by +// HandleManageA11yPageReady(). +TEST_F(AccessibilityHandlerTest, ManageA11yPageReadyTabletModeEnabled) { + test_tablet_mode_->SetEnabledForTest(true); + handler_->HandleManageA11yPageReady(/* args */ nullptr); + + const content::TestWebUI::CallData& call_data = *web_ui_.call_data().back(); + + // Ensure tablet mode is returned as supported. + EXPECT_TRUE(call_data.arg3()->GetBool()); +} + +} // namespace settings +} // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc index a8b296703d0..e6d80c5a757 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc @@ -23,6 +23,7 @@ #include "chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h" #include "chrome/grit/generated_resources.h" #include "chromeos/components/account_manager/account_manager_factory.h" +#include "components/signin/public/identity_manager/consent_level.h" #include "components/user_manager/user.h" #include "google_apis/gaia/gaia_auth_util.h" #include "google_apis/gaia/google_service_auth_error.h" @@ -273,12 +274,13 @@ void AccountManagerUIHandler::OnGetAccounts( GetEnterpriseDomainFromUsername(user->GetDisplayEmail())); } else if (profile_->GetProfilePolicyConnector()->IsManaged()) { device_account.SetOrganization(GetEnterpriseDomainFromUsername( - identity_manager_->GetPrimaryAccountInfo().email)); + identity_manager_ + ->GetPrimaryAccountInfo(signin::ConsentLevel::kNotRequired) + .email)); } // Device account must show up at the top. - accounts.GetList().insert(accounts.GetList().begin(), - device_account.Build()); + accounts.Insert(accounts.GetList().begin(), device_account.Build()); } ResolveJavascriptCallback(callback_id, accounts); @@ -418,17 +420,26 @@ void AccountManagerUIHandler::OnAccountRemoved( RefreshUI(); } -// |signin::IdentityManager::Observer| overrides. For newly added accounts, -// |signin::IdentityManager| may take some time to fetch user's full name and -// account image. Whenever that is completed, we may need to update the UI with -// this new set of information. Note that we may be listening to -// |signin::IdentityManager| but we still consider |AccountManager| to be the -// source of truth for account list. +// |signin::IdentityManager::Observer| overrides. +// +// For newly added accounts, |signin::IdentityManager| may take some time to +// fetch user's full name and account image. Whenever that is completed, we may +// need to update the UI with this new set of information. Note that we may be +// listening to |signin::IdentityManager| but we still consider |AccountManager| +// to be the source of truth for account list. void AccountManagerUIHandler::OnExtendedAccountInfoUpdated( const AccountInfo& info) { RefreshUI(); } +void AccountManagerUIHandler::OnErrorStateOfRefreshTokenUpdatedForAccount( + const CoreAccountInfo& account_info, + const GoogleServiceAuthError& error) { + if (error.state() != GoogleServiceAuthError::NONE) { + RefreshUI(); + } +} + void AccountManagerUIHandler::RefreshUI() { FireWebUIListener("accounts-changed"); } diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.h b/chromium/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.h index 39f24fbbbec..21e8adf1bc8 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.h @@ -44,6 +44,9 @@ class AccountManagerUIHandler : public ::settings::SettingsPageUIHandler, // |signin::IdentityManager::Observer| overrides. void OnExtendedAccountInfoUpdated(const AccountInfo& info) override; + void OnErrorStateOfRefreshTokenUpdatedForAccount( + const CoreAccountInfo& account_info, + const GoogleServiceAuthError& error) override; private: friend class AccountManagerUIHandlerTest; diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/ambient_mode_handler.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/ambient_mode_handler.cc new file mode 100644 index 00000000000..e3c7e6d7645 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/ambient_mode_handler.cc @@ -0,0 +1,32 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/chromeos/ambient_mode_handler.h" + +#include "base/bind.h" +#include "base/values.h" + +namespace chromeos { +namespace settings { + +AmbientModeHandler::AmbientModeHandler() = default; + +AmbientModeHandler::~AmbientModeHandler() = default; + +void AmbientModeHandler::RegisterMessages() { + web_ui()->RegisterMessageCallback( + "onAmbientModePageReady", + base::BindRepeating(&AmbientModeHandler::HandleInitialized, + base::Unretained(this))); +} + +void AmbientModeHandler::HandleInitialized(const base::ListValue* args) { + CHECK(args); + CHECK(args->empty()); + + AllowJavascript(); +} + +} // namespace settings +} // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/ambient_mode_handler.h b/chromium/chrome/browser/ui/webui/settings/chromeos/ambient_mode_handler.h new file mode 100644 index 00000000000..a52b109160a --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/ambient_mode_handler.h @@ -0,0 +1,39 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_AMBIENT_MODE_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_AMBIENT_MODE_HANDLER_H_ + +#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" + +namespace base { +class ListValue; +} // namespace base + +namespace chromeos { +namespace settings { + +// Chrome OS ambient mode settings page UI handler, to allow users to customize +// photo frame and other related functionalities. +class AmbientModeHandler : public ::settings::SettingsPageUIHandler { + public: + AmbientModeHandler(); + AmbientModeHandler(const AmbientModeHandler&) = delete; + AmbientModeHandler& operator=(const AmbientModeHandler&) = delete; + ~AmbientModeHandler() override; + + // settings::SettingsPageUIHandler: + void RegisterMessages() override; + void OnJavascriptAllowed() override {} + void OnJavascriptDisallowed() override {} + + private: + // WebUI call to signal js side is ready. + void HandleInitialized(const base::ListValue* args); +}; + +} // namespace settings +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_AMBIENT_MODE_HANDLER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/calculator/size_calculator.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/calculator/size_calculator.cc new file mode 100644 index 00000000000..c9cfb838ce3 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/calculator/size_calculator.cc @@ -0,0 +1,393 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/chromeos/calculator/size_calculator.h" + +#include <numeric> + +#include "base/system/sys_info.h" +#include "base/task/post_task.h" +#include "base/task/thread_pool.h" +#include "base/values.h" +#include "chrome/browser/browsing_data/browsing_data_appcache_helper.h" +#include "chrome/browser/browsing_data/browsing_data_cache_storage_helper.h" +#include "chrome/browser/browsing_data/browsing_data_cookie_helper.h" +#include "chrome/browser/browsing_data/browsing_data_database_helper.h" +#include "chrome/browser/browsing_data/browsing_data_file_system_helper.h" +#include "chrome/browser/browsing_data/browsing_data_flash_lso_helper.h" +#include "chrome/browser/browsing_data/browsing_data_indexed_db_helper.h" +#include "chrome/browser/browsing_data/browsing_data_service_worker_helper.h" +#include "chrome/browser/chromeos/crostini/crostini_features.h" +#include "chrome/browser/chromeos/file_manager/path_util.h" +#include "chrome/browser/profiles/profile.h" +#include "chromeos/cryptohome/cryptohome_util.h" +#include "chromeos/dbus/cryptohome/cryptohome_client.h" +#include "components/arc/arc_service_manager.h" +#include "components/arc/session/arc_bridge_service.h" +#include "components/arc/storage_manager/arc_storage_manager.h" +#include "components/browsing_data/content/conditional_cache_counting_helper.h" +#include "components/browsing_data/content/local_storage_helper.h" +#include "components/user_manager/user_manager.h" +#include "content/public/browser/storage_partition.h" + +namespace chromeos { +namespace settings { +namespace calculator { + +namespace { + +void GetSizeStatBlocking(const base::FilePath& mount_path, + int64_t* total_size, + int64_t* available_size) { + int64_t size = base::SysInfo::AmountOfTotalDiskSpace(mount_path); + if (size >= 0) + *total_size = size; + size = base::SysInfo::AmountOfFreeDiskSpace(mount_path); + if (size >= 0) + *available_size = size; +} + +} // namespace + +SizeCalculator::SizeCalculator(const CalculationType& calculation_type) + : calculation_type_(calculation_type) {} + +SizeCalculator::~SizeCalculator() {} + +void SizeCalculator::StartCalculation() { + if (calculating_) + return; + calculating_ = true; + PerformCalculation(); +} + +void SizeCalculator::AddObserver(SizeCalculator::Observer* observer) { + observers_.AddObserver(observer); +} + +void SizeCalculator::RemoveObserver(SizeCalculator::Observer* observer) { + observers_.RemoveObserver(observer); +} + +void SizeCalculator::NotifySizeCalculated( + int64_t total_bytes, + const base::Optional<int64_t>& available_bytes) { + calculating_ = false; + for (SizeCalculator::Observer& observer : observers_) { + observer.OnSizeCalculated(calculation_type_, total_bytes, available_bytes); + } +} + +SizeStatCalculator::SizeStatCalculator(Profile* profile) + : SizeCalculator(CalculationType::kInUse), profile_(profile) {} + +SizeStatCalculator::~SizeStatCalculator() = default; +void SizeStatCalculator::PerformCalculation() { + const base::FilePath my_files_path = + file_manager::util::GetMyFilesFolderForProfile(profile_); + + int64_t* total_size = new int64_t(0); + int64_t* available_size = new int64_t(0); + base::ThreadPool::PostTaskAndReply( + FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, + base::Bind(&GetSizeStatBlocking, my_files_path, total_size, + available_size), + base::Bind(&SizeStatCalculator::OnGetSizeStat, + weak_ptr_factory_.GetWeakPtr(), base::Owned(total_size), + base::Owned(available_size))); +} + +void SizeStatCalculator::OnGetSizeStat(int64_t* total_bytes, + int64_t* available_bytes) { + NotifySizeCalculated(*total_bytes, *available_bytes); +} + +MyFilesSizeCalculator::MyFilesSizeCalculator(Profile* profile) + : SizeCalculator(CalculationType::kMyFiles), profile_(profile) {} + +MyFilesSizeCalculator::~MyFilesSizeCalculator() = default; + +void MyFilesSizeCalculator::PerformCalculation() { + const base::FilePath my_files_path = + file_manager::util::GetMyFilesFolderForProfile(profile_); + + const base::FilePath android_files_path = + base::FilePath(file_manager::util::GetAndroidFilesPath()); + + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, + base::BindOnce(&MyFilesSizeCalculator::ComputeLocalFilesSize, + base::Unretained(this), my_files_path, android_files_path), + base::BindOnce(&MyFilesSizeCalculator::OnGetMyFilesSize, + weak_ptr_factory_.GetWeakPtr())); +} + +int64_t MyFilesSizeCalculator::ComputeLocalFilesSize( + const base::FilePath& my_files_path, + const base::FilePath& android_files_path) { + int64_t size = 0; + + // Compute directory size of My Files. + size += base::ComputeDirectorySize(my_files_path); + + // Compute directory size of Play Files. + size += base::ComputeDirectorySize(android_files_path); + + // Remove size of Download. If Android is enabled, the size of the Download + // folder is counted in both My Files and Play files. If Android is disabled, + // the Download folder doesn't exist and the returned size is 0. + const base::FilePath download_files_path = + android_files_path.AppendASCII("Download"); + size -= base::ComputeDirectorySize(download_files_path); + + return size; +} + +void MyFilesSizeCalculator::OnGetMyFilesSize(int64_t total_bytes) { + NotifySizeCalculated(total_bytes); +} + +BrowsingDataSizeCalculator::BrowsingDataSizeCalculator(Profile* profile) + : SizeCalculator(CalculationType::kBrowsingData), profile_(profile) {} + +BrowsingDataSizeCalculator::~BrowsingDataSizeCalculator() = default; + +void BrowsingDataSizeCalculator::PerformCalculation() { + has_browser_cache_size_ = false; + has_browser_site_data_size_ = false; + + // Fetch the size of http cache in browsing data. + browsing_data::ConditionalCacheCountingHelper::Count( + content::BrowserContext::GetDefaultStoragePartition(profile_), + base::Time(), base::Time::Max(), + base::BindOnce(&BrowsingDataSizeCalculator::OnGetCacheSize, + weak_ptr_factory_.GetWeakPtr())); + + // Fetch the size of site data in browsing data. + if (!site_data_size_collector_.get()) { + content::StoragePartition* storage_partition = + content::BrowserContext::GetDefaultStoragePartition(profile_); + site_data_size_collector_ = std::make_unique<SiteDataSizeCollector>( + storage_partition->GetPath(), + new BrowsingDataCookieHelper(storage_partition), + new BrowsingDataDatabaseHelper(profile_), + new browsing_data::LocalStorageHelper(profile_), + new BrowsingDataAppCacheHelper(storage_partition->GetAppCacheService()), + new BrowsingDataIndexedDBHelper(storage_partition), + BrowsingDataFileSystemHelper::Create( + storage_partition->GetFileSystemContext()), + new BrowsingDataServiceWorkerHelper( + storage_partition->GetServiceWorkerContext()), + new BrowsingDataCacheStorageHelper( + storage_partition->GetCacheStorageContext()), + BrowsingDataFlashLSOHelper::Create(profile_)); + } + site_data_size_collector_->Fetch( + base::Bind(&BrowsingDataSizeCalculator::OnGetBrowsingDataSize, + weak_ptr_factory_.GetWeakPtr(), /*is_site_data=*/true)); +} + +void BrowsingDataSizeCalculator::OnGetCacheSize(bool is_upper_limit, + int64_t size) { + DCHECK(!is_upper_limit); + OnGetBrowsingDataSize(/*is_site_data=*/false, size); +} + +void BrowsingDataSizeCalculator::OnGetBrowsingDataSize(bool is_site_data, + int64_t size) { + if (is_site_data) { + has_browser_site_data_size_ = true; + browser_site_data_size_ = size; + } else { + has_browser_cache_size_ = true; + browser_cache_size_ = size; + } + if (has_browser_cache_size_ && has_browser_site_data_size_) { + int64_t browsing_data_size; + if (browser_cache_size_ >= 0 && browser_site_data_size_ >= 0) { + browsing_data_size = browser_site_data_size_ + browser_cache_size_; + } else { + browsing_data_size = -1; + } + calculating_ = false; + NotifySizeCalculated(browsing_data_size); + } +} + +AppsSizeCalculator::AppsSizeCalculator(Profile* profile) + : SizeCalculator(CalculationType::kAppsExtensions), profile_(profile) {} + +AppsSizeCalculator::~AppsSizeCalculator() { + arc::ArcServiceManager::Get() + ->arc_bridge_service() + ->storage_manager() + ->RemoveObserver(this); +} + +void AppsSizeCalculator::OnConnectionReady() { + is_android_running_ = true; + StartCalculation(); +} + +void AppsSizeCalculator::OnConnectionClosed() { + is_android_running_ = false; +} + +void AppsSizeCalculator::AddObserver(SizeCalculator::Observer* observer) { + // Start observing arc mojo connection when the first observer is added, to + // allow the calculation of android apps. + if (!observers_.might_have_observers()) { + arc::ArcServiceManager::Get() + ->arc_bridge_service() + ->storage_manager() + ->AddObserver(this); + } + observers_.AddObserver(observer); +} + +void AppsSizeCalculator::RemoveObserver(SizeCalculator::Observer* observer) { + observers_.RemoveObserver(observer); + // Stop observing arc connection if all observers have been removed. + if (!observers_.might_have_observers()) { + arc::ArcServiceManager::Get() + ->arc_bridge_service() + ->storage_manager() + ->RemoveObserver(this); + } +} + +void AppsSizeCalculator::PerformCalculation() { + apps_extensions_size_ = 0; + has_apps_extensions_size_ = false; + android_apps_size_ = 0; + has_android_apps_size_ = false; + + UpdateAppsSize(); + UpdateAndroidAppsSize(); +} + +void AppsSizeCalculator::UpdateAppsSize() { + // Apps and extensions installed from the web store located in + // [user-hash]/Extensions. + const base::FilePath extensions_path = + profile_->GetPath().AppendASCII("Extensions"); + + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, + base::BindOnce(&base::ComputeDirectorySize, extensions_path), + base::BindOnce(&AppsSizeCalculator::OnGetAppsSize, + weak_ptr_factory_.GetWeakPtr())); +} + +void AppsSizeCalculator::OnGetAppsSize(int64_t total_bytes) { + apps_extensions_size_ = total_bytes; + has_apps_extensions_size_ = true; + UpdateAppsAndExtensionsSize(); +} + +void AppsSizeCalculator::UpdateAndroidAppsSize() { + if (!is_android_running_) { + has_android_apps_size_ = true; + UpdateAppsAndExtensionsSize(); + return; + } + + bool success = false; + auto* arc_storage_manager = + arc::ArcStorageManager::GetForBrowserContext(profile_); + if (arc_storage_manager) { + success = arc_storage_manager->GetApplicationsSize( + base::BindOnce(&AppsSizeCalculator::OnGetAndroidAppsSize, + weak_ptr_factory_.GetWeakPtr())); + } + if (!success) { + has_android_apps_size_ = true; + UpdateAppsAndExtensionsSize(); + } +} + +void AppsSizeCalculator::OnGetAndroidAppsSize( + bool succeeded, + arc::mojom::ApplicationsSizePtr size) { + has_android_apps_size_ = true; + if (succeeded) { + android_apps_size_ = size->total_code_bytes + size->total_data_bytes + + size->total_cache_bytes; + } + UpdateAppsAndExtensionsSize(); +} + +void AppsSizeCalculator::UpdateAppsAndExtensionsSize() { + if (has_apps_extensions_size_ && has_android_apps_size_) { + calculating_ = false; + NotifySizeCalculated(apps_extensions_size_ + android_apps_size_); + } +} + +CrostiniSizeCalculator::CrostiniSizeCalculator(Profile* profile) + : SizeCalculator(CalculationType::kCrostini), profile_(profile) {} + +CrostiniSizeCalculator::~CrostiniSizeCalculator() = default; + +void CrostiniSizeCalculator::PerformCalculation() { + if (!crostini::CrostiniFeatures::Get()->IsEnabled(profile_)) { + NotifySizeCalculated(0); + return; + } + + crostini::CrostiniManager::GetForProfile(profile_)->ListVmDisks( + base::BindOnce(&CrostiniSizeCalculator::OnGetCrostiniSize, + weak_ptr_factory_.GetWeakPtr())); +} + +void CrostiniSizeCalculator::OnGetCrostiniSize(crostini::CrostiniResult result, + int64_t total_bytes) { + calculating_ = false; + NotifySizeCalculated(total_bytes); +} + +OtherUsersSizeCalculator::OtherUsersSizeCalculator() + : SizeCalculator(CalculationType::kOtherUsers) {} + +OtherUsersSizeCalculator::~OtherUsersSizeCalculator() = default; + +void OtherUsersSizeCalculator::PerformCalculation() { + other_users_.clear(); + user_sizes_.clear(); + const user_manager::UserList& users = + user_manager::UserManager::Get()->GetUsers(); + for (auto* user : users) { + if (user->is_active()) + continue; + other_users_.push_back(user); + CryptohomeClient::Get()->GetAccountDiskUsage( + cryptohome::CreateAccountIdentifierFromAccountId(user->GetAccountId()), + base::BindOnce(&OtherUsersSizeCalculator::OnGetOtherUserSize, + weak_ptr_factory_.GetWeakPtr())); + } + // We should show "0 B" if there is no other user. + if (other_users_.empty()) { + NotifySizeCalculated(0); + } +} + +void OtherUsersSizeCalculator::OnGetOtherUserSize( + base::Optional<cryptohome::BaseReply> reply) { + user_sizes_.push_back(cryptohome::AccountDiskUsageReplyToUsageSize(reply)); + if (user_sizes_.size() != other_users_.size()) + return; + int64_t other_users_total_bytes; + // If all the requests succeed, shows the total bytes in the UI. + if (std::count(user_sizes_.begin(), user_sizes_.end(), -1) == 0) { + other_users_total_bytes = + std::accumulate(user_sizes_.begin(), user_sizes_.end(), 0LL); + } else { + other_users_total_bytes = -1; + } + NotifySizeCalculated(other_users_total_bytes); +} + +} // namespace calculator +} // namespace settings +} // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/calculator/size_calculator.h b/chromium/chrome/browser/ui/webui/settings/chromeos/calculator/size_calculator.h new file mode 100644 index 00000000000..8f483f50b95 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/calculator/size_calculator.h @@ -0,0 +1,296 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_CALCULATOR_SIZE_CALCULATOR_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_CALCULATOR_SIZE_CALCULATOR_H_ + +#include <array> +#include <bitset> +#include <memory> +#include <string> +#include <vector> + +#include "base/files/file_util.h" +#include "base/memory/weak_ptr.h" +#include "base/observer_list_types.h" +#include "base/values.h" +#include "chrome/browser/browsing_data/site_data_size_collector.h" +#include "chrome/browser/chromeos/crostini/crostini_manager.h" +#include "chromeos/dbus/cryptohome/rpc.pb.h" +#include "components/arc/mojom/storage_manager.mojom.h" +#include "components/arc/session/connection_observer.h" +#include "components/arc/storage_manager/arc_storage_manager.h" +#include "components/user_manager/user.h" + +class Profile; + +namespace chromeos { +namespace settings { +namespace calculator { + +// Base class for the calculation of a specific storage item. Instances of this +// class rely on their observers calling StartCalculation, and are designed to +// notify observers about the calculated sizes. +class SizeCalculator { + public: + // Enumeration listing the items displayed on the storage page. + enum class CalculationType { + kInUse = 0, + kMyFiles, + kBrowsingData, + kAppsExtensions, + kCrostini, + kOtherUsers, + kLast = kOtherUsers, + kSystem, + }; + + // Implement this interface to be notified about item size callbacks. + class Observer : public base::CheckedObserver { + public: + virtual void OnSizeCalculated( + const CalculationType& item_id, + int64_t total_bytes, + const base::Optional<int64_t>& available_bytes) = 0; + }; + + // Total number of storage items. + static constexpr int kCalculationTypeCount = + static_cast<int>(CalculationType::kLast) + 1; + + explicit SizeCalculator(const CalculationType& calculation_type); + virtual ~SizeCalculator(); + + // Starts the size calculation of a given storage item. + void StartCalculation(); + + // Adds an observer. + virtual void AddObserver(Observer* observer); + + // Removes an observer. + virtual void RemoveObserver(Observer* observer); + + protected: + // Performs the size calculation. + virtual void PerformCalculation() = 0; + + // Notify the StorageHandler about the calculated storage item size + void NotifySizeCalculated( + int64_t total_bytes, + const base::Optional<int64_t>& available_bytes = base::nullopt); + + // Item id. + const CalculationType calculation_type_; + + // Flag indicating that fetch operations for storage size are ongoing. + bool calculating_ = false; + // Observers being notified about storage items size changes. + base::ObserverList<SizeCalculator::Observer> observers_; +}; + +// Class handling the interactions with the filesystem to get storage +// statistics, using OnSizeStatCalculated to notify observers. +class SizeStatCalculator : public SizeCalculator { + public: + explicit SizeStatCalculator(Profile* profile); + ~SizeStatCalculator() override; + + SizeStatCalculator(const SizeStatCalculator&) = delete; + SizeStatCalculator& operator=(const SizeStatCalculator&) = delete; + + private: + friend class SizeStatTestAPI; + + void PerformCalculation() override; + + // Updates disk space information. + void OnGetSizeStat(int64_t* total_bytes, int64_t* available_bytes); + + Profile* profile_; + base::WeakPtrFactory<SizeStatCalculator> weak_ptr_factory_{this}; +}; + +// Class handling the calculation of the size of the user's personal files: My +// files + Android Play files. +class MyFilesSizeCalculator : public SizeCalculator { + public: + explicit MyFilesSizeCalculator(Profile* profile); + ~MyFilesSizeCalculator() override; + + MyFilesSizeCalculator(const MyFilesSizeCalculator&) = delete; + MyFilesSizeCalculator& operator=(const MyFilesSizeCalculator&) = delete; + + private: + friend class MyFilesSizeTestAPI; + + void PerformCalculation() override; + + // Computes the size of My Files and Play files. + int64_t ComputeLocalFilesSize(const base::FilePath& my_files_path, + const base::FilePath& android_files_path); + + // Updates the size of My Files and Play files. + void OnGetMyFilesSize(int64_t total_bytes); + + Profile* profile_; + base::WeakPtrFactory<MyFilesSizeCalculator> weak_ptr_factory_{this}; +}; + +// Class handling the calculation of browsing data and cache. +class BrowsingDataSizeCalculator : public SizeCalculator { + public: + explicit BrowsingDataSizeCalculator(Profile* profile); + ~BrowsingDataSizeCalculator() override; + + BrowsingDataSizeCalculator(const BrowsingDataSizeCalculator&) = delete; + BrowsingDataSizeCalculator& operator=(const BrowsingDataSizeCalculator&) = + delete; + + private: + friend class BrowsingDataSizeTestAPI; + + void PerformCalculation() override; + + // Callback to receive the cache size. + void OnGetCacheSize(bool is_upper_limit, int64_t size); + + // Callback to update the size of browsing data. + void OnGetBrowsingDataSize(bool is_site_data, int64_t size); + + // Total size of cache data in browsing data. + int64_t browser_cache_size_ = -1; + + // True if we have already received the size of http cache. + bool has_browser_cache_size_ = false; + + // Total size of site data in browsing data. + int64_t browser_site_data_size_ = -1; + + // True if we have already received the size of http cache. + bool has_browser_site_data_size_ = false; + + // Helper to compute the total size of all types of site date. + std::unique_ptr<SiteDataSizeCollector> site_data_size_collector_; + + Profile* profile_; + base::WeakPtrFactory<BrowsingDataSizeCalculator> weak_ptr_factory_{this}; +}; + +// Class handling the calculation of the size of the user's apps and extensions. +class AppsSizeCalculator + : public SizeCalculator, + public arc::ConnectionObserver<arc::mojom::StorageManagerInstance> { + public: + explicit AppsSizeCalculator(Profile* profile); + ~AppsSizeCalculator() override; + + AppsSizeCalculator(const AppsSizeCalculator&) = delete; + AppsSizeCalculator& operator=(const AppsSizeCalculator&) = delete; + + // arc::ConnectionObserver<arc::mojom::StorageManagerInstance>: + void OnConnectionReady() override; + void OnConnectionClosed() override; + + // Adds an observer. When the first observer is added, start observing the arc + // mojo connection UpdateAndroidAppsSize relies on. + void AddObserver(Observer* observer) override; + + // Removes an observer. When the last observer is removed, stop observing the + // arc mojo connection. + void RemoveObserver(Observer* observer) override; + + private: + friend class AppsSizeTestAPI; + + void PerformCalculation() override; + + // Requests updating the size of web store apps and extensions. + void UpdateAppsSize(); + + // Callback to update web store apps and extensions size. + void OnGetAppsSize(int64_t total_bytes); + + // Requests updating the size of android apps. + void UpdateAndroidAppsSize(); + + // Callback to update Android apps and cache. + void OnGetAndroidAppsSize(bool succeeded, + arc::mojom::ApplicationsSizePtr size); + + // Updates apps and extensions size. + void UpdateAppsAndExtensionsSize(); + + // Total size of apps and extensions + int64_t apps_extensions_size_ = 0; + + // True if we have already received the size of apps and extensions. + bool has_apps_extensions_size_ = false; + + // Total size of android apps + int64_t android_apps_size_ = 0; + + // True if we have already received the size of Android apps. + bool has_android_apps_size_ = false; + + // A flag for keeping track of the mojo connection status to the ARC + // container. + bool is_android_running_ = false; + + Profile* profile_; + base::WeakPtrFactory<AppsSizeCalculator> weak_ptr_factory_{this}; +}; + +// Class handling the calculation of crostini VM size. +class CrostiniSizeCalculator : public SizeCalculator { + public: + explicit CrostiniSizeCalculator(Profile* profile); + ~CrostiniSizeCalculator() override; + + CrostiniSizeCalculator(const CrostiniSizeCalculator&) = delete; + CrostiniSizeCalculator& operator=(const CrostiniSizeCalculator&) = delete; + + private: + friend class CrostiniSizeTestAPI; + + void PerformCalculation() override; + + // Callback to update the size of Crostini VMs. + void OnGetCrostiniSize(crostini::CrostiniResult result, int64_t size); + + Profile* profile_; + base::WeakPtrFactory<CrostiniSizeCalculator> weak_ptr_factory_{this}; +}; + +// Class handling the calculation of other users' cryptohomes. +class OtherUsersSizeCalculator : public SizeCalculator { + public: + OtherUsersSizeCalculator(); + ~OtherUsersSizeCalculator() override; + + OtherUsersSizeCalculator(const OtherUsersSizeCalculator&) = delete; + OtherUsersSizeCalculator& operator=(const OtherUsersSizeCalculator&) = delete; + + private: + friend class OtherUsersSizeTestAPI; + + void PerformCalculation() override; + + // Callback to update the sizes of the other users. + void OnGetOtherUserSize(base::Optional<cryptohome::BaseReply> reply); + + // The list of other users whose directory sizes will be accumulated as the + // size of "Other users". + user_manager::UserList other_users_; + + // Fetched sizes of user directories. + std::vector<int64_t> user_sizes_; + + base::WeakPtrFactory<OtherUsersSizeCalculator> weak_ptr_factory_{this}; +}; + +} // namespace calculator +} // namespace settings +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_CALCULATOR_SIZE_CALCULATOR_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/calculator/size_calculator_test_api.h b/chromium/chrome/browser/ui/webui/settings/chromeos/calculator/size_calculator_test_api.h new file mode 100644 index 00000000000..2e0850df244 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/calculator/size_calculator_test_api.h @@ -0,0 +1,156 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_CALCULATOR_SIZE_CALCULATOR_TEST_API_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_CALCULATOR_SIZE_CALCULATOR_TEST_API_H_ + +#include <utility> + +#include "chrome/browser/ui/webui/settings/chromeos/calculator/size_calculator.h" +#include "chrome/browser/ui/webui/settings/chromeos/device_storage_handler.h" + +namespace chromeos { +namespace settings { +namespace calculator { + +class SizeStatTestAPI { + public: + explicit SizeStatTestAPI(StorageHandler* handler, + SizeStatCalculator* size_stat_calculator) { + size_stat_calculator_ = size_stat_calculator; + size_stat_calculator_->AddObserver(handler); + } + + void StartCalculation() { size_stat_calculator_->StartCalculation(); } + + void SimulateOnGetSizeStat(int64_t* total_size, int64_t* available_size) { + size_stat_calculator_->OnGetSizeStat(total_size, available_size); + } + + private: + SizeStatCalculator* size_stat_calculator_; +}; + +class MyFilesSizeTestAPI { + public: + explicit MyFilesSizeTestAPI(StorageHandler* handler, + MyFilesSizeCalculator* my_files_size_calculator) { + my_files_size_calculator_ = my_files_size_calculator; + my_files_size_calculator_->AddObserver(handler); + } + + void StartCalculation() { my_files_size_calculator_->StartCalculation(); } + + void SimulateOnGetTotalBytes(int64_t total_bytes) { + my_files_size_calculator_->NotifySizeCalculated(total_bytes); + } + + private: + MyFilesSizeCalculator* my_files_size_calculator_; +}; + +class BrowsingDataSizeTestAPI { + public: + explicit BrowsingDataSizeTestAPI( + StorageHandler* handler, + BrowsingDataSizeCalculator* browsing_data_size_calculator) { + browsing_data_size_calculator_ = browsing_data_size_calculator; + browsing_data_size_calculator_->AddObserver(handler); + } + + void StartCalculation() { + browsing_data_size_calculator_->StartCalculation(); + } + + void SimulateOnGetBrowsingDataSize(bool is_site_data, int64_t size) { + browsing_data_size_calculator_->OnGetBrowsingDataSize(is_site_data, size); + } + + private: + BrowsingDataSizeCalculator* browsing_data_size_calculator_; +}; + +class AppsSizeTestAPI { + public: + explicit AppsSizeTestAPI(StorageHandler* handler, + AppsSizeCalculator* apps_size_calculator) { + apps_size_calculator_ = apps_size_calculator; + apps_size_calculator_->AddObserver(handler); + } + + void StartCalculation() { apps_size_calculator_->StartCalculation(); } + + void SimulateOnGetAppsSize(int64_t total_bytes) { + apps_size_calculator_->OnGetAppsSize(total_bytes); + } + + void SimulateOnGetAndroidAppsSize(bool succeeded, + uint64_t total_code_bytes, + uint64_t total_data_bytes, + uint64_t total_cache_bytes) { + arc::mojom::ApplicationsSizePtr result( + ::arc::mojom::ApplicationsSize::New()); + result->total_code_bytes = total_code_bytes; + result->total_data_bytes = total_data_bytes; + result->total_cache_bytes = total_cache_bytes; + apps_size_calculator_->OnGetAndroidAppsSize(succeeded, std::move(result)); + } + + private: + AppsSizeCalculator* apps_size_calculator_; +}; + +class CrostiniSizeTestAPI { + public: + explicit CrostiniSizeTestAPI( + StorageHandler* handler, + CrostiniSizeCalculator* crostini_size_calculator) { + crostini_size_calculator_ = crostini_size_calculator; + crostini_size_calculator_->AddObserver(handler); + } + + void StartCalculation() { crostini_size_calculator_->StartCalculation(); } + + void SimulateOnGetCrostiniSize(int64_t size) { + crostini_size_calculator_->OnGetCrostiniSize( + crostini::CrostiniResult::SUCCESS, size); + } + + private: + CrostiniSizeCalculator* crostini_size_calculator_; +}; + +class OtherUsersSizeTestAPI { + public: + explicit OtherUsersSizeTestAPI( + StorageHandler* handler, + OtherUsersSizeCalculator* other_users_size_calculator) { + other_users_size_calculator_ = other_users_size_calculator; + other_users_size_calculator_->AddObserver(handler); + } + + void StartCalculation() { other_users_size_calculator_->StartCalculation(); } + + void InitializeOtherUserSize(int user_count) { + // When calling OnGetOtherUserSize, a callback is fired when + // user_sizes_.size() == other_users_.size(). We want to control the size of + // |other_users_|, rather than its content. This function initializes + // other_users_ as a list of |user_count| nullptrs. + other_users_size_calculator_->other_users_ = + user_manager::UserList(user_count); + } + + void SimulateOnGetOtherUserSize(base::Optional<cryptohome::BaseReply> reply) { + other_users_size_calculator_->OnGetOtherUserSize(reply); + } + + private: + OtherUsersSizeCalculator* other_users_size_calculator_; +}; + +} // namespace calculator +} // namespace settings +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_CALCULATOR_SIZE_CALCULATOR_TEST_API_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.cc index ed3cdc8465d..4bd641f16e6 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.cc @@ -18,6 +18,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/task/post_task.h" +#include "base/task/thread_pool.h" #include "base/values.h" #include "chrome/browser/chromeos/accessibility/accessibility_manager.h" #include "chrome/browser/chromeos/camera_presence_notifier.h" @@ -228,8 +229,8 @@ void ChangePictureHandler::SendSelectedImage() { DCHECK(previous_image_.IsThreadSafe()); // Post a task because GetBitmapDataUrl does PNG encoding, which is // slow for large images. - base::PostTaskAndReplyWithResult( - FROM_HERE, {base::ThreadPool(), base::TaskPriority::USER_BLOCKING}, + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::TaskPriority::USER_BLOCKING}, base::BindOnce(&webui::GetBitmapDataUrl, *previous_image_.bitmap()), base::BindOnce(&ChangePictureHandler::SendOldImage, weak_ptr_factory_.GetWeakPtr())); diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h b/chromium/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h index a3bb95d292e..1be240f6115 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h @@ -9,7 +9,7 @@ #include "base/memory/weak_ptr.h" #include "base/scoped_observer.h" #include "chrome/browser/chromeos/camera_presence_notifier.h" -#include "chrome/browser/image_decoder.h" +#include "chrome/browser/image_decoder/image_decoder.h" #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" #include "components/user_manager/user_manager.h" #include "ui/gfx/image/image_skia.h" diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc index 1c966904f49..1351b63b654 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc @@ -9,21 +9,27 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/callback_forward.h" #include "base/metrics/histogram_functions.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/browser_process_platform_part.h" +#include "chrome/browser/chromeos/crostini/crostini_disk.h" +#include "chrome/browser/chromeos/crostini/crostini_features.h" +#include "chrome/browser/chromeos/crostini/crostini_installer.h" +#include "chrome/browser/chromeos/crostini/crostini_port_forwarder.h" +#include "chrome/browser/chromeos/crostini/crostini_pref_names.h" +#include "chrome/browser/chromeos/crostini/crostini_types.mojom.h" #include "chrome/browser/chromeos/crostini/crostini_util.h" #include "chrome/browser/chromeos/file_manager/path_util.h" #include "chrome/browser/chromeos/guest_os/guest_os_share_path.h" -#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/lifetime/application_lifetime.h" -#include "chrome/browser/policy/profile_policy_connector.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_dialog.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" #include "components/user_manager/user_manager.h" #include "content/public/browser/browser_thread.h" +#include "ui/display/screen.h" namespace chromeos { namespace settings { @@ -105,11 +111,42 @@ void CrostiniHandler::RegisterMessages() { "disableArcAdbSideload", base::BindRepeating(&CrostiniHandler::HandleDisableArcAdbRequest, weak_ptr_factory_.GetWeakPtr())); + web_ui()->RegisterMessageCallback( + "requestCrostiniContainerUpgradeView", + base::BindRepeating(&CrostiniHandler::HandleRequestContainerUpgradeView, + weak_ptr_factory_.GetWeakPtr())); + web_ui()->RegisterMessageCallback( + "requestCrostiniUpgraderDialogStatus", + base::BindRepeating( + &CrostiniHandler::HandleCrostiniUpgraderDialogStatusRequest, + weak_ptr_factory_.GetWeakPtr())); + web_ui()->RegisterMessageCallback( + "requestCrostiniContainerUpgradeAvailable", + base::BindRepeating( + &CrostiniHandler::HandleCrostiniContainerUpgradeAvailableRequest, + weak_ptr_factory_.GetWeakPtr())); + web_ui()->RegisterMessageCallback( + "addCrostiniPortForward", + base::BindRepeating(&CrostiniHandler::HandleAddCrostiniPortForward, + weak_ptr_factory_.GetWeakPtr())); + web_ui()->RegisterMessageCallback( + "getCrostiniDiskInfo", + base::BindRepeating(&CrostiniHandler::HandleGetCrostiniDiskInfo, + weak_ptr_factory_.GetWeakPtr())); + web_ui()->RegisterMessageCallback( + "resizeCrostiniDisk", + base::BindRepeating(&CrostiniHandler::HandleResizeCrostiniDisk, + weak_ptr_factory_.GetWeakPtr())); + web_ui()->RegisterMessageCallback( + "checkCrostiniMicSharingStatus", + base::BindRepeating(&CrostiniHandler::HandleCheckCrostiniMicSharingStatus, + weak_ptr_factory_.GetWeakPtr())); } void CrostiniHandler::OnJavascriptAllowed() { - crostini::CrostiniManager::GetForProfile(profile_) - ->AddInstallerViewStatusObserver(this); + auto* crostini_manager = crostini::CrostiniManager::GetForProfile(profile_); + crostini_manager->AddCrostiniDialogStatusObserver(this); + crostini_manager->AddCrostiniContainerPropertiesObserver(this); if (chromeos::CrosUsbDetector::Get()) { chromeos::CrosUsbDetector::Get()->AddUsbDeviceObserver(this); } @@ -117,11 +154,9 @@ void CrostiniHandler::OnJavascriptAllowed() { } void CrostiniHandler::OnJavascriptDisallowed() { - if (crostini::CrostiniManager::GetForProfile(profile_) - ->HasInstallerViewStatusObserver(this)) { - crostini::CrostiniManager::GetForProfile(profile_) - ->RemoveInstallerViewStatusObserver(this); - } + auto* crostini_manager = crostini::CrostiniManager::GetForProfile(profile_); + crostini_manager->RemoveCrostiniDialogStatusObserver(this); + crostini_manager->RemoveCrostiniContainerPropertiesObserver(this); if (chromeos::CrosUsbDetector::Get()) { chromeos::CrosUsbDetector::Get()->RemoveUsbDeviceObserver(this); } @@ -131,8 +166,8 @@ void CrostiniHandler::OnJavascriptDisallowed() { void CrostiniHandler::HandleRequestCrostiniInstallerView( const base::ListValue* args) { AllowJavascript(); - ShowCrostiniInstallerView(Profile::FromWebUI(web_ui()), - crostini::CrostiniUISurface::kSettings); + crostini::CrostiniInstaller::GetForProfile(Profile::FromWebUI(web_ui())) + ->ShowDialog(crostini::CrostiniUISurface::kSettings); } void CrostiniHandler::HandleRequestRemoveCrostini(const base::ListValue* args) { @@ -144,40 +179,42 @@ void CrostiniHandler::HandleRequestRemoveCrostini(const base::ListValue* args) { void CrostiniHandler::HandleGetCrostiniSharedPathsDisplayText( const base::ListValue* args) { AllowJavascript(); - CHECK_EQ(2U, args->GetSize()); - std::string callback_id; - const base::ListValue* paths; - CHECK(args->GetString(0, &callback_id)); - CHECK(args->GetList(1, &paths)); + CHECK_EQ(2U, args->GetList().size()); + std::string callback_id = args->GetList()[0].GetString(); + base::Value::ConstListView paths = args->GetList()[1].GetList(); base::ListValue texts; - for (auto it = paths->begin(); it != paths->end(); ++it) { + for (size_t i = 0; i < paths.size(); ++i) { texts.AppendString(file_manager::util::GetPathDisplayTextForSettings( - profile_, it->GetString())); + profile_, paths[i].GetString())); } ResolveJavascriptCallback(base::Value(callback_id), texts); } void CrostiniHandler::HandleRemoveCrostiniSharedPath( const base::ListValue* args) { - CHECK_EQ(2U, args->GetSize()); - std::string vm_name; - CHECK(args->GetString(0, &vm_name)); - std::string path; - CHECK(args->GetString(1, &path)); + AllowJavascript(); + CHECK_EQ(3U, args->GetList().size()); + std::string callback_id = args->GetList()[0].GetString(); + std::string vm_name = args->GetList()[1].GetString(); + std::string path = args->GetList()[2].GetString(); guest_os::GuestOsSharePath::GetForProfile(profile_)->UnsharePath( vm_name, base::FilePath(path), /*unpersist=*/true, - base::BindOnce( - [](const std::string& path, bool result, - const std::string& failure_reason) { - if (!result) { - LOG(ERROR) << "Error unsharing " << path << ": " - << failure_reason; - } - }, - path)); + base::BindOnce(&CrostiniHandler::OnCrostiniSharedPathRemoved, + weak_ptr_factory_.GetWeakPtr(), callback_id, path)); +} + +void CrostiniHandler::OnCrostiniSharedPathRemoved( + const std::string& callback_id, + const std::string& path, + bool result, + const std::string& failure_reason) { + if (!result) { + LOG(ERROR) << "Error unsharing " << path << ": " << failure_reason; + } + ResolveJavascriptCallback(base::Value(callback_id), base::Value(result)); } namespace { @@ -195,12 +232,35 @@ base::ListValue UsbDevicesToListValue( } return usb_devices_list; } + +base::Value CrostiniDiskInfoToValue( + std::unique_ptr<crostini::CrostiniDiskInfo> disk_info) { + base::Value disk_value(base::Value::Type::DICTIONARY); + if (!disk_info) { + disk_value.SetBoolKey("succeeded", false); + return disk_value; + } + disk_value.SetBoolKey("succeeded", true); + disk_value.SetBoolKey("canResize", disk_info->can_resize); + disk_value.SetBoolKey("isUserChosenSize", disk_info->is_user_chosen_size); + disk_value.SetIntKey("defaultIndex", disk_info->default_index); + base::Value ticks(base::Value::Type::LIST); + for (const auto& tick : disk_info->ticks) { + base::Value t(base::Value::Type::DICTIONARY); + t.SetDoubleKey("value", static_cast<double>(tick->value)); + t.SetStringKey("ariaValue", tick->aria_value); + t.SetStringKey("label", tick->label); + ticks.Append(std::move(t)); + } + disk_value.SetKey("ticks", std::move(ticks)); + return disk_value; +} } // namespace void CrostiniHandler::HandleGetCrostiniSharedUsbDevices( const base::ListValue* args) { AllowJavascript(); - CHECK_EQ(1U, args->GetSize()); + CHECK_EQ(1U, args->GetList().size()); std::string callback_id = args->GetList()[0].GetString(); @@ -217,7 +277,7 @@ void CrostiniHandler::HandleGetCrostiniSharedUsbDevices( void CrostiniHandler::HandleSetCrostiniUsbDeviceShared( const base::ListValue* args) { - CHECK_EQ(2U, args->GetSize()); + CHECK_EQ(2U, args->GetList().size()); const auto& args_list = args->GetList(); std::string guid = args_list[0].GetString(); bool shared = args_list[1].GetBool(); @@ -245,14 +305,14 @@ void CrostiniHandler::OnUsbDevicesChanged() { void CrostiniHandler::HandleExportCrostiniContainer( const base::ListValue* args) { - CHECK_EQ(0U, args->GetSize()); + CHECK_EQ(0U, args->GetList().size()); crostini::CrostiniExportImport::GetForProfile(profile_)->ExportContainer( web_ui()->GetWebContents()); } void CrostiniHandler::HandleImportCrostiniContainer( const base::ListValue* args) { - CHECK_EQ(0U, args->GetSize()); + CHECK_EQ(0U, args->GetList().size()); crostini::CrostiniExportImport::GetForProfile(profile_)->ImportContainer( web_ui()->GetWebContents()); } @@ -260,45 +320,57 @@ void CrostiniHandler::HandleImportCrostiniContainer( void CrostiniHandler::HandleCrostiniInstallerStatusRequest( const base::ListValue* args) { AllowJavascript(); - CHECK_EQ(0U, args->GetSize()); + CHECK_EQ(0U, args->GetList().size()); bool status = crostini::CrostiniManager::GetForProfile(profile_) - ->GetInstallerViewStatus(); - OnCrostiniInstallerViewStatusChanged(status); + ->GetCrostiniDialogStatus(crostini::DialogType::INSTALLER); + OnCrostiniDialogStatusChanged(crostini::DialogType::INSTALLER, status); } void CrostiniHandler::HandleCrostiniExportImportOperationStatusRequest( const base::ListValue* args) { AllowJavascript(); - CHECK_EQ(0U, args->GetSize()); + CHECK_EQ(0U, args->GetList().size()); bool in_progress = crostini::CrostiniExportImport::GetForProfile(profile_) ->GetExportImportOperationStatus(); OnCrostiniExportImportOperationStatusChanged(in_progress); } -void CrostiniHandler::OnCrostiniInstallerViewStatusChanged(bool status) { +void CrostiniHandler::OnCrostiniDialogStatusChanged( + crostini::DialogType dialog_type, + bool status) { // It's technically possible for this to be called before Javascript is // enabled, in which case we must not call FireWebUIListener if (IsJavascriptAllowed()) { // Other side listens with cr.addWebUIListener - FireWebUIListener("crostini-installer-status-changed", base::Value(status)); + switch (dialog_type) { + case crostini::DialogType::INSTALLER: + FireWebUIListener("crostini-installer-status-changed", + base::Value(status)); + break; + case crostini::DialogType::UPGRADER: + FireWebUIListener("crostini-upgrader-status-changed", + base::Value(status)); + break; + case crostini::DialogType::REMOVER: + FireWebUIListener("crostini-remover-status-changed", + base::Value(status)); + break; + default: + NOTREACHED(); + break; + } } } -void CrostiniHandler::OnCrostiniExportImportOperationStatusChanged( - bool in_progress) { - // Other side listens with cr.addWebUIListener - FireWebUIListener("crostini-export-import-operation-status-changed", - base::Value(in_progress)); -} - -void CrostiniHandler::HandleQueryArcAdbRequest(const base::ListValue* args) { - AllowJavascript(); - CHECK_EQ(0U, args->GetSize()); - - chromeos::SessionManagerClient* client = - chromeos::SessionManagerClient::Get(); - client->QueryAdbSideload(base::Bind(&CrostiniHandler::OnQueryAdbSideload, - weak_ptr_factory_.GetWeakPtr())); +void CrostiniHandler::OnContainerOsReleaseChanged( + const crostini::ContainerId& container_id, + bool can_upgrade) { + if (crostini::CrostiniFeatures::Get()->IsContainerUpgradeUIAllowed( + profile_) && + container_id == crostini::DefaultContainerId()) { + FireWebUIListener("crostini-container-upgrade-available-changed", + base::Value(can_upgrade)); + } } void CrostiniHandler::OnQueryAdbSideload( @@ -317,7 +389,7 @@ void CrostiniHandler::OnQueryAdbSideload( } void CrostiniHandler::HandleEnableArcAdbRequest(const base::ListValue* args) { - CHECK_EQ(0U, args->GetSize()); + CHECK_EQ(0U, args->GetList().size()); if (!CheckEligibilityToChangeArcAdbSideloading()) return; @@ -331,7 +403,7 @@ void CrostiniHandler::HandleEnableArcAdbRequest(const base::ListValue* args) { } void CrostiniHandler::HandleDisableArcAdbRequest(const base::ListValue* args) { - CHECK_EQ(0U, args->GetSize()); + CHECK_EQ(0U, args->GetList().size()); if (!CheckEligibilityToChangeArcAdbSideloading()) return; @@ -346,28 +418,133 @@ void CrostiniHandler::HandleDisableArcAdbRequest(const base::ListValue* args) { } bool CrostiniHandler::CheckEligibilityToChangeArcAdbSideloading() const { - if (!chromeos::ProfileHelper::IsOwnerProfile(profile_)) { - DVLOG(1) << "Only the owner can change adb sideloading status"; - return false; - } + return crostini::CrostiniFeatures::Get()->CanChangeAdbSideloading(profile_); +} - if (user_manager::UserManager::Get()->IsLoggedInAsChildUser()) { - DVLOG(1) << "adb sideloading is currently unsupported for child account"; - return false; - } +void CrostiniHandler::LaunchTerminal() { + crostini::LaunchCrostiniApp( + profile_, crostini::GetTerminalId(), + display::Screen::GetScreen()->GetPrimaryDisplay().id()); +} - if (profile_->GetProfilePolicyConnector()->IsManaged()) { - DVLOG(1) << "adb sideloading is currently unsupported for managed user"; - return false; - } +void CrostiniHandler::HandleRequestContainerUpgradeView( + const base::ListValue* args) { + CHECK_EQ(0U, args->GetList().size()); + chromeos::CrostiniUpgraderDialog::Show( + base::BindOnce(&CrostiniHandler::LaunchTerminal, + weak_ptr_factory_.GetWeakPtr()), + // If the user cancels the upgrade, we won't need to restart Crostini and + // we don't want to run the launch closure which would launch Terminal. + /*only_run_launch_closure_on_restart=*/true); +} - policy::BrowserPolicyConnectorChromeOS* connector = - g_browser_process->platform_part()->browser_policy_connector_chromeos(); - if (connector->IsEnterpriseManaged()) { - DVLOG(1) << "adb sideloading is currently unsupported on managed device"; - return false; - } - return true; +void CrostiniHandler::OnCrostiniExportImportOperationStatusChanged( + bool in_progress) { + // Other side listens with cr.addWebUIListener + FireWebUIListener("crostini-export-import-operation-status-changed", + base::Value(in_progress)); +} + +void CrostiniHandler::HandleQueryArcAdbRequest(const base::ListValue* args) { + AllowJavascript(); + CHECK_EQ(0U, args->GetList().size()); + + chromeos::SessionManagerClient* client = + chromeos::SessionManagerClient::Get(); + client->QueryAdbSideload(base::Bind(&CrostiniHandler::OnQueryAdbSideload, + weak_ptr_factory_.GetWeakPtr())); +} + +void CrostiniHandler::HandleCrostiniUpgraderDialogStatusRequest( + const base::ListValue* args) { + AllowJavascript(); + CHECK_EQ(0U, args->GetList().size()); + bool is_open = crostini::CrostiniManager::GetForProfile(profile_) + ->GetCrostiniDialogStatus(crostini::DialogType::UPGRADER); + OnCrostiniDialogStatusChanged(crostini::DialogType::UPGRADER, is_open); +} + +void CrostiniHandler::HandleCrostiniContainerUpgradeAvailableRequest( + const base::ListValue* args) { + AllowJavascript(); + + bool can_upgrade = crostini::ShouldAllowContainerUpgrade(profile_); + OnContainerOsReleaseChanged(crostini::DefaultContainerId(), can_upgrade); +} + +void CrostiniHandler::HandleAddCrostiniPortForward( + const base::ListValue* args) { + CHECK_EQ(6U, args->GetList().size()); + + std::string callback_id = args->GetList()[0].GetString(); + std::string vm_name = args->GetList()[1].GetString(); + std::string container_name = args->GetList()[2].GetString(); + int port_number = args->GetList()[3].GetInt(); + int protocol_type = args->GetList()[4].GetInt(); + std::string label = args->GetList()[5].GetString(); + + crostini::CrostiniPortForwarder::GetForProfile(profile_)->AddPort( + crostini::ContainerId(std::move(vm_name), std::move(container_name)), + port_number, + static_cast<crostini::CrostiniPortForwarder::Protocol>(protocol_type), + std::move(label), + base::Bind(&CrostiniHandler::OnPortForwardComplete, + weak_ptr_factory_.GetWeakPtr(), std::move(callback_id))); +} + +void CrostiniHandler::OnPortForwardComplete(std::string callback_id, + bool success) { + ResolveJavascriptCallback(base::Value(callback_id), base::Value(success)); +} + +void CrostiniHandler::ResolveGetCrostiniDiskInfoCallback( + const std::string& callback_id, + std::unique_ptr<crostini::CrostiniDiskInfo> disk_info) { + ResolveJavascriptCallback(base::Value(std::move(callback_id)), + CrostiniDiskInfoToValue(std::move(disk_info))); +} + +void CrostiniHandler::HandleGetCrostiniDiskInfo(const base::ListValue* args) { + AllowJavascript(); + CHECK_EQ(2U, args->GetList().size()); + std::string callback_id = args->GetList()[0].GetString(); + std::string vm_name = args->GetList()[1].GetString(); + crostini::disk::GetDiskInfo( + base::BindOnce(&CrostiniHandler::ResolveGetCrostiniDiskInfoCallback, + weak_ptr_factory_.GetWeakPtr(), std::move(callback_id)), + profile_, std::move(vm_name)); +} + +void CrostiniHandler::HandleResizeCrostiniDisk(const base::ListValue* args) { + CHECK_EQ(3U, args->GetList().size()); + std::string callback_id = args->GetList()[0].GetString(); + std::string vm_name = args->GetList()[1].GetString(); + double bytes = args->GetList()[2].GetDouble(); + crostini::disk::ResizeCrostiniDisk( + profile_, std::move(vm_name), bytes, + base::BindOnce(&CrostiniHandler::ResolveResizeCrostiniDiskCallback, + weak_ptr_factory_.GetWeakPtr(), std::move(callback_id))); +} + +void CrostiniHandler::ResolveResizeCrostiniDiskCallback( + const std::string& callback_id, + bool succeeded) { + ResolveJavascriptCallback(base::Value(std::move(callback_id)), + base::Value(succeeded)); +} + +void CrostiniHandler::HandleCheckCrostiniMicSharingStatus( + const base::ListValue* args) { + CHECK_EQ(2U, args->GetList().size()); + std::string callback_id = args->GetList()[0].GetString(); + bool proposed_value = args->GetList()[1].GetBool(); + bool requiresRestart = + crostini::IsCrostiniRunning(profile_) && + profile_->GetPrefs()->GetBoolean( + crostini::prefs::kCrostiniMicSharingAtLastLaunch) != proposed_value; + + ResolveJavascriptCallback(base::Value(std::move(callback_id)), + base::Value(requiresRestart)); } } // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/crostini_handler.h b/chromium/chrome/browser/ui/webui/settings/chromeos/crostini_handler.h index bab8509806a..f51fc69e1b7 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/crostini_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/crostini_handler.h @@ -18,14 +18,16 @@ class Profile; namespace crostini { enum class CrostiniResult; -} +struct CrostiniDiskInfo; +} // namespace crostini namespace chromeos { namespace settings { class CrostiniHandler : public ::settings::SettingsPageUIHandler, - public crostini::InstallerViewStatusObserver, + public crostini::CrostiniDialogStatusObserver, public crostini::CrostiniExportImport::Observer, + public crostini::CrostiniContainerPropertiesObserver, public chromeos::CrosUsbDeviceObserver { public: explicit CrostiniHandler(Profile* profile); @@ -45,6 +47,10 @@ class CrostiniHandler : public ::settings::SettingsPageUIHandler, void HandleGetCrostiniSharedPathsDisplayText(const base::ListValue* args); // Remove a specified path from being shared. void HandleRemoveCrostiniSharedPath(const base::ListValue* args); + void OnCrostiniSharedPathRemoved(const std::string& callback_id, + const std::string& path, + bool result, + const std::string& failure_reason); // Returns a list of available USB devices. void HandleGetCrostiniSharedUsbDevices(const base::ListValue* args); // Set the share state of a USB device. @@ -57,8 +63,12 @@ class CrostiniHandler : public ::settings::SettingsPageUIHandler, void HandleImportCrostiniContainer(const base::ListValue* args); // Handle a request for the CrostiniInstallerView status. void HandleCrostiniInstallerStatusRequest(const base::ListValue* args); - // Handle the CrostiniInstallerView opening/closing. - void OnCrostiniInstallerViewStatusChanged(bool open) override; + // crostini::CrostiniDialogStatusObserver + void OnCrostiniDialogStatusChanged(crostini::DialogType dialog_type, + bool open) override; + // crostini::CrostiniContainerPropertiesObserver + void OnContainerOsReleaseChanged(const crostini::ContainerId& container_id, + bool can_upgrade) override; // Handle a request for the CrostiniExportImport operation status. void HandleCrostiniExportImportOperationStatusRequest( const base::ListValue* args); @@ -70,6 +80,10 @@ class CrostiniHandler : public ::settings::SettingsPageUIHandler, void HandleEnableArcAdbRequest(const base::ListValue* args); // Handle a request for disabling adb sideloading in ARC. void HandleDisableArcAdbRequest(const base::ListValue* args); + // Launch the Crostini terminal. + void LaunchTerminal(); + // Handle a request for showing the container upgrade view. + void HandleRequestContainerUpgradeView(const base::ListValue* args); // Callback of HandleQueryArcAdbRequest. void OnQueryAdbSideload( SessionManagerClient::AdbSideloadResponseCode response_code, @@ -77,6 +91,26 @@ class CrostiniHandler : public ::settings::SettingsPageUIHandler, // Returns whether the current user can change adb sideloading configuration // on current device. bool CheckEligibilityToChangeArcAdbSideloading() const; + // Handle a request for the CrostiniUpgraderDialog status. + void HandleCrostiniUpgraderDialogStatusRequest(const base::ListValue* args); + // Handle a request for the availability of a container upgrade. + void HandleCrostiniContainerUpgradeAvailableRequest( + const base::ListValue* args); + // Handles a request for forwarding a new port. + void HandleAddCrostiniPortForward(const base::ListValue* args); + // Callback of port forwarding requests. + void OnPortForwardComplete(std::string callback_id, bool success); + // Fetches disk info for a VM, can be slow (seconds). + void HandleGetCrostiniDiskInfo(const base::ListValue* args); + void ResolveGetCrostiniDiskInfoCallback( + const std::string& callback_id, + std::unique_ptr<crostini::CrostiniDiskInfo> disk_info); + // Handles a request to resize a Crostini disk. + void HandleResizeCrostiniDisk(const base::ListValue* args); + void ResolveResizeCrostiniDiskCallback(const std::string& callback_id, + bool succeeded); + // Checks if a restart is required to update mic sharing settings. + void HandleCheckCrostiniMicSharingStatus(const base::ListValue* args); Profile* profile_; // weak_ptr_factory_ should always be last member. diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc index 74f1ab84039..fd6f8acdd11 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc @@ -14,12 +14,14 @@ #include "base/files/file_util.h" #include "base/json/json_string_value_serializer.h" #include "base/logging.h" +#include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/optional.h" #include "base/path_service.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/task/post_task.h" +#include "base/task/thread_pool.h" #include "base/threading/sequenced_task_runner_handle.h" #include "base/values.h" #include "chrome/browser/browser_process.h" @@ -37,12 +39,11 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/chrome_select_file_policy.h" +#include "chrome/browser/ui/webui/settings/chromeos/server_printer_url_util.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/pref_names.h" -#include "chrome/common/webui_url_constants.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/debug_daemon/debug_daemon_client.h" -#include "chromeos/printing/ppd_cache.h" #include "chromeos/printing/ppd_line_reader.h" #include "chromeos/printing/printer_configuration.h" #include "chromeos/printing/printer_translator.h" @@ -58,6 +59,7 @@ #include "net/base/ip_endpoint.h" #include "net/url_request/url_request_context_getter.h" #include "printing/backend/print_backend.h" +#include "printing/printer_status.h" #include "url/gurl.h" namespace chromeos { @@ -113,8 +115,8 @@ void QueryAutoconf(const std::string& printer_uri, // Behavior for querying a non-IPP uri is undefined and disallowed. if (!IsIppUri(printer_uri) || !optional.has_value()) { PRINTER_LOG(ERROR) << "Printer uri is invalid: " << printer_uri; - std::move(callback).Run(PrinterQueryResult::UNKNOWN_FAILURE, "", "", "", {}, - false); + std::move(callback).Run(PrinterQueryResult::UNKNOWN_FAILURE, + printing::PrinterStatus(), "", "", "", {}, false); return; } @@ -168,6 +170,7 @@ std::unique_ptr<chromeos::Printer> DictToPrinter( std::string printer_make_and_model; std::string printer_address; std::string printer_protocol; + std::string print_server_uri; if (!printer_dict.GetString("printerId", &printer_id) || !printer_dict.GetString("printerName", &printer_name) || @@ -176,7 +179,8 @@ std::unique_ptr<chromeos::Printer> DictToPrinter( !printer_dict.GetString("printerModel", &printer_model) || !printer_dict.GetString("printerMakeAndModel", &printer_make_and_model) || !printer_dict.GetString("printerAddress", &printer_address) || - !printer_dict.GetString("printerProtocol", &printer_protocol)) { + !printer_dict.GetString("printerProtocol", &printer_protocol) || + !printer_dict.GetString("printServerUri", &print_server_uri)) { return nullptr; } @@ -195,6 +199,7 @@ std::unique_ptr<chromeos::Printer> DictToPrinter( printer->set_model(printer_model); printer->set_make_and_model(printer_make_and_model); printer->set_uri(printer_uri); + printer->set_print_server_uri(print_server_uri); return printer; } @@ -237,11 +242,6 @@ void SetPpdReference(const Printer::PpdReference& ppd_ref, base::Value* info) { } } -bool IsFilledPpdReference(const Printer::PpdReference& ppd_ref) { - return ppd_ref.autoconf || !ppd_ref.user_supplied_ppd_url.empty() || - !ppd_ref.effective_make_and_model.empty(); -} - Printer::PpdReference GetPpdReference(const base::Value* info) { const char ppd_ref_pathname[] = "printerPpdReference"; auto* user_supplied_ppd_url = @@ -267,40 +267,11 @@ Printer::PpdReference GetPpdReference(const base::Value* info) { return ret; } -bool ConvertToGURL(const std::string& url, GURL* gurl) { - *gurl = GURL(url); - if (!gurl->is_valid()) { - // URL is not valid. - return false; - } - if (!gurl->SchemeIsHTTPOrHTTPS() && !gurl->SchemeIs("ipp") && - !gurl->SchemeIs("ipps")) { - // URL has unsupported scheme; we support only: http, https, ipp, ipps. - return false; - } - // Replaces ipp/ipps by http/https. IPP standard describes protocol built - // on top of HTTP, so both types of addresses have the same meaning in the - // context of IPP interface. Moreover, the URL must have http/https scheme - // to pass IsStandard() test from GURL library (see "Validation of the URL - // address" below). - bool set_ipp_port = false; - if (gurl->SchemeIs("ipp")) { - set_ipp_port = (gurl->IntPort() == url::PORT_UNSPECIFIED); - *gurl = GURL("http" + url.substr(url.find_first_of(':'))); - } else if (gurl->SchemeIs("ipps")) { - *gurl = GURL("https" + url.substr(url.find_first_of(':'))); - } - // The default port for ipp is 631. If the schema ipp is replaced by http - // and the port is not explicitly defined in the url, we have to overwrite - // the default http port with the default ipp port. For ipps we do nothing - // because implementers use the same port for ipps and https. - if (set_ipp_port) { - GURL::Replacements replacement; - replacement.SetPortStr("631"); - *gurl = gurl->ReplaceComponents(replacement); - } - // Validation of the URL address. - return gurl->IsStandard(); +GURL GenerateHttpCupsServerUrl(const GURL& server_url) { + GURL::Replacements replacement; + replacement.SetSchemeStr("http"); + replacement.SetPortStr("631"); + return server_url.ReplaceComponents(replacement); } } // namespace @@ -405,6 +376,10 @@ void CupsPrintersHandler::RegisterMessages() { web_ui()->RegisterMessageCallback( "getEulaUrl", base::BindRepeating(&CupsPrintersHandler::HandleGetEulaUrl, base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "queryPrintServer", + base::BindRepeating(&CupsPrintersHandler::HandleQueryPrintServer, + base::Unretained(this))); } void CupsPrintersHandler::OnJavascriptAllowed() { @@ -513,8 +488,8 @@ void CupsPrintersHandler::HandleGetPrinterInfo(const base::ListValue* args) { if (printer_address.empty()) { // Run the failure callback. - OnAutoconfQueried(callback_id, PrinterQueryResult::UNKNOWN_FAILURE, "", "", - "", {}, false); + OnAutoconfQueried(callback_id, PrinterQueryResult::UNKNOWN_FAILURE, + printing::PrinterStatus(), "", "", "", {}, false); return; } @@ -541,6 +516,7 @@ void CupsPrintersHandler::OnAutoconfQueriedDiscovered( const std::string& callback_id, Printer printer, PrinterQueryResult result, + const printing::PrinterStatus& printer_status, const std::string& make, const std::string& model, const std::string& make_and_model, @@ -587,6 +563,7 @@ void CupsPrintersHandler::OnAutoconfQueriedDiscovered( void CupsPrintersHandler::OnAutoconfQueried( const std::string& callback_id, PrinterQueryResult result, + const printing::PrinterStatus& printer_status, const std::string& make, const std::string& model, const std::string& make_and_model, @@ -736,7 +713,7 @@ void CupsPrintersHandler::AddOrReconfigurePrinter(const base::ListValue* args, // Check if the printer already has a valid ppd_reference. Printer::PpdReference ppd_ref = GetPpdReference(printer_dict); - if (IsFilledPpdReference(ppd_ref)) { + if (ppd_ref.IsFilled()) { *printer->mutable_ppd_reference() = ppd_ref; } else if (!printer_ppd_path.empty()) { GURL tmp = net::FilePathToFileURL(base::FilePath(printer_ppd_path)); @@ -1003,9 +980,8 @@ void CupsPrintersHandler::FileSelected(const base::FilePath& path, // VerifyPpdContents() in order to determine whether the file appears to be a // PPD file. The task's priority is USER_BLOCKING because the this task // updates the UI as a result of a direct user action. - base::PostTaskAndReplyWithResult( - FROM_HERE, - {base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_BLOCKING}, + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING}, base::BindOnce(&ReadFileToStringWithMaxSize, path, kPpdMaxLineLength), base::BindOnce(&CupsPrintersHandler::VerifyPpdContents, weak_factory_.GetWeakPtr(), path)); @@ -1239,7 +1215,7 @@ void CupsPrintersHandler::OnGetEulaUrl(const std::string& callback_id, return; } - GURL eula_url(chrome::kChromeUIOSCreditsURL + license); + GURL eula_url = PrinterConfigurer::GeneratePrinterEulaUrl(license); ResolveJavascriptCallback( base::Value(callback_id), eula_url.is_valid() ? base::Value(eula_url.spec()) : base::Value()); @@ -1283,27 +1259,45 @@ void CupsPrintersHandler::HandleQueryPrintServer(const base::ListValue* args) { CHECK(args->GetString(0, &callback_id)); CHECK(args->GetString(1, &server_url)); - GURL server_gurl; - if (!ConvertToGURL(server_url, &server_gurl)) { + base::Optional<GURL> converted_server_url = + GenerateServerPrinterUrlWithValidScheme(server_url); + if (!converted_server_url) { RejectJavascriptCallback( base::Value(callback_id), base::Value(PrintServerQueryResult::kIncorrectUrl)); return; } + // Use fallback only if HasValidServerPrinterScheme is false. + QueryPrintServer(callback_id, converted_server_url.value(), + !HasValidServerPrinterScheme(GURL(server_url))); +} + +void CupsPrintersHandler::QueryPrintServer(const std::string& callback_id, + const GURL& server_url, + bool should_fallback) { server_printers_fetcher_ = std::make_unique<ServerPrintersFetcher>( - server_gurl, "(from user)", + server_url, "(from user)", base::BindRepeating(&CupsPrintersHandler::OnQueryPrintServerCompleted, - weak_factory_.GetWeakPtr(), callback_id)); + weak_factory_.GetWeakPtr(), callback_id, + should_fallback)); } void CupsPrintersHandler::OnQueryPrintServerCompleted( const std::string& callback_id, + bool should_fallback, const ServerPrintersFetcher* sender, const GURL& server_url, std::vector<PrinterDetector::DetectedPrinter>&& returned_printers) { const PrintServerQueryResult result = sender->GetLastError(); if (result != PrintServerQueryResult::kNoErrors) { + if (should_fallback) { + // Apply the fallback query. + QueryPrintServer(callback_id, GenerateHttpCupsServerUrl(server_url), + /*should_fallback=*/false); + return; + } + RejectJavascriptCallback(base::Value(callback_id), base::Value(result)); return; } @@ -1313,9 +1307,10 @@ void CupsPrintersHandler::OnQueryPrintServerCompleted( printers_manager_->GetPrinters(PrinterClass::kSaved); std::set<GURL> known_printers; for (const Printer& printer : saved_printers) { - GURL gurl; - if (ConvertToGURL(printer.uri(), &gurl)) - known_printers.insert(gurl); + base::Optional<GURL> gurl = + GenerateServerPrinterUrlWithValidScheme(printer.uri()); + if (gurl) + known_printers.insert(gurl.value()); } // Built final list of printers and a list of current names. If "current name" @@ -1325,11 +1320,10 @@ void CupsPrintersHandler::OnQueryPrintServerCompleted( printers.reserve(returned_printers.size()); for (PrinterDetector::DetectedPrinter& printer : returned_printers) { printers.push_back(std::move(printer.printer)); - GURL printer_gurl; - if (ConvertToGURL(printers.back().uri(), &printer_gurl)) { - if (known_printers.count(printer_gurl)) - printers.pop_back(); - } + base::Optional<GURL> printer_gurl = + GenerateServerPrinterUrlWithValidScheme(printers.back().uri()); + if (printer_gurl && known_printers.count(printer_gurl.value())) + printers.pop_back(); } // Delete fetcher object. diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h b/chromium/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h index 6e80a910a18..82de71cf6cc 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h @@ -18,7 +18,7 @@ #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" #include "chromeos/printing/ppd_provider.h" #include "chromeos/printing/printer_configuration.h" -#include "printing/printer_query_result_chromeos.h" +#include "printing/printer_query_result.h" #include "ui/shell_dialogs/select_file_dialog.h" namespace base { @@ -30,6 +30,10 @@ namespace local_discovery { class EndpointResolver; } // namespace local_discovery +namespace printing { +struct PrinterStatus; +} // namespace printing + class GURL; class Profile; @@ -77,14 +81,17 @@ class CupsPrintersHandler : public ::settings::SettingsPageUIHandler, void HandleGetPrinterInfo(const base::ListValue* args); // Handles the callback for HandleGetPrinterInfo. |callback_id| is the - // identifier to resolve the correct Promise. |success| indicates if the query - // was successful. |make| is the detected printer manufacturer. |model| is the + // identifier to resolve the correct Promise. |result| indicates if the query + // was successful. |printer_status| contains the current status of the + // printer. |make| is the detected printer manufacturer. |model| is the // detected model. |make_and_model| is the unparsed printer-make-and-model // string. |ipp_everywhere| indicates if configuration using the CUPS IPP - // Everywhere driver should be attempted. If |success| is false, the values of - // |make|, |model|, |make_and_model|, and |ipp_everywhere| are not specified. + // Everywhere driver should be attempted. If |result| is not SUCCESS, the + // values of |printer_status|, |make|, |model|, |make_and_model|, and + // |ipp_everywhere| are not specified. void OnAutoconfQueried(const std::string& callback_id, printing::PrinterQueryResult result, + const printing::PrinterStatus& printer_status, const std::string& make, const std::string& model, const std::string& make_and_model, @@ -96,6 +103,7 @@ class CupsPrintersHandler : public ::settings::SettingsPageUIHandler, const std::string& callback_id, Printer printer, printing::PrinterQueryResult result, + const printing::PrinterStatus& printer_status, const std::string& make, const std::string& model, const std::string& make_and_model, @@ -214,8 +222,14 @@ class CupsPrintersHandler : public ::settings::SettingsPageUIHandler, const net::IPEndPoint& endpoint); void HandleQueryPrintServer(const base::ListValue* args); + + void QueryPrintServer(const std::string& callback_id, + const GURL& server_url, + bool should_fallback); + void OnQueryPrintServerCompleted( const std::string& callback_id, + bool should_fallback, const ServerPrintersFetcher* sender, const GURL& server_url, std::vector<PrinterDetector::DetectedPrinter>&& returned_printers); diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc index 59656e6e848..39ceb89c02a 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc @@ -168,8 +168,8 @@ void DateTimeHandler::HandleShowParentAccessForTimeZone( ash::LoginScreen::Get()->ShowParentAccessWidget( user_manager::UserManager::Get()->GetActiveUser()->GetAccountId(), - base::BindRepeating(&DateTimeHandler::OnParentAccessValidation, - weak_ptr_factory_.GetWeakPtr()), + base::BindOnce(&DateTimeHandler::OnParentAccessValidation, + weak_ptr_factory_.GetWeakPtr()), ash::ParentAccessRequestReason::kChangeTimezone, false /* extra_dimmer */, base::Time()); } diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.cc index ee16a539c7b..7195f59a799 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.cc @@ -6,7 +6,6 @@ #include "ash/public/cpp/keyboard_shortcut_viewer.h" #include "ash/public/cpp/tablet_mode.h" -#include "ash/public/mojom/constants.mojom.h" #include "base/bind.h" #include "base/command_line.h" #include "base/values.h" @@ -21,25 +20,33 @@ namespace { struct KeyboardsStateResult { bool has_internal_keyboard = false; - bool has_external_non_apple_keyboard = false; - bool has_apple_keyboard = false; + bool has_external_apple_keyboard = false; + bool has_external_chromeos_keyboard = false; + bool has_external_generic_keyboard = false; }; KeyboardsStateResult GetKeyboardsState() { KeyboardsStateResult result; for (const ui::InputDevice& keyboard : ui::DeviceDataManager::GetInstance()->GetKeyboardDevices()) { - result.has_internal_keyboard |= - (keyboard.type == ui::INPUT_DEVICE_INTERNAL); - - const ui::EventRewriterChromeOS::DeviceType type = - ui::EventRewriterChromeOS::GetDeviceType(keyboard); - if (type == ui::EventRewriterChromeOS::kDeviceAppleKeyboard) { - result.has_apple_keyboard = true; - } else if (type == - ui::EventRewriterChromeOS::kDeviceExternalNonAppleKeyboard || - type == ui::EventRewriterChromeOS::kDeviceExternalUnknown) { - result.has_external_non_apple_keyboard = true; + switch (ui::EventRewriterChromeOS::GetDeviceType(keyboard)) { + case ui::EventRewriterChromeOS::kDeviceInternalKeyboard: + result.has_internal_keyboard = true; + break; + case ui::EventRewriterChromeOS::kDeviceExternalAppleKeyboard: + result.has_external_apple_keyboard = true; + break; + case ui::EventRewriterChromeOS::kDeviceExternalChromeOsKeyboard: + result.has_external_chromeos_keyboard = true; + break; + case ui::EventRewriterChromeOS::kDeviceExternalGenericKeyboard: + case ui::EventRewriterChromeOS::kDeviceExternalUnknown: + result.has_external_generic_keyboard = true; + break; + case ui::EventRewriterChromeOS::kDeviceHotrodRemote: + case ui::EventRewriterChromeOS::kDeviceVirtualCoreKeyboard: + case ui::EventRewriterChromeOS::kDeviceUnknown: + break; } } @@ -131,8 +138,8 @@ void KeyboardHandler::UpdateShowKeys() { // kHasChromeOSKeyboard will be unset on Chromebooks that have standalone Caps // Lock keys. const KeyboardsStateResult keyboards_state = GetKeyboardsState(); - const bool has_caps_lock = keyboards_state.has_apple_keyboard || - keyboards_state.has_external_non_apple_keyboard || + const bool has_caps_lock = keyboards_state.has_external_apple_keyboard || + keyboards_state.has_external_generic_keyboard || !base::CommandLine::ForCurrentProcess()->HasSwitch( chromeos::switches::kHasChromeOSKeyboard); @@ -140,9 +147,10 @@ void KeyboardHandler::UpdateShowKeys() { keyboard_params.SetKey("showCapsLock", base::Value(has_caps_lock)); keyboard_params.SetKey( "showExternalMetaKey", - base::Value(keyboards_state.has_external_non_apple_keyboard)); - keyboard_params.SetKey("showAppleCommandKey", - base::Value(keyboards_state.has_apple_keyboard)); + base::Value(keyboards_state.has_external_generic_keyboard)); + keyboard_params.SetKey( + "showAppleCommandKey", + base::Value(keyboards_state.has_external_apple_keyboard)); keyboard_params.SetKey("hasInternalKeyboard", base::Value(keyboards_state.has_internal_keyboard)); diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler_unittest.cc index 8f4f6318a50..a558502222a 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler_unittest.cc @@ -15,6 +15,7 @@ #include "base/observer_list.h" #include "chromeos/constants/chromeos_switches.h" #include "content/public/test/test_web_ui.h" +#include "device/udev_linux/fake_udev_loader.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/events/devices/device_data_manager_test_api.h" #include "ui/events/devices/input_device.h" @@ -192,11 +193,46 @@ TEST_F(KeyboardHandlerTest, NonChromeOSKeyboard) { } TEST_F(KeyboardHandlerTest, ExternalKeyboard) { + auto fake_udev = std::make_unique<testing::FakeUdevLoader>(); + + // Standard internal keyboard on x86 device. + const ui::InputDevice internal_kbd( + 1, ui::INPUT_DEVICE_INTERNAL, "AT Translated Set 2 keyboard", "", + base::FilePath("/devices/platform/i8042/serio0/input/input1"), 1, 1, + 0xab41); + fake_udev->AddFakeDevice(internal_kbd.name, internal_kbd.sys_path.value(), {}, + {}); + // Generic external USB keyboard. + const ui::InputDevice external_generic_kbd( + 2, ui::INPUT_DEVICE_USB, "Logitech USB Keyboard", "", + base::FilePath("/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/" + "0003:046D:C31C.0007/" + "input/input2"), + 0x046d, 0xc31c, 0x0111); + fake_udev->AddFakeDevice(external_generic_kbd.name, + external_generic_kbd.sys_path.value(), {}, {}); + // Apple keyboard. + const ui::InputDevice external_apple_kbd( + 3, ui::INPUT_DEVICE_USB, "Apple Inc. Apple Keyboard", "", + base::FilePath("/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.1/" + "0003:05AC:026C.000A/input/input3"), + 0x05ac, 0x026c, 0x0111); + fake_udev->AddFakeDevice(external_apple_kbd.name, + external_apple_kbd.sys_path.value(), {}, {}); + // Chrome OS external USB keyboard. + const ui::InputDevice external_chromeos_kbd( + 4, ui::INPUT_DEVICE_USB, "LG USB Keyboard", "", + base::FilePath("/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/" + "0003:04CA:0082.000B/input/input4"), + 0x04ca, 0x0082, 0x0111); + fake_udev->AddFakeDevice(external_chromeos_kbd.name, + external_chromeos_kbd.sys_path.value(), {}, + {{"CROS_KEYBOARD_TOP_ROW_LAYOUT", "1"}}); + // An internal keyboard shouldn't change the defaults. base::CommandLine::ForCurrentProcess()->AppendSwitch( chromeos::switches::kHasChromeOSKeyboard); - device_data_manager_test_api_.SetKeyboardDevices(std::vector<ui::InputDevice>{ - {1, ui::INPUT_DEVICE_INTERNAL, "internal keyboard"}}); + device_data_manager_test_api_.SetKeyboardDevices({internal_kbd}); handler_test_api_.Initialize(); EXPECT_TRUE(HasInternalSearchKey()); EXPECT_FALSE(HasCapsLock()); @@ -206,20 +242,28 @@ TEST_F(KeyboardHandlerTest, ExternalKeyboard) { // Simulate an external keyboard being connected. We should assume there's a // Caps Lock and Meta keys now. - device_data_manager_test_api_.SetKeyboardDevices(std::vector<ui::InputDevice>{ - {1, ui::INPUT_DEVICE_INTERNAL, "internal keyboard"}, - {2, ui::INPUT_DEVICE_USB, "external keyboard"}}); + device_data_manager_test_api_.SetKeyboardDevices( + std::vector<ui::InputDevice>{internal_kbd, external_generic_kbd}); EXPECT_TRUE(HasInternalSearchKey()); EXPECT_TRUE(HasCapsLock()); EXPECT_TRUE(HasExternalMetaKey()); EXPECT_FALSE(HasAppleCommandKey()); EXPECT_FALSE(HasAssistantKey()); + // However when connecting external ChromeOS-branded keyboard, we should not + // see neither CapsLock not meta keys. + device_data_manager_test_api_.SetKeyboardDevices( + std::vector<ui::InputDevice>{internal_kbd, external_chromeos_kbd}); + EXPECT_TRUE(HasInternalSearchKey()); + EXPECT_FALSE(HasCapsLock()); + EXPECT_FALSE(HasExternalMetaKey()); + EXPECT_FALSE(HasAppleCommandKey()); + EXPECT_FALSE(HasAssistantKey()); + // Simulate an external Apple keyboard being connected. Now users can remap // the command key. - device_data_manager_test_api_.SetKeyboardDevices(std::vector<ui::InputDevice>{ - {1, ui::INPUT_DEVICE_INTERNAL, "internal keyboard"}, - {3, ui::INPUT_DEVICE_USB, "Apple Inc. Apple Keyboard"}}); + device_data_manager_test_api_.SetKeyboardDevices( + std::vector<ui::InputDevice>{internal_kbd, external_apple_kbd}); EXPECT_TRUE(HasInternalSearchKey()); EXPECT_TRUE(HasCapsLock()); EXPECT_FALSE(HasExternalMetaKey()); @@ -228,9 +272,8 @@ TEST_F(KeyboardHandlerTest, ExternalKeyboard) { // Simulate two external keyboards (Apple and non-Apple) are connected at the // same time. - device_data_manager_test_api_.SetKeyboardDevices(std::vector<ui::InputDevice>{ - {2, ui::INPUT_DEVICE_USB, "external keyboard"}, - {3, ui::INPUT_DEVICE_USB, "Apple Inc. Apple Keyboard"}}); + device_data_manager_test_api_.SetKeyboardDevices( + std::vector<ui::InputDevice>{external_generic_kbd, external_apple_kbd}); EXPECT_FALSE(HasInternalSearchKey()); EXPECT_TRUE(HasCapsLock()); EXPECT_TRUE(HasExternalMetaKey()); @@ -242,7 +285,8 @@ TEST_F(KeyboardHandlerTest, ExternalKeyboard) { // should show the capslock and external meta remapping. // https://crbug.com/834594. device_data_manager_test_api_.SetKeyboardDevices(std::vector<ui::InputDevice>{ - {4, ui::INPUT_DEVICE_USB, "Topre Corporation Realforce 87"}}); + {5, ui::INPUT_DEVICE_USB, "Topre Corporation Realforce 87", "", + external_generic_kbd.sys_path, 0x046d, 0xc31c, 0x0111}}); EXPECT_FALSE(HasInternalSearchKey()); EXPECT_TRUE(HasCapsLock()); EXPECT_TRUE(HasExternalMetaKey()); diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/device_power_handler.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/device_power_handler.cc index 1906a330cd5..a5c66d6f18f 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/device_power_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/device_power_handler.cc @@ -79,11 +79,34 @@ int PowerSourceToDisplayId( } // namespace +PowerHandler::IdleBehaviorInfo::IdleBehaviorInfo() = default; +PowerHandler::IdleBehaviorInfo::~IdleBehaviorInfo() = default; + +PowerHandler::IdleBehaviorInfo::IdleBehaviorInfo( + const std::set<PowerHandler::IdleBehavior>& possible_behaviors, + const PowerHandler::IdleBehavior& current_behavior, + const bool is_managed) + : possible_behaviors(possible_behaviors), + current_behavior(current_behavior), + is_managed(is_managed) {} + +PowerHandler::IdleBehaviorInfo::IdleBehaviorInfo(const IdleBehaviorInfo& o) = + default; + const char PowerHandler::kPowerManagementSettingsChangedName[] = "power-management-settings-changed"; -const char PowerHandler::kIdleBehaviorKey[] = "idleBehavior"; -const char PowerHandler::kIdleControlledKey[] = "idleControlled"; + +const char PowerHandler::kPossibleAcIdleBehaviorsKey[] = + "possibleAcIdleBehaviors"; +const char PowerHandler::kPossibleBatteryIdleBehaviorsKey[] = + "possibleBatteryIdleBehaviors"; +const char PowerHandler::kCurrentAcIdleBehaviorKey[] = "currentAcIdleBehavior"; +const char PowerHandler::kCurrentBatteryIdleBehaviorKey[] = + "currentBatteryIdleBehavior"; const char PowerHandler::kLidClosedBehaviorKey[] = "lidClosedBehavior"; +const char PowerHandler::kAcIdleManagedKey[] = "acIdleManaged"; +const char PowerHandler::kBatteryIdleManagedKey[] = "batteryIdleManaged"; + const char PowerHandler::kLidClosedControlledKey[] = "lidClosedControlled"; const char PowerHandler::kHasLidKey[] = "hasLid"; @@ -96,9 +119,11 @@ void PowerHandler::TestAPI::RequestPowerManagementSettings() { handler_->HandleRequestPowerManagementSettings(&args); } -void PowerHandler::TestAPI::SetIdleBehavior(IdleBehavior behavior) { +void PowerHandler::TestAPI::SetIdleBehavior(IdleBehavior behavior, + bool when_on_ac) { base::ListValue args; args.AppendInteger(static_cast<int>(behavior)); + args.AppendBoolean(when_on_ac); handler_->HandleSetIdleBehavior(&args); } @@ -205,49 +230,48 @@ void PowerHandler::HandleSetIdleBehavior(const base::ListValue* args) { AllowJavascript(); int value = 0; + bool when_on_ac = true; CHECK(args->GetInteger(0, &value)); + CHECK(args->GetBoolean(1, &when_on_ac)); + + const char* idle_pref = when_on_ac ? ash::prefs::kPowerAcIdleAction + : ash::prefs::kPowerBatteryIdleAction; + const char* screen_dim_delay_pref = + when_on_ac ? ash::prefs::kPowerAcScreenDimDelayMs + : ash::prefs::kPowerBatteryScreenDimDelayMs; + const char* screen_off_delay_pref = + when_on_ac ? ash::prefs::kPowerAcScreenOffDelayMs + : ash::prefs::kPowerBatteryScreenOffDelayMs; + const char* screen_lock_delay_pref = + when_on_ac ? ash::prefs::kPowerAcScreenLockDelayMs + : ash::prefs::kPowerBatteryScreenLockDelayMs; + switch (static_cast<IdleBehavior>(value)) { case IdleBehavior::DISPLAY_OFF_SLEEP: - // The default behavior is to turn the display off and sleep. Clear the - // prefs so we use the default delays. - prefs_->ClearPref(ash::prefs::kPowerAcIdleAction); - prefs_->ClearPref(ash::prefs::kPowerAcScreenDimDelayMs); - prefs_->ClearPref(ash::prefs::kPowerAcScreenOffDelayMs); - prefs_->ClearPref(ash::prefs::kPowerAcScreenLockDelayMs); - prefs_->ClearPref(ash::prefs::kPowerBatteryIdleAction); - prefs_->ClearPref(ash::prefs::kPowerBatteryScreenDimDelayMs); - prefs_->ClearPref(ash::prefs::kPowerBatteryScreenOffDelayMs); - prefs_->ClearPref(ash::prefs::kPowerBatteryScreenLockDelayMs); + // The default behavior is to turn the display off and sleep. + // Clear the prefs so we use the default delays. + prefs_->ClearPref(idle_pref); + prefs_->ClearPref(screen_dim_delay_pref); + prefs_->ClearPref(screen_off_delay_pref); + prefs_->ClearPref(screen_lock_delay_pref); break; case IdleBehavior::DISPLAY_OFF: - // Override idle actions to keep the system awake, but use the default - // screen delays. - prefs_->SetInteger(ash::prefs::kPowerAcIdleAction, - PowerPolicyController::ACTION_DO_NOTHING); - prefs_->ClearPref(ash::prefs::kPowerAcScreenDimDelayMs); - prefs_->ClearPref(ash::prefs::kPowerAcScreenOffDelayMs); - prefs_->ClearPref(ash::prefs::kPowerAcScreenLockDelayMs); - prefs_->SetInteger(ash::prefs::kPowerBatteryIdleAction, - PowerPolicyController::ACTION_DO_NOTHING); - prefs_->ClearPref(ash::prefs::kPowerBatteryScreenDimDelayMs); - prefs_->ClearPref(ash::prefs::kPowerBatteryScreenOffDelayMs); - prefs_->ClearPref(ash::prefs::kPowerBatteryScreenLockDelayMs); + // Override idle actions to keep the system awake, but use the + // default screen delays. + prefs_->SetInteger(idle_pref, PowerPolicyController::ACTION_DO_NOTHING); + prefs_->ClearPref(screen_dim_delay_pref); + prefs_->ClearPref(screen_off_delay_pref); + prefs_->ClearPref(screen_lock_delay_pref); break; case IdleBehavior::DISPLAY_ON: - // Override idle actions and set screen delays to 0 in order to disable - // them (i.e. keep the screen on). - prefs_->SetInteger(ash::prefs::kPowerAcIdleAction, - PowerPolicyController::ACTION_DO_NOTHING); - prefs_->SetInteger(ash::prefs::kPowerAcScreenDimDelayMs, 0); - prefs_->SetInteger(ash::prefs::kPowerAcScreenOffDelayMs, 0); - prefs_->SetInteger(ash::prefs::kPowerAcScreenLockDelayMs, 0); - prefs_->SetInteger(ash::prefs::kPowerBatteryIdleAction, - PowerPolicyController::ACTION_DO_NOTHING); - prefs_->SetInteger(ash::prefs::kPowerBatteryScreenDimDelayMs, 0); - prefs_->SetInteger(ash::prefs::kPowerBatteryScreenOffDelayMs, 0); - prefs_->SetInteger(ash::prefs::kPowerBatteryScreenLockDelayMs, 0); + // Override idle actions and set screen delays to 0 in order to + // disable them (i.e. keep the screen on). + prefs_->SetInteger(idle_pref, PowerPolicyController::ACTION_DO_NOTHING); + prefs_->SetInteger(screen_dim_delay_pref, 0); + prefs_->SetInteger(screen_off_delay_pref, 0); + prefs_->SetInteger(screen_lock_delay_pref, 0); break; - default: + case IdleBehavior::OTHER: NOTREACHED() << "Invalid idle behavior " << value; } } @@ -336,32 +360,10 @@ void PowerHandler::SendPowerSources() { } void PowerHandler::SendPowerManagementSettings(bool force) { - // Infer the idle behavior based on the idle action (determining whether we'll - // sleep eventually or not) and the AC screen-off delay. Policy can request - // more-nuanced combinations of AC/battery actions and delays, but we wouldn't - // be able to display something meaningful in the UI in those cases anyway. - const PowerPolicyController::Action idle_action = - static_cast<PowerPolicyController::Action>( - prefs_->GetInteger(ash::prefs::kPowerAcIdleAction)); - IdleBehavior idle_behavior = IdleBehavior::OTHER; - if (idle_action == PowerPolicyController::ACTION_SUSPEND) { - idle_behavior = IdleBehavior::DISPLAY_OFF_SLEEP; - } else if (idle_action == PowerPolicyController::ACTION_DO_NOTHING) { - idle_behavior = - (prefs_->GetInteger(ash::prefs::kPowerAcScreenOffDelayMs) > 0 - ? IdleBehavior::DISPLAY_OFF - : IdleBehavior::DISPLAY_ON); - } - - const bool idle_controlled = - prefs_->IsManagedPreference(ash::prefs::kPowerAcIdleAction) || - prefs_->IsManagedPreference(ash::prefs::kPowerAcScreenDimDelayMs) || - prefs_->IsManagedPreference(ash::prefs::kPowerAcScreenOffDelayMs) || - prefs_->IsManagedPreference(ash::prefs::kPowerAcScreenLockDelayMs) || - prefs_->IsManagedPreference(ash::prefs::kPowerBatteryIdleAction) || - prefs_->IsManagedPreference(ash::prefs::kPowerBatteryScreenDimDelayMs) || - prefs_->IsManagedPreference(ash::prefs::kPowerBatteryScreenOffDelayMs) || - prefs_->IsManagedPreference(ash::prefs::kPowerBatteryScreenLockDelayMs); + const PowerHandler::IdleBehaviorInfo ac_idle_info = + GetAllowedIdleBehaviors(PowerSource::kAc); + const PowerHandler::IdleBehaviorInfo battery_idle_info = + GetAllowedIdleBehaviors(PowerSource::kBattery); const PowerPolicyController::Action lid_closed_behavior = static_cast<PowerPolicyController::Action>( @@ -371,23 +373,37 @@ void PowerHandler::SendPowerManagementSettings(bool force) { const bool has_lid = lid_state_ != PowerManagerClient::LidState::NOT_PRESENT; // Don't notify the UI if nothing changed. - if (!force && idle_behavior == last_idle_behavior_ && - idle_controlled == last_idle_controlled_ && + if (!force && ac_idle_info == last_ac_idle_info_ && + battery_idle_info == last_battery_idle_info_ && lid_closed_behavior == last_lid_closed_behavior_ && lid_closed_controlled == last_lid_closed_controlled_ && - has_lid == last_has_lid_) + has_lid == last_has_lid_) { return; + } base::DictionaryValue dict; - dict.SetInteger(kIdleBehaviorKey, static_cast<int>(idle_behavior)); - dict.SetBoolean(kIdleControlledKey, idle_controlled); + base::Value* list = dict.SetKey(kPossibleAcIdleBehaviorsKey, + base::Value(base::Value::Type::LIST)); + for (auto idle_behavior : ac_idle_info.possible_behaviors) + list->Append(static_cast<int>(idle_behavior)); + + list = dict.SetKey(kPossibleBatteryIdleBehaviorsKey, + base::Value(base::Value::Type::LIST)); + for (auto idle_behavior : battery_idle_info.possible_behaviors) + list->Append(static_cast<int>(idle_behavior)); + dict.SetInteger(kCurrentAcIdleBehaviorKey, + static_cast<int>(ac_idle_info.current_behavior)); + dict.SetInteger(kCurrentBatteryIdleBehaviorKey, + static_cast<int>(battery_idle_info.current_behavior)); dict.SetInteger(kLidClosedBehaviorKey, lid_closed_behavior); + dict.SetBoolean(kAcIdleManagedKey, ac_idle_info.is_managed); + dict.SetBoolean(kBatteryIdleManagedKey, battery_idle_info.is_managed); dict.SetBoolean(kLidClosedControlledKey, lid_closed_controlled); dict.SetBoolean(kHasLidKey, has_lid); FireWebUIListener(kPowerManagementSettingsChangedName, dict); - last_idle_behavior_ = idle_behavior; - last_idle_controlled_ = idle_controlled; + last_ac_idle_info_ = ac_idle_info; + last_battery_idle_info_ = battery_idle_info; last_lid_closed_behavior_ = lid_closed_behavior; last_lid_closed_controlled_ = lid_closed_controlled; last_has_lid_ = has_lid; @@ -401,5 +417,159 @@ void PowerHandler::OnGotSwitchStates( SendPowerManagementSettings(false /* force */); } +PowerHandler::IdleBehaviorInfo PowerHandler::GetAllowedIdleBehaviors( + PowerSource power_source) { + const char* idle_pref = power_source == PowerSource::kAc + ? ash::prefs::kPowerAcIdleAction + : ash::prefs::kPowerBatteryIdleAction; + const char* screen_off_delay_pref = + power_source == PowerSource::kAc + ? ash::prefs::kPowerAcScreenOffDelayMs + : ash::prefs::kPowerBatteryScreenOffDelayMs; + + std::set<IdleBehavior> possible_behaviors; + IdleBehavior current_idle_behavior; + + // If idle action is managed and set to suspend, only possible idle + // behaviour is sleep with display off. + if (prefs_->IsManagedPreference(idle_pref) && + prefs_->GetInteger(idle_pref) == PowerPolicyController::ACTION_SUSPEND) { + current_idle_behavior = IdleBehavior::DISPLAY_OFF_SLEEP; + possible_behaviors.insert(IdleBehavior::DISPLAY_OFF_SLEEP); + return IdleBehaviorInfo(possible_behaviors, current_idle_behavior, + IsIdleManaged(power_source)); + } + + // If idle action is managed and set to SHUT_DOWN/STOP_SESSION, only + // possible idle behaviour is other. + if (prefs_->IsManagedPreference(idle_pref) && + (prefs_->GetInteger(idle_pref) == + PowerPolicyController::ACTION_STOP_SESSION || + prefs_->GetInteger(idle_pref) == + PowerPolicyController::ACTION_SHUT_DOWN)) { + current_idle_behavior = IdleBehavior::OTHER; + possible_behaviors.insert(IdleBehavior::OTHER); + return IdleBehaviorInfo(possible_behaviors, current_idle_behavior, + IsIdleManaged(power_source)); + } + + // Note that after this point |idle_pref| should either be: + // 1. Not managed. + // 2. Or managed and set to + // PowerPolicyController::ACTION_DO_NOTHING. + DCHECK(!prefs_->IsManagedPreference(idle_pref) || + (prefs_->GetInteger(idle_pref) == + PowerPolicyController::ACTION_DO_NOTHING)); + + // If screen off delay is managed and set to a value greater than 0 + // and + // 1. If idle action is managed and set to DO_NOTHING, only + // possible idle behavior is DISPLAY_OFF. + // 2. If idle action is not managed then possible idle options + // are DiSPLAY_OFF and DISPLAY_OFF_SLEEP + if (prefs_->IsManagedPreference(screen_off_delay_pref) && + prefs_->GetInteger(screen_off_delay_pref) > 0) { + if (prefs_->IsManagedPreference(idle_pref) && + prefs_->GetInteger(idle_pref) == + PowerPolicyController::ACTION_DO_NOTHING) { + current_idle_behavior = IdleBehavior::DISPLAY_OFF; + possible_behaviors.insert(IdleBehavior::DISPLAY_OFF); + return IdleBehaviorInfo(possible_behaviors, current_idle_behavior, + IsIdleManaged(power_source)); + } + + possible_behaviors.insert(IdleBehavior::DISPLAY_OFF); + possible_behaviors.insert(IdleBehavior::DISPLAY_OFF_SLEEP); + // Set the current default option based on the current idle action. + const PowerPolicyController::Action idle_action = + static_cast<PowerPolicyController::Action>( + prefs_->GetInteger(idle_pref)); + + if (idle_action == PowerPolicyController::ACTION_SUSPEND) + current_idle_behavior = IdleBehavior::DISPLAY_OFF_SLEEP; + else + current_idle_behavior = IdleBehavior::DISPLAY_OFF; + return IdleBehaviorInfo(possible_behaviors, current_idle_behavior, + IsIdleManaged(power_source)); + } + + // If idle action is managed and set to DO_NOTHING, and + // 1. If screen off delay is also managed (and set to 0), only + // possible idle + // action is DISPLAY_ON. + // 2. If AC screen off delay is not managed, possible idle actions + // are DISPLAY_ON && DISPLAY_OFF. + if (prefs_->IsManagedPreference(idle_pref) && + prefs_->GetInteger(idle_pref) == + PowerPolicyController::ACTION_DO_NOTHING) { + if (prefs_->IsManagedPreference(screen_off_delay_pref)) { + // Note that we reach here only when screen off delays are + // set by enterprise policy to 0 to prevent display from turning + // off. + DCHECK(prefs_->GetInteger(screen_off_delay_pref) == 0); + current_idle_behavior = IdleBehavior::DISPLAY_ON; + possible_behaviors.insert(IdleBehavior::DISPLAY_ON); + return IdleBehaviorInfo(possible_behaviors, current_idle_behavior, + IsIdleManaged(power_source)); + } + possible_behaviors.insert(IdleBehavior::DISPLAY_ON); + possible_behaviors.insert(IdleBehavior::DISPLAY_OFF); + // Set the current default option based on the current screen off + // delay. + current_idle_behavior = prefs_->GetInteger(screen_off_delay_pref) > 0 + ? IdleBehavior::DISPLAY_OFF + : IdleBehavior::DISPLAY_ON; + return IdleBehaviorInfo(possible_behaviors, current_idle_behavior, + IsIdleManaged(power_source)); + } + + // Looks like we did not find enterprise policy restricitng the idle + // options. So add all three idle options to what user can select + // from. + possible_behaviors.insert(IdleBehavior::DISPLAY_ON); + possible_behaviors.insert(IdleBehavior::DISPLAY_OFF); + possible_behaviors.insert(IdleBehavior::DISPLAY_OFF_SLEEP); + + // Infer the idle behavior based on the current idle action + // (determining whether we'll sleep eventually or not) and the AC + // screen-off delay. + const PowerPolicyController::Action idle_action = + static_cast<PowerPolicyController::Action>(prefs_->GetInteger(idle_pref)); + + if (idle_action == PowerPolicyController::ACTION_SUSPEND) { + current_idle_behavior = IdleBehavior::DISPLAY_OFF_SLEEP; + } else if (idle_action == PowerPolicyController::ACTION_DO_NOTHING) { + current_idle_behavior = (prefs_->GetInteger(screen_off_delay_pref) > 0 + ? IdleBehavior::DISPLAY_OFF + : IdleBehavior::DISPLAY_ON); + } else { + current_idle_behavior = IdleBehavior::OTHER; + possible_behaviors.insert(IdleBehavior::OTHER); + } + + return IdleBehaviorInfo(possible_behaviors, current_idle_behavior, + IsIdleManaged(power_source)); +} + +bool PowerHandler::IsIdleManaged(PowerSource power_source) { + switch (power_source) { + case PowerSource::kAc: + return prefs_->IsManagedPreference(ash::prefs::kPowerAcIdleAction) || + prefs_->IsManagedPreference( + ash::prefs::kPowerAcScreenDimDelayMs) || + prefs_->IsManagedPreference( + ash::prefs::kPowerAcScreenOffDelayMs) || + prefs_->IsManagedPreference(ash::prefs::kPowerAcScreenLockDelayMs); + case PowerSource::kBattery: + return prefs_->IsManagedPreference(ash::prefs::kPowerBatteryIdleAction) || + prefs_->IsManagedPreference( + ash::prefs::kPowerBatteryScreenDimDelayMs) || + prefs_->IsManagedPreference( + ash::prefs::kPowerBatteryScreenOffDelayMs) || + prefs_->IsManagedPreference( + ash::prefs::kPowerBatteryScreenLockDelayMs); + } +} + } // namespace settings } // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/device_power_handler.h b/chromium/chrome/browser/ui/webui/settings/chromeos/device_power_handler.h index d55a3944bd5..1d125b0295a 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/device_power_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/device_power_handler.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_DEVICE_POWER_HANDLER_H_ #include <memory> +#include <set> #include "base/macros.h" #include "base/memory/weak_ptr.h" @@ -22,7 +23,7 @@ class PrefService; namespace base { class ListValue; class TimeTicks; -} +} // namespace base namespace chromeos { namespace settings { @@ -43,8 +44,12 @@ class PowerHandler : public ::settings::SettingsPageUIHandler, // WebUI message name and dictionary keys. Shared with tests. static const char kPowerManagementSettingsChangedName[]; - static const char kIdleBehaviorKey[]; - static const char kIdleControlledKey[]; + static const char kPossibleAcIdleBehaviorsKey[]; + static const char kPossibleBatteryIdleBehaviorsKey[]; + static const char kAcIdleManagedKey[]; + static const char kBatteryIdleManagedKey[]; + static const char kCurrentAcIdleBehaviorKey[]; + static const char kCurrentBatteryIdleBehaviorKey[]; static const char kLidClosedBehaviorKey[]; static const char kLidClosedControlledKey[]; static const char kHasLidKey[]; @@ -56,7 +61,9 @@ class PowerHandler : public ::settings::SettingsPageUIHandler, ~TestAPI(); void RequestPowerManagementSettings(); - void SetIdleBehavior(IdleBehavior behavior); + // Sets AC idle behavior to |behavior| if |when_on_ac| is true. Otherwise + // sets battery idle behavior to |behavior|. + void SetIdleBehavior(IdleBehavior behavior, bool when_on_ac); void SetLidClosedBehavior(PowerPolicyController::Action behavior); private: @@ -80,6 +87,33 @@ class PowerHandler : public ::settings::SettingsPageUIHandler, const base::TimeTicks& timestamp) override; private: + enum class PowerSource { kAc, kBattery }; + + // Struct holding possible idle behaviors and the current behavior while + // charging/when on battery. + struct IdleBehaviorInfo { + IdleBehaviorInfo(); + IdleBehaviorInfo(const std::set<IdleBehavior>& possible_behaviors, + const IdleBehavior& current_behavior, + const bool is_managed); + + IdleBehaviorInfo(const IdleBehaviorInfo& o); + ~IdleBehaviorInfo(); + + bool operator==(const IdleBehaviorInfo& o) const { + return (possible_behaviors == o.possible_behaviors && + current_behavior == o.current_behavior && + is_managed == o.is_managed); + } + + // All possible idle behaviors. + std::set<IdleBehavior> possible_behaviors; + // Current idle behavior. + IdleBehavior current_behavior = IdleBehavior::DISPLAY_OFF_SLEEP; + // Whether enterpise policy manages idle behavior. + bool is_managed = false; + }; + // Handler to request updating the power status. void HandleUpdatePowerStatus(const base::ListValue* args); @@ -109,7 +143,16 @@ class PowerHandler : public ::settings::SettingsPageUIHandler, void OnGotSwitchStates( base::Optional<PowerManagerClient::SwitchStates> result); - PrefService* prefs_; // Not owned. + // Returns all possible idle behaviors (that a user can choose from) and + // current idle behavior based on enterprise policy and other factors when on + // |power_source|. + IdleBehaviorInfo GetAllowedIdleBehaviors(PowerSource power_source); + + // Returns true if the enterprise policy enforces any settings that can impact + // the idle behavior of the device when on |power_source|. + bool IsIdleManaged(PowerSource power_source); + + PrefService* const prefs_; // Used to watch power management prefs for changes so the UI can be notified. std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_; @@ -123,10 +166,10 @@ class PowerHandler : public ::settings::SettingsPageUIHandler, // Last values sent by SendPowerManagementSettings(), cached here so // SendPowerManagementSettings() can avoid spamming the UI after this class // changes multiple prefs at once. - IdleBehavior last_idle_behavior_ = IdleBehavior::DISPLAY_OFF_SLEEP; + IdleBehaviorInfo last_ac_idle_info_; + IdleBehaviorInfo last_battery_idle_info_; PowerPolicyController::Action last_lid_closed_behavior_ = PowerPolicyController::ACTION_SUSPEND; - bool last_idle_controlled_ = false; bool last_lid_closed_controlled_ = false; bool last_has_lid_ = true; diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/device_power_handler_browsertest.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/device_power_handler_browsertest.cc index c27e55cb6d4..c928ccd2d75 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/device_power_handler_browsertest.cc +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/device_power_handler_browsertest.cc @@ -2,9 +2,8 @@ // 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/chromeos/device_power_handler.h" - #include <memory> +#include <set> #include <utility> #include "ash/public/cpp/ash_pref_names.h" @@ -13,6 +12,7 @@ #include "base/run_loop.h" #include "base/values.h" #include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/webui/settings/chromeos/device_power_handler.h" #include "chrome/test/base/in_process_browser_test.h" #include "chromeos/dbus/power/fake_power_manager_client.h" #include "chromeos/dbus/power/power_policy_controller.h" @@ -24,8 +24,8 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -using testing::Return; using testing::_; +using testing::Return; namespace chromeos { namespace settings { @@ -48,6 +48,34 @@ class TestPowerHandler : public PowerHandler { class PowerHandlerTest : public InProcessBrowserTest { protected: + struct DevicePowerSettings { + // Initialize with initial settings. + DevicePowerSettings() { + possible_ac_behaviors.insert( + PowerHandler::IdleBehavior::DISPLAY_OFF_SLEEP); + possible_ac_behaviors.insert(PowerHandler::IdleBehavior::DISPLAY_OFF); + possible_ac_behaviors.insert(PowerHandler::IdleBehavior::DISPLAY_ON); + possible_battery_behaviors.insert( + PowerHandler::IdleBehavior::DISPLAY_OFF_SLEEP); + possible_battery_behaviors.insert( + PowerHandler::IdleBehavior::DISPLAY_OFF); + possible_battery_behaviors.insert(PowerHandler::IdleBehavior::DISPLAY_ON); + } + + std::set<PowerHandler::IdleBehavior> possible_ac_behaviors; + std::set<PowerHandler::IdleBehavior> possible_battery_behaviors; + PowerHandler::IdleBehavior current_ac_behavior = + PowerHandler::IdleBehavior::DISPLAY_OFF_SLEEP; + PowerHandler::IdleBehavior current_battery_behavior = + PowerHandler::IdleBehavior::DISPLAY_OFF_SLEEP; + bool ac_idle_managed = false; + bool battery_idle_managed = false; + PowerPolicyController::Action lid_closed_behavior = + PowerPolicyController::ACTION_SUSPEND; + bool lid_closed_controlled = false; + bool has_lid = true; + }; + PowerHandlerTest() = default; ~PowerHandlerTest() override = default; @@ -99,23 +127,32 @@ class PowerHandlerTest : public InProcessBrowserTest { return std::string(); } - // Returns a string for the given settings that can be compared against the - // output of GetLastSettingsChangedMessage(). - std::string CreateSettingsChangedString( - PowerHandler::IdleBehavior idle_behavior, - bool idle_controlled, - PowerPolicyController::Action lid_closed_behavior, - bool lid_closed_controlled, - bool has_lid) { + // Returns a string for the given |settings|. Used to verify expected + // settings are sent to the UI. + std::string ToString(const DevicePowerSettings& settings) { base::DictionaryValue dict; - dict.SetInteger(PowerHandler::kIdleBehaviorKey, - static_cast<int>(idle_behavior)); - dict.SetBoolean(PowerHandler::kIdleControlledKey, idle_controlled); - dict.SetInteger(PowerHandler::kLidClosedBehaviorKey, lid_closed_behavior); + base::Value* list = dict.SetKey(PowerHandler::kPossibleAcIdleBehaviorsKey, + base::Value(base::Value::Type::LIST)); + for (auto idle_behavior : settings.possible_ac_behaviors) + list->Append(static_cast<int>(idle_behavior)); + + list = dict.SetKey(PowerHandler::kPossibleBatteryIdleBehaviorsKey, + base::Value(base::Value::Type::LIST)); + for (auto idle_behavior : settings.possible_battery_behaviors) + list->Append(static_cast<int>(idle_behavior)); + + dict.SetInteger(PowerHandler::kCurrentAcIdleBehaviorKey, + static_cast<int>(settings.current_ac_behavior)); + dict.SetInteger(PowerHandler::kCurrentBatteryIdleBehaviorKey, + static_cast<int>(settings.current_battery_behavior)); + dict.SetBoolean(PowerHandler::kAcIdleManagedKey, settings.ac_idle_managed); + dict.SetBoolean(PowerHandler::kBatteryIdleManagedKey, + settings.battery_idle_managed); + dict.SetInteger(PowerHandler::kLidClosedBehaviorKey, + settings.lid_closed_behavior); dict.SetBoolean(PowerHandler::kLidClosedControlledKey, - lid_closed_controlled); - dict.SetBoolean(PowerHandler::kHasLidKey, has_lid); - + settings.lid_closed_controlled); + dict.SetBoolean(PowerHandler::kHasLidKey, settings.has_lid); std::string out; EXPECT_TRUE(base::JSONWriter::Write(dict, &out)); return out; @@ -129,6 +166,12 @@ class PowerHandlerTest : public InProcessBrowserTest { return GetPrefs()->GetInteger(name); } + // Trigger power pref managed change. + void UpdateChromePolicy(policy::PolicyMap* policy_map) { + provider_.UpdateChromePolicy(*policy_map); + base::RunLoop().RunUntilIdle(); + } + // Sets a policy update which will cause power pref managed change. void SetPolicyForPolicyKey(policy::PolicyMap* policy_map, const std::string& policy_key, @@ -136,8 +179,7 @@ class PowerHandlerTest : public InProcessBrowserTest { policy_map->Set(policy_key, policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD, std::move(value), nullptr); - provider_.UpdateChromePolicy(*policy_map); - base::RunLoop().RunUntilIdle(); + UpdateChromePolicy(policy_map); } std::unique_ptr<TestPowerHandler> handler_; @@ -154,155 +196,215 @@ class PowerHandlerTest : public InProcessBrowserTest { // Verifies that settings are sent to WebUI when requested. IN_PROC_BROWSER_TEST_F(PowerHandlerTest, SendInitialSettings) { test_api_->RequestPowerManagementSettings(); - EXPECT_EQ( - CreateSettingsChangedString( - PowerHandler::IdleBehavior::DISPLAY_OFF_SLEEP, - false /* idle_controlled */, PowerPolicyController::ACTION_SUSPEND, - false /* lid_closed_controlled */, true /* has_lid */), - GetLastSettingsChangedMessage()); + // Initialized to initial settings. + DevicePowerSettings settings; + EXPECT_EQ(ToString(settings), GetLastSettingsChangedMessage()); } // Verifies that WebUI receives updated settings when the lid state changes. IN_PROC_BROWSER_TEST_F(PowerHandlerTest, SendSettingsForLidStateChanges) { chromeos::FakePowerManagerClient::Get()->SetLidState( PowerManagerClient::LidState::NOT_PRESENT, base::TimeTicks()); - EXPECT_EQ( - CreateSettingsChangedString( - PowerHandler::IdleBehavior::DISPLAY_OFF_SLEEP, - false /* idle_controlled */, PowerPolicyController::ACTION_SUSPEND, - false /* lid_closed_controlled */, false /* has_lid */), - GetLastSettingsChangedMessage()); + + DevicePowerSettings settings; + settings.has_lid = false; + EXPECT_EQ(ToString(settings), GetLastSettingsChangedMessage()); chromeos::FakePowerManagerClient::Get()->SetLidState( PowerManagerClient::LidState::OPEN, base::TimeTicks()); - EXPECT_EQ( - CreateSettingsChangedString( - PowerHandler::IdleBehavior::DISPLAY_OFF_SLEEP, - false /* idle_controlled */, PowerPolicyController::ACTION_SUSPEND, - false /* lid_closed_controlled */, true /* has_lid */), - GetLastSettingsChangedMessage()); + settings.has_lid = true; + EXPECT_EQ(ToString(settings), GetLastSettingsChangedMessage()); } -// Verifies that when various prefs are controlled, the corresponding settings -// are reported as controlled to WebUI. +// Verifies that when various prefs are controlled, the corresponding +// settings are reported as controlled/managed to WebUI. IN_PROC_BROWSER_TEST_F(PowerHandlerTest, SendSettingsForControlledPrefs) { policy::PolicyMap policy_map; - // Making an arbitrary delay pref managed should result in the idle setting - // being reported as controlled. + // Making an arbitrary AC delay pref managed should result in the AC idle + // setting being reported as managed. SetPolicyForPolicyKey(&policy_map, policy::key::kScreenDimDelayAC, std::make_unique<base::Value>(10000)); - EXPECT_EQ( - CreateSettingsChangedString( - PowerHandler::IdleBehavior::DISPLAY_OFF_SLEEP, - true /* idle_controlled */, PowerPolicyController::ACTION_SUSPEND, - false /* lid_closed_controlled */, true /* has_lid */), - GetLastSettingsChangedMessage()); + DevicePowerSettings settings; + settings.ac_idle_managed = true; + EXPECT_EQ(ToString(settings), GetLastSettingsChangedMessage()); + + // Ditto for battery delay pref managed. + SetPolicyForPolicyKey(&policy_map, policy::key::kScreenDimDelayBattery, + std::make_unique<base::Value>(10000)); + settings.battery_idle_managed = true; + EXPECT_EQ(ToString(settings), GetLastSettingsChangedMessage()); // Ditto for making the lid action pref managed. SetPolicyForPolicyKey( &policy_map, policy::key::kLidCloseAction, std::make_unique<base::Value>(PowerPolicyController::ACTION_SUSPEND)); - EXPECT_EQ( - CreateSettingsChangedString( - PowerHandler::IdleBehavior::DISPLAY_OFF_SLEEP, - true /* idle_controlled */, PowerPolicyController::ACTION_SUSPEND, - true /* lid_closed_controlled */, true /* has_lid */), - GetLastSettingsChangedMessage()); + settings.lid_closed_controlled = true; + EXPECT_EQ(ToString(settings), GetLastSettingsChangedMessage()); } -// Verifies that idle-related prefs are distilled into the proper WebUI -// settings. +// Verifies that idle-related prefs (when not managed by enterpise policy) +// are distilled into the proper WebUI settings. IN_PROC_BROWSER_TEST_F(PowerHandlerTest, SendIdleSettingForPrefChanges) { - // Set a do-nothing idle action and a nonzero screen-off delay. + // Initial power settings. + DevicePowerSettings settings; + // Set a AC do-nothing idle action and a AC nonzero screen-off delay. User + // should see all three options (DISPLAY_ON, DISPLAY_OFF and + // DISPLAY_OFF_SLEEP) and the selected setting when on AC should be set to + // DISPLAY_OFF. GetPrefs()->Set(ash::prefs::kPowerAcIdleAction, base::Value(PowerPolicyController::ACTION_DO_NOTHING)); GetPrefs()->Set(ash::prefs::kPowerAcScreenOffDelayMs, base::Value(10000)); - EXPECT_EQ(CreateSettingsChangedString(PowerHandler::IdleBehavior::DISPLAY_OFF, - false /* idle_controlled */, - PowerPolicyController::ACTION_SUSPEND, - false /* lid_closed_controlled */, - true /* has_lid */), - GetLastSettingsChangedMessage()); - - // Now set the delay to zero and check that the setting goes to "display on". - GetPrefs()->Set(ash::prefs::kPowerAcScreenOffDelayMs, base::Value(0)); - EXPECT_EQ(CreateSettingsChangedString(PowerHandler::IdleBehavior::DISPLAY_ON, - false /* idle_controlled */, - PowerPolicyController::ACTION_SUSPEND, - false /* lid_closed_controlled */, - true /* has_lid */), - GetLastSettingsChangedMessage()); + + // Current AC idle behavior should be DISPLAY_OFF. + settings.current_ac_behavior = PowerHandler::IdleBehavior::DISPLAY_OFF; + EXPECT_EQ(ToString(settings), GetLastSettingsChangedMessage()); + + // Now set the battery screen off delay to zero along with battery do-nothing + // idle action and check that the selected setting goes to "display on" when + // on battery. + GetPrefs()->Set(ash::prefs::kPowerBatteryIdleAction, + base::Value(PowerPolicyController::ACTION_DO_NOTHING)); + GetPrefs()->Set(ash::prefs::kPowerBatteryScreenOffDelayMs, base::Value(0)); + + // Current battery idle behavior should be DISPLAY_ON. + settings.current_battery_behavior = PowerHandler::IdleBehavior::DISPLAY_ON; + EXPECT_EQ(ToString(settings), GetLastSettingsChangedMessage()); // Other idle actions should result in an "other" setting. GetPrefs()->Set(ash::prefs::kPowerAcIdleAction, base::Value(PowerPolicyController::ACTION_STOP_SESSION)); - EXPECT_EQ(CreateSettingsChangedString( - PowerHandler::IdleBehavior::OTHER, false /* idle_controlled */, - PowerPolicyController::ACTION_SUSPEND, - false /* lid_closed_controlled */, true /* has_lid */), - GetLastSettingsChangedMessage()); + // Current AC idle behavior should be OTHER. + settings.current_ac_behavior = PowerHandler::IdleBehavior::OTHER; + // Possible AC idle behaviors should include OTHER too. + settings.possible_ac_behaviors.insert(PowerHandler::IdleBehavior::OTHER); + EXPECT_EQ(ToString(settings), GetLastSettingsChangedMessage()); +} + +// Verifies that idle-related prefs when managed by enterpise policy are +// distilled into the proper WebUI settings. +IN_PROC_BROWSER_TEST_F(PowerHandlerTest, SendManagedIdleSettingForPrefChanges) { + policy::PolicyMap policy_map; + // Set Enterpise policy that forces AC idle action to suspend. Only possible + // AC idle option visible to the user should be DISPLAY_OFF_SLEEP and the + // current should also be set to same. + SetPolicyForPolicyKey(&policy_map, policy::key::kIdleActionAC, + std::make_unique<base::Value>( + chromeos::PowerPolicyController::ACTION_SUSPEND)); + DevicePowerSettings settings; + std::set<PowerHandler::IdleBehavior> behaviors; + behaviors.insert(PowerHandler::IdleBehavior::DISPLAY_OFF_SLEEP); + settings.possible_ac_behaviors = behaviors; + settings.ac_idle_managed = true; + EXPECT_EQ(ToString(settings), GetLastSettingsChangedMessage()); + + // Set Enterpise policy that forces battery idle action to Shutdown. Only + // possible battery idle option visible to the user then should be OTHER and + // the default should also be set to same. + SetPolicyForPolicyKey(&policy_map, policy::key::kIdleActionBattery, + std::make_unique<base::Value>( + chromeos::PowerPolicyController::ACTION_SHUT_DOWN)); + behaviors.clear(); + behaviors.insert(PowerHandler::IdleBehavior::OTHER); + settings.possible_battery_behaviors = behaviors; + settings.current_battery_behavior = PowerHandler::IdleBehavior::OTHER; + settings.battery_idle_managed = true; + EXPECT_EQ(ToString(settings), GetLastSettingsChangedMessage()); + // Erase battery idle action. + policy_map.Erase(policy::key::kIdleActionBattery); + + // Set battery idle action to DO_NOTHING in Enterpise policy. The user then + // should not see DISPLAY_OFF_SLEEP in available options. + SetPolicyForPolicyKey( + &policy_map, policy::key::kIdleActionBattery, + std::make_unique<base::Value>( + chromeos::PowerPolicyController::ACTION_DO_NOTHING)); + behaviors.clear(); + behaviors.insert(PowerHandler::IdleBehavior::DISPLAY_OFF); + behaviors.insert(PowerHandler::IdleBehavior::DISPLAY_ON); + settings.possible_battery_behaviors = behaviors; + settings.current_battery_behavior = PowerHandler::IdleBehavior::DISPLAY_OFF; + EXPECT_EQ(ToString(settings), GetLastSettingsChangedMessage()); + + // Set battery screen delay in Enterprise policy on top of DO_NOTHING idle + // action. The user should see only see DISPLAY_OFF as the possible battery + // idle action. + SetPolicyForPolicyKey(&policy_map, policy::key::kScreenOffDelayBattery, + std::make_unique<base::Value>(10000)); + behaviors.clear(); + behaviors.insert(PowerHandler::IdleBehavior::DISPLAY_OFF); + settings.possible_battery_behaviors = behaviors; + EXPECT_EQ(ToString(settings), GetLastSettingsChangedMessage()); + + // Now stop enforcing battery idle action (to DO_NOTHING) in enterprise + // policy. The user should see DISPLAY_OFF and DISPLAY_OFF_SLEEP as + // the possible battery idle actions. + policy_map.Erase(policy::key::kIdleActionBattery); + UpdateChromePolicy(&policy_map); + settings.possible_battery_behaviors.insert( + PowerHandler::IdleBehavior::DISPLAY_OFF_SLEEP); + settings.current_battery_behavior = + PowerHandler::IdleBehavior::DISPLAY_OFF_SLEEP; + EXPECT_EQ(ToString(settings), GetLastSettingsChangedMessage()); } // Verifies that the lid-closed pref's value is sent directly to WebUI. IN_PROC_BROWSER_TEST_F(PowerHandlerTest, SendLidSettingForPrefChanges) { GetPrefs()->Set(ash::prefs::kPowerLidClosedAction, base::Value(PowerPolicyController::ACTION_SHUT_DOWN)); - EXPECT_EQ( - CreateSettingsChangedString( - PowerHandler::IdleBehavior::DISPLAY_OFF_SLEEP, - false /* idle_controlled */, PowerPolicyController::ACTION_SHUT_DOWN, - false /* lid_closed_controlled */, true /* has_lid */), - GetLastSettingsChangedMessage()); + DevicePowerSettings settings; + settings.lid_closed_behavior = PowerPolicyController::ACTION_SHUT_DOWN; + EXPECT_EQ(ToString(settings), GetLastSettingsChangedMessage()); GetPrefs()->Set(ash::prefs::kPowerLidClosedAction, base::Value(PowerPolicyController::ACTION_STOP_SESSION)); - EXPECT_EQ(CreateSettingsChangedString( - PowerHandler::IdleBehavior::DISPLAY_OFF_SLEEP, - false /* idle_controlled */, - PowerPolicyController::ACTION_STOP_SESSION, - false /* lid_closed_controlled */, true /* has_lid */), - GetLastSettingsChangedMessage()); + settings.lid_closed_behavior = PowerPolicyController::ACTION_STOP_SESSION; + EXPECT_EQ(ToString(settings), GetLastSettingsChangedMessage()); } // Verifies that requests from WebUI to update the idle behavior update prefs // appropriately. IN_PROC_BROWSER_TEST_F(PowerHandlerTest, SetIdleBehavior) { - // Request the "Keep display on" setting and check that prefs are set + // Request the "Keep display on" AC setting and check that prefs are set // appropriately. - test_api_->SetIdleBehavior(PowerHandler::IdleBehavior::DISPLAY_ON); + test_api_->SetIdleBehavior(PowerHandler::IdleBehavior::DISPLAY_ON, + true /* is_ac */); EXPECT_EQ(PowerPolicyController::ACTION_DO_NOTHING, GetIntPref(ash::prefs::kPowerAcIdleAction)); EXPECT_EQ(0, GetIntPref(ash::prefs::kPowerAcScreenDimDelayMs)); EXPECT_EQ(0, GetIntPref(ash::prefs::kPowerAcScreenOffDelayMs)); EXPECT_EQ(0, GetIntPref(ash::prefs::kPowerAcScreenLockDelayMs)); - EXPECT_EQ(PowerPolicyController::ACTION_DO_NOTHING, - GetIntPref(ash::prefs::kPowerBatteryIdleAction)); - EXPECT_EQ(0, GetIntPref(ash::prefs::kPowerBatteryScreenDimDelayMs)); - EXPECT_EQ(0, GetIntPref(ash::prefs::kPowerBatteryScreenOffDelayMs)); - EXPECT_EQ(0, GetIntPref(ash::prefs::kPowerBatteryScreenLockDelayMs)); + EXPECT_EQ(-1, GetIntPref(ash::prefs::kPowerBatteryIdleAction)); + EXPECT_EQ(-1, GetIntPref(ash::prefs::kPowerBatteryScreenDimDelayMs)); + EXPECT_EQ(-1, GetIntPref(ash::prefs::kPowerBatteryScreenOffDelayMs)); + EXPECT_EQ(-1, GetIntPref(ash::prefs::kPowerBatteryScreenLockDelayMs)); - // "Turn off display" should set the idle prefs but clear the screen - // delays. - test_api_->SetIdleBehavior(PowerHandler::IdleBehavior::DISPLAY_OFF); + // "Turn off display" battery setting should set the battery idle pref but + // clear the battery screen delays. + test_api_->SetIdleBehavior(PowerHandler::IdleBehavior::DISPLAY_OFF, + false /* is_battery */); EXPECT_EQ(PowerPolicyController::ACTION_DO_NOTHING, GetIntPref(ash::prefs::kPowerAcIdleAction)); - EXPECT_EQ(-1, GetIntPref(ash::prefs::kPowerAcScreenDimDelayMs)); - EXPECT_EQ(-1, GetIntPref(ash::prefs::kPowerAcScreenOffDelayMs)); - EXPECT_EQ(-1, GetIntPref(ash::prefs::kPowerAcScreenLockDelayMs)); + EXPECT_EQ(0, GetIntPref(ash::prefs::kPowerAcScreenDimDelayMs)); + EXPECT_EQ(0, GetIntPref(ash::prefs::kPowerAcScreenOffDelayMs)); + EXPECT_EQ(0, GetIntPref(ash::prefs::kPowerAcScreenLockDelayMs)); EXPECT_EQ(PowerPolicyController::ACTION_DO_NOTHING, GetIntPref(ash::prefs::kPowerBatteryIdleAction)); EXPECT_EQ(-1, GetIntPref(ash::prefs::kPowerBatteryScreenDimDelayMs)); EXPECT_EQ(-1, GetIntPref(ash::prefs::kPowerBatteryScreenOffDelayMs)); EXPECT_EQ(-1, GetIntPref(ash::prefs::kPowerBatteryScreenLockDelayMs)); - // Now switch to the "Keep display on" setting (to set the prefs again) and - // check that the "Turn off display and sleep" setting clears all the prefs. - test_api_->SetIdleBehavior(PowerHandler::IdleBehavior::DISPLAY_ON); - test_api_->SetIdleBehavior(PowerHandler::IdleBehavior::DISPLAY_OFF_SLEEP); - EXPECT_EQ(-1, GetIntPref(ash::prefs::kPowerAcIdleAction)); - EXPECT_EQ(-1, GetIntPref(ash::prefs::kPowerAcScreenDimDelayMs)); - EXPECT_EQ(-1, GetIntPref(ash::prefs::kPowerAcScreenOffDelayMs)); - EXPECT_EQ(-1, GetIntPref(ash::prefs::kPowerAcScreenLockDelayMs)); + // Now switch to the "Keep display on" battery setting (to set the prefs + // again) and check that the "Turn off display and sleep" battery setting + // clears all the battery prefs. + test_api_->SetIdleBehavior(PowerHandler::IdleBehavior::DISPLAY_ON, + false /* is_battery */); + test_api_->SetIdleBehavior(PowerHandler::IdleBehavior::DISPLAY_OFF_SLEEP, + false /* is_battery */); + EXPECT_EQ(PowerPolicyController::ACTION_DO_NOTHING, + GetIntPref(ash::prefs::kPowerAcIdleAction)); + EXPECT_EQ(0, GetIntPref(ash::prefs::kPowerAcScreenDimDelayMs)); + EXPECT_EQ(0, GetIntPref(ash::prefs::kPowerAcScreenOffDelayMs)); + EXPECT_EQ(0, GetIntPref(ash::prefs::kPowerAcScreenLockDelayMs)); EXPECT_EQ(-1, GetIntPref(ash::prefs::kPowerBatteryIdleAction)); EXPECT_EQ(-1, GetIntPref(ash::prefs::kPowerBatteryScreenDimDelayMs)); EXPECT_EQ(-1, GetIntPref(ash::prefs::kPowerBatteryScreenOffDelayMs)); diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/device_storage_handler.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/device_storage_handler.cc index 0eebb3c1814..128d85cb80b 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/device_storage_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/device_storage_handler.cc @@ -6,46 +6,16 @@ #include <algorithm> #include <limits> -#include <numeric> +#include <memory> #include <string> +#include <utility> -#include "base/bind.h" -#include "base/feature_list.h" -#include "base/files/file_util.h" -#include "base/system/sys_info.h" -#include "base/task/post_task.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/browsing_data/browsing_data_appcache_helper.h" -#include "chrome/browser/browsing_data/browsing_data_cache_storage_helper.h" -#include "chrome/browser/browsing_data/browsing_data_cookie_helper.h" -#include "chrome/browser/browsing_data/browsing_data_database_helper.h" -#include "chrome/browser/browsing_data/browsing_data_file_system_helper.h" -#include "chrome/browser/browsing_data/browsing_data_flash_lso_helper.h" -#include "chrome/browser/browsing_data/browsing_data_indexed_db_helper.h" -#include "chrome/browser/browsing_data/browsing_data_local_storage_helper.h" -#include "chrome/browser/browsing_data/browsing_data_service_worker_helper.h" #include "chrome/browser/chromeos/arc/arc_util.h" -#include "chrome/browser/chromeos/crostini/crostini_features.h" -#include "chrome/browser/chromeos/crostini/crostini_manager.h" -#include "chrome/browser/chromeos/crostini/crostini_util.h" -#include "chrome/browser/chromeos/drive/file_system_util.h" #include "chrome/browser/chromeos/file_manager/path_util.h" #include "chrome/browser/platform_util.h" -#include "chrome/browser/profiles/profile.h" #include "chrome/grit/generated_resources.h" -#include "chromeos/cryptohome/cryptohome_util.h" -#include "chromeos/dbus/cryptohome/cryptohome_client.h" -#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/disks/disk.h" #include "components/arc/arc_features.h" -#include "components/arc/arc_prefs.h" -#include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" -#include "components/arc/session/arc_bridge_service.h" -#include "components/browsing_data/content/conditional_cache_counting_helper.h" -#include "components/user_manager/user_manager.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/storage_partition.h" #include "content/public/browser/web_ui_data_source.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/text/bytes_formatting.h" @@ -55,41 +25,43 @@ using chromeos::disks::DiskMountManager; namespace chromeos { namespace settings { -namespace { - -void GetSizeStatBlocking(const base::FilePath& mount_path, - int64_t* total_size, - int64_t* available_size) { - int64_t size = base::SysInfo::AmountOfTotalDiskSpace(mount_path); - if (size >= 0) - *total_size = size; - size = base::SysInfo::AmountOfFreeDiskSpace(mount_path); - if (size >= 0) - *available_size = size; -} - -// Threshold to show a message indicating space is critically low (512 MB). -const int64_t kSpaceCriticallyLowBytes = 512 * 1024 * 1024; -// Threshold to show a message indicating space is low (1 GB). -const int64_t kSpaceLowBytes = 1 * 1024 * 1024 * 1024; +namespace { constexpr char kAndroidEnabled[] = "androidEnabled"; +const char* CalculationTypeToEventName( + calculator::SizeCalculator::CalculationType x) { + switch (x) { + case calculator::SizeCalculator::CalculationType::kSystem: + return "storage-system-size-changed"; + case calculator::SizeCalculator::CalculationType::kInUse: + return "storage-size-stat-changed"; + case calculator::SizeCalculator::CalculationType::kMyFiles: + return "storage-my-files-size-changed"; + case calculator::SizeCalculator::CalculationType::kBrowsingData: + return "storage-browsing-data-size-changed"; + case calculator::SizeCalculator::CalculationType::kAppsExtensions: + return "storage-apps-size-changed"; + case calculator::SizeCalculator::CalculationType::kCrostini: + return "storage-crostini-size-changed"; + case calculator::SizeCalculator::CalculationType::kOtherUsers: + return "storage-other-users-size-changed"; + } + NOTREACHED(); + return ""; +} + } // namespace StorageHandler::StorageHandler(Profile* profile, content::WebUIDataSource* html_source) - : browser_cache_size_(-1), - has_browser_cache_size_(false), - browser_site_data_size_(-1), - has_browser_site_data_size_(false), - updating_downloads_size_(false), - updating_browsing_data_size_(false), - updating_android_size_(false), - updating_crostini_size_(false), - updating_other_users_size_(false), - is_android_running_(false), + : size_stat_calculator_(profile), + my_files_size_calculator_(profile), + browsing_data_size_calculator_(profile), + apps_size_calculator_(profile), + crostini_size_calculator_(profile), + other_users_size_calculator_(), profile_(profile), source_name_(html_source->GetSource()), arc_observer_(this), @@ -101,11 +73,7 @@ StorageHandler::StorageHandler(Profile* profile, } StorageHandler::~StorageHandler() { - DiskMountManager::GetInstance()->RemoveObserver(this); - arc::ArcServiceManager::Get() - ->arc_bridge_service() - ->storage_manager() - ->RemoveObserver(this); + StopObservingEvents(); } void StorageHandler::RegisterMessages() { @@ -120,8 +88,8 @@ void StorageHandler::RegisterMessages() { base::BindRepeating(&StorageHandler::HandleUpdateStorageInfo, base::Unretained(this))); web_ui()->RegisterMessageCallback( - "openDownloads", base::BindRepeating(&StorageHandler::HandleOpenDownloads, - base::Unretained(this))); + "openMyFiles", base::BindRepeating(&StorageHandler::HandleOpenMyFiles, + base::Unretained(this))); web_ui()->RegisterMessageCallback( "openArcStorage", base::BindRepeating(&StorageHandler::HandleOpenArcStorage, @@ -136,35 +104,48 @@ void StorageHandler::OnJavascriptAllowed() { if (base::FeatureList::IsEnabled(arc::kUsbStorageUIFeature)) arc_observer_.Add(arc::ArcSessionManager::Get()); - // Start observing the mojo connection UpdateAndroidSize() relies on. Note - // that OnConnectionReady() will be called immediately if the connection has - // already been established. - arc::ArcServiceManager::Get() - ->arc_bridge_service() - ->storage_manager() - ->AddObserver(this); - // Start observing mount/unmount events to update the connected device list. DiskMountManager::GetInstance()->AddObserver(this); + + // Start observing calculators. + size_stat_calculator_.AddObserver(this); + my_files_size_calculator_.AddObserver(this); + browsing_data_size_calculator_.AddObserver(this); + apps_size_calculator_.AddObserver(this); + crostini_size_calculator_.AddObserver(this); + other_users_size_calculator_.AddObserver(this); } void StorageHandler::OnJavascriptDisallowed() { // Ensure that pending callbacks do not complete and cause JS to be evaluated. weak_ptr_factory_.InvalidateWeakPtrs(); - // Stop observing mount/unmount events to update the connected device list. - DiskMountManager::GetInstance()->RemoveObserver(this); - - // Stop observing the mojo connection so that OnConnectionReady() and - // OnConnectionClosed() that use FireWebUIListener() won't be called while JS - // is disabled. - arc::ArcServiceManager::Get() - ->arc_bridge_service() - ->storage_manager() - ->RemoveObserver(this); - if (base::FeatureList::IsEnabled(arc::kUsbStorageUIFeature)) arc_observer_.Remove(arc::ArcSessionManager::Get()); + + StopObservingEvents(); +} + +int64_t StorageHandler::RoundByteSize(int64_t bytes) { + if (bytes < 0) { + NOTREACHED() << "Negative bytes value"; + return -1; + } + + // Subtract one to the original number of bytes. + bytes--; + // Set all the lower bits to 1. + bytes |= bytes >> 1; + bytes |= bytes >> 2; + bytes |= bytes >> 4; + bytes |= bytes >> 8; + bytes |= bytes >> 16; + bytes |= bytes >> 32; + // Add one. The one bit beyond the highest set bit is set to 1. All the lower + // bits are set to 0. + bytes++; + + return bytes; } void StorageHandler::HandleUpdateAndroidEnabled( @@ -176,20 +157,18 @@ void StorageHandler::HandleUpdateAndroidEnabled( void StorageHandler::HandleUpdateStorageInfo(const base::ListValue* args) { AllowJavascript(); - UpdateSizeStat(); - UpdateDownloadsSize(); - UpdateBrowsingDataSize(); - UpdateAndroidRunning(); - UpdateAndroidSize(); - UpdateCrostiniSize(); - UpdateOtherUsersSize(); + size_stat_calculator_.StartCalculation(); + my_files_size_calculator_.StartCalculation(); + browsing_data_size_calculator_.StartCalculation(); + apps_size_calculator_.StartCalculation(); + crostini_size_calculator_.StartCalculation(); + other_users_size_calculator_.StartCalculation(); } -void StorageHandler::HandleOpenDownloads( - const base::ListValue* unused_args) { - const base::FilePath downloads_path = - file_manager::util::GetDownloadsFolderForProfile(profile_); - platform_util::OpenItem(profile_, downloads_path, platform_util::OPEN_FOLDER, +void StorageHandler::HandleOpenMyFiles(const base::ListValue* unused_args) { + const base::FilePath my_files_path = + file_manager::util::GetMyFilesFolderForProfile(profile_); + platform_util::OpenItem(profile_, my_files_path, platform_util::OPEN_FOLDER, platform_util::OpenOperationCallback()); } @@ -206,233 +185,6 @@ void StorageHandler::HandleUpdateExternalStorages( UpdateExternalStorages(); } -void StorageHandler::UpdateSizeStat() { - const base::FilePath downloads_path = - file_manager::util::GetDownloadsFolderForProfile(profile_); - - int64_t* total_size = new int64_t(0); - int64_t* available_size = new int64_t(0); - base::PostTaskAndReply( - FROM_HERE, - {base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE}, - base::Bind(&GetSizeStatBlocking, downloads_path, total_size, - available_size), - base::Bind(&StorageHandler::OnGetSizeStat, weak_ptr_factory_.GetWeakPtr(), - base::Owned(total_size), base::Owned(available_size))); -} - -void StorageHandler::OnGetSizeStat(int64_t* total_size, - int64_t* available_size) { - int64_t used_size = *total_size - *available_size; - base::DictionaryValue size_stat; - size_stat.SetString("totalSize", ui::FormatBytes(*total_size)); - size_stat.SetString("availableSize", ui::FormatBytes(*available_size)); - size_stat.SetString("usedSize", ui::FormatBytes(used_size)); - size_stat.SetDouble("usedRatio", - static_cast<double>(used_size) / *total_size); - int storage_space_state = STORAGE_SPACE_NORMAL; - if (*available_size < kSpaceCriticallyLowBytes) - storage_space_state = STORAGE_SPACE_CRITICALLY_LOW; - else if (*available_size < kSpaceLowBytes) - storage_space_state = STORAGE_SPACE_LOW; - size_stat.SetInteger("spaceState", storage_space_state); - - FireWebUIListener("storage-size-stat-changed", size_stat); -} - -void StorageHandler::UpdateDownloadsSize() { - if (updating_downloads_size_) - return; - updating_downloads_size_ = true; - - const base::FilePath downloads_path = - file_manager::util::GetDownloadsFolderForProfile(profile_); - - base::PostTaskAndReplyWithResult( - FROM_HERE, - {base::ThreadPool(), base::MayBlock(), base::TaskPriority::BEST_EFFORT}, - base::Bind(&base::ComputeDirectorySize, downloads_path), - base::Bind(&StorageHandler::OnGetDownloadsSize, - weak_ptr_factory_.GetWeakPtr())); -} - -void StorageHandler::OnGetDownloadsSize(int64_t size) { - updating_downloads_size_ = false; - FireWebUIListener("storage-downloads-size-changed", - base::Value(ui::FormatBytes(size))); -} - -void StorageHandler::UpdateBrowsingDataSize() { - if (updating_browsing_data_size_) - return; - updating_browsing_data_size_ = true; - - has_browser_cache_size_ = false; - has_browser_site_data_size_ = false; - // Fetch the size of http cache in browsing data. - browsing_data::ConditionalCacheCountingHelper::Count( - content::BrowserContext::GetDefaultStoragePartition(profile_), - base::Time(), base::Time::Max(), - base::BindOnce(&StorageHandler::OnGetCacheSize, - weak_ptr_factory_.GetWeakPtr())); - - // Fetch the size of site data in browsing data. - if (!site_data_size_collector_.get()) { - content::StoragePartition* storage_partition = - content::BrowserContext::GetDefaultStoragePartition(profile_); - site_data_size_collector_ = std::make_unique<SiteDataSizeCollector>( - storage_partition->GetPath(), - new BrowsingDataCookieHelper(storage_partition), - new BrowsingDataDatabaseHelper(profile_), - new BrowsingDataLocalStorageHelper(profile_), - new BrowsingDataAppCacheHelper(storage_partition->GetAppCacheService()), - new BrowsingDataIndexedDBHelper( - storage_partition->GetIndexedDBContext()), - BrowsingDataFileSystemHelper::Create( - storage_partition->GetFileSystemContext()), - new BrowsingDataServiceWorkerHelper( - storage_partition->GetServiceWorkerContext()), - new BrowsingDataCacheStorageHelper( - storage_partition->GetCacheStorageContext()), - BrowsingDataFlashLSOHelper::Create(profile_)); - } - site_data_size_collector_->Fetch( - base::Bind(&StorageHandler::OnGetBrowsingDataSize, - weak_ptr_factory_.GetWeakPtr(), true)); -} - -void StorageHandler::OnGetCacheSize(bool is_upper_limit, int64_t size) { - DCHECK(!is_upper_limit); - OnGetBrowsingDataSize(false, size); -} - -void StorageHandler::OnGetBrowsingDataSize(bool is_site_data, int64_t size) { - if (is_site_data) { - has_browser_site_data_size_ = true; - browser_site_data_size_ = size; - } else { - has_browser_cache_size_ = true; - browser_cache_size_ = size; - } - if (has_browser_cache_size_ && has_browser_site_data_size_) { - base::string16 size_string; - if (browser_cache_size_ >= 0 && browser_site_data_size_ >= 0) { - size_string = ui::FormatBytes( - browser_site_data_size_ + browser_cache_size_); - } else { - size_string = - l10n_util::GetStringUTF16(IDS_SETTINGS_STORAGE_SIZE_UNKNOWN); - } - updating_browsing_data_size_ = false; - FireWebUIListener("storage-browsing-data-size-changed", - base::Value(size_string)); - } -} - -void StorageHandler::UpdateAndroidRunning() { - FireWebUIListener("storage-android-running-changed", - base::Value(is_android_running_)); -} - -void StorageHandler::UpdateAndroidSize() { - if (!is_android_running_) - return; - - if (updating_android_size_) - return; - updating_android_size_ = true; - - bool success = false; - auto* arc_storage_manager = - arc::ArcStorageManager::GetForBrowserContext(profile_); - if (arc_storage_manager) { - success = arc_storage_manager->GetApplicationsSize(base::BindOnce( - &StorageHandler::OnGetAndroidSize, weak_ptr_factory_.GetWeakPtr())); - } - if (!success) - updating_android_size_ = false; -} - -void StorageHandler::OnGetAndroidSize(bool succeeded, - arc::mojom::ApplicationsSizePtr size) { - base::string16 size_string; - if (succeeded) { - uint64_t total_bytes = size->total_code_bytes + size->total_data_bytes + - size->total_cache_bytes; - size_string = ui::FormatBytes(total_bytes); - } else { - size_string = l10n_util::GetStringUTF16(IDS_SETTINGS_STORAGE_SIZE_UNKNOWN); - } - updating_android_size_ = false; - FireWebUIListener("storage-android-size-changed", base::Value(size_string)); -} - -void StorageHandler::UpdateCrostiniSize() { - if (!crostini::CrostiniFeatures::Get()->IsEnabled(profile_)) { - return; - } - - if (updating_crostini_size_) - return; - updating_crostini_size_ = true; - - crostini::CrostiniManager::GetForProfile(profile_)->ListVmDisks( - base::BindOnce(&StorageHandler::OnGetCrostiniSize, - weak_ptr_factory_.GetWeakPtr())); -} - -void StorageHandler::OnGetCrostiniSize(crostini::CrostiniResult result, - int64_t size) { - updating_crostini_size_ = false; - FireWebUIListener("storage-crostini-size-changed", - base::Value(ui::FormatBytes(size))); -} - -void StorageHandler::UpdateOtherUsersSize() { - if (updating_other_users_size_) - return; - updating_other_users_size_ = true; - - other_users_.clear(); - user_sizes_.clear(); - const user_manager::UserList& users = - user_manager::UserManager::Get()->GetUsers(); - for (auto* user : users) { - if (user->is_active()) - continue; - other_users_.push_back(user); - CryptohomeClient::Get()->GetAccountDiskUsage( - cryptohome::CreateAccountIdentifierFromAccountId(user->GetAccountId()), - base::BindOnce(&StorageHandler::OnGetOtherUserSize, - weak_ptr_factory_.GetWeakPtr())); - } - // We should show "0 B" if there is no other user. - if (other_users_.empty()) { - updating_other_users_size_ = false; - FireWebUIListener("storage-other-users-size-changed", - base::Value(ui::FormatBytes(0))); - } -} - -void StorageHandler::OnGetOtherUserSize( - base::Optional<cryptohome::BaseReply> reply) { - user_sizes_.push_back(cryptohome::AccountDiskUsageReplyToUsageSize(reply)); - if (user_sizes_.size() == other_users_.size()) { - base::string16 size_string; - // If all the requests succeed, shows the total bytes in the UI. - if (std::count(user_sizes_.begin(), user_sizes_.end(), -1) == 0) { - size_string = ui::FormatBytes( - std::accumulate(user_sizes_.begin(), user_sizes_.end(), 0LL)); - } else { - size_string = - l10n_util::GetStringUTF16(IDS_SETTINGS_STORAGE_SIZE_UNKNOWN); - } - updating_other_users_size_ = false; - FireWebUIListener("storage-other-users-size-changed", - base::Value(size_string)); - } -} - void StorageHandler::UpdateExternalStorages() { base::Value devices(base::Value::Type::LIST); for (const auto& itr : DiskMountManager::GetInstance()->mount_points()) { @@ -463,19 +215,7 @@ void StorageHandler::UpdateExternalStorages() { FireWebUIListener("onExternalStoragesUpdated", devices); } -void StorageHandler::OnConnectionReady() { - is_android_running_ = true; - UpdateAndroidRunning(); - UpdateAndroidSize(); -} - -void StorageHandler::OnConnectionClosed() { - is_android_running_ = false; - UpdateAndroidRunning(); -} - void StorageHandler::OnArcPlayStoreEnabledChanged(bool enabled) { - FireWebUIListener("storage-android-enabled-changed", base::Value(enabled)); auto update = std::make_unique<base::DictionaryValue>(); update->SetKey(kAndroidEnabled, base::Value(enabled)); content::WebUIDataSource::Update(profile_, source_name_, std::move(update)); @@ -494,6 +234,114 @@ void StorageHandler::OnMountEvent( UpdateExternalStorages(); } +void StorageHandler::OnSizeCalculated( + const calculator::SizeCalculator::CalculationType& calculation_type, + int64_t total_bytes, + const base::Optional<int64_t>& available_bytes) { + if (available_bytes) { + UpdateSizeStat(calculation_type, total_bytes, available_bytes.value()); + } else { + UpdateStorageItem(calculation_type, total_bytes); + } +} + +void StorageHandler::StopObservingEvents() { + // Stop observing mount/unmount events to update the connected device list. + DiskMountManager::GetInstance()->RemoveObserver(this); + + // Stop observing calculators. + size_stat_calculator_.RemoveObserver(this); + my_files_size_calculator_.RemoveObserver(this); + browsing_data_size_calculator_.RemoveObserver(this); + apps_size_calculator_.RemoveObserver(this); + crostini_size_calculator_.RemoveObserver(this); + other_users_size_calculator_.RemoveObserver(this); +} + +void StorageHandler::UpdateStorageItem( + const calculator::SizeCalculator::CalculationType& calculation_type, + int64_t total_bytes) { + // When the system size has been calculated, UpdateSystemSize calls this + // method with the calculation type kSystem. This check prevents an infinite + // loop. + if (calculation_type != calculator::SizeCalculator::CalculationType::kSystem) + UpdateSystemSize(calculation_type, total_bytes); + + base::string16 message; + if (total_bytes < 0) { + message = l10n_util::GetStringUTF16(IDS_SETTINGS_STORAGE_SIZE_UNKNOWN); + } else { + message = ui::FormatBytes(total_bytes); + } + + if (calculation_type == + calculator::SizeCalculator::CalculationType::kOtherUsers) { + bool no_other_users = (total_bytes == 0); + FireWebUIListener(CalculationTypeToEventName(calculation_type), + base::Value(message), base::Value(no_other_users)); + } else { + FireWebUIListener(CalculationTypeToEventName(calculation_type), + base::Value(message)); + } +} + +void StorageHandler::UpdateSizeStat( + const calculator::SizeCalculator::CalculationType& calculation_type, + int64_t total_bytes, + int64_t available_bytes) { + int64_t rounded_total_bytes = RoundByteSize(total_bytes); + int64_t in_use_total_bytes_ = rounded_total_bytes - available_bytes; + + UpdateSystemSize(calculation_type, in_use_total_bytes_); + + base::DictionaryValue size_stat; + size_stat.SetString("availableSize", ui::FormatBytes(available_bytes)); + size_stat.SetString("usedSize", ui::FormatBytes(in_use_total_bytes_)); + size_stat.SetDouble("usedRatio", static_cast<double>(in_use_total_bytes_) / + rounded_total_bytes); + int storage_space_state = + static_cast<int>(StorageSpaceState::kStorageSpaceNormal); + if (available_bytes < kSpaceCriticallyLowBytes) + storage_space_state = + static_cast<int>(StorageSpaceState::kStorageSpaceCriticallyLow); + else if (available_bytes < kSpaceLowBytes) + storage_space_state = static_cast<int>(StorageSpaceState::kStorageSpaceLow); + size_stat.SetInteger("spaceState", storage_space_state); + + FireWebUIListener(CalculationTypeToEventName(calculation_type), size_stat); +} + +void StorageHandler::UpdateSystemSize( + const calculator::SizeCalculator::CalculationType& calculation_type, + int64_t total_bytes) { + const int item_index = static_cast<int>(calculation_type); + storage_items_total_bytes_[item_index] = total_bytes > 0 ? total_bytes : 0; + calculation_state_.set(item_index); + + // Update system size. We only display the total system size when the size of + // all categories has been updated. If some size calculations are pending, + // return early and wait for all calculations to complete. + if (!calculation_state_.all()) + return; + + int64_t system_bytes = 0; + for (int i = 0; i < calculator::SizeCalculator::kCalculationTypeCount; ++i) { + int64_t total_bytes_for_current_item = storage_items_total_bytes_[i]; + // If the storage is in use, add to the system's total storage. + if (i == + static_cast<int>(calculator::SizeCalculator::CalculationType::kInUse)) { + system_bytes += total_bytes_for_current_item; + continue; + } + // Otherwise, this storage amount counts against the total storage + // amount. + system_bytes -= total_bytes_for_current_item; + } + + OnSizeCalculated(calculator::SizeCalculator::CalculationType::kSystem, + system_bytes); +} + bool StorageHandler::IsEligibleForAndroidStorage(std::string source_path) { // Android's StorageManager volume concept relies on assumption that it is // local filesystem. Hence, special volumes like DriveFS should not be diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/device_storage_handler.h b/chromium/chrome/browser/ui/webui/settings/chromeos/device_storage_handler.h index 4c901c9913a..cdd352797a6 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/device_storage_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/device_storage_handler.h @@ -5,25 +5,12 @@ #ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_DEVICE_STORAGE_HANDLER_H_ #define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_DEVICE_STORAGE_HANDLER_H_ -#include <stdint.h> - -#include <memory> #include <string> -#include <vector> -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/optional.h" -#include "base/scoped_observer.h" -#include "chrome/browser/browsing_data/site_data_size_collector.h" #include "chrome/browser/chromeos/arc/session/arc_session_manager.h" +#include "chrome/browser/ui/webui/settings/chromeos/calculator/size_calculator.h" #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" -#include "chromeos/dbus/cryptohome/rpc.pb.h" #include "chromeos/disks/disk_mount_manager.h" -#include "components/arc/mojom/storage_manager.mojom.h" -#include "components/arc/session/connection_observer.h" -#include "components/arc/storage_manager/arc_storage_manager.h" -#include "components/user_manager/user.h" #include "third_party/re2/src/re2/re2.h" class Profile; @@ -39,20 +26,25 @@ enum class CrostiniResult; namespace chromeos { namespace settings { -class StorageHandler - : public ::settings::SettingsPageUIHandler, - public arc::ConnectionObserver<arc::mojom::StorageManagerInstance>, - public arc::ArcSessionManager::Observer, - public chromeos::disks::DiskMountManager::Observer { - public: - // Enumeration for device state about remaining space. These values must be - // kept in sync with settings.StorageSpaceState in JS code. - enum StorageSpaceState { - STORAGE_SPACE_NORMAL = 0, - STORAGE_SPACE_LOW = 1, - STORAGE_SPACE_CRITICALLY_LOW = 2, - }; +// Enumeration for device state about remaining space. These values must be +// kept in sync with settings.StorageSpaceState in JS code. +enum class StorageSpaceState { + kStorageSpaceNormal = 0, + kStorageSpaceLow = 1, + kStorageSpaceCriticallyLow = 2, +}; + +// Threshold to show a message indicating space is critically low (512 MB). +const int64_t kSpaceCriticallyLowBytes = 512 * 1024 * 1024; +// Threshold to show a message indicating space is low (1 GB). +const int64_t kSpaceLowBytes = 1 * 1024 * 1024 * 1024; + +class StorageHandler : public ::settings::SettingsPageUIHandler, + public arc::ArcSessionManager::Observer, + public chromeos::disks::DiskMountManager::Observer, + public calculator::SizeCalculator::Observer { + public: StorageHandler(Profile* profile, content::WebUIDataSource* html_source); ~StorageHandler() override; @@ -61,10 +53,6 @@ class StorageHandler void OnJavascriptAllowed() override; void OnJavascriptDisallowed() override; - // arc::ConnectionObserver<arc::mojom::StorageManagerInstance>: - void OnConnectionReady() override; - void OnConnectionClosed() override; - // arc::ArcSessionManager::Observer: void OnArcPlayStoreEnabledChanged(bool enabled) override; @@ -74,56 +62,42 @@ class StorageHandler const chromeos::disks::DiskMountManager::MountPointInfo& mount_info) override; + // chromeos::settings::calculator::SizeCalculator::Observer: + void OnSizeCalculated( + const calculator::SizeCalculator::CalculationType& calculation_type, + int64_t total_bytes, + const base::Optional<int64_t>& available_bytes = base::nullopt) override; + + // Remove the handler from the list of observers of every observed instances. + void StopObservingEvents(); + + protected: + // Round a given number of bytes up to the next power of 2. + // Ex: 14 => 16, 150 => 256. + int64_t RoundByteSize(int64_t bytes); + private: // Handlers of JS messages. void HandleUpdateAndroidEnabled(const base::ListValue* unused_args); void HandleUpdateStorageInfo(const base::ListValue* unused_args); - void HandleOpenDownloads(const base::ListValue* unused_args); + void HandleOpenMyFiles(const base::ListValue* unused_args); void HandleOpenArcStorage(const base::ListValue* unused_args); void HandleUpdateExternalStorages(const base::ListValue* unused_args); - // Requests updating disk space information. - void UpdateSizeStat(); - - // Callback to update the UI about disk space information. - void OnGetSizeStat(int64_t* total_size, int64_t* available_size); - - // Requests updating the size of Downloads directory. - void UpdateDownloadsSize(); - - // Callback to update the UI about the size of Downloads directory. - void OnGetDownloadsSize(int64_t size); - - // Requests updating the size of browsing data. - void UpdateBrowsingDataSize(); - - // Callback to receive the cache size. - void OnGetCacheSize(bool is_upper_limit, int64_t size); - - // Callback to update the UI about the size of browsing data. - void OnGetBrowsingDataSize(bool is_site_data, int64_t size); - - // Requests updating the flag that hides the Android size UI. - void UpdateAndroidRunning(); - - // Requests updating the space size used by Android apps and cache. - void UpdateAndroidSize(); - - // Callback to update the UI about Android apps and cache. - void OnGetAndroidSize(bool succeeded, arc::mojom::ApplicationsSizePtr size); - - // Requests updating the space size used by Crostini VMs and their apps and - // cache. - void UpdateCrostiniSize(); - - // Callback to update the UI about Crostini VMs and their apps and cache. - void OnGetCrostiniSize(crostini::CrostiniResult result, int64_t size); - - // Requests updating the total size of other users' data. - void UpdateOtherUsersSize(); - - // Callback to save the fetched user sizes and update the UI. - void OnGetOtherUserSize(base::Optional<cryptohome::BaseReply> reply); + // Update storage sizes on the UI. + void UpdateStorageItem( + const calculator::SizeCalculator::CalculationType& calculation_type, + int64_t total_bytes); + void UpdateSizeStat( + const calculator::SizeCalculator::CalculationType& calculation_type, + int64_t total_bytes, + int64_t available_bytes); + + // Marks the size of |item| as calculated. When all storage items have been + // calculated, then "System" size can be calculated. + void UpdateSystemSize( + const calculator::SizeCalculator::CalculationType& calculation_type, + int64_t total_bytes); // Updates list of external storages. void UpdateExternalStorages(); @@ -132,38 +106,21 @@ class StorageHandler // storage. bool IsEligibleForAndroidStorage(std::string source_path); - // Total size of cache data in browsing data. - int64_t browser_cache_size_; - - // True if we have already received the size of http cache. - bool has_browser_cache_size_; - - // Total size of site data in browsing data. - int64_t browser_site_data_size_; - - // True if we have already received the size of site data. - bool has_browser_site_data_size_; - - // Helper to compute the total size of all types of site date. - std::unique_ptr<SiteDataSizeCollector> site_data_size_collector_; - - // The list of other users whose directory sizes will be accumulated as the - // size of "Other users". - user_manager::UserList other_users_; - - // Fetched sizes of user directories. - std::vector<int64_t> user_sizes_; - - // Flags indicating fetch operations for storage sizes are ongoing. - bool updating_downloads_size_; - bool updating_browsing_data_size_; - bool updating_android_size_; - bool updating_crostini_size_; - bool updating_other_users_size_; - - // A flag for keeping track of the mojo connection status to the ARC - // container. - bool is_android_running_; + // Instances calculating the size of each storage items. + calculator::SizeStatCalculator size_stat_calculator_; + calculator::MyFilesSizeCalculator my_files_size_calculator_; + calculator::BrowsingDataSizeCalculator browsing_data_size_calculator_; + calculator::AppsSizeCalculator apps_size_calculator_; + calculator::CrostiniSizeCalculator crostini_size_calculator_; + calculator::OtherUsersSizeCalculator other_users_size_calculator_; + + // Controls if the size of each storage item has been calculated. + std::bitset<calculator::SizeCalculator::kCalculationTypeCount> + calculation_state_; + + // Keeps track of the size of each storage item. + int64_t storage_items_total_bytes_ + [calculator::SizeCalculator::kCalculationTypeCount] = {0}; Profile* const profile_; const std::string source_name_; diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/device_storage_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/device_storage_handler_unittest.cc new file mode 100644 index 00000000000..57c1ab89f3c --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/device_storage_handler_unittest.cc @@ -0,0 +1,516 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "base/files/file.h" +#include "base/files/file_util.h" +#include "base/path_service.h" +#include "base/strings/utf_string_conversions.h" +#include "base/system/sys_info.h" +#include "chrome/browser/chromeos/arc/session/arc_session_manager.h" +#include "chrome/browser/chromeos/arc/test/test_arc_session_manager.h" +#include "chrome/browser/chromeos/file_manager/fake_disk_mount_manager.h" +#include "chrome/browser/chromeos/file_manager/path_util.h" +#include "chrome/browser/chromeos/scoped_set_running_on_chromeos_for_testing.h" +#include "chrome/browser/ui/webui/settings/chromeos/calculator/size_calculator_test_api.h" +#include "chrome/browser/ui/webui/settings/chromeos/device_storage_handler.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/webui_url_constants.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/testing_profile_manager.h" +#include "components/arc/arc_service_manager.h" +#include "components/arc/test/fake_arc_session.h" +#include "content/public/browser/web_ui_data_source.h" +#include "content/public/test/browser_task_environment.h" +#include "content/public/test/test_web_ui.h" +#include "storage/browser/file_system/external_mount_points.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/text/bytes_formatting.h" + +namespace chromeos { +namespace settings { + +namespace { + +const char kLsbRelease[] = + "CHROMEOS_RELEASE_NAME=Chrome OS\n" + "CHROMEOS_RELEASE_VERSION=1.2.3.4\n"; + +class TestStorageHandler : public StorageHandler { + public: + explicit TestStorageHandler(Profile* profile, + content::WebUIDataSource* html_source) + : StorageHandler(profile, html_source) {} + + // Pull WebUIMessageHandler::set_web_ui() into public so tests can call it. + using StorageHandler::RoundByteSize; + using StorageHandler::set_web_ui; +}; + +class StorageHandlerTest : public testing::Test { + public: + StorageHandlerTest() = default; + ~StorageHandlerTest() override = default; + + void SetUp() override { + // The storage handler requires an instance of DiskMountManager, + // ArcServiceManager and ArcSessionManager. + chromeos::disks::DiskMountManager::InitializeForTesting( + new file_manager::FakeDiskMountManager); + arc_service_manager_ = std::make_unique<arc::ArcServiceManager>(); + arc_session_manager_ = arc::CreateTestArcSessionManager( + std::make_unique<arc::ArcSessionRunner>( + base::BindRepeating(arc::FakeArcSession::Create))); + + // Initialize profile. + profile_manager_ = std::make_unique<TestingProfileManager>( + TestingBrowserProcess::GetGlobal()); + ASSERT_TRUE(profile_manager_->SetUp()); + profile_ = profile_manager_->CreateTestingProfile("p1"); + + // Initialize storage handler. + content::WebUIDataSource* html_source = + content::WebUIDataSource::Create(chrome::kChromeUIOSSettingsHost); + handler_ = std::make_unique<TestStorageHandler>(profile_, html_source); + handler_->set_web_ui(&web_ui_); + handler_->AllowJavascriptForTesting(); + + // Initialize tests APIs. + size_stat_test_api_ = std::make_unique<calculator::SizeStatTestAPI>( + handler_.get(), new calculator::SizeStatCalculator(profile_)); + my_files_size_test_api_ = std::make_unique<calculator::MyFilesSizeTestAPI>( + handler_.get(), new calculator::MyFilesSizeCalculator(profile_)); + browsing_data_size_test_api_ = + std::make_unique<calculator::BrowsingDataSizeTestAPI>( + handler_.get(), + new calculator::BrowsingDataSizeCalculator(profile_)); + apps_size_test_api_ = std::make_unique<calculator::AppsSizeTestAPI>( + handler_.get(), new calculator::AppsSizeCalculator(profile_)); + crostini_size_test_api_ = std::make_unique<calculator::CrostiniSizeTestAPI>( + handler_.get(), new calculator::CrostiniSizeCalculator(profile_)); + other_users_size_test_api_ = + std::make_unique<calculator::OtherUsersSizeTestAPI>( + handler_.get(), new calculator::OtherUsersSizeCalculator()); + + // Create and register My files directory. + // By emulating chromeos running, GetMyFilesFolderForProfile will return the + // profile's temporary location instead of $HOME/Downloads. + chromeos::ScopedSetRunningOnChromeOSForTesting fake_release(kLsbRelease, + base::Time()); + const base::FilePath my_files_path = + file_manager::util::GetMyFilesFolderForProfile(profile_); + CHECK(base::CreateDirectory(my_files_path)); + CHECK(storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem( + file_manager::util::GetDownloadsMountPointName(profile_), + storage::kFileSystemTypeNativeLocal, storage::FileSystemMountOption(), + my_files_path)); + } + + void TearDown() override { + handler_.reset(); + size_stat_test_api_.reset(); + my_files_size_test_api_.reset(); + browsing_data_size_test_api_.reset(); + apps_size_test_api_.reset(); + crostini_size_test_api_.reset(); + other_users_size_test_api_.reset(); + chromeos::disks::DiskMountManager::Shutdown(); + storage::ExternalMountPoints::GetSystemInstance()->RevokeAllFileSystems(); + } + + protected: + // From a given amount of total size and available size as input, returns the + // space state determined by the OnGetSizeState function. + int GetSpaceState(int64_t* total_size, int64_t* available_size) { + size_stat_test_api_->SimulateOnGetSizeStat(total_size, available_size); + task_environment_.RunUntilIdle(); + const base::Value* dictionary = + GetWebUICallbackMessage("storage-size-stat-changed"); + EXPECT_TRUE(dictionary) << "No 'storage-size-stat-changed' callback"; + int space_state = dictionary->FindKey("spaceState")->GetInt(); + return space_state; + } + + // Expects a callback message with a given |event_name|. A non null + // base::Value is returned if the callback message is found and has associated + // data. + const base::Value* GetWebUICallbackMessage(const std::string& event_name) { + for (auto it = web_ui_.call_data().rbegin(); + it != web_ui_.call_data().rend(); ++it) { + const content::TestWebUI::CallData* data = it->get(); + std::string name; + if (data->function_name() != "cr.webUIListenerCallback" || + !data->arg1()->GetAsString(&name)) { + continue; + } + if (name == event_name) + return data->arg2(); + } + return nullptr; + } + + // Get the path to file manager's test data directory. + base::FilePath GetTestDataFilePath(const std::string& file_name) { + // Get the path to file manager's test data directory. + base::FilePath source_dir; + CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &source_dir)); + base::FilePath test_data_dir = source_dir.AppendASCII("chrome") + .AppendASCII("test") + .AppendASCII("data") + .AppendASCII("chromeos") + .AppendASCII("file_manager"); + + // Return full test data path to the given |file_name|. + return test_data_dir.Append(base::FilePath::FromUTF8Unsafe(file_name)); + } + + // Copy a file from the file manager's test data directory to the specified + // target_path. + void AddFile(const std::string& file_name, + int64_t expected_size, + base::FilePath target_path) { + const base::FilePath entry_path = GetTestDataFilePath(file_name); + target_path = target_path.AppendASCII(file_name); + ASSERT_TRUE(base::CopyFile(entry_path, target_path)) + << "Copy from " << entry_path.value() << " to " << target_path.value() + << " failed."; + // Verify file size. + base::stat_wrapper_t stat; + const int res = base::File::Lstat(target_path.value().c_str(), &stat); + ASSERT_FALSE(res < 0) << "Couldn't stat" << target_path.value(); + ASSERT_EQ(expected_size, stat.st_size); + } + + std::unique_ptr<TestStorageHandler> handler_; + content::TestWebUI web_ui_; + content::BrowserTaskEnvironment task_environment_; + std::unique_ptr<TestingProfileManager> profile_manager_; + Profile* profile_; + std::unique_ptr<calculator::SizeStatTestAPI> size_stat_test_api_; + std::unique_ptr<calculator::MyFilesSizeTestAPI> my_files_size_test_api_; + std::unique_ptr<calculator::BrowsingDataSizeTestAPI> + browsing_data_size_test_api_; + std::unique_ptr<calculator::AppsSizeTestAPI> apps_size_test_api_; + std::unique_ptr<calculator::CrostiniSizeTestAPI> crostini_size_test_api_; + std::unique_ptr<calculator::OtherUsersSizeTestAPI> other_users_size_test_api_; + + private: + std::unique_ptr<arc::ArcServiceManager> arc_service_manager_; + std::unique_ptr<arc::ArcSessionManager> arc_session_manager_; + DISALLOW_COPY_AND_ASSIGN(StorageHandlerTest); +}; + +TEST_F(StorageHandlerTest, RoundByteSize) { + static const struct { + int64_t bytes; + const char* expected; + } cases[] = { + {0, "0 B"}, + {3, "4 B"}, + {4, "4 B"}, + {5, "8 B"}, + {8 * 1024 - 1, "8.0 KB"}, + {8 * 1024, "8.0 KB"}, + {8 * 1024 + 1, "16.0 KB"}, + {31 * 1024 * 1024, "32.0 MB"}, + {32 * 1024 * 1024, "32.0 MB"}, + {50 * 1024 * 1024, "64.0 MB"}, + {65LL * 1024 * 1024 * 1024, "128 GB"}, + {130LL * 1024 * 1024 * 1024, "256 GB"}, + {130LL * 1024 * 1024 * 1024, "256 GB"}, + {1LL * 1024 * 1024 * 1024 * 1024, "1.0 TB"}, + {1LL * 1024 * 1024 * 1024 * 1024 + 1, "2.0 TB"}, + {(1LL << 61) + 1, "4,096 PB"}, + }; + + for (auto& c : cases) { + int64_t rounded_bytes = handler_->RoundByteSize(c.bytes); + EXPECT_EQ(base::ASCIIToUTF16(c.expected), ui::FormatBytes(rounded_bytes)); + } +} + +TEST_F(StorageHandlerTest, GlobalSizeStat) { + // Get local filesystem storage statistics. + const base::FilePath mount_path = + file_manager::util::GetMyFilesFolderForProfile(profile_); + int64_t total_size = base::SysInfo::AmountOfTotalDiskSpace(mount_path); + int64_t available_size = base::SysInfo::AmountOfFreeDiskSpace(mount_path); + + // Round the total size. + int64_t rounded_total_size = handler_->RoundByteSize(total_size); + int64_t used_size = rounded_total_size - available_size; + double used_ratio = static_cast<double>(used_size) / rounded_total_size; + + // Get statistics from storage handler's UpdateSizeStat. + size_stat_test_api_->StartCalculation(); + task_environment_.RunUntilIdle(); + + const base::Value* dictionary = + GetWebUICallbackMessage("storage-size-stat-changed"); + ASSERT_TRUE(dictionary) << "No 'storage-size-stat-changed' callback"; + + const std::string& storage_handler_available_size = + dictionary->FindKey("availableSize")->GetString(); + const std::string& storage_handler_used_size = + dictionary->FindKey("usedSize")->GetString(); + double storage_handler_used_ratio = + dictionary->FindKey("usedRatio")->GetDouble(); + + EXPECT_EQ(ui::FormatBytes(available_size), + base::ASCIIToUTF16(storage_handler_available_size)); + EXPECT_EQ(ui::FormatBytes(used_size), + base::ASCIIToUTF16(storage_handler_used_size)); + double diff = used_ratio > storage_handler_used_ratio + ? used_ratio - storage_handler_used_ratio + : storage_handler_used_ratio - used_ratio; + // Running the test while writing data on disk (~400MB/s), the difference + // between the values returned by the two AmountOfFreeDiskSpace calls is never + // more than 100KB. By expecting diff to be less than 100KB / + // rounded_total_size, the test is very unlikely to be flaky. + EXPECT_LE(diff, static_cast<double>(100 * 1024) / rounded_total_size); +} + +TEST_F(StorageHandlerTest, StorageSpaceState) { + // Less than 512 MB available, space state is critically low. + int64_t total_size = 1024 * 1024 * 1024; + int64_t available_size = 512 * 1024 * 1024 - 1; + int space_state = GetSpaceState(&total_size, &available_size); + EXPECT_EQ(static_cast<int>(StorageSpaceState::kStorageSpaceCriticallyLow), + space_state); + + // Less than 1GB available, space state is low. + available_size = 512 * 1024 * 1024; + space_state = GetSpaceState(&total_size, &available_size); + EXPECT_EQ(static_cast<int>(StorageSpaceState::kStorageSpaceLow), space_state); + available_size = 1024 * 1024 * 1024 - 1; + space_state = GetSpaceState(&total_size, &available_size); + EXPECT_EQ(static_cast<int>(StorageSpaceState::kStorageSpaceLow), space_state); + + // From 1GB, normal space state. + available_size = 1024 * 1024 * 1024; + space_state = GetSpaceState(&total_size, &available_size); + EXPECT_EQ(static_cast<int>(StorageSpaceState::kStorageSpaceNormal), + space_state); +} + +TEST_F(StorageHandlerTest, MyFilesSize) { + base::ScopedAllowBlockingForTesting allow_blocking; + + const base::FilePath my_files_path = + file_manager::util::GetMyFilesFolderForProfile(profile_); + const base::FilePath downloads_path = + file_manager::util::GetDownloadsFolderForProfile(profile_); + const base::FilePath android_files_path = + profile_->GetPath().Append("AndroidFiles"); + const base::FilePath android_files_download_path = + android_files_path.Append("Download"); + + // Create directories. + CHECK(base::CreateDirectory(downloads_path)); + CHECK(base::CreateDirectory(android_files_path)); + CHECK(base::CreateDirectory(android_files_download_path)); + + // Register android files mount point. + CHECK(storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem( + file_manager::util::GetAndroidFilesMountPointName(), + storage::kFileSystemTypeNativeLocal, storage::FileSystemMountOption(), + android_files_path)); + + // Add files in My files and android files. + AddFile("random.bin", 8092, my_files_path); // ~7.9 KB + AddFile("tall.pdf", 15271, android_files_path); // ~14.9 KB + // Add file in Downloads and simulate bind mount with + // [android files]/Download. + AddFile("video.ogv", 59943, downloads_path); // ~58.6 KB + AddFile("video.ogv", 59943, android_files_download_path); + + // Calculate My files size. + my_files_size_test_api_->StartCalculation(); + task_environment_.RunUntilIdle(); + + const base::Value* callback = + GetWebUICallbackMessage("storage-my-files-size-changed"); + ASSERT_TRUE(callback) << "No 'storage-my-files-size-changed' callback"; + + // Check return value. + EXPECT_EQ("81.4 KB", callback->GetString()); +} + +TEST_F(StorageHandlerTest, AppsExtensionsSize) { + // The data for apps and extensions apps_size_test_api_installed from the + // webstore is stored in the Extensions folder. Add data at a random location + // in the Extensions folder and check UI callback message. + const base::FilePath extensions_data_path = + profile_->GetPath() + .AppendASCII("Extensions") + .AppendASCII("fake_extension_id"); + CHECK(base::CreateDirectory(extensions_data_path)); + AddFile("id3Audio.mp3", 180999, extensions_data_path); // ~177 KB + + // Calculate web store apps and extensions size. + apps_size_test_api_->StartCalculation(); + task_environment_.RunUntilIdle(); + + const base::Value* callback = + GetWebUICallbackMessage("storage-apps-size-changed"); + ASSERT_TRUE(callback) << "No 'storage-apps-size-changed' callback"; + + // Check return value. + EXPECT_EQ("177 KB", callback->GetString()); + + // Simulate android apps size callback. + // 592840 + 25284 + 9987 = 628111 ~613 KB. + apps_size_test_api_->SimulateOnGetAndroidAppsSize(true /* succeeded */, + 592840, 25284, 9987); + task_environment_.RunUntilIdle(); + + callback = GetWebUICallbackMessage("storage-apps-size-changed"); + ASSERT_TRUE(callback) << "No 'storage-apps-size-changed' callback"; + + // Check return value. + EXPECT_EQ("790 KB", callback->GetString()); + + // Add more data in the Extensions folder. Android is not running and the size + // of android apps is back down to 0 B. + AddFile("video_long.ogv", 230096, extensions_data_path); // ~225 KB + + // Calculate web store apps and extensions size. + apps_size_test_api_->StartCalculation(); + task_environment_.RunUntilIdle(); + + callback = GetWebUICallbackMessage("storage-apps-size-changed"); + ASSERT_TRUE(callback) << "No 'storage-apps-size-changed' callback"; + + // Check return value. + EXPECT_EQ("401 KB", callback->GetString()); +} + +TEST_F(StorageHandlerTest, SystemSize) { + // The "System" row on the storage page displays the difference between the + // total amount of used space and the sum of the sizes of the different + // storage items of the storage page (My files, Browsing data, apps etc...) + // This test simulates callbacks from each one of these storage items; the + // calculation of the "System" size should only happen when all of the other + // storage items have been calculated. + const int64_t KB = 1024; + const int64_t MB = 1024 * KB; + const int64_t GB = 1024 * MB; + const int64_t TB = 1024 * GB; + + // Simulate size stat callback. + int64_t total_size = TB; + int64_t available_size = 100 * GB; + size_stat_test_api_->SimulateOnGetSizeStat(&total_size, &available_size); + const base::Value* callback = + GetWebUICallbackMessage("storage-size-stat-changed"); + ASSERT_TRUE(callback) << "No 'storage-size-stat-changed' callback"; + EXPECT_EQ("100 GB", callback->FindKey("availableSize")->GetString()); + EXPECT_EQ("924 GB", callback->FindKey("usedSize")->GetString()); + // Expect no system size callback until every other item has been updated. + ASSERT_FALSE(GetWebUICallbackMessage("storage-system-size-changed")); + + // Simulate my files size callback. + my_files_size_test_api_->SimulateOnGetTotalBytes(400 * GB); + callback = GetWebUICallbackMessage("storage-my-files-size-changed"); + ASSERT_TRUE(callback) << "No 'storage-my-files-size-changed' callback"; + EXPECT_EQ("400 GB", callback->GetString()); + ASSERT_FALSE(GetWebUICallbackMessage("storage-system-size-changed")); + + // Simulate browsing data callbacks. Has to be called with + // both |is_data_site| = true and false. + browsing_data_size_test_api_->SimulateOnGetBrowsingDataSize( + true /* is_site_data */, 10 * GB); + ASSERT_FALSE(GetWebUICallbackMessage("storage-browsing-data-size-changed")); + ASSERT_FALSE(GetWebUICallbackMessage("storage-system-size-changed")); + browsing_data_size_test_api_->SimulateOnGetBrowsingDataSize( + false /* is_site_data */, 14 * GB); + callback = GetWebUICallbackMessage("storage-browsing-data-size-changed"); + ASSERT_TRUE(callback) << "No 'storage-browsing-data-size-changed' callback"; + EXPECT_EQ("24.0 GB", callback->GetString()); + ASSERT_FALSE(GetWebUICallbackMessage("storage-system-size-changed")); + + // Simulate apps and extensions size callbacks. + apps_size_test_api_->SimulateOnGetAppsSize(29 * GB); + apps_size_test_api_->SimulateOnGetAndroidAppsSize(false, 0, 0, 0); + callback = GetWebUICallbackMessage("storage-apps-size-changed"); + ASSERT_TRUE(callback) << "No 'storage-apps-size-changed' callback"; + EXPECT_EQ("29.0 GB", callback->GetString()); + ASSERT_FALSE(GetWebUICallbackMessage("storage-system-size-changed")); + apps_size_test_api_->SimulateOnGetAndroidAppsSize( + true /* succeeded */, 724 * MB, 100 * MB, 200 * MB); + callback = GetWebUICallbackMessage("storage-apps-size-changed"); + ASSERT_TRUE(callback) << "No 'storage-apps-size-changed' callback"; + EXPECT_EQ("30.0 GB", callback->GetString()); + ASSERT_FALSE(GetWebUICallbackMessage("storage-system-size-changed")); + + // Simulate crostini size callback. + crostini_size_test_api_->SimulateOnGetCrostiniSize(70 * GB); + callback = GetWebUICallbackMessage("storage-crostini-size-changed"); + ASSERT_TRUE(callback) << "No 'storage-crostini-size-changed' callback"; + EXPECT_EQ("70.0 GB", callback->GetString()); + ASSERT_FALSE(GetWebUICallbackMessage("storage-system-size-changed")); + + // Simulate other users size callback. No callback message until the sizes of + // every users is calculated. + std::vector<int64_t> other_user_sizes = + std::vector<int64_t>{200 * GB, 50 * GB, 50 * GB}; + other_users_size_test_api_->InitializeOtherUserSize(other_user_sizes.size()); + for (std::size_t i = 0; i < other_user_sizes.size(); i++) { + cryptohome::BaseReply result; + result.set_error(cryptohome::CRYPTOHOME_ERROR_NOT_SET); + cryptohome::GetAccountDiskUsageReply* usage_reply = + result.MutableExtension(cryptohome::GetAccountDiskUsageReply::reply); + usage_reply->set_size(other_user_sizes[i]); + base::Optional<cryptohome::BaseReply> reply = std::move(result); + other_users_size_test_api_->SimulateOnGetOtherUserSize(reply); + if (i < other_user_sizes.size() - 1) { + ASSERT_FALSE(GetWebUICallbackMessage("storage-other-users-size-changed")); + ASSERT_FALSE(GetWebUICallbackMessage("storage-system-size-changed")); + } else { + // When the size of the last user's cryptohome is calculated, we expect a + // callback with the "Other users" size. + callback = GetWebUICallbackMessage("storage-other-users-size-changed"); + ASSERT_TRUE(callback) << "No 'storage-other-users-size-changed' callback"; + EXPECT_EQ("300 GB", callback->GetString()); + // Every item size has been calculated, system size should also be + // updated. + callback = GetWebUICallbackMessage("storage-system-size-changed"); + ASSERT_TRUE(callback) << "No 'storage-system-size-changed' callback"; + EXPECT_EQ("100 GB", callback->GetString()); + } + } + + // If there's an error while calculating the size of browsing data, the size + // of browsing data and system should be displayed as "Unknown". + browsing_data_size_test_api_->SimulateOnGetBrowsingDataSize( + true /* is_site_data */, -1); + callback = GetWebUICallbackMessage("storage-browsing-data-size-changed"); + ASSERT_TRUE(callback) << "No 'storage-browsing-data-size-changed' callback"; + EXPECT_EQ("Unknown", callback->GetString()); + // The missing 24.0 GB of browsing data should be reflected in the system + // section instead. We expect the displayed size to be 100 + 24 GB. + callback = GetWebUICallbackMessage("storage-system-size-changed"); + ASSERT_TRUE(callback) << "No 'storage-system-size-changed' callback"; + EXPECT_EQ("124 GB", callback->GetString()); + + // No error while recalculating browsing data size, the UI should be updated + // with the right sizes. + browsing_data_size_test_api_->SimulateOnGetBrowsingDataSize( + true /* is_site_data */, 10 * GB); + callback = GetWebUICallbackMessage("storage-browsing-data-size-changed"); + ASSERT_TRUE(callback) << "No 'storage-browsing-data-size-changed' callback"; + EXPECT_EQ("24.0 GB", callback->GetString()); + callback = GetWebUICallbackMessage("storage-system-size-changed"); + ASSERT_TRUE(callback) << "No 'storage-system-size-changed' callback"; + EXPECT_EQ("100 GB", callback->GetString()); +} + +} // namespace + +} // namespace settings +} // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/fingerprint_handler.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/fingerprint_handler.cc index 601eeaf2435..0a90a0e3039 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/fingerprint_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/fingerprint_handler.cc @@ -20,9 +20,7 @@ #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" #include "components/prefs/pref_service.h" -#include "content/public/browser/system_connector.h" -#include "services/device/public/mojom/constants.mojom.h" -#include "services/service_manager/public/cpp/connector.h" +#include "content/public/browser/device_service.h" #include "ui/base/l10n/l10n_util.h" using session_manager::SessionManager; @@ -57,8 +55,8 @@ std::unique_ptr<base::DictionaryValue> GetFingerprintsInfo( } // namespace FingerprintHandler::FingerprintHandler(Profile* profile) : profile_(profile) { - content::GetSystemConnector()->Connect( - device::mojom::kServiceName, fp_service_.BindNewPipeAndPassReceiver()); + content::GetDeviceService().BindFingerprint( + fp_service_.BindNewPipeAndPassReceiver()); user_id_ = ProfileHelper::Get()->GetUserIdHashFromProfile(profile); } diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/internet_handler.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/internet_handler.cc index e75796ecd32..bd301cfcb91 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/internet_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/internet_handler.cc @@ -143,7 +143,8 @@ void InternetHandler::ConfigureThirdPartyVpn(const base::ListValue* args) { return; } if (network->type() != shill::kTypeVPN) { - NET_LOG(ERROR) << "ConfigureThirdPartyVpn: Network is not a VPN: " << guid; + NET_LOG(ERROR) << "ConfigureThirdPartyVpn: Network is not a VPN: " + << NetworkId(network); return; } @@ -169,7 +170,8 @@ void InternetHandler::ConfigureThirdPartyVpn(const base::ListValue* args) { } NET_LOG(ERROR) << "ConfigureThirdPartyVpn: Unsupported VPN type: " - << network->GetVpnProviderType() << " For: " << guid; + << network->GetVpnProviderType() + << " For: " << NetworkId(network); } void InternetHandler::RequestGmsCoreNotificationsDisabledDeviceNames( diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/internet_strings_provider.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/internet_strings_provider.cc new file mode 100644 index 00000000000..90a75cf7418 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/internet_strings_provider.cc @@ -0,0 +1,252 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/chromeos/internet_strings_provider.h" + +#include "ash/public/cpp/network_config_service.h" +#include "base/bind.h" +#include "base/no_destructor.h" +#include "chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.h" +#include "chrome/browser/ui/webui/webui_util.h" +#include "chrome/common/url_constants.h" +#include "chrome/common/webui_url_constants.h" +#include "chrome/grit/chromium_strings.h" +#include "chrome/grit/generated_resources.h" +#include "chromeos/strings/grit/chromeos_strings.h" +#include "components/strings/grit/components_strings.h" +#include "content/public/browser/web_ui_data_source.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/webui/web_ui_util.h" + +namespace chromeos { +namespace settings { +namespace { + +const std::vector<SearchConcept>& GetNetworkSearchConcepts() { + static const base::NoDestructor<std::vector<SearchConcept>> tags({ + {IDS_SETTINGS_TAG_NETWORK_SETTINGS, + chrome::kNetworksSubPage, + mojom::SearchResultIcon::kWifi, + {IDS_SETTINGS_TAG_NETWORK_SETTINGS_ALT1, SearchConcept::kAltTagEnd}}, + }); + return *tags; +} + +const std::vector<SearchConcept>& GetEthernetSearchConcepts() { + static const base::NoDestructor<std::vector<SearchConcept>> tags({ + {IDS_SETTINGS_TAG_ETHERNET_SETTINGS, + chrome::kEthernetSettingsSubPage, + mojom::SearchResultIcon::kEthernet, + {IDS_SETTINGS_TAG_ETHERNET_SETTINGS_ALT1, SearchConcept::kAltTagEnd}}, + }); + return *tags; +} + +const std::vector<SearchConcept>& GetWifiSearchConcepts() { + static const base::NoDestructor<std::vector<SearchConcept>> tags({ + {IDS_SETTINGS_TAG_WIFI_SETTINGS, chrome::kWiFiSettingsSubPage, + mojom::SearchResultIcon::kWifi}, + {IDS_SETTINGS_TAG_TURN_ON_WIFI, + chrome::kWiFiSettingsSubPage, + mojom::SearchResultIcon::kWifi, + {IDS_SETTINGS_TAG_TURN_ON_WIFI_ALT1, SearchConcept::kAltTagEnd}}, + {IDS_SETTINGS_TAG_TURN_OFF_WIFI, + chrome::kWiFiSettingsSubPage, + mojom::SearchResultIcon::kWifi, + {IDS_SETTINGS_TAG_TURN_OFF_WIFI_ALT1, SearchConcept::kAltTagEnd}}, + {IDS_SETTINGS_TAG_CONNECT_WIFI, chrome::kWiFiSettingsSubPage, + mojom::SearchResultIcon::kWifi}, + {IDS_SETTINGS_TAG_DISCONNECT_WIFI, chrome::kWiFiSettingsSubPage, + mojom::SearchResultIcon::kWifi}, + }); + return *tags; +} + +} // namespace + +InternetStringsProvider::InternetStringsProvider(Profile* profile, + Delegate* per_page_delegate) + : OsSettingsPerPageStringsProvider(profile, per_page_delegate) { + // General network search tags are always added. + delegate()->AddSearchTags(GetNetworkSearchConcepts()); + + // Receive updates when devices (e.g., Ethernet, Wi-Fi) go on/offline. + ash::GetNetworkConfigService( + cros_network_config_.BindNewPipeAndPassReceiver()); + cros_network_config_->AddObserver(receiver_.BindNewPipeAndPassRemote()); + + // Fetch initial list of devices. + FetchDeviceList(); +} + +InternetStringsProvider::~InternetStringsProvider() = default; + +void InternetStringsProvider::AddUiStrings( + content::WebUIDataSource* html_source) const { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"internetAddConnection", IDS_SETTINGS_INTERNET_ADD_CONNECTION}, + {"internetAddConnectionExpandA11yLabel", + IDS_SETTINGS_INTERNET_ADD_CONNECTION_EXPAND_ACCESSIBILITY_LABEL}, + {"internetAddConnectionNotAllowed", + IDS_SETTINGS_INTERNET_ADD_CONNECTION_NOT_ALLOWED}, + {"internetAddThirdPartyVPN", IDS_SETTINGS_INTERNET_ADD_THIRD_PARTY_VPN}, + {"internetAddVPN", IDS_SETTINGS_INTERNET_ADD_VPN}, + {"internetAddWiFi", IDS_SETTINGS_INTERNET_ADD_WIFI}, + {"internetConfigName", IDS_SETTINGS_INTERNET_CONFIG_NAME}, + {"internetDetailPageTitle", IDS_SETTINGS_INTERNET_DETAIL}, + {"internetDeviceEnabling", IDS_SETTINGS_INTERNET_DEVICE_ENABLING}, + {"internetDeviceInitializing", IDS_SETTINGS_INTERNET_DEVICE_INITIALIZING}, + {"internetJoinType", IDS_SETTINGS_INTERNET_JOIN_TYPE}, + {"internetKnownNetworksPageTitle", IDS_SETTINGS_INTERNET_KNOWN_NETWORKS}, + {"internetMobileSearching", IDS_SETTINGS_INTERNET_MOBILE_SEARCH}, + {"internetNoNetworks", IDS_SETTINGS_INTERNET_NO_NETWORKS}, + {"internetPageTitle", IDS_SETTINGS_INTERNET}, + {"internetSummaryButtonA11yLabel", + IDS_SETTINGS_INTERNET_SUMMARY_BUTTON_ACCESSIBILITY_LABEL}, + {"internetToggleMobileA11yLabel", + IDS_SETTINGS_INTERNET_TOGGLE_MOBILE_ACCESSIBILITY_LABEL}, + {"internetToggleTetherLabel", IDS_SETTINGS_INTERNET_TOGGLE_TETHER_LABEL}, + {"internetToggleTetherSubtext", + IDS_SETTINGS_INTERNET_TOGGLE_TETHER_SUBTEXT}, + {"internetToggleWiFiA11yLabel", + IDS_SETTINGS_INTERNET_TOGGLE_WIFI_ACCESSIBILITY_LABEL}, + {"knownNetworksAll", IDS_SETTINGS_INTERNET_KNOWN_NETWORKS_ALL}, + {"knownNetworksButton", IDS_SETTINGS_INTERNET_KNOWN_NETWORKS_BUTTON}, + {"knownNetworksMessage", IDS_SETTINGS_INTERNET_KNOWN_NETWORKS_MESSAGE}, + {"knownNetworksPreferred", + IDS_SETTINGS_INTERNET_KNOWN_NETWORKS_PREFFERED}, + {"knownNetworksMenuAddPreferred", + IDS_SETTINGS_INTERNET_KNOWN_NETWORKS_MENU_ADD_PREFERRED}, + {"knownNetworksMenuRemovePreferred", + IDS_SETTINGS_INTERNET_KNOWN_NETWORKS_MENU_REMOVE_PREFERRED}, + {"knownNetworksMenuForget", + IDS_SETTINGS_INTERNET_KNOWN_NETWORKS_MENU_FORGET}, + {"networkAllowDataRoaming", + IDS_SETTINGS_SETTINGS_NETWORK_ALLOW_DATA_ROAMING}, + {"networkAllowDataRoamingEnabledHome", + IDS_SETTINGS_SETTINGS_NETWORK_ALLOW_DATA_ROAMING_ENABLED_HOME}, + {"networkAllowDataRoamingEnabledRoaming", + IDS_SETTINGS_SETTINGS_NETWORK_ALLOW_DATA_ROAMING_ENABLED_ROAMING}, + {"networkAllowDataRoamingDisabled", + IDS_SETTINGS_SETTINGS_NETWORK_ALLOW_DATA_ROAMING_DISABLED}, + {"networkAlwaysOnVpn", IDS_SETTINGS_INTERNET_NETWORK_ALWAYS_ON_VPN}, + {"networkAutoConnect", IDS_SETTINGS_INTERNET_NETWORK_AUTO_CONNECT}, + {"networkAutoConnectCellular", + IDS_SETTINGS_INTERNET_NETWORK_AUTO_CONNECT_CELLULAR}, + {"networkButtonActivate", IDS_SETTINGS_INTERNET_BUTTON_ACTIVATE}, + {"networkButtonConfigure", IDS_SETTINGS_INTERNET_BUTTON_CONFIGURE}, + {"networkButtonConnect", IDS_SETTINGS_INTERNET_BUTTON_CONNECT}, + {"networkButtonDisconnect", IDS_SETTINGS_INTERNET_BUTTON_DISCONNECT}, + {"networkButtonForget", IDS_SETTINGS_INTERNET_BUTTON_FORGET}, + {"networkButtonViewAccount", IDS_SETTINGS_INTERNET_BUTTON_VIEW_ACCOUNT}, + {"networkConnectNotAllowed", IDS_SETTINGS_INTERNET_CONNECT_NOT_ALLOWED}, + {"networkIPAddress", IDS_SETTINGS_INTERNET_NETWORK_IP_ADDRESS}, + {"networkIPConfigAuto", IDS_SETTINGS_INTERNET_NETWORK_IP_CONFIG_AUTO}, + {"networkNameserversLearnMore", IDS_LEARN_MORE}, + {"networkPrefer", IDS_SETTINGS_INTERNET_NETWORK_PREFER}, + {"networkPrimaryUserControlled", + IDS_SETTINGS_INTERNET_NETWORK_PRIMARY_USER_CONTROLLED}, + {"networkScanningLabel", IDS_NETWORK_SCANNING_MESSAGE}, + {"networkSectionAdvanced", + IDS_SETTINGS_INTERNET_NETWORK_SECTION_ADVANCED}, + {"networkSectionAdvancedA11yLabel", + IDS_SETTINGS_INTERNET_NETWORK_SECTION_ADVANCED_ACCESSIBILITY_LABEL}, + {"networkSectionNetwork", IDS_SETTINGS_INTERNET_NETWORK_SECTION_NETWORK}, + {"networkSectionNetworkExpandA11yLabel", + IDS_SETTINGS_INTERNET_NETWORK_SECTION_NETWORK_ACCESSIBILITY_LABEL}, + {"networkSectionProxy", IDS_SETTINGS_INTERNET_NETWORK_SECTION_PROXY}, + {"networkSectionProxyExpandA11yLabel", + IDS_SETTINGS_INTERNET_NETWORK_SECTION_PROXY_ACCESSIBILITY_LABEL}, + {"networkShared", IDS_SETTINGS_INTERNET_NETWORK_SHARED}, + {"networkVpnBuiltin", IDS_NETWORK_TYPE_VPN_BUILTIN}, + {"networkOutOfRange", IDS_SETTINGS_INTERNET_WIFI_NETWORK_OUT_OF_RANGE}, + {"cellularContactSpecificCarrier", + IDS_SETTINGS_INTERNET_CELLULAR_CONTACT_SPECIFIC_CARRIER}, + {"cellularContactDefaultCarrier", + IDS_SETTINGS_INTERNET_CELLULAR_CONTACT_DEFAULT_CARRIER}, + {"tetherPhoneOutOfRange", + IDS_SETTINGS_INTERNET_TETHER_PHONE_OUT_OF_RANGE}, + {"gmscoreNotificationsTitle", + IDS_SETTINGS_INTERNET_GMSCORE_NOTIFICATIONS_TITLE}, + {"gmscoreNotificationsOneDeviceSubtitle", + IDS_SETTINGS_INTERNET_GMSCORE_NOTIFICATIONS_ONE_DEVICE_SUBTITLE}, + {"gmscoreNotificationsTwoDevicesSubtitle", + IDS_SETTINGS_INTERNET_GMSCORE_NOTIFICATIONS_TWO_DEVICES_SUBTITLE}, + {"gmscoreNotificationsManyDevicesSubtitle", + IDS_SETTINGS_INTERNET_GMSCORE_NOTIFICATIONS_MANY_DEVICES_SUBTITLE}, + {"gmscoreNotificationsFirstStep", + IDS_SETTINGS_INTERNET_GMSCORE_NOTIFICATIONS_FIRST_STEP}, + {"gmscoreNotificationsSecondStep", + IDS_SETTINGS_INTERNET_GMSCORE_NOTIFICATIONS_SECOND_STEP}, + {"gmscoreNotificationsThirdStep", + IDS_SETTINGS_INTERNET_GMSCORE_NOTIFICATIONS_THIRD_STEP}, + {"gmscoreNotificationsFourthStep", + IDS_SETTINGS_INTERNET_GMSCORE_NOTIFICATIONS_FOURTH_STEP}, + {"tetherConnectionDialogTitle", + IDS_SETTINGS_INTERNET_TETHER_CONNECTION_DIALOG_TITLE}, + {"tetherConnectionAvailableDeviceTitle", + IDS_SETTINGS_INTERNET_TETHER_CONNECTION_AVAILABLE_DEVICE_TITLE}, + {"tetherConnectionBatteryPercentage", + IDS_SETTINGS_INTERNET_TETHER_CONNECTION_BATTERY_PERCENTAGE}, + {"tetherConnectionExplanation", + IDS_SETTINGS_INTERNET_TETHER_CONNECTION_EXPLANATION}, + {"tetherConnectionCarrierWarning", + IDS_SETTINGS_INTERNET_TETHER_CONNECTION_CARRIER_WARNING}, + {"tetherConnectionDescriptionTitle", + IDS_SETTINGS_INTERNET_TETHER_CONNECTION_DESCRIPTION_TITLE}, + {"tetherConnectionDescriptionMobileData", + IDS_SETTINGS_INTERNET_TETHER_CONNECTION_DESCRIPTION_MOBILE_DATA}, + {"tetherConnectionDescriptionBattery", + IDS_SETTINGS_INTERNET_TETHER_CONNECTION_DESCRIPTION_BATTERY}, + {"tetherConnectionDescriptionWiFi", + IDS_SETTINGS_INTERNET_TETHER_CONNECTION_DESCRIPTION_WIFI}, + {"tetherConnectionNotNowButton", + IDS_SETTINGS_INTERNET_TETHER_CONNECTION_NOT_NOW_BUTTON}, + {"tetherConnectionConnectButton", + IDS_SETTINGS_INTERNET_TETHER_CONNECTION_CONNECT_BUTTON}, + {"tetherEnableBluetooth", IDS_ENABLE_BLUETOOTH}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + chromeos::network_element::AddLocalizedStrings(html_source); + chromeos::network_element::AddOncLocalizedStrings(html_source); + chromeos::network_element::AddDetailsLocalizedStrings(html_source); + chromeos::network_element::AddConfigLocalizedStrings(html_source); + chromeos::network_element::AddErrorLocalizedStrings(html_source); + + html_source->AddString("networkGoogleNameserversLearnMoreUrl", + chrome::kGoogleNameserversLearnMoreURL); + html_source->AddString( + "internetNoNetworksMobileData", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_INTERNET_LOOKING_FOR_MOBILE_NETWORK, + GetHelpUrlWithBoard(chrome::kInstantTetheringLearnMoreURL))); +} + +void InternetStringsProvider::OnDeviceStateListChanged() { + FetchDeviceList(); +} + +void InternetStringsProvider::FetchDeviceList() { + cros_network_config_->GetDeviceStateList(base::BindOnce( + &InternetStringsProvider::OnDeviceList, base::Unretained(this))); +} + +void InternetStringsProvider::OnDeviceList( + std::vector<network_config::mojom::DeviceStatePropertiesPtr> devices) { + // Start with no search tags. + delegate()->RemoveSearchTags(GetEthernetSearchConcepts()); + delegate()->RemoveSearchTags(GetWifiSearchConcepts()); + + // Add a search tag each time we see a device type. + for (const auto& device : devices) { + if (device->type == network_config::mojom::NetworkType::kEthernet) + delegate()->AddSearchTags(GetEthernetSearchConcepts()); + else if (device->type == network_config::mojom::NetworkType::kWiFi) + delegate()->AddSearchTags(GetWifiSearchConcepts()); + } +} + +} // namespace settings +} // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/internet_strings_provider.h b/chromium/chrome/browser/ui/webui/settings/chromeos/internet_strings_provider.h new file mode 100644 index 00000000000..4a0e2a2511e --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/internet_strings_provider.h @@ -0,0 +1,59 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_INTERNET_STRINGS_PROVIDER_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_INTERNET_STRINGS_PROVIDER_H_ + +#include <vector> + +#include "chrome/browser/ui/webui/settings/chromeos/os_settings_per_page_strings_provider.h" +#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" + +class Profile; + +namespace content { +class WebUIDataSource; +} // namespace content + +namespace chromeos { +namespace settings { + +class InternetStringsProvider + : public OsSettingsPerPageStringsProvider, + public network_config::mojom::CrosNetworkConfigObserver { + public: + InternetStringsProvider(Profile* profile, Delegate* per_page_delegate); + ~InternetStringsProvider() override; + + private: + // OsSettingsPerPageStringsProvider: + void AddUiStrings(content::WebUIDataSource* html_source) const override; + + // network_config::mojom::CrosNetworkConfigObserver: + void OnActiveNetworksChanged( + std::vector<network_config::mojom::NetworkStatePropertiesPtr> networks) + override {} + void OnNetworkStateChanged( + chromeos::network_config::mojom::NetworkStatePropertiesPtr network) + override {} + void OnNetworkStateListChanged() override {} + void OnVpnProvidersChanged() override {} + void OnNetworkCertificatesChanged() override {} + void OnDeviceStateListChanged() override; + + void FetchDeviceList(); + void OnDeviceList( + std::vector<network_config::mojom::DeviceStatePropertiesPtr> devices); + + mojo::Receiver<network_config::mojom::CrosNetworkConfigObserver> receiver_{ + this}; + mojo::Remote<network_config::mojom::CrosNetworkConfig> cros_network_config_; +}; + +} // namespace settings +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_INTERNET_STRINGS_PROVIDER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/multidevice_handler.h b/chromium/chrome/browser/ui/webui/settings/chromeos/multidevice_handler.h index 8ee0b692ac1..a103760bd1e 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/multidevice_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/multidevice_handler.h @@ -13,7 +13,7 @@ #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" #include "chromeos/components/multidevice/remote_device_ref.h" #include "chromeos/services/multidevice_setup/public/cpp/multidevice_setup_client.h" -#include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h" +#include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom-forward.h" #include "components/prefs/pref_change_registrar.h" class PrefService; diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.cc new file mode 100644 index 00000000000..653188ccf20 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.cc @@ -0,0 +1,2136 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/chromeos/os_settings_localized_strings_provider.h" + +#include "ash/public/cpp/ash_features.h" +#include "ash/public/mojom/assistant_state_controller.mojom.h" +#include "base/command_line.h" +#include "base/feature_list.h" +#include "base/i18n/number_formatting.h" +#include "base/no_destructor.h" +#include "base/strings/strcat.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "base/system/sys_info.h" +#include "build/branding_buildflags.h" +#include "build/build_config.h" +#include "build/buildflag.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/browser_process_platform_part.h" +#include "chrome/browser/chromeos/account_manager/account_manager_util.h" +#include "chrome/browser/chromeos/arc/arc_util.h" +#include "chrome/browser/chromeos/assistant/assistant_util.h" +#include "chrome/browser/chromeos/crostini/crostini_features.h" +#include "chrome/browser/chromeos/crostini/crostini_util.h" +#include "chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h" +#include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h" +#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" +#include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/policy/profile_policy_connector.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/supervised_user/supervised_user_service.h" +#include "chrome/browser/supervised_user/supervised_user_service_factory.h" +#include "chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.h" +#include "chrome/browser/ui/webui/chromeos/bluetooth_dialog_localized_strings_provider.h" +#include "chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.h" +#include "chrome/browser/ui/webui/chromeos/smb_shares/smb_shares_localized_strings_provider.h" +#include "chrome/browser/ui/webui/management_ui.h" +#include "chrome/browser/ui/webui/policy_indicator_localized_strings_provider.h" +#include "chrome/browser/ui/webui/settings/chromeos/internet_strings_provider.h" +#include "chrome/browser/ui/webui/settings/chromeos/search/search_concept.h" +#include "chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.h" +#include "chrome/browser/ui/webui/webui_util.h" +#include "chrome/common/chrome_features.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/url_constants.h" +#include "chrome/common/webui_url_constants.h" +#include "chrome/grit/chromium_strings.h" +#include "chrome/grit/generated_resources.h" +#include "chrome/grit/locale_settings.h" +#include "chrome/services/local_search_service/public/mojom/types.mojom.h" +#include "chromeos/constants/chromeos_features.h" +#include "chromeos/constants/chromeos_switches.h" +#include "chromeos/services/assistant/public/features.h" +#include "chromeos/services/multidevice_setup/public/cpp/url_provider.h" +#include "chromeos/strings/grit/chromeos_strings.h" +#include "components/google/core/common/google_util.h" +#include "components/prefs/pref_service.h" +#include "components/strings/grit/components_strings.h" +#include "components/version_ui/version_ui_constants.h" +#include "content/public/browser/web_ui_data_source.h" +#include "content/public/common/content_features.h" +#include "content/public/common/content_switches.h" +#include "device/bluetooth/strings/grit/bluetooth_strings.h" +#include "media/base/media_switches.h" +#include "ui/accessibility/accessibility_switches.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/webui/web_ui_util.h" +#include "ui/chromeos/devicetype_utils.h" +#include "ui/chromeos/events/keyboard_layout_util.h" +#include "ui/display/display_features.h" +#include "ui/display/display_switches.h" +#include "ui/display/manager/touch_device_manager.h" + +namespace chromeos { +namespace settings { +namespace { + +std::vector<local_search_service::mojom::DataPtr> ConceptVectorToDataPtrVector( + const std::vector<SearchConcept>& tags_group) { + std::vector<local_search_service::mojom::DataPtr> data_list; + + for (const auto& concept : tags_group) { + std::vector<base::string16> search_tags; + + // Add the canonical tag. + search_tags.push_back( + l10n_util::GetStringUTF16(concept.canonical_message_id)); + + // Add all alternate tags. + for (size_t i = 0; i < SearchConcept::kMaxAltTagsPerConcept; ++i) { + int curr_alt_tag = concept.alt_tag_ids[i]; + if (curr_alt_tag == SearchConcept::kAltTagEnd) + break; + search_tags.push_back(l10n_util::GetStringUTF16(curr_alt_tag)); + } + + // Note: A stringified version of the canonical tag message ID is used as + // the identifier for this search data. + data_list.push_back(local_search_service::mojom::Data::New( + base::NumberToString(concept.canonical_message_id), search_tags)); + } + + return data_list; +} + +// Generates a Google Help URL which includes a "board type" parameter. Some +// help pages need to be adjusted depending on the type of CrOS device that is +// accessing the page. +base::string16 GetHelpUrlWithBoard(const std::string& original_url) { + return base::ASCIIToUTF16(original_url + + "&b=" + base::SysInfo::GetLsbReleaseBoard()); +} + +bool IsDeviceManaged() { + policy::BrowserPolicyConnectorChromeOS* connector = + g_browser_process->platform_part()->browser_policy_connector_chromeos(); + return connector->IsEnterpriseManaged(); +} + +bool IsProfileManaged(Profile* profile) { + return profile->GetProfilePolicyConnector()->IsManaged(); +} + +void AddCommonStrings(content::WebUIDataSource* html_source, Profile* profile) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"add", IDS_ADD}, + {"advancedPageTitle", IDS_SETTINGS_ADVANCED}, + {"back", IDS_ACCNAME_BACK}, + {"basicPageTitle", IDS_SETTINGS_BASIC}, + {"cancel", IDS_CANCEL}, + {"clear", IDS_SETTINGS_CLEAR}, + {"close", IDS_CLOSE}, + {"confirm", IDS_CONFIRM}, + {"continue", IDS_SETTINGS_CONTINUE}, + {"controlledByExtension", IDS_SETTINGS_CONTROLLED_BY_EXTENSION}, + {"custom", IDS_SETTINGS_CUSTOM}, + {"delete", IDS_SETTINGS_DELETE}, + {"deviceOff", IDS_SETTINGS_DEVICE_OFF}, + {"deviceOn", IDS_SETTINGS_DEVICE_ON}, + {"disable", IDS_DISABLE}, + {"done", IDS_DONE}, + {"edit", IDS_SETTINGS_EDIT}, + {"extensionsLinkTooltip", IDS_SETTINGS_MENU_EXTENSIONS_LINK_TOOLTIP}, + {"learnMore", IDS_LEARN_MORE}, + {"menu", IDS_MENU}, + {"menuButtonLabel", IDS_SETTINGS_MENU_BUTTON_LABEL}, + {"moreActions", IDS_SETTINGS_MORE_ACTIONS}, + {"ok", IDS_OK}, + {"restart", IDS_SETTINGS_RESTART}, + {"save", IDS_SAVE}, + {"searchResultBubbleText", IDS_SEARCH_RESULT_BUBBLE_TEXT}, + {"searchResultsBubbleText", IDS_SEARCH_RESULTS_BUBBLE_TEXT}, + {"settings", IDS_SETTINGS_SETTINGS}, + {"settingsAltPageTitle", IDS_SETTINGS_ALT_PAGE_TITLE}, + {"subpageArrowRoleDescription", IDS_SETTINGS_SUBPAGE_BUTTON}, + {"notValidWebAddress", IDS_SETTINGS_NOT_VALID_WEB_ADDRESS}, + {"notValidWebAddressForContentType", + IDS_SETTINGS_NOT_VALID_WEB_ADDRESS_FOR_CONTENT_TYPE}, + + // Common font related strings shown in a11y and appearance sections. + {"quickBrownFox", IDS_SETTINGS_QUICK_BROWN_FOX}, + {"verySmall", IDS_SETTINGS_VERY_SMALL_FONT}, + {"small", IDS_SETTINGS_SMALL_FONT}, + {"medium", IDS_SETTINGS_MEDIUM_FONT}, + {"large", IDS_SETTINGS_LARGE_FONT}, + {"veryLarge", IDS_SETTINGS_VERY_LARGE_FONT}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + html_source->AddBoolean( + "isGuest", + user_manager::UserManager::Get()->IsLoggedInAsGuest() || + user_manager::UserManager::Get()->IsLoggedInAsPublicAccount()); + + html_source->AddBoolean("isSupervised", profile->IsSupervised()); +} + +void AddA11yStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"a11yPageTitle", IDS_SETTINGS_ACCESSIBILITY}, + {"a11yWebStore", IDS_SETTINGS_ACCESSIBILITY_WEB_STORE}, + {"moreFeaturesLinkDescription", + IDS_SETTINGS_MORE_FEATURES_LINK_DESCRIPTION}, + {"accessibleImageLabelsTitle", + IDS_SETTINGS_ACCESSIBLE_IMAGE_LABELS_TITLE}, + {"accessibleImageLabelsSubtitle", + IDS_SETTINGS_ACCESSIBLE_IMAGE_LABELS_SUBTITLE}, + {"settingsSliderRoleDescription", + IDS_SETTINGS_SLIDER_MIN_MAX_ARIA_ROLE_DESCRIPTION}, + {"manageAccessibilityFeatures", + IDS_SETTINGS_ACCESSIBILITY_MANAGE_ACCESSIBILITY_FEATURES}, + {"optionsInMenuLabel", IDS_SETTINGS_OPTIONS_IN_MENU_LABEL}, + {"largeMouseCursorLabel", IDS_SETTINGS_LARGE_MOUSE_CURSOR_LABEL}, + {"largeMouseCursorSizeLabel", IDS_SETTINGS_LARGE_MOUSE_CURSOR_SIZE_LABEL}, + {"largeMouseCursorSizeDefaultLabel", + IDS_SETTINGS_LARGE_MOUSE_CURSOR_SIZE_DEFAULT_LABEL}, + {"largeMouseCursorSizeLargeLabel", + IDS_SETTINGS_LARGE_MOUSE_CURSOR_SIZE_LARGE_LABEL}, + {"highContrastLabel", IDS_SETTINGS_HIGH_CONTRAST_LABEL}, + {"stickyKeysLabel", IDS_SETTINGS_STICKY_KEYS_LABEL}, + {"chromeVoxLabel", IDS_SETTINGS_CHROMEVOX_LABEL}, + {"chromeVoxOptionsLabel", IDS_SETTINGS_CHROMEVOX_OPTIONS_LABEL}, + {"screenMagnifierLabel", IDS_SETTINGS_SCREEN_MAGNIFIER_LABEL}, + {"screenMagnifierZoomLabel", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_LABEL}, + {"dockedMagnifierLabel", IDS_SETTINGS_DOCKED_MAGNIFIER_LABEL}, + {"dockedMagnifierZoomLabel", IDS_SETTINGS_DOCKED_MAGNIFIER_ZOOM_LABEL}, + {"screenMagnifierZoom2x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_2_X}, + {"screenMagnifierZoom4x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_4_X}, + {"screenMagnifierZoom6x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_6_X}, + {"screenMagnifierZoom8x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_8_X}, + {"screenMagnifierZoom10x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_10_X}, + {"screenMagnifierZoom12x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_12_X}, + {"screenMagnifierZoom14x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_14_X}, + {"screenMagnifierZoom16x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_16_X}, + {"screenMagnifierZoom18x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_18_X}, + {"screenMagnifierZoom20x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_20_X}, + {"tapDraggingLabel", IDS_SETTINGS_TAP_DRAGGING_LABEL}, + {"clickOnStopLabel", IDS_SETTINGS_CLICK_ON_STOP_LABEL}, + {"delayBeforeClickLabel", IDS_SETTINGS_DELAY_BEFORE_CLICK_LABEL}, + {"delayBeforeClickExtremelyShort", + IDS_SETTINGS_DELAY_BEFORE_CLICK_EXTREMELY_SHORT}, + {"delayBeforeClickVeryShort", IDS_SETTINGS_DELAY_BEFORE_CLICK_VERY_SHORT}, + {"delayBeforeClickShort", IDS_SETTINGS_DELAY_BEFORE_CLICK_SHORT}, + {"delayBeforeClickLong", IDS_SETTINGS_DELAY_BEFORE_CLICK_LONG}, + {"delayBeforeClickVeryLong", IDS_SETTINGS_DELAY_BEFORE_CLICK_VERY_LONG}, + {"autoclickRevertToLeftClick", + IDS_SETTINGS_AUTOCLICK_REVERT_TO_LEFT_CLICK}, + {"autoclickStabilizeCursorPosition", + IDS_SETTINGS_AUTOCLICK_STABILIZE_CURSOR_POSITION}, + {"autoclickMovementThresholdLabel", + IDS_SETTINGS_AUTOCLICK_MOVEMENT_THRESHOLD_LABEL}, + {"autoclickMovementThresholdExtraSmall", + IDS_SETTINGS_AUTOCLICK_MOVEMENT_THRESHOLD_EXTRA_SMALL}, + {"autoclickMovementThresholdSmall", + IDS_SETTINGS_AUTOCLICK_MOVEMENT_THRESHOLD_SMALL}, + {"autoclickMovementThresholdDefault", + IDS_SETTINGS_AUTOCLICK_MOVEMENT_THRESHOLD_DEFAULT}, + {"autoclickMovementThresholdLarge", + IDS_SETTINGS_AUTOCLICK_MOVEMENT_THRESHOLD_LARGE}, + {"autoclickMovementThresholdExtraLarge", + IDS_SETTINGS_AUTOCLICK_MOVEMENT_THRESHOLD_EXTRA_LARGE}, + {"dictationDescription", + IDS_SETTINGS_ACCESSIBILITY_DICTATION_DESCRIPTION}, + {"dictationLabel", IDS_SETTINGS_ACCESSIBILITY_DICTATION_LABEL}, + {"onScreenKeyboardLabel", IDS_SETTINGS_ON_SCREEN_KEYBOARD_LABEL}, + {"monoAudioLabel", IDS_SETTINGS_MONO_AUDIO_LABEL}, + {"startupSoundLabel", IDS_SETTINGS_STARTUP_SOUND_LABEL}, + {"a11yExplanation", IDS_SETTINGS_ACCESSIBILITY_EXPLANATION}, + {"caretHighlightLabel", + IDS_SETTINGS_ACCESSIBILITY_CARET_HIGHLIGHT_DESCRIPTION}, + {"cursorHighlightLabel", + IDS_SETTINGS_ACCESSIBILITY_CURSOR_HIGHLIGHT_DESCRIPTION}, + {"focusHighlightLabel", + IDS_SETTINGS_ACCESSIBILITY_FOCUS_HIGHLIGHT_DESCRIPTION}, + {"selectToSpeakTitle", IDS_SETTINGS_ACCESSIBILITY_SELECT_TO_SPEAK_TITLE}, + {"selectToSpeakDisabledDescription", + IDS_SETTINGS_ACCESSIBILITY_SELECT_TO_SPEAK_DISABLED_DESCRIPTION}, + {"selectToSpeakDescription", + IDS_SETTINGS_ACCESSIBILITY_SELECT_TO_SPEAK_DESCRIPTION}, + {"selectToSpeakDescriptionWithoutKeyboard", + IDS_SETTINGS_ACCESSIBILITY_SELECT_TO_SPEAK_DESCRIPTION_WITHOUT_KEYBOARD}, + {"selectToSpeakOptionsLabel", + IDS_SETTINGS_ACCESSIBILITY_SELECT_TO_SPEAK_OPTIONS_LABEL}, + {"switchAccessLabel", + IDS_SETTINGS_ACCESSIBILITY_SWITCH_ACCESS_DESCRIPTION}, + {"switchAccessOptionsLabel", + IDS_SETTINGS_ACCESSIBILITY_SWITCH_ACCESS_OPTIONS_LABEL}, + {"manageSwitchAccessSettings", + IDS_SETTINGS_MANAGE_SWITCH_ACCESS_SETTINGS}, + {"switchAssignmentHeading", IDS_SETTINGS_SWITCH_ASSIGNMENT_HEADING}, + {"switchAssignOptionNone", IDS_SETTINGS_SWITCH_ASSIGN_OPTION_NONE}, + {"switchAssignOptionSpace", IDS_SETTINGS_SWITCH_ASSIGN_OPTION_SPACE}, + {"switchAssignOptionEnter", IDS_SETTINGS_SWITCH_ASSIGN_OPTION_ENTER}, + {"assignSelectSwitchLabel", IDS_SETTINGS_ASSIGN_SELECT_SWITCH_LABEL}, + {"assignNextSwitchLabel", IDS_SETTINGS_ASSIGN_NEXT_SWITCH_LABEL}, + {"assignPreviousSwitchLabel", IDS_SETTINGS_ASSIGN_PREVIOUS_SWITCH_LABEL}, + {"switchAccessAutoScanHeading", + IDS_SETTINGS_SWITCH_ACCESS_AUTO_SCAN_HEADING}, + {"switchAccessAutoScanLabel", IDS_SETTINGS_SWITCH_ACCESS_AUTO_SCAN_LABEL}, + {"switchAccessAutoScanSpeedLabel", + IDS_SETTINGS_SWITCH_ACCESS_AUTO_SCAN_SPEED_LABEL}, + {"switchAccessAutoScanKeyboardSpeedLabel", + IDS_SETTINGS_SWITCH_ACCESS_AUTO_SCAN_KEYBOARD_SPEED_LABEL}, + {"durationInSeconds", IDS_SETTINGS_DURATION_IN_SECONDS}, + {"manageAccessibilityFeatures", + IDS_SETTINGS_ACCESSIBILITY_MANAGE_ACCESSIBILITY_FEATURES}, + {"textToSpeechHeading", + IDS_SETTINGS_ACCESSIBILITY_TEXT_TO_SPEECH_HEADING}, + {"displayHeading", IDS_SETTINGS_ACCESSIBILITY_DISPLAY_HEADING}, + {"displaySettingsTitle", + IDS_SETTINGS_ACCESSIBILITY_DISPLAY_SETTINGS_TITLE}, + {"displaySettingsDescription", + IDS_SETTINGS_ACCESSIBILITY_DISPLAY_SETTINGS_DESCRIPTION}, + {"appearanceSettingsTitle", + IDS_SETTINGS_ACCESSIBILITY_APPEARANCE_SETTINGS_TITLE}, + {"appearanceSettingsDescription", + IDS_SETTINGS_ACCESSIBILITY_APPEARANCE_SETTINGS_DESCRIPTION}, + {"keyboardAndTextInputHeading", + IDS_SETTINGS_ACCESSIBILITY_KEYBOARD_AND_TEXT_INPUT_HEADING}, + {"keyboardSettingsTitle", + IDS_SETTINGS_ACCESSIBILITY_KEYBOARD_SETTINGS_TITLE}, + {"keyboardSettingsDescription", + IDS_SETTINGS_ACCESSIBILITY_KEYBOARD_SETTINGS_DESCRIPTION}, + {"mouseAndTouchpadHeading", + IDS_SETTINGS_ACCESSIBILITY_MOUSE_AND_TOUCHPAD_HEADING}, + {"mouseSettingsTitle", IDS_SETTINGS_ACCESSIBILITY_MOUSE_SETTINGS_TITLE}, + {"mouseSettingsDescription", + IDS_SETTINGS_ACCESSIBILITY_MOUSE_SETTINGS_DESCRIPTION}, + {"audioAndCaptionsHeading", + IDS_SETTINGS_ACCESSIBILITY_AUDIO_AND_CAPTIONS_HEADING}, + {"additionalFeaturesTitle", + IDS_SETTINGS_ACCESSIBILITY_ADDITIONAL_FEATURES_TITLE}, + {"manageTtsSettings", IDS_SETTINGS_MANAGE_TTS_SETTINGS}, + {"ttsSettingsLinkDescription", IDS_SETTINGS_TTS_LINK_DESCRIPTION}, + {"textToSpeechVoices", IDS_SETTINGS_TEXT_TO_SPEECH_VOICES}, + {"textToSpeechNoVoicesMessage", + IDS_SETTINGS_TEXT_TO_SPEECH_NO_VOICES_MESSAGE}, + {"textToSpeechMoreLanguages", IDS_SETTINGS_TEXT_TO_SPEECH_MORE_LANGUAGES}, + {"textToSpeechProperties", IDS_SETTINGS_TEXT_TO_SPEECH_PROPERTIES}, + {"textToSpeechRate", IDS_SETTINGS_TEXT_TO_SPEECH_RATE}, + {"textToSpeechRateMinimumLabel", + IDS_SETTINGS_TEXT_TO_SPEECH_RATE_MINIMUM_LABEL}, + {"textToSpeechRateMaximumLabel", + IDS_SETTINGS_TEXT_TO_SPEECH_RATE_MAXIMUM_LABEL}, + {"textToSpeechPitch", IDS_SETTINGS_TEXT_TO_SPEECH_PITCH}, + {"textToSpeechPitchMinimumLabel", + IDS_SETTINGS_TEXT_TO_SPEECH_PITCH_MINIMUM_LABEL}, + {"textToSpeechPitchMaximumLabel", + IDS_SETTINGS_TEXT_TO_SPEECH_PITCH_MAXIMUM_LABEL}, + {"textToSpeechVolume", IDS_SETTINGS_TEXT_TO_SPEECH_VOLUME}, + {"textToSpeechVolumeMinimumLabel", + IDS_SETTINGS_TEXT_TO_SPEECH_VOLUME_MINIMUM_LABEL}, + {"textToSpeechVolumeMaximumLabel", + IDS_SETTINGS_TEXT_TO_SPEECH_VOLUME_MAXIMUM_LABEL}, + {"percentage", IDS_SETTINGS_PERCENTAGE}, + {"defaultPercentage", IDS_SETTINGS_DEFAULT_PERCENTAGE}, + {"textToSpeechPreviewHeading", + IDS_SETTINGS_TEXT_TO_SPEECH_PREVIEW_HEADING}, + {"textToSpeechPreviewInputLabel", + IDS_SETTINGS_TEXT_TO_SPEECH_PREVIEW_INPUT_LABEL}, + {"textToSpeechPreviewInput", IDS_SETTINGS_TEXT_TO_SPEECH_PREVIEW_INPUT}, + {"textToSpeechPreviewVoice", IDS_SETTINGS_TEXT_TO_SPEECH_PREVIEW_VOICE}, + {"textToSpeechPreviewPlay", IDS_SETTINGS_TEXT_TO_SPEECH_PREVIEW_PLAY}, + {"textToSpeechEngines", IDS_SETTINGS_TEXT_TO_SPEECH_ENGINES}, + {"tabletModeShelfNavigationButtonsSettingLabel", + IDS_SETTINGS_A11Y_TABLET_MODE_SHELF_BUTTONS_LABEL}, + {"tabletModeShelfNavigationButtonsSettingDescription", + IDS_SETTINGS_A11Y_TABLET_MODE_SHELF_BUTTONS_DESCRIPTION}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + html_source->AddString("accountManagerLearnMoreUrl", + chrome::kAccountManagerLearnMoreURL); + html_source->AddString("a11yLearnMoreUrl", + chrome::kChromeAccessibilityHelpURL); + + base::CommandLine& cmd = *base::CommandLine::ForCurrentProcess(); + html_source->AddBoolean( + "showExperimentalAccessibilitySwitchAccess", + cmd.HasSwitch(::switches::kEnableExperimentalAccessibilitySwitchAccess)); + + html_source->AddBoolean( + "showExperimentalAccessibilitySwitchAccessImprovedTextInput", + cmd.HasSwitch( + ::switches::kEnableExperimentalAccessibilitySwitchAccessText)); + + html_source->AddBoolean("showExperimentalA11yLabels", + base::FeatureList::IsEnabled( + ::features::kExperimentalAccessibilityLabels)); + + html_source->AddBoolean( + "showTabletModeShelfNavigationButtonsSettings", + ash::features::IsHideShelfControlsInTabletModeEnabled()); + + html_source->AddString("tabletModeShelfNavigationButtonsLearnMoreUrl", + chrome::kTabletModeGesturesLearnMoreURL); + + html_source->AddBoolean("enableLiveCaption", + base::FeatureList::IsEnabled(media::kLiveCaption)); + + ::settings::AddCaptionSubpageStrings(html_source); +} + +void AddLanguagesStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"orderLanguagesInstructions", + IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_ORDERING_INSTRUCTIONS}, + {"osLanguagesPageTitle", IDS_OS_SETTINGS_LANGUAGES_AND_INPUT_PAGE_TITLE}, + {"osLanguagesListTitle", IDS_OS_SETTINGS_LANGUAGES_LIST_TITLE}, + {"inputMethodsListTitle", + IDS_SETTINGS_LANGUAGES_INPUT_METHODS_LIST_TITLE}, + {"inputMethodEnabled", IDS_SETTINGS_LANGUAGES_INPUT_METHOD_ENABLED}, + {"inputMethodsExpandA11yLabel", + IDS_SETTINGS_LANGUAGES_INPUT_METHODS_EXPAND_ACCESSIBILITY_LABEL}, + {"inputMethodsManagedbyPolicy", + IDS_SETTINGS_LANGUAGES_INPUT_METHODS_MANAGED_BY_POLICY}, + {"manageInputMethods", IDS_SETTINGS_LANGUAGES_INPUT_METHODS_MANAGE}, + {"manageInputMethodsPageTitle", + IDS_SETTINGS_LANGUAGES_MANAGE_INPUT_METHODS_TITLE}, + {"showImeMenu", IDS_SETTINGS_LANGUAGES_SHOW_IME_MENU}, + {"displayLanguageRestart", + IDS_SETTINGS_LANGUAGES_RESTART_TO_DISPLAY_LANGUAGE}, + {"moveDown", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_DOWN}, + {"displayInThisLanguage", + IDS_SETTINGS_LANGUAGES_DISPLAY_IN_THIS_LANGUAGE}, + {"searchLanguages", IDS_SETTINGS_LANGUAGE_SEARCH}, + {"addLanguagesDialogTitle", + IDS_SETTINGS_LANGUAGES_MANAGE_LANGUAGES_TITLE}, + {"moveToTop", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_TO_TOP}, + {"isDisplayedInThisLanguage", + IDS_SETTINGS_LANGUAGES_IS_DISPLAYED_IN_THIS_LANGUAGE}, + {"removeLanguage", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_REMOVE}, + {"addLanguages", IDS_SETTINGS_LANGUAGES_LANGUAGES_ADD}, + {"moveUp", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_UP}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + html_source->AddString( + "languagesLearnMoreURL", + base::ASCIIToUTF16(chrome::kLanguageSettingsLearnMoreUrl)); +} + +void AddPersonalizationStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"ambientModeTitle", IDS_OS_SETTINGS_AMBIENT_MODE_TITLE}, + {"ambientModeEnabled", IDS_OS_SETTINGS_AMBIENT_MODE_ENABLED}, + {"ambientModeDisabled", IDS_OS_SETTINGS_AMBIENT_MODE_DISABLED}, + {"ambientModeOn", IDS_OS_SETTINGS_AMBIENT_MODE_ON}, + {"ambientModeOff", IDS_OS_SETTINGS_AMBIENT_MODE_OFF}, + {"ambientModeTopicSourceTitle", + IDS_OS_SETTINGS_AMBIENT_MODE_TOPIC_SOURCE_TITLE}, + {"ambientModeTopicSourceGooglePhotos", + IDS_OS_SETTINGS_AMBIENT_MODE_TOPIC_SOURCE_GOOGLE_PHOTOS}, + {"ambientModeTopicSourceArtGallery", + IDS_OS_SETTINGS_AMBIENT_MODE_TOPIC_SOURCE_ART_GALLERY}, + {"changePictureTitle", IDS_OS_SETTINGS_CHANGE_PICTURE_TITLE}, + {"openWallpaperApp", IDS_OS_SETTINGS_OPEN_WALLPAPER_APP}, + {"personalizationPageTitle", IDS_OS_SETTINGS_PERSONALIZATION}, + {"setWallpaper", IDS_OS_SETTINGS_SET_WALLPAPER}, + {"takePhoto", IDS_SETTINGS_CHANGE_PICTURE_TAKE_PHOTO}, + {"captureVideo", IDS_SETTINGS_CHANGE_PICTURE_CAPTURE_VIDEO}, + {"discardPhoto", IDS_SETTINGS_CHANGE_PICTURE_DISCARD_PHOTO}, + {"previewAltText", IDS_SETTINGS_CHANGE_PICTURE_PREVIEW_ALT}, + {"switchModeToVideo", IDS_SETTINGS_CHANGE_PICTURE_SWITCH_MODE_TO_VIDEO}, + {"profilePhoto", IDS_SETTINGS_CHANGE_PICTURE_PROFILE_PHOTO}, + {"changePicturePageDescription", IDS_SETTINGS_CHANGE_PICTURE_DIALOG_TEXT}, + {"switchModeToCamera", IDS_SETTINGS_CHANGE_PICTURE_SWITCH_MODE_TO_CAMERA}, + {"chooseFile", IDS_SETTINGS_CHANGE_PICTURE_CHOOSE_FILE}, + {"oldPhoto", IDS_SETTINGS_CHANGE_PICTURE_OLD_PHOTO}, + {"oldVideo", IDS_SETTINGS_CHANGE_PICTURE_OLD_VIDEO}, + {"authorCreditText", IDS_SETTINGS_CHANGE_PICTURE_AUTHOR_CREDIT_TEXT}, + {"photoCaptureAccessibleText", + IDS_SETTINGS_PHOTO_CAPTURE_ACCESSIBLE_TEXT}, + {"photoDiscardAccessibleText", + IDS_SETTINGS_PHOTO_DISCARD_ACCESSIBLE_TEXT}, + {"photoModeAccessibleText", IDS_SETTINGS_PHOTO_MODE_ACCESSIBLE_TEXT}, + {"videoModeAccessibleText", IDS_SETTINGS_VIDEO_MODE_ACCESSIBLE_TEXT}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + html_source->AddBoolean( + "changePictureVideoModeEnabled", + base::FeatureList::IsEnabled(::features::kChangePictureVideoMode)); + html_source->AddBoolean("isAmbientModeEnabled", + chromeos::features::IsAmbientModeEnabled()); +} + +void AddFingerprintListStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"lockScreenAddFingerprint", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_ADD_FINGERPRINT_BUTTON}, + {"lockScreenRegisteredFingerprints", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_REGISTERED_FINGERPRINTS_LABEL}, + {"lockScreenFingerprintWarning", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_FINGERPRINT_LESS_SECURE}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); +} + +void AddSetupPinDialogStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"configurePinChoosePinTitle", + IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_CHOOSE_PIN_TITLE}, + {"configurePinConfirmPinTitle", + IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_CONFIRM_PIN_TITLE}, + {"configurePinMismatched", IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_MISMATCHED}, + {"configurePinTooShort", IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_TOO_SHORT}, + {"configurePinTooLong", IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_TOO_LONG}, + {"configurePinWeakPin", IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_WEAK_PIN}, + {"pinKeyboardPlaceholderPin", IDS_PIN_KEYBOARD_HINT_TEXT_PIN}, + {"pinKeyboardPlaceholderPinPassword", + IDS_PIN_KEYBOARD_HINT_TEXT_PIN_PASSWORD}, + {"pinKeyboardDeleteAccessibleName", + IDS_PIN_KEYBOARD_DELETE_ACCESSIBLE_NAME}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + // Format numbers to be used on the pin keyboard. + for (int j = 0; j <= 9; j++) { + html_source->AddString("pinKeyboard" + base::NumberToString(j), + base::FormatNumber(int64_t{j})); + } +} + +void AddSetupFingerprintDialogStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"configureFingerprintTitle", IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_TITLE}, + {"configureFingerprintAddAnotherButton", + IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_ADD_ANOTHER_BUTTON}, + {"configureFingerprintInstructionReadyStep", + IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_READY}, + {"configureFingerprintLiftFinger", + IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_LIFT_FINGER}, + {"configureFingerprintTryAgain", + IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_TRY_AGAIN}, + {"configureFingerprintImmobile", + IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_FINGER_IMMOBILE}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); +} + +void AddFingerprintStrings(content::WebUIDataSource* html_source) { + int instruction_id, aria_label_id; + using FingerprintLocation = chromeos::quick_unlock::FingerprintLocation; + switch (chromeos::quick_unlock::GetFingerprintLocation()) { + case FingerprintLocation::TABLET_POWER_BUTTON: + instruction_id = + IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_LOCATE_SCANNER_POWER_BUTTON; + aria_label_id = + IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_LOCATE_SCANNER_POWER_BUTTON_ARIA_LABEL; + break; + case FingerprintLocation::KEYBOARD_BOTTOM_LEFT: + instruction_id = + IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_LOCATE_SCANNER_KEYBOARD; + aria_label_id = + IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_LOCATE_SCANNER_KEYBOARD_BOTTOM_LEFT_ARIA_LABEL; + break; + case FingerprintLocation::KEYBOARD_BOTTOM_RIGHT: + instruction_id = + IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_LOCATE_SCANNER_KEYBOARD; + aria_label_id = + IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_LOCATE_SCANNER_KEYBOARD_BOTTOM_RIGHT_ARIA_LABEL; + break; + case FingerprintLocation::KEYBOARD_TOP_RIGHT: + instruction_id = + IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_LOCATE_SCANNER_KEYBOARD; + aria_label_id = + IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_LOCATE_SCANNER_KEYBOARD_TOP_RIGHT_ARIA_LABEL; + break; + } + html_source->AddLocalizedString( + "configureFingerprintInstructionLocateScannerStep", instruction_id); + html_source->AddLocalizedString("configureFingerprintScannerStepAriaLabel", + aria_label_id); +} + +void AddAccountManagerPageStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"accountManagerDescription", IDS_SETTINGS_ACCOUNT_MANAGER_DESCRIPTION}, + {"accountManagerChildDescription", + IDS_SETTINGS_ACCOUNT_MANAGER_CHILD_DESCRIPTION}, + {"accountListHeader", IDS_SETTINGS_ACCOUNT_MANAGER_LIST_HEADER}, + {"accountManagerPrimaryAccountTooltip", + IDS_SETTINGS_ACCOUNT_MANAGER_PRIMARY_ACCOUNT_TOOLTIP}, + {"accountManagerEducationAccountLabel", + IDS_SETTINGS_ACCOUNT_MANAGER_EDUCATION_ACCOUNT}, + {"removeAccountLabel", IDS_SETTINGS_ACCOUNT_MANAGER_REMOVE_ACCOUNT_LABEL}, + {"addAccountLabel", IDS_SETTINGS_ACCOUNT_MANAGER_ADD_ACCOUNT_LABEL}, + {"addSchoolAccountLabel", + IDS_SETTINGS_ACCOUNT_MANAGER_ADD_SCHOOL_ACCOUNT_LABEL}, + {"accountManagerSecondaryAccountsDisabledText", + IDS_SETTINGS_ACCOUNT_MANAGER_SECONDARY_ACCOUNTS_DISABLED_TEXT}, + {"accountManagerSecondaryAccountsDisabledChildText", + IDS_SETTINGS_ACCOUNT_MANAGER_SECONDARY_ACCOUNTS_DISABLED_CHILD_TEXT}, + {"accountManagerSignedOutAccountName", + IDS_SETTINGS_ACCOUNT_MANAGER_SIGNED_OUT_ACCOUNT_PLACEHOLDER}, + {"accountManagerUnmigratedAccountName", + IDS_SETTINGS_ACCOUNT_MANAGER_UNMIGRATED_ACCOUNT_PLACEHOLDER}, + {"accountManagerMigrationLabel", + IDS_SETTINGS_ACCOUNT_MANAGER_MIGRATION_LABEL}, + {"accountManagerReauthenticationLabel", + IDS_SETTINGS_ACCOUNT_MANAGER_REAUTHENTICATION_LABEL}, + {"accountManagerMigrationTooltip", + IDS_SETTINGS_ACCOUNT_MANAGER_MIGRATION_TOOLTIP}, + {"accountManagerReauthenticationTooltip", + IDS_SETTINGS_ACCOUNT_MANAGER_REAUTHENTICATION_TOOLTIP}, + {"accountManagerMoreActionsTooltip", + IDS_SETTINGS_ACCOUNT_MANAGER_MORE_ACTIONS_TOOLTIP}, + {"accountManagerManagedLabel", + IDS_SETTINGS_ACCOUNT_MANAGER_MANAGEMENT_STATUS_MANAGED_ACCOUNT}, + {"accountManagerUnmanagedLabel", + IDS_SETTINGS_ACCOUNT_MANAGER_MANAGEMENT_STATUS_UNMANAGED_ACCOUNT}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); +} + +void AddSyncControlsStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"syncEverythingCheckboxLabel", + IDS_SETTINGS_SYNC_EVERYTHING_CHECKBOX_LABEL}, + {"wallpaperCheckboxLabel", IDS_OS_SETTINGS_WALLPAPER_CHECKBOX_LABEL}, + {"osSyncTurnOff", IDS_OS_SETTINGS_SYNC_TURN_OFF}, + {"osSyncSettingsCheckboxLabel", + IDS_OS_SETTINGS_SYNC_SETTINGS_CHECKBOX_LABEL}, + {"wifiConfigurationsCheckboxLabel", + IDS_SETTINGS_WIFI_CONFIGURATIONS_CHECKBOX_LABEL}, + {"osSyncAppsCheckboxLabel", IDS_OS_SETTINGS_SYNC_APPS_CHECKBOX_LABEL}, + {"osSyncTurnOn", IDS_OS_SETTINGS_SYNC_TURN_ON}, + {"osSyncFeatureLabel", IDS_OS_SETTINGS_SYNC_FEATURE_LABEL}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + html_source->AddString( + "browserSettingsSyncSetupUrl", + base::StrCat({chrome::kChromeUISettingsURL, chrome::kSyncSetupSubPage})); +} + +void AddCrostiniStrings(content::WebUIDataSource* html_source, + Profile* profile) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"crostiniPageTitle", IDS_SETTINGS_CROSTINI_TITLE}, + {"crostiniPageLabel", IDS_SETTINGS_CROSTINI_LABEL}, + {"crostiniEnable", IDS_SETTINGS_TURN_ON}, + {"crostiniSharedPaths", IDS_SETTINGS_CROSTINI_SHARED_PATHS}, + {"crostiniSharedPathsListHeading", + IDS_SETTINGS_CROSTINI_SHARED_PATHS_LIST_HEADING}, + {"crostiniSharedPathsInstructionsAdd", + IDS_SETTINGS_CROSTINI_SHARED_PATHS_INSTRUCTIONS_ADD}, + {"crostiniSharedPathsInstructionsRemove", + IDS_SETTINGS_CROSTINI_SHARED_PATHS_INSTRUCTIONS_REMOVE}, + {"crostiniSharedPathsRemoveSharing", + IDS_SETTINGS_CROSTINI_SHARED_PATHS_REMOVE_SHARING}, + {"crostiniSharedPathsRemoveFailureDialogMessage", + IDS_SETTINGS_CROSTINI_SHARED_PATHS_REMOVE_FAILURE_DIALOG_MESSAGE}, + {"crostiniSharedPathsRemoveFailureDialogTitle", + IDS_SETTINGS_CROSTINI_SHARED_PATHS_REMOVE_FAILURE_DIALOG_TITLE}, + {"crostiniSharedPathsRemoveFailureTryAgain", + IDS_SETTINGS_CROSTINI_SHARED_PATHS_REMOVE_FAILURE_TRY_AGAIN}, + {"crostiniSharedPathsListEmptyMessage", + IDS_SETTINGS_CROSTINI_SHARED_PATHS_LIST_EMPTY_MESSAGE}, + {"crostiniExportImportTitle", IDS_SETTINGS_CROSTINI_EXPORT_IMPORT_TITLE}, + {"crostiniExport", IDS_SETTINGS_CROSTINI_EXPORT}, + {"crostiniExportLabel", IDS_SETTINGS_CROSTINI_EXPORT_LABEL}, + {"crostiniImport", IDS_SETTINGS_CROSTINI_IMPORT}, + {"crostiniImportLabel", IDS_SETTINGS_CROSTINI_IMPORT_LABEL}, + {"crostiniImportConfirmationDialogTitle", + IDS_SETTINGS_CROSTINI_CONFIRM_IMPORT_DIALOG_WINDOW_TITLE}, + {"crostiniImportConfirmationDialogMessage", + IDS_SETTINGS_CROSTINI_CONFIRM_IMPORT_DIALOG_WINDOW_MESSAGE}, + {"crostiniImportConfirmationDialogConfirmationButton", + IDS_SETTINGS_CROSTINI_IMPORT}, + {"crostiniRemoveButton", IDS_SETTINGS_CROSTINI_REMOVE_BUTTON}, + {"crostiniSharedUsbDevicesLabel", + IDS_SETTINGS_CROSTINI_SHARED_USB_DEVICES_LABEL}, + {"crostiniSharedUsbDevicesDescription", + IDS_SETTINGS_CROSTINI_SHARED_USB_DEVICES_DESCRIPTION}, + {"crostiniSharedUsbDevicesExtraDescription", + IDS_SETTINGS_CROSTINI_SHARED_USB_DEVICES_EXTRA_DESCRIPTION}, + {"crostiniSharedUsbDevicesListEmptyMessage", + IDS_SETTINGS_CROSTINI_SHARED_USB_DEVICES_LIST_EMPTY_MESSAGE}, + {"crostiniArcAdbTitle", IDS_SETTINGS_CROSTINI_ARC_ADB_TITLE}, + {"crostiniArcAdbDescription", IDS_SETTINGS_CROSTINI_ARC_ADB_DESCRIPTION}, + {"crostiniArcAdbLabel", IDS_SETTINGS_CROSTINI_ARC_ADB_LABEL}, + {"crostiniArcAdbRestartButton", + IDS_SETTINGS_CROSTINI_ARC_ADB_RESTART_BUTTON}, + {"crostiniArcAdbConfirmationTitleEnable", + IDS_SETTINGS_CROSTINI_ARC_ADB_CONFIRMATION_TITLE_ENABLE}, + {"crostiniArcAdbConfirmationTitleDisable", + IDS_SETTINGS_CROSTINI_ARC_ADB_CONFIRMATION_TITLE_DISABLE}, + {"crostiniContainerUpgrade", + IDS_SETTINGS_CROSTINI_CONTAINER_UPGRADE_MESSAGE}, + {"crostiniContainerUpgradeSubtext", + IDS_SETTINGS_CROSTINI_CONTAINER_UPGRADE_SUBTEXT}, + {"crostiniContainerUpgradeButton", + IDS_SETTINGS_CROSTINI_CONTAINER_UPGRADE_BUTTON}, + {"crostiniPortForwarding", IDS_SETTINGS_CROSTINI_PORT_FORWARDING}, + {"crostiniPortForwardingDescription", + IDS_SETTINGS_CROSTINI_PORT_FORWARDING_DESCRIPTION}, + {"crostiniPortForwardingNoPorts", + IDS_SETTINGS_CROSTINI_PORT_FORWARDING_NO_PORTS}, + {"crostiniPortForwardingTableTitle", + IDS_SETTINGS_CROSTINI_PORT_FORWARDING_TABLE_TITLE}, + {"crostiniPortForwardingListPortNumber", + IDS_SETTINGS_CROSTINI_PORT_FORWARDING_LIST_PORT_NUMBER}, + {"crostiniPortForwardingListLabel", + IDS_SETTINGS_CROSTINI_PORT_FORWARDING_LIST_LABEL}, + {"crostiniPortForwardingAddPortButton", + IDS_SETTINGS_CROSTINI_PORT_FORWARDING_ADD_PORT_BUTTON}, + {"crostiniPortForwardingAddPortButtonDescription", + IDS_SETTINGS_CROSTINI_PORT_FORWARDING_ADD_PORT_BUTTON_DESCRIPTION}, + {"crostiniPortForwardingAddPortDialogTitle", + IDS_SETTINGS_CROSTINI_PORT_FORWARDING_ADD_PORT_DIALOG_TITLE}, + {"crostiniPortForwardingAddPortDialogLabel", + IDS_SETTINGS_CROSTINI_PORT_FORWARDING_ADD_PORT_DIALOG_LABEL}, + {"crostiniPortForwardingTCP", IDS_SETTINGS_CROSTINI_PORT_FORWARDING_TCP}, + {"crostiniPortForwardingUDP", IDS_SETTINGS_CROSTINI_PORT_FORWARDING_UDP}, + {"crostiniPortForwardingAddError", + IDS_SETTINGS_CROSTINI_PORT_FORWARDING_ADD_ERROR}, + {"crostiniDiskResizeTitle", IDS_SETTINGS_CROSTINI_DISK_RESIZE_TITLE}, + {"crostiniDiskResizeShowButton", + IDS_SETTINGS_CROSTINI_DISK_RESIZE_SHOW_BUTTON}, + {"crostiniDiskResizeLabel", IDS_SETTINGS_CROSTINI_DISK_RESIZE_LABEL}, + {"crostiniDiskResizeUnsupported", + IDS_SETTINGS_CROSTINI_DISK_RESIZE_UNSUPPORTED}, + {"crostiniDiskResizeLoading", IDS_SETTINGS_CROSTINI_DISK_RESIZE_LOADING}, + {"crostiniDiskResizeError", IDS_SETTINGS_CROSTINI_DISK_RESIZE_ERROR}, + {"crostiniDiskResizeErrorRetry", + IDS_SETTINGS_CROSTINI_DISK_RESIZE_ERROR_RETRY}, + {"crostiniDiskResizeCancel", IDS_SETTINGS_CROSTINI_DISK_RESIZE_CANCEL}, + {"crostiniDiskResizeGoButton", + IDS_SETTINGS_CROSTINI_DISK_RESIZE_GO_BUTTON}, + {"crostiniDiskResizeInProgress", + IDS_SETTINGS_CROSTINI_DISK_RESIZE_IN_PROGRESS}, + {"crostiniDiskResizeResizingError", + IDS_SETTINGS_CROSTINI_DISK_RESIZE_RESIZING_ERROR}, + {"crostiniDiskResizeDone", IDS_SETTINGS_CROSTINI_DISK_RESIZE_DONE}, + {"crostiniMicTitle", IDS_SETTINGS_CROSTINI_MIC_TITLE}, + {"crostiniMicDialogTitle", IDS_SETTINGS_CROSTINI_MIC_DIALOG_TITLE}, + {"crostiniMicDialogLabel", IDS_SETTINGS_CROSTINI_MIC_DIALOG_LABEL}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + html_source->AddString( + "crostiniSubtext", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_CROSTINI_SUBTEXT, ui::GetChromeOSDeviceName(), + GetHelpUrlWithBoard(chrome::kLinuxAppsLearnMoreURL))); + html_source->AddString( + "crostiniArcAdbPowerwashRequiredSublabel", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_CROSTINI_ARC_ADB_POWERWASH_REQUIRED_SUBLABEL, + base::ASCIIToUTF16(chrome::kArcAdbSideloadingLearnMoreURL))); + html_source->AddString("crostiniRemove", l10n_util::GetStringFUTF16( + IDS_SETTINGS_CROSTINI_REMOVE, + ui::GetChromeOSDeviceName())); + html_source->AddString( + "crostiniArcAdbConfirmationMessageEnable", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_CROSTINI_ARC_ADB_CONFIRMATION_MESSAGE_ENABLE, + ui::GetChromeOSDeviceName())); + html_source->AddString( + "crostiniArcAdbConfirmationMessageDisable", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_CROSTINI_ARC_ADB_CONFIRMATION_MESSAGE_DISABLE, + ui::GetChromeOSDeviceName())); + html_source->AddString( + "crostiniSharedPathsInstructionsLocate", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_CROSTINI_SHARED_PATHS_INSTRUCTIONS_LOCATE, + base::ASCIIToUTF16( + crostini::ContainerChromeOSBaseDirectory().value()))); + html_source->AddBoolean( + "showCrostiniExportImport", + crostini::CrostiniFeatures::Get()->IsExportImportUIAllowed(profile)); + html_source->AddBoolean("arcAdbSideloadingSupported", + base::FeatureList::IsEnabled( + chromeos::features::kArcAdbSideloadingFeature)); + html_source->AddBoolean("showCrostiniPortForwarding", + base::FeatureList::IsEnabled( + chromeos::features::kCrostiniPortForwarding)); + html_source->AddBoolean("isOwnerProfile", + chromeos::ProfileHelper::IsOwnerProfile(profile)); + html_source->AddBoolean("isEnterpriseManaged", + IsDeviceManaged() || IsProfileManaged(profile)); + html_source->AddBoolean( + "canChangeAdbSideloading", + crostini::CrostiniFeatures::Get()->CanChangeAdbSideloading(profile)); + html_source->AddBoolean("showCrostiniContainerUpgrade", + crostini::ShouldAllowContainerUpgrade(profile)); + html_source->AddBoolean( + "showCrostiniDiskResize", + base::FeatureList::IsEnabled(chromeos::features::kCrostiniDiskResizing)); + html_source->AddBoolean("showCrostiniMic", + base::FeatureList::IsEnabled( + chromeos::features::kCrostiniShowMicSetting)); +} + +void AddPluginVmStrings(content::WebUIDataSource* html_source, + Profile* profile) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"pluginVmPageTitle", IDS_SETTINGS_PLUGIN_VM_PAGE_TITLE}, + {"pluginVmPageLabel", IDS_SETTINGS_PLUGIN_VM_PAGE_LABEL}, + {"pluginVmPageSubtext", IDS_SETTINGS_PLUGIN_VM_PAGE_SUBTEXT}, + {"pluginVmPageEnable", IDS_SETTINGS_TURN_ON}, + {"pluginVmPrinterAccess", IDS_SETTINGS_PLUGIN_VM_PRINTER_ACCESS}, + {"pluginVmSharedPaths", IDS_SETTINGS_PLUGIN_VM_SHARED_PATHS}, + {"pluginVmSharedPathsListHeading", + IDS_SETTINGS_PLUGIN_VM_SHARED_PATHS_LIST_HEADING}, + {"pluginVmSharedPathsInstructionsAdd", + IDS_SETTINGS_PLUGIN_VM_SHARED_PATHS_INSTRUCTIONS_ADD}, + {"pluginVmSharedPathsInstructionsRemove", + IDS_SETTINGS_PLUGIN_VM_SHARED_PATHS_INSTRUCTIONS_REMOVE}, + {"pluginVmSharedPathsRemoveSharing", + IDS_SETTINGS_PLUGIN_VM_SHARED_PATHS_REMOVE_SHARING}, + {"pluginVmRemove", IDS_SETTINGS_PLUGIN_VM_REMOVE_LABEL}, + {"pluginVmRemoveButton", IDS_SETTINGS_PLUGIN_VM_REMOVE_BUTTON}, + {"pluginVmRemoveConfirmationDialogMessage", + IDS_SETTINGS_PLUGIN_VM_CONFIRM_REMOVE_DIALOG_BODY}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); +} + +void AddAndroidAppStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"androidAppsPageLabel", IDS_SETTINGS_ANDROID_APPS_LABEL}, + {"androidAppsEnable", IDS_SETTINGS_TURN_ON}, + {"androidAppsManageApps", IDS_SETTINGS_ANDROID_APPS_MANAGE_APPS}, + {"androidAppsRemove", IDS_SETTINGS_ANDROID_APPS_REMOVE}, + {"androidAppsRemoveButton", IDS_SETTINGS_ANDROID_APPS_REMOVE_BUTTON}, + {"androidAppsDisableDialogTitle", + IDS_SETTINGS_ANDROID_APPS_DISABLE_DIALOG_TITLE}, + {"androidAppsDisableDialogMessage", + IDS_SETTINGS_ANDROID_APPS_DISABLE_DIALOG_MESSAGE}, + {"androidAppsDisableDialogRemove", + IDS_SETTINGS_ANDROID_APPS_DISABLE_DIALOG_REMOVE}, + {"androidAppsManageAppLinks", IDS_SETTINGS_ANDROID_APPS_MANAGE_APP_LINKS}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + html_source->AddLocalizedString("androidAppsPageTitle", + arc::IsPlayStoreAvailable() + ? IDS_SETTINGS_ANDROID_APPS_TITLE + : IDS_SETTINGS_ANDROID_SETTINGS_TITLE); + html_source->AddString( + "androidAppsSubtext", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_ANDROID_APPS_SUBTEXT, ui::GetChromeOSDeviceName(), + GetHelpUrlWithBoard(chrome::kAndroidAppsLearnMoreURL))); +} + +void AddAppsStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"appsPageTitle", IDS_SETTINGS_APPS_TITLE}, + {"appManagementTitle", IDS_SETTINGS_APPS_LINK_TEXT}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); +} + +void AddAppManagementStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"appManagementAppInstalledByPolicyLabel", + IDS_APP_MANAGEMENT_POLICY_APP_POLICY_STRING}, + {"appManagementCameraPermissionLabel", IDS_APP_MANAGEMENT_CAMERA}, + {"appManagementContactsPermissionLabel", IDS_APP_MANAGEMENT_CONTACTS}, + {"appManagementLocationPermissionLabel", IDS_APP_MANAGEMENT_LOCATION}, + {"appManagementMicrophonePermissionLabel", IDS_APP_MANAGEMENT_MICROPHONE}, + {"appManagementMoreSettingsLabel", IDS_APP_MANAGEMENT_MORE_SETTINGS}, + {"appManagementNoAppsFound", IDS_APP_MANAGEMENT_NO_APPS_FOUND}, + {"appManagementNoPermissions", + IDS_APPLICATION_INFO_APP_NO_PERMISSIONS_TEXT}, + {"appManagementNotificationsLabel", IDS_APP_MANAGEMENT_NOTIFICATIONS}, + {"appManagementPermissionsLabel", IDS_APP_MANAGEMENT_PERMISSIONS}, + {"appManagementPinToShelfLabel", IDS_APP_MANAGEMENT_PIN_TO_SHELF}, + {"appManagementSearchPrompt", IDS_APP_MANAGEMENT_SEARCH_PROMPT}, + {"appManagementStoragePermissionLabel", IDS_APP_MANAGEMENT_STORAGE}, + {"appManagementUninstallLabel", IDS_APP_MANAGEMENT_UNINSTALL_APP}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); +} + +void AddParentalControlStrings(content::WebUIDataSource* html_source, + Profile* profile) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"parentalControlsPageTitle", IDS_SETTINGS_PARENTAL_CONTROLS_PAGE_TITLE}, + {"parentalControlsPageSetUpLabel", + IDS_SETTINGS_PARENTAL_CONTROLS_PAGE_SET_UP_LABEL}, + {"parentalControlsPageViewSettingsLabel", + IDS_SETTINGS_PARENTAL_CONTROLS_PAGE_VIEW_SETTINGS_LABEL}, + {"parentalControlsPageConnectToInternetLabel", + IDS_SETTINGS_PARENTAL_CONTROLS_PAGE_CONNECT_TO_INTERNET_LABEL}, + {"parentalControlsSetUpButtonLabel", + IDS_SETTINGS_PARENTAL_CONTROLS_SET_UP_BUTTON_LABEL}, + {"parentalControlsSetUpButtonRole", + IDS_SETTINGS_PARENTAL_CONTROLS_SET_UP_BUTTON_ROLE}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + html_source->AddBoolean( + "isChild", user_manager::UserManager::Get()->IsLoggedInAsChildUser()); + + if (user_manager::UserManager::Get()->IsLoggedInAsChildUser()) { + SupervisedUserService* supervised_user_service = + SupervisedUserServiceFactory::GetForProfile(profile); + std::string custodian = supervised_user_service->GetCustodianName(); + std::string second_custodian = + supervised_user_service->GetSecondCustodianName(); + + base::string16 child_managed_tooltip; + if (second_custodian.empty()) { + child_managed_tooltip = l10n_util::GetStringFUTF16( + IDS_SETTINGS_ACCOUNT_MANAGER_CHILD_MANAGED_BY_ONE_PARENT_TOOLTIP, + base::UTF8ToUTF16(custodian)); + } else { + child_managed_tooltip = l10n_util::GetStringFUTF16( + IDS_SETTINGS_ACCOUNT_MANAGER_CHILD_MANAGED_BY_TWO_PARENTS_TOOLTIP, + base::UTF8ToUTF16(custodian), base::UTF8ToUTF16(second_custodian)); + } + html_source->AddString("accountManagerPrimaryAccountChildManagedTooltip", + child_managed_tooltip); + } +} + +void AddBluetoothStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"bluetoothConnected", IDS_SETTINGS_BLUETOOTH_CONNECTED}, + {"bluetoothConnectedWithBattery", + IDS_SETTINGS_BLUETOOTH_CONNECTED_WITH_BATTERY}, + {"bluetoothConnecting", IDS_SETTINGS_BLUETOOTH_CONNECTING}, + {"bluetoothDeviceListPaired", IDS_SETTINGS_BLUETOOTH_DEVICE_LIST_PAIRED}, + {"bluetoothDeviceListUnpaired", + IDS_SETTINGS_BLUETOOTH_DEVICE_LIST_UNPAIRED}, + {"bluetoothConnect", IDS_SETTINGS_BLUETOOTH_CONNECT}, + {"bluetoothDisconnect", IDS_SETTINGS_BLUETOOTH_DISCONNECT}, + {"bluetoothToggleA11yLabel", + IDS_SETTINGS_BLUETOOTH_TOGGLE_ACCESSIBILITY_LABEL}, + {"bluetoothExpandA11yLabel", + IDS_SETTINGS_BLUETOOTH_EXPAND_ACCESSIBILITY_LABEL}, + {"bluetoothNoDevices", IDS_SETTINGS_BLUETOOTH_NO_DEVICES}, + {"bluetoothNoDevicesFound", IDS_SETTINGS_BLUETOOTH_NO_DEVICES_FOUND}, + {"bluetoothNotConnected", IDS_SETTINGS_BLUETOOTH_NOT_CONNECTED}, + {"bluetoothPageTitle", IDS_SETTINGS_BLUETOOTH}, + {"bluetoothPairDevicePageTitle", + IDS_SETTINGS_BLUETOOTH_PAIR_DEVICE_TITLE}, + {"bluetoothRemove", IDS_SETTINGS_BLUETOOTH_REMOVE}, + {"bluetoothPrimaryUserControlled", + IDS_SETTINGS_BLUETOOTH_PRIMARY_USER_CONTROLLED}, + {"bluetoothDeviceType_computer", + IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_COMPUTER}, + {"bluetoothDeviceType_phone", + IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_PHONE}, + {"bluetoothDeviceType_modem", + IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_MODEM}, + {"bluetoothDeviceType_audio", + IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_AUDIO}, + {"bluetoothDeviceType_carAudio", + IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_CAR_AUDIO}, + {"bluetoothDeviceType_video", + IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_VIDEO}, + {"bluetoothDeviceType_peripheral", + IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_PERIPHERAL}, + {"bluetoothDeviceType_joystick", + IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_JOYSTICK}, + {"bluetoothDeviceType_gamepad", + IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_GAMEPAD}, + {"bluetoothDeviceType_keyboard", + IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_KEYBOARD}, + {"bluetoothDeviceType_mouse", + IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_MOUSE}, + {"bluetoothDeviceType_tablet", + IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_TABLET}, + {"bluetoothDeviceType_keyboardMouseCombo", + IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_KEYBOARD_MOUSE_COMBO}, + {"bluetoothDeviceType_unknown", + IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_UNKNOWN}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + chromeos::bluetooth_dialog::AddLocalizedStrings(html_source); +} + +void AddChromeOSUserStrings(content::WebUIDataSource* html_source, + Profile* profile) { + user_manager::UserManager* user_manager = user_manager::UserManager::Get(); + + const user_manager::User* user = + chromeos::ProfileHelper::Get()->GetUserByProfile(profile); + const user_manager::User* primary_user = user_manager->GetPrimaryUser(); + std::string primary_user_email = primary_user->GetAccountId().GetUserEmail(); + html_source->AddString("primaryUserEmail", primary_user_email); + html_source->AddString("browserSettingsBannerText", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_BROWSER_SETTINGS_BANNER, + base::ASCIIToUTF16(chrome::kChromeUISettingsURL))); + html_source->AddBoolean("isActiveDirectoryUser", + user && user->IsActiveDirectoryUser()); + html_source->AddBoolean( + "isSecondaryUser", + user && user->GetAccountId() != primary_user->GetAccountId()); + html_source->AddString( + "secondaryUserBannerText", + l10n_util::GetStringFUTF16(IDS_SETTINGS_SECONDARY_USER_BANNER, + base::ASCIIToUTF16(primary_user_email))); + + if (!IsDeviceManaged() && !user_manager->IsCurrentUserOwner()) { + html_source->AddString("ownerEmail", + user_manager->GetOwnerAccountId().GetUserEmail()); + } +} + +void AddDevicePointersStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kPointersStrings[] = { + {"mouseTitle", IDS_SETTINGS_MOUSE_TITLE}, + {"touchpadTitle", IDS_SETTINGS_TOUCHPAD_TITLE}, + {"mouseAndTouchpadTitle", IDS_SETTINGS_MOUSE_AND_TOUCHPAD_TITLE}, + {"touchpadTapToClickEnabledLabel", + IDS_SETTINGS_TOUCHPAD_TAP_TO_CLICK_ENABLED_LABEL}, + {"touchpadSpeed", IDS_SETTINGS_TOUCHPAD_SPEED_LABEL}, + {"pointerSlow", IDS_SETTINGS_POINTER_SPEED_SLOW_LABEL}, + {"pointerFast", IDS_SETTINGS_POINTER_SPEED_FAST_LABEL}, + {"mouseScrollSpeed", IDS_SETTINGS_MOUSE_SCROLL_SPEED_LABEL}, + {"mouseSpeed", IDS_SETTINGS_MOUSE_SPEED_LABEL}, + {"mouseSwapButtons", IDS_SETTINGS_MOUSE_SWAP_BUTTONS_LABEL}, + {"mouseReverseScroll", IDS_SETTINGS_MOUSE_REVERSE_SCROLL_LABEL}, + {"mouseAccelerationLabel", IDS_SETTINGS_MOUSE_ACCELERATION_LABEL}, + {"mouseScrollAccelerationLabel", + IDS_SETTINGS_MOUSE_SCROLL_ACCELERATION_LABEL}, + {"touchpadAccelerationLabel", IDS_SETTINGS_TOUCHPAD_ACCELERATION_LABEL}, + {"touchpadScrollAccelerationLabel", + IDS_SETTINGS_TOUCHPAD_SCROLL_ACCELERATION_LABEL}, + {"touchpadScrollSpeed", IDS_SETTINGS_TOUCHPAD_SCROLL_SPEED_LABEL}, + }; + AddLocalizedStringsBulk(html_source, kPointersStrings); + + html_source->AddString("naturalScrollLearnMoreLink", + GetHelpUrlWithBoard(chrome::kNaturalScrollHelpURL)); + + html_source->AddBoolean( + "allowDisableMouseAcceleration", + base::FeatureList::IsEnabled(::features::kAllowDisableMouseAcceleration)); + html_source->AddBoolean( + "allowScrollSettings", + base::FeatureList::IsEnabled(features::kAllowScrollSettings)); +} + +void AddDeviceKeyboardStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString keyboard_strings[] = { + {"keyboardTitle", IDS_SETTINGS_KEYBOARD_TITLE}, + {"keyboardKeyCtrl", IDS_SETTINGS_KEYBOARD_KEY_LEFT_CTRL}, + {"keyboardKeyAlt", IDS_SETTINGS_KEYBOARD_KEY_LEFT_ALT}, + {"keyboardKeyCapsLock", IDS_SETTINGS_KEYBOARD_KEY_CAPS_LOCK}, + {"keyboardKeyCommand", IDS_SETTINGS_KEYBOARD_KEY_COMMAND}, + {"keyboardKeyDiamond", IDS_SETTINGS_KEYBOARD_KEY_DIAMOND}, + {"keyboardKeyEscape", IDS_SETTINGS_KEYBOARD_KEY_ESCAPE}, + {"keyboardKeyBackspace", IDS_SETTINGS_KEYBOARD_KEY_BACKSPACE}, + {"keyboardKeyAssistant", IDS_SETTINGS_KEYBOARD_KEY_ASSISTANT}, + {"keyboardKeyDisabled", IDS_SETTINGS_KEYBOARD_KEY_DISABLED}, + {"keyboardKeyExternalCommand", + IDS_SETTINGS_KEYBOARD_KEY_EXTERNAL_COMMAND}, + {"keyboardKeyExternalMeta", IDS_SETTINGS_KEYBOARD_KEY_EXTERNAL_META}, + {"keyboardKeyMeta", IDS_SETTINGS_KEYBOARD_KEY_META}, + {"keyboardSendFunctionKeys", IDS_SETTINGS_KEYBOARD_SEND_FUNCTION_KEYS}, + {"keyboardEnableAutoRepeat", IDS_SETTINGS_KEYBOARD_AUTO_REPEAT_ENABLE}, + {"keyRepeatDelay", IDS_SETTINGS_KEYBOARD_AUTO_REPEAT_DELAY}, + {"keyRepeatDelayLong", IDS_SETTINGS_KEYBOARD_AUTO_REPEAT_DELAY_LONG}, + {"keyRepeatDelayShort", IDS_SETTINGS_KEYBOARD_AUTO_REPEAT_DELAY_SHORT}, + {"keyRepeatRate", IDS_SETTINGS_KEYBOARD_AUTO_REPEAT_RATE}, + {"keyRepeatRateSlow", IDS_SETTINGS_KEYBOARD_AUTO_REPEAT_RATE_SLOW}, + {"keyRepeatRateFast", IDS_SETTINGS_KEYBOARD_AUTO_REPEAT_FAST}, + {"showKeyboardShortcutViewer", + IDS_SETTINGS_KEYBOARD_SHOW_SHORTCUT_VIEWER}, + {"keyboardShowLanguageAndInput", + IDS_SETTINGS_KEYBOARD_SHOW_LANGUAGE_AND_INPUT}, + }; + AddLocalizedStringsBulk(html_source, keyboard_strings); + + html_source->AddLocalizedString("keyboardKeySearch", + ui::DeviceUsesKeyboardLayout2() + ? IDS_SETTINGS_KEYBOARD_KEY_LAUNCHER + : IDS_SETTINGS_KEYBOARD_KEY_SEARCH); + html_source->AddLocalizedString( + "keyboardSendFunctionKeysDescription", + ui::DeviceUsesKeyboardLayout2() + ? IDS_SETTINGS_KEYBOARD_SEND_FUNCTION_KEYS_LAYOUT2_DESCRIPTION + : IDS_SETTINGS_KEYBOARD_SEND_FUNCTION_KEYS_DESCRIPTION); +} + +void AddDeviceStylusStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kStylusStrings[] = { + {"stylusTitle", IDS_SETTINGS_STYLUS_TITLE}, + {"stylusEnableStylusTools", IDS_SETTINGS_STYLUS_ENABLE_STYLUS_TOOLS}, + {"stylusAutoOpenStylusTools", IDS_SETTINGS_STYLUS_AUTO_OPEN_STYLUS_TOOLS}, + {"stylusFindMoreAppsPrimary", IDS_SETTINGS_STYLUS_FIND_MORE_APPS_PRIMARY}, + {"stylusFindMoreAppsSecondary", + IDS_SETTINGS_STYLUS_FIND_MORE_APPS_SECONDARY}, + {"stylusNoteTakingApp", IDS_SETTINGS_STYLUS_NOTE_TAKING_APP_LABEL}, + {"stylusNoteTakingAppEnabledOnLockScreen", + IDS_SETTINGS_STYLUS_NOTE_TAKING_APP_LOCK_SCREEN_CHECKBOX}, + {"stylusNoteTakingAppKeepsLastNoteOnLockScreen", + IDS_SETTINGS_STYLUS_NOTE_TAKING_APP_KEEP_LATEST_NOTE}, + {"stylusNoteTakingAppLockScreenSettingsHeader", + IDS_SETTINGS_STYLUS_LOCK_SCREEN_NOTES_TITLE}, + {"stylusNoteTakingAppNoneAvailable", + IDS_SETTINGS_STYLUS_NOTE_TAKING_APP_NONE_AVAILABLE}, + {"stylusNoteTakingAppWaitingForAndroid", + IDS_SETTINGS_STYLUS_NOTE_TAKING_APP_WAITING_FOR_ANDROID}}; + AddLocalizedStringsBulk(html_source, kStylusStrings); +} + +void AddDeviceDisplayStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kDisplayStrings[] = { + {"displayTitle", IDS_SETTINGS_DISPLAY_TITLE}, + {"displayArrangementText", IDS_SETTINGS_DISPLAY_ARRANGEMENT_TEXT}, + {"displayArrangementTitle", IDS_SETTINGS_DISPLAY_ARRANGEMENT_TITLE}, + {"displayMirror", IDS_SETTINGS_DISPLAY_MIRROR}, + {"displayMirrorDisplayName", IDS_SETTINGS_DISPLAY_MIRROR_DISPLAY_NAME}, + {"displayAmbientColorTitle", IDS_SETTINGS_DISPLAY_AMBIENT_COLOR_TITLE}, + {"displayAmbientColorSubtitle", + IDS_SETTINGS_DISPLAY_AMBIENT_COLOR_SUBTITLE}, + {"displayNightLightLabel", IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_LABEL}, + {"displayNightLightOnAtSunset", + IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_ON_AT_SUNSET}, + {"displayNightLightOffAtSunrise", + IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_OFF_AT_SUNRISE}, + {"displayNightLightScheduleCustom", + IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_SCHEDULE_CUSTOM}, + {"displayNightLightScheduleLabel", + IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_SCHEDULE_LABEL}, + {"displayNightLightScheduleNever", + IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_SCHEDULE_NEVER}, + {"displayNightLightScheduleSunsetToSunRise", + IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_SCHEDULE_SUNSET_TO_SUNRISE}, + {"displayNightLightStartTime", + IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_START_TIME}, + {"displayNightLightStopTime", IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_STOP_TIME}, + {"displayNightLightText", IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_TEXT}, + {"displayNightLightTemperatureLabel", + IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_TEMPERATURE_LABEL}, + {"displayNightLightTempSliderMaxLabel", + IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_TEMP_SLIDER_MAX_LABEL}, + {"displayNightLightTempSliderMinLabel", + IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_TEMP_SLIDER_MIN_LABEL}, + {"displayUnifiedDesktop", IDS_SETTINGS_DISPLAY_UNIFIED_DESKTOP}, + {"displayUnifiedDesktopOn", IDS_SETTINGS_DISPLAY_UNIFIED_DESKTOP_ON}, + {"displayUnifiedDesktopOff", IDS_SETTINGS_DISPLAY_UNIFIED_DESKTOP_OFF}, + {"displayResolutionTitle", IDS_SETTINGS_DISPLAY_RESOLUTION_TITLE}, + {"displayResolutionText", IDS_SETTINGS_DISPLAY_RESOLUTION_TEXT}, + {"displayResolutionTextBest", IDS_SETTINGS_DISPLAY_RESOLUTION_TEXT_BEST}, + {"displayResolutionTextNative", + IDS_SETTINGS_DISPLAY_RESOLUTION_TEXT_NATIVE}, + {"displayResolutionSublabel", IDS_SETTINGS_DISPLAY_RESOLUTION_SUBLABEL}, + {"displayResolutionMenuItem", IDS_SETTINGS_DISPLAY_RESOLUTION_MENU_ITEM}, + {"displayResolutionInterlacedMenuItem", + IDS_SETTINGS_DISPLAY_RESOLUTION_INTERLACED_MENU_ITEM}, + {"displayZoomTitle", IDS_SETTINGS_DISPLAY_ZOOM_TITLE}, + {"displayZoomSublabel", IDS_SETTINGS_DISPLAY_ZOOM_SUBLABEL}, + {"displayZoomValue", IDS_SETTINGS_DISPLAY_ZOOM_VALUE}, + {"displayZoomLogicalResolutionText", + IDS_SETTINGS_DISPLAY_ZOOM_LOGICAL_RESOLUTION_TEXT}, + {"displayZoomNativeLogicalResolutionNativeText", + IDS_SETTINGS_DISPLAY_ZOOM_LOGICAL_RESOLUTION_NATIVE_TEXT}, + {"displayZoomLogicalResolutionDefaultText", + IDS_SETTINGS_DISPLAY_ZOOM_LOGICAL_RESOLUTION_DEFAULT_TEXT}, + {"displaySizeSliderMinLabel", IDS_SETTINGS_DISPLAY_ZOOM_SLIDER_MINIMUM}, + {"displaySizeSliderMaxLabel", IDS_SETTINGS_DISPLAY_ZOOM_SLIDER_MAXIMUM}, + {"displayScreenTitle", IDS_SETTINGS_DISPLAY_SCREEN}, + {"displayScreenExtended", IDS_SETTINGS_DISPLAY_SCREEN_EXTENDED}, + {"displayScreenPrimary", IDS_SETTINGS_DISPLAY_SCREEN_PRIMARY}, + {"displayOrientation", IDS_SETTINGS_DISPLAY_ORIENTATION}, + {"displayOrientationStandard", IDS_SETTINGS_DISPLAY_ORIENTATION_STANDARD}, + {"displayOrientationAutoRotate", + IDS_SETTINGS_DISPLAY_ORIENTATION_AUTO_ROTATE}, + {"displayOverscanPageText", IDS_SETTINGS_DISPLAY_OVERSCAN_TEXT}, + {"displayOverscanPageTitle", IDS_SETTINGS_DISPLAY_OVERSCAN_TITLE}, + {"displayOverscanSubtitle", IDS_SETTINGS_DISPLAY_OVERSCAN_SUBTITLE}, + {"displayOverscanInstructions", + IDS_SETTINGS_DISPLAY_OVERSCAN_INSTRUCTIONS}, + {"displayOverscanResize", IDS_SETTINGS_DISPLAY_OVERSCAN_RESIZE}, + {"displayOverscanPosition", IDS_SETTINGS_DISPLAY_OVERSCAN_POSITION}, + {"displayOverscanReset", IDS_SETTINGS_DISPLAY_OVERSCAN_RESET}, + {"displayTouchCalibrationTitle", + IDS_SETTINGS_DISPLAY_TOUCH_CALIBRATION_TITLE}, + {"displayTouchCalibrationText", + IDS_SETTINGS_DISPLAY_TOUCH_CALIBRATION_TEXT}}; + AddLocalizedStringsBulk(html_source, kDisplayStrings); + + base::CommandLine& cmd = *base::CommandLine::ForCurrentProcess(); + html_source->AddBoolean("unifiedDesktopAvailable", + cmd.HasSwitch(::switches::kEnableUnifiedDesktop)); + + html_source->AddBoolean("listAllDisplayModes", + display::features::IsListAllDisplayModesEnabled()); + + html_source->AddBoolean("deviceSupportsAmbientColor", + ash::features::IsAllowAmbientEQEnabled()); + + html_source->AddBoolean( + "enableTouchCalibrationSetting", + cmd.HasSwitch(chromeos::switches::kEnableTouchCalibrationSetting)); + + html_source->AddBoolean("hasExternalTouchDevice", + display::HasExternalTouchscreenDevice()); +} + +void AddDeviceStorageStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kStorageStrings[] = { + {"storageTitle", IDS_SETTINGS_STORAGE_TITLE}, + {"storageItemInUse", IDS_SETTINGS_STORAGE_ITEM_IN_USE}, + {"storageItemAvailable", IDS_SETTINGS_STORAGE_ITEM_AVAILABLE}, + {"storageItemSystem", IDS_SETTINGS_STORAGE_ITEM_SYSTEM}, + {"storageItemMyFiles", IDS_SETTINGS_STORAGE_ITEM_MY_FILES}, + {"storageItemBrowsingData", IDS_SETTINGS_STORAGE_ITEM_BROWSING_DATA}, + {"storageItemApps", IDS_SETTINGS_STORAGE_ITEM_APPS}, + {"storageItemCrostini", IDS_SETTINGS_STORAGE_ITEM_CROSTINI}, + {"storageItemOtherUsers", IDS_SETTINGS_STORAGE_ITEM_OTHER_USERS}, + {"storageSizeComputing", IDS_SETTINGS_STORAGE_SIZE_CALCULATING}, + {"storageSizeUnknown", IDS_SETTINGS_STORAGE_SIZE_UNKNOWN}, + {"storageSpaceLowMessageTitle", + IDS_SETTINGS_STORAGE_SPACE_LOW_MESSAGE_TITLE}, + {"storageSpaceLowMessageLine1", + IDS_SETTINGS_STORAGE_SPACE_LOW_MESSAGE_LINE_1}, + {"storageSpaceLowMessageLine2", + IDS_SETTINGS_STORAGE_SPACE_LOW_MESSAGE_LINE_2}, + {"storageSpaceCriticallyLowMessageTitle", + IDS_SETTINGS_STORAGE_SPACE_CRITICALLY_LOW_MESSAGE_TITLE}, + {"storageSpaceCriticallyLowMessageLine1", + IDS_SETTINGS_STORAGE_SPACE_CRITICALLY_LOW_MESSAGE_LINE_1}, + {"storageSpaceCriticallyLowMessageLine2", + IDS_SETTINGS_STORAGE_SPACE_CRITICALLY_LOW_MESSAGE_LINE_2}, + {"storageExternal", IDS_SETTINGS_STORAGE_EXTERNAL}, + {"storageExternalStorageEmptyListHeader", + IDS_SETTINGS_STORAGE_EXTERNAL_STORAGE_EMPTY_LIST_HEADER}, + {"storageExternalStorageListHeader", + IDS_SETTINGS_STORAGE_EXTERNAL_STORAGE_LIST_HEADER}, + {"storageOverviewAriaLabel", IDS_SETTINGS_STORAGE_OVERVIEW_ARIA_LABEL}}; + AddLocalizedStringsBulk(html_source, kStorageStrings); + + html_source->AddString( + "storageAndroidAppsExternalDrivesNote", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_STORAGE_ANDROID_APPS_ACCESS_EXTERNAL_DRIVES_NOTE, + base::ASCIIToUTF16(chrome::kArcExternalStorageLearnMoreURL))); +} + +void AddDevicePowerStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kPowerStrings[] = { + {"powerTitle", IDS_SETTINGS_POWER_TITLE}, + {"powerSourceLabel", IDS_SETTINGS_POWER_SOURCE_LABEL}, + {"powerSourceBattery", IDS_SETTINGS_POWER_SOURCE_BATTERY}, + {"powerSourceAcAdapter", IDS_SETTINGS_POWER_SOURCE_AC_ADAPTER}, + {"powerSourceLowPowerCharger", + IDS_SETTINGS_POWER_SOURCE_LOW_POWER_CHARGER}, + {"calculatingPower", IDS_SETTINGS_POWER_SOURCE_CALCULATING}, + {"powerIdleLabel", IDS_SETTINGS_POWER_IDLE_LABEL}, + {"powerIdleWhileChargingLabel", + IDS_SETTINGS_POWER_IDLE_WHILE_CHARGING_LABEL}, + {"powerIdleWhileChargingAriaLabel", + IDS_SETTINGS_POWER_IDLE_WHILE_CHARGING_ARIA_LABEL}, + {"powerIdleWhileOnBatteryLabel", + IDS_SETTINGS_POWER_IDLE_WHILE_ON_BATTERY_LABEL}, + {"powerIdleWhileOnBatteryAriaLabel", + IDS_SETTINGS_POWER_IDLE_WHILE_ON_BATTERY_ARIA_LABEL}, + {"powerIdleDisplayOffSleep", IDS_SETTINGS_POWER_IDLE_DISPLAY_OFF_SLEEP}, + {"powerIdleDisplayOff", IDS_SETTINGS_POWER_IDLE_DISPLAY_OFF}, + {"powerIdleDisplayOn", IDS_SETTINGS_POWER_IDLE_DISPLAY_ON}, + {"powerIdleOther", IDS_SETTINGS_POWER_IDLE_OTHER}, + {"powerLidSleepLabel", IDS_SETTINGS_POWER_LID_CLOSED_SLEEP_LABEL}, + {"powerLidSignOutLabel", IDS_SETTINGS_POWER_LID_CLOSED_SIGN_OUT_LABEL}, + {"powerLidShutDownLabel", IDS_SETTINGS_POWER_LID_CLOSED_SHUT_DOWN_LABEL}, + }; + AddLocalizedStringsBulk(html_source, kPowerStrings); +} + +void AddDeviceStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kDeviceStrings[] = { + {"devicePageTitle", IDS_SETTINGS_DEVICE_TITLE}, + {"scrollLabel", IDS_SETTINGS_SCROLL_LABEL}, + {"touchPadScrollLabel", IDS_OS_SETTINGS_TOUCHPAD_REVERSE_SCROLL_LABEL}, + }; + AddLocalizedStringsBulk(html_source, kDeviceStrings); + + AddDevicePointersStrings(html_source); + AddDeviceKeyboardStrings(html_source); + AddDeviceStylusStrings(html_source); + AddDeviceDisplayStrings(html_source); + AddDeviceStorageStrings(html_source); + AddDevicePowerStrings(html_source); +} + +void AddFilesStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"disconnectGoogleDriveAccount", IDS_SETTINGS_DISCONNECT_GOOGLE_DRIVE}, + {"filesPageTitle", IDS_OS_SETTINGS_FILES}, + {"smbSharesTitle", IDS_SETTINGS_DOWNLOADS_SMB_SHARES}, + {"smbSharesLearnMoreLabel", + IDS_SETTINGS_DOWNLOADS_SMB_SHARES_LEARN_MORE_LABEL}, + {"addSmbShare", IDS_SETTINGS_DOWNLOADS_SMB_SHARES_ADD_SHARE}, + {"smbShareAddedSuccessfulMessage", + IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_SUCCESS_MESSAGE}, + {"smbShareAddedErrorMessage", + IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_ERROR_MESSAGE}, + {"smbShareAddedAuthFailedMessage", + IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_AUTH_FAILED_MESSAGE}, + {"smbShareAddedNotFoundMessage", + IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_NOT_FOUND_MESSAGE}, + {"smbShareAddedUnsupportedDeviceMessage", + IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_UNSUPPORTED_DEVICE_MESSAGE}, + {"smbShareAddedMountExistsMessage", + IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_MOUNT_EXISTS_MESSAGE}, + {"smbShareAddedTooManyMountsMessage", + IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_TOO_MANY_MOUNTS_MESSAGE}, + {"smbShareAddedInvalidURLMessage", + IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_MOUNT_INVALID_URL_MESSAGE}, + {"smbShareAddedInvalidSSOURLMessage", + IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_MOUNT_INVALID_SSO_URL_MESSAGE}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + chromeos::smb_dialog::AddLocalizedStrings(html_source); + + html_source->AddString("smbSharesLearnMoreURL", + GetHelpUrlWithBoard(chrome::kSmbSharesLearnMoreURL)); +} + +void AddEasyUnlockStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"easyUnlockSectionTitle", IDS_SETTINGS_EASY_UNLOCK_SECTION_TITLE}, + {"easyUnlockUnlockDeviceOnly", + IDS_SETTINGS_EASY_UNLOCK_UNLOCK_DEVICE_ONLY}, + {"easyUnlockUnlockDeviceAndAllowSignin", + IDS_SETTINGS_EASY_UNLOCK_UNLOCK_DEVICE_AND_ALLOW_SIGNIN}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); +} + +void AddMultideviceStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"multidevicePageTitle", IDS_SETTINGS_MULTIDEVICE}, + {"multideviceSetupButton", IDS_SETTINGS_MULTIDEVICE_SETUP_BUTTON}, + {"multideviceVerifyButton", IDS_SETTINGS_MULTIDEVICE_VERIFY_BUTTON}, + {"multideviceSetupItemHeading", + IDS_SETTINGS_MULTIDEVICE_SETUP_ITEM_HEADING}, + {"multideviceEnabled", IDS_SETTINGS_MULTIDEVICE_ENABLED}, + {"multideviceDisabled", IDS_SETTINGS_MULTIDEVICE_DISABLED}, + {"multideviceSmartLockItemTitle", IDS_SETTINGS_EASY_UNLOCK_SECTION_TITLE}, + {"multideviceInstantTetheringItemTitle", + IDS_SETTINGS_MULTIDEVICE_INSTANT_TETHERING}, + {"multideviceInstantTetheringItemSummary", + IDS_SETTINGS_MULTIDEVICE_INSTANT_TETHERING_SUMMARY}, + {"multideviceAndroidMessagesItemTitle", + IDS_SETTINGS_MULTIDEVICE_ANDROID_MESSAGES}, + {"multideviceForgetDevice", IDS_SETTINGS_MULTIDEVICE_FORGET_THIS_DEVICE}, + {"multideviceSmartLockOptions", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_OPTIONS_LOCK}, + {"multideviceForgetDeviceDisconnect", + IDS_SETTINGS_MULTIDEVICE_FORGET_THIS_DEVICE_DISCONNECT}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + html_source->AddString( + "multideviceForgetDeviceSummary", + ui::SubstituteChromeOSDeviceType( + IDS_SETTINGS_MULTIDEVICE_FORGET_THIS_DEVICE_EXPLANATION)); + html_source->AddString( + "multideviceForgetDeviceDialogMessage", + ui::SubstituteChromeOSDeviceType( + IDS_SETTINGS_MULTIDEVICE_FORGET_DEVICE_DIALOG_MESSAGE)); + html_source->AddString( + "multideviceVerificationText", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_MULTIDEVICE_VERIFICATION_TEXT, + base::UTF8ToUTF16( + chromeos::multidevice_setup:: + GetBoardSpecificBetterTogetherSuiteLearnMoreUrl() + .spec()))); + html_source->AddString( + "multideviceSetupSummary", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_MULTIDEVICE_SETUP_SUMMARY, ui::GetChromeOSDeviceName(), + base::UTF8ToUTF16( + chromeos::multidevice_setup:: + GetBoardSpecificBetterTogetherSuiteLearnMoreUrl() + .spec()))); + html_source->AddString( + "multideviceNoHostText", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_MULTIDEVICE_NO_ELIGIBLE_HOSTS, + base::UTF8ToUTF16( + chromeos::multidevice_setup:: + GetBoardSpecificBetterTogetherSuiteLearnMoreUrl() + .spec()))); + html_source->AddString( + "multideviceAndroidMessagesItemSummary", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_MULTIDEVICE_ANDROID_MESSAGES_SUMMARY, + ui::GetChromeOSDeviceName(), + base::UTF8ToUTF16(chromeos::multidevice_setup:: + GetBoardSpecificMessagesLearnMoreUrl() + .spec()))); + html_source->AddString( + "multideviceSmartLockItemSummary", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_MULTIDEVICE_SMART_LOCK_SUMMARY, + ui::GetChromeOSDeviceName(), + GetHelpUrlWithBoard(chrome::kEasyUnlockLearnMoreUrl))); + + AddEasyUnlockStrings(html_source); +} + +void AddKerberosAccountsPageStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"kerberosAccountsAddAccountLabel", + IDS_SETTINGS_KERBEROS_ACCOUNTS_ADD_ACCOUNT_LABEL}, + {"kerberosAccountsRefreshNowLabel", + IDS_SETTINGS_KERBEROS_ACCOUNTS_REFRESH_NOW_LABEL}, + {"kerberosAccountsSetAsActiveAccountLabel", + IDS_SETTINGS_KERBEROS_ACCOUNTS_SET_AS_ACTIVE_ACCOUNT_LABEL}, + {"kerberosAccountsSignedOut", IDS_SETTINGS_KERBEROS_ACCOUNTS_SIGNED_OUT}, + {"kerberosAccountsListHeader", + IDS_SETTINGS_KERBEROS_ACCOUNTS_LIST_HEADER}, + {"kerberosAccountsRemoveAccountLabel", + IDS_SETTINGS_KERBEROS_ACCOUNTS_REMOVE_ACCOUNT_LABEL}, + {"kerberosAccountsReauthenticationLabel", + IDS_SETTINGS_KERBEROS_ACCOUNTS_REAUTHENTICATION_LABEL}, + {"kerberosAccountsTicketActive", + IDS_SETTINGS_KERBEROS_ACCOUNTS_TICKET_ACTIVE}, + {"kerberosAccountsAccountRemovedTip", + IDS_SETTINGS_KERBEROS_ACCOUNTS_ACCOUNT_REMOVED_TIP}, + {"kerberosAccountsAccountRefreshedTip", + IDS_SETTINGS_KERBEROS_ACCOUNTS_ACCOUNT_REFRESHED_TIP}, + {"kerberosAccountsSignedIn", IDS_SETTINGS_KERBEROS_ACCOUNTS_SIGNED_IN}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + PrefService* local_state = g_browser_process->local_state(); + + // Whether new Kerberos accounts may be added. + html_source->AddBoolean( + "kerberosAddAccountsAllowed", + local_state->GetBoolean(prefs::kKerberosAddAccountsAllowed)); + + // Kerberos accounts page with "Learn more" link. + html_source->AddString( + "kerberosAccountsDescription", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_KERBEROS_ACCOUNTS_DESCRIPTION, + GetHelpUrlWithBoard(chrome::kKerberosAccountsLearnMoreURL))); +} + +void AddKerberosAddAccountDialogStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"kerberosAccountsAdvancedConfigLabel", + IDS_SETTINGS_KERBEROS_ACCOUNTS_ADVANCED_CONFIG_LABEL}, + {"kerberosAdvancedConfigTitle", + IDS_SETTINGS_KERBEROS_ADVANCED_CONFIG_TITLE}, + {"kerberosAdvancedConfigDesc", + IDS_SETTINGS_KERBEROS_ADVANCED_CONFIG_DESC}, + {"addKerberosAccountRememberPassword", + IDS_SETTINGS_ADD_KERBEROS_ACCOUNT_REMEMBER_PASSWORD}, + {"kerberosPassword", IDS_SETTINGS_KERBEROS_PASSWORD}, + {"kerberosUsername", IDS_SETTINGS_KERBEROS_USERNAME}, + {"addKerberosAccountDescription", + IDS_SETTINGS_ADD_KERBEROS_ACCOUNT_DESCRIPTION}, + {"kerberosErrorNetworkProblem", + IDS_SETTINGS_KERBEROS_ERROR_NETWORK_PROBLEM}, + {"kerberosErrorUsernameInvalid", + IDS_SETTINGS_KERBEROS_ERROR_USERNAME_INVALID}, + {"kerberosErrorUsernameUnknown", + IDS_SETTINGS_KERBEROS_ERROR_USERNAME_UNKNOWN}, + {"kerberosErrorDuplicatePrincipalName", + IDS_SETTINGS_KERBEROS_ERROR_DUPLICATE_PRINCIPAL_NAME}, + {"kerberosErrorContactingServer", + IDS_SETTINGS_KERBEROS_ERROR_CONTACTING_SERVER}, + {"kerberosErrorPasswordInvalid", + IDS_SETTINGS_KERBEROS_ERROR_PASSWORD_INVALID}, + {"kerberosErrorPasswordExpired", + IDS_SETTINGS_KERBEROS_ERROR_PASSWORD_EXPIRED}, + {"kerberosErrorKdcEncType", IDS_SETTINGS_KERBEROS_ERROR_KDC_ENC_TYPE}, + {"kerberosErrorGeneral", IDS_SETTINGS_KERBEROS_ERROR_GENERAL}, + {"kerberosConfigErrorSectionNestedInGroup", + IDS_SETTINGS_KERBEROS_CONFIG_ERROR_SECTION_NESTED_IN_GROUP}, + {"kerberosConfigErrorSectionSyntax", + IDS_SETTINGS_KERBEROS_CONFIG_ERROR_SECTION_SYNTAX}, + {"kerberosConfigErrorExpectedOpeningCurlyBrace", + IDS_SETTINGS_KERBEROS_CONFIG_ERROR_EXPECTED_OPENING_CURLY_BRACE}, + {"kerberosConfigErrorExtraCurlyBrace", + IDS_SETTINGS_KERBEROS_CONFIG_ERROR_EXTRA_CURLY_BRACE}, + {"kerberosConfigErrorRelationSyntax", + IDS_SETTINGS_KERBEROS_CONFIG_ERROR_RELATION_SYNTAX_ERROR}, + {"kerberosConfigErrorKeyNotSupported", + IDS_SETTINGS_KERBEROS_CONFIG_ERROR_KEY_NOT_SUPPORTED}, + {"kerberosConfigErrorSectionNotSupported", + IDS_SETTINGS_KERBEROS_CONFIG_ERROR_SECTION_NOT_SUPPORTED}, + {"kerberosConfigErrorKrb5FailedToParse", + IDS_SETTINGS_KERBEROS_CONFIG_ERROR_KRB5_FAILED_TO_PARSE}, + {"addKerberosAccountRefreshButtonLabel", + IDS_SETTINGS_ADD_KERBEROS_ACCOUNT_REFRESH_BUTTON_LABEL}, + {"addKerberosAccount", IDS_SETTINGS_ADD_KERBEROS_ACCOUNT}, + {"refreshKerberosAccount", IDS_SETTINGS_REFRESH_KERBEROS_ACCOUNT}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + PrefService* local_state = g_browser_process->local_state(); + + // Whether the 'Remember password' checkbox is enabled. + html_source->AddBoolean( + "kerberosRememberPasswordEnabled", + local_state->GetBoolean(prefs::kKerberosRememberPasswordEnabled)); + + // Kerberos default configuration. + html_source->AddString( + "defaultKerberosConfig", + chromeos::KerberosCredentialsManager::GetDefaultKerberosConfig()); +} + +void AddLockScreenPageStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"lockScreenNotificationTitle", + IDS_ASH_SETTINGS_LOCK_SCREEN_NOTIFICATION_TITLE}, + {"lockScreenNotificationHideSensitive", + IDS_ASH_SETTINGS_LOCK_SCREEN_NOTIFICATION_HIDE_SENSITIVE}, + {"enableScreenlock", IDS_SETTINGS_PEOPLE_ENABLE_SCREENLOCK}, + {"lockScreenNotificationShow", + IDS_ASH_SETTINGS_LOCK_SCREEN_NOTIFICATION_SHOW}, + {"lockScreenPinOrPassword", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_PIN_OR_PASSWORD}, + {"lockScreenSetupFingerprintButton", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_FINGERPRINT_SETUP_BUTTON}, + {"lockScreenNotificationHide", + IDS_ASH_SETTINGS_LOCK_SCREEN_NOTIFICATION_HIDE}, + {"lockScreenEditFingerprints", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_EDIT_FINGERPRINTS}, + {"lockScreenPasswordOnly", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_PASSWORD_ONLY}, + {"lockScreenChangePinButton", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_CHANGE_PIN_BUTTON}, + {"lockScreenEditFingerprintsDescription", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_EDIT_FINGERPRINTS_DESCRIPTION}, + {"lockScreenNumberFingerprints", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_NUM_FINGERPRINTS}, + {"lockScreenNone", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_NONE}, + {"lockScreenFingerprintNewName", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_NEW_FINGERPRINT_DEFAULT_NAME}, + {"lockScreenDeleteFingerprintLabel", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_DELETE_FINGERPRINT_ARIA_LABEL}, + {"lockScreenOptionsLock", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_OPTIONS_LOCK}, + {"lockScreenOptionsLoginLock", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_OPTIONS_LOGIN_LOCK}, + {"lockScreenSetupPinButton", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_SETUP_PIN_BUTTON}, + {"lockScreenTitleLock", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_TITLE_LOCK}, + {"lockScreenTitleLoginLock", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_TITLE_LOGIN_LOCK}, + {"passwordPromptEnterPasswordLock", + IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_ENTER_PASSWORD_LOCK}, + {"passwordPromptEnterPasswordLoginLock", + IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_ENTER_PASSWORD_LOGIN_LOCK}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); +} + +void AddUsersStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"usersModifiedByOwnerLabel", IDS_SETTINGS_USERS_MODIFIED_BY_OWNER_LABEL}, + {"guestBrowsingLabel", IDS_SETTINGS_USERS_GUEST_BROWSING_LABEL}, + {"settingsManagedLabel", IDS_SETTINGS_USERS_MANAGED_LABEL}, + {"showOnSigninLabel", IDS_SETTINGS_USERS_SHOW_ON_SIGNIN_LABEL}, + {"restrictSigninLabel", IDS_SETTINGS_USERS_RESTRICT_SIGNIN_LABEL}, + {"deviceOwnerLabel", IDS_SETTINGS_USERS_DEVICE_OWNER_LABEL}, + {"removeUserTooltip", IDS_SETTINGS_USERS_REMOVE_USER_TOOLTIP}, + {"addUsers", IDS_SETTINGS_USERS_ADD_USERS}, + {"addUsersEmail", IDS_SETTINGS_USERS_ADD_USERS_EMAIL}, + {"userExistsError", IDS_SETTINGS_USER_EXISTS_ERROR}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); +} + +void AddGoogleAssistantStrings(content::WebUIDataSource* html_source, + Profile* profile) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"googleAssistantPageTitle", IDS_SETTINGS_GOOGLE_ASSISTANT}, + {"googleAssistantEnableContext", IDS_ASSISTANT_SCREEN_CONTEXT_TITLE}, + {"googleAssistantEnableContextDescription", + IDS_ASSISTANT_SCREEN_CONTEXT_DESC}, + {"googleAssistantEnableHotword", + IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD}, + {"googleAssistantEnableHotwordDescription", + IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_DESCRIPTION}, + {"googleAssistantVoiceSettings", + IDS_SETTINGS_GOOGLE_ASSISTANT_VOICE_SETTINGS}, + {"googleAssistantVoiceSettingsDescription", + IDS_ASSISTANT_VOICE_MATCH_RECORDING}, + {"googleAssistantVoiceSettingsRetrainButton", + IDS_SETTINGS_GOOGLE_ASSISTANT_VOICE_SETTINGS_RETRAIN}, + {"googleAssistantEnableHotwordWithoutDspDescription", + IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_WITHOUT_DSP_DESCRIPTION}, + {"googleAssistantEnableHotwordWithoutDspRecommended", + IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_WITHOUT_DSP_RECOMMENDED}, + {"googleAssistantEnableHotwordWithoutDspAlwaysOn", + IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_WITHOUT_DSP_ALWAYS_ON}, + {"googleAssistantEnableHotwordWithoutDspOff", + IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_WITHOUT_DSP_OFF}, + {"googleAssistantEnableNotification", + IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_NOTIFICATION}, + {"googleAssistantEnableNotificationDescription", + IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_NOTIFICATION_DESCRIPTION}, + {"googleAssistantLaunchWithMicOpen", + IDS_SETTINGS_GOOGLE_ASSISTANT_LAUNCH_WITH_MIC_OPEN}, + {"googleAssistantLaunchWithMicOpenDescription", + IDS_SETTINGS_GOOGLE_ASSISTANT_LAUNCH_WITH_MIC_OPEN_DESCRIPTION}, + {"googleAssistantSettings", IDS_SETTINGS_GOOGLE_ASSISTANT_SETTINGS}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + html_source->AddBoolean("hotwordDspAvailable", + chromeos::IsHotwordDspAvailable()); + html_source->AddBoolean( + "voiceMatchDisabled", + chromeos::assistant::features::IsVoiceMatchDisabled()); +} + +void AddPrintingStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"printingPageTitle", IDS_SETTINGS_PRINTING}, + {"cupsPrintersTitle", IDS_SETTINGS_PRINTING_CUPS_PRINTERS}, + {"cupsPrintersLearnMoreLabel", + IDS_SETTINGS_PRINTING_CUPS_PRINTERS_LEARN_MORE_LABEL}, + {"addCupsPrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_ADD_PRINTER}, + {"editPrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_EDIT}, + {"removePrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_REMOVE}, + {"setupPrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTER_SETUP_BUTTON}, + {"setupPrinterAria", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_SETUP_BUTTON_ARIA}, + {"savePrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTER_SAVE_BUTTON}, + {"savePrinterAria", IDS_SETTINGS_PRINTING_CUPS_PRINTER_SAVE_BUTTON_ARIA}, + {"searchLabel", IDS_SETTINGS_PRINTING_CUPS_SEARCH_LABEL}, + {"noSearchResults", IDS_SEARCH_NO_RESULTS}, + {"printerDetailsTitle", IDS_SETTINGS_PRINTING_CUPS_PRINTER_DETAILS_TITLE}, + {"printerName", IDS_SETTINGS_PRINTING_CUPS_PRINTER_DETAILS_NAME}, + {"printerModel", IDS_SETTINGS_PRINTING_CUPS_PRINTER_DETAILS_MODEL}, + {"printerQueue", IDS_SETTINGS_PRINTING_CUPS_PRINTER_DETAILS_QUEUE}, + {"savedPrintersTitle", IDS_SETTINGS_PRINTING_CUPS_SAVED_PRINTERS_TITLE}, + {"savedPrintersCountMany", + IDS_SETTINGS_PRINTING_CUPS_PRINTERS_SAVED_PRINTERS_COUNT_MANY}, + {"savedPrintersCountOne", + IDS_SETTINGS_PRINTING_CUPS_PRINTERS_SAVED_PRINTERS_COUNT_ONE}, + {"savedPrintersCountNone", + IDS_SETTINGS_PRINTING_CUPS_PRINTERS_SAVED_PRINTERS_COUNT_NONE}, + {"showMorePrinters", IDS_SETTINGS_PRINTING_CUPS_SHOW_MORE}, + {"addPrintersNearbyTitle", + IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTERS_NEARBY_TITLE}, + {"addPrintersManuallyTitle", + IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTERS_MANUALLY_TITLE}, + {"manufacturerAndModelDialogTitle", + IDS_SETTINGS_PRINTING_CUPS_SELECT_MANUFACTURER_AND_MODEL_TITLE}, + {"nearbyPrintersListTitle", + IDS_SETTINGS_PRINTING_CUPS_PRINTERS_AVAILABLE_PRINTERS}, + {"nearbyPrintersCountMany", + IDS_SETTINGS_PRINTING_CUPS_PRINTERS_AVAILABLE_PRINTERS_COUNT_MANY}, + {"nearbyPrintersCountOne", + IDS_SETTINGS_PRINTING_CUPS_PRINTERS_AVAILABLE_PRINTER_COUNT_ONE}, + {"nearbyPrintersCountNone", + IDS_SETTINGS_PRINTING_CUPS_PRINTERS_AVAILABLE_PRINTER_COUNT_NONE}, + {"nearbyPrintersListDescription", + IDS_SETTINGS_PRINTING_CUPS_PRINTERS_ADD_DETECTED_OR_NEW_PRINTER}, + {"manufacturerAndModelAdditionalInformation", + IDS_SETTINGS_PRINTING_CUPS_MANUFACTURER_MODEL_ADDITIONAL_INFORMATION}, + {"addPrinterButtonText", + IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTER_BUTTON_ADD}, + {"printerDetailsAdvanced", IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADVANCED}, + {"printerDetailsA11yLabel", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADVANCED_ACCESSIBILITY_LABEL}, + {"printerAddress", IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADVANCED_ADDRESS}, + {"printerProtocol", IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADVANCED_PROTOCOL}, + {"printerURI", IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADVANCED_URI}, + {"manuallyAddPrinterButtonText", + IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTER_BUTTON_MANUAL_ADD}, + {"discoverPrintersButtonText", + IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTER_BUTTON_DISCOVER_PRINTERS}, + {"printerProtocolIpp", IDS_SETTINGS_PRINTING_CUPS_PRINTER_PROTOCOL_IPP}, + {"printerProtocolIpps", IDS_SETTINGS_PRINTING_CUPS_PRINTER_PROTOCOL_IPPS}, + {"printerProtocolHttp", IDS_SETTINGS_PRINTING_CUPS_PRINTER_PROTOCOL_HTTP}, + {"printerProtocolHttps", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_PROTOCOL_HTTPS}, + {"printerProtocolAppSocket", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_PROTOCOL_APP_SOCKET}, + {"printerProtocolLpd", IDS_SETTINGS_PRINTING_CUPS_PRINTER_PROTOCOL_LPD}, + {"printerProtocolUsb", IDS_SETTINGS_PRINTING_CUPS_PRINTER_PROTOCOL_USB}, + {"printerProtocolIppUsb", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_PROTOCOL_IPPUSB}, + {"printerConfiguringMessage", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_CONFIGURING_MESSAGE}, + {"printerManufacturer", IDS_SETTINGS_PRINTING_CUPS_PRINTER_MANUFACTURER}, + {"selectDriver", IDS_SETTINGS_PRINTING_CUPS_PRINTER_SELECT_DRIVER}, + {"selectDriverButtonText", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_BUTTON_SELECT_DRIVER}, + {"selectDriverButtonAriaLabel", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_BUTTON_SELECT_DRIVER_ARIA_LABEL}, + {"selectDriverErrorMessage", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_INVALID_DRIVER}, + {"printerAddedSuccessfulMessage", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_DONE_MESSAGE}, + {"printerEditedSuccessfulMessage", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_EDITED_PRINTER_DONE_MESSAGE}, + {"printerUnavailableMessage", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_UNAVAILABLE_MESSAGE}, + {"noPrinterNearbyMessage", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_NO_PRINTER_NEARBY}, + {"searchingNearbyPrinters", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_SEARCHING_NEARBY_PRINTER}, + {"printerAddedFailedMessage", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_ERROR_MESSAGE}, + {"printerAddedFatalErrorMessage", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_FATAL_ERROR_MESSAGE}, + {"printerAddedUnreachableMessage", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_PRINTER_UNREACHABLE_MESSAGE}, + {"printerAddedPpdTooLargeMessage", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_PPD_TOO_LARGE_MESSAGE}, + {"printerAddedInvalidPpdMessage", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_INVALID_PPD_MESSAGE}, + {"printerAddedPpdNotFoundMessage", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_PPD_NOT_FOUND}, + {"printerAddedPpdUnretrievableMessage", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_PPD_UNRETRIEVABLE}, + {"printerAddedNativePrintersNotAllowedMessage", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_NATIVE_PRINTERS_NOT_ALLOWED_MESSAGE}, + {"editPrinterInvalidPrinterUpdate", + IDS_SETTINGS_PRINTING_CUPS_EDIT_PRINTER_INVALID_PRINTER_UPDATE}, + {"requireNetworkMessage", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_REQUIRE_INTERNET_MESSAGE}, + {"checkNetworkMessage", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_CHECK_CONNECTION_MESSAGE}, + {"noInternetConnection", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_NO_INTERNET_CONNECTION}, + {"checkNetworkAndTryAgain", + IDS_SETTINGS_PRINTING_CUPS_PRINTER_CONNECT_TO_NETWORK_SUBTEXT}, + {"editPrinterDialogTitle", + IDS_SETTINGS_PRINTING_CUPS_EDIT_PRINTER_DIALOG_TITLE}, + {"editPrinterButtonText", IDS_SETTINGS_PRINTING_CUPS_EDIT_PRINTER_BUTTON}, + {"currentPpdMessage", + IDS_SETTINGS_PRINTING_CUPS_EDIT_PRINTER_CURRENT_PPD_MESSAGE}, + {"printerEulaNotice", IDS_SETTINGS_PRINTING_CUPS_EULA_NOTICE}, + {"ippPrinterUnreachable", IDS_SETTINGS_PRINTING_CUPS_IPP_URI_UNREACHABLE}, + {"generalPrinterDialogError", + IDS_SETTINGS_PRINTING_CUPS_DIALOG_GENERAL_ERROR}, + {"printServerButtonText", IDS_SETTINGS_PRINTING_CUPS_PRINT_SERVER}, + {"addPrintServerTitle", + IDS_SETTINGS_PRINTING_CUPS_ADD_PRINT_SERVER_TITLE}, + {"printServerAddress", IDS_SETTINGS_PRINTING_CUPS_PRINT_SERVER_ADDRESS}, + {"printServerFoundZeroPrinters", + IDS_SETTINGS_PRINTING_CUPS_PRINT_SERVER_FOUND_ZERO_PRINTERS}, + {"printServerFoundOnePrinter", + IDS_SETTINGS_PRINTING_CUPS_PRINT_SERVER_FOUND_ONE_PRINTER}, + {"printServerFoundManyPrinters", + IDS_SETTINGS_PRINTING_CUPS_PRINT_SERVER_FOUND_MANY_PRINTERS}, + {"printServerInvalidUrlAddress", + IDS_SETTINGS_PRINTING_CUPS_PRINT_SERVER_INVALID_URL_ADDRESS}, + {"printServerConnectionError", + IDS_SETTINGS_PRINTING_CUPS_PRINT_SERVER_CONNECTION_ERROR}, + {"printServerConfigurationErrorMessage", + IDS_SETTINGS_PRINTING_CUPS_PRINT_SERVER_REACHABLE_BUT_CANNOT_ADD}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + html_source->AddString("printingCUPSPrintLearnMoreUrl", + GetHelpUrlWithBoard(chrome::kCupsPrintLearnMoreURL)); + html_source->AddString( + "printingCUPSPrintPpdLearnMoreUrl", + GetHelpUrlWithBoard(chrome::kCupsPrintPPDLearnMoreURL)); + html_source->AddBoolean( + "consumerPrintServerUiEnabled", + base::FeatureList::IsEnabled(::features::kPrintServerUi)); +} + +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}, + // TODO(dpapad): IDS_DOWNLOAD_CLEAR_SEARCH and IDS_HISTORY_CLEAR_SEARCH + // are identical, merge them to one and re-use here. + {"clearSearch", IDS_DOWNLOAD_CLEAR_SEARCH}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + html_source->AddString( + "searchNoOsResultsHelp", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_SEARCH_NO_RESULTS_HELP, + base::ASCIIToUTF16(chrome::kOsSettingsSearchHelpURL))); + + html_source->AddBoolean( + "newOsSettingsSearch", + base::FeatureList::IsEnabled(chromeos::features::kNewOsSettingsSearch)); +} + +void AddDateTimeStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"dateTimePageTitle", IDS_SETTINGS_DATE_TIME}, + {"timeZone", IDS_SETTINGS_TIME_ZONE}, + {"selectTimeZoneResolveMethod", + IDS_SETTINGS_SELECT_TIME_ZONE_RESOLVE_METHOD}, + {"timeZoneGeolocation", IDS_SETTINGS_TIME_ZONE_GEOLOCATION}, + {"timeZoneButton", IDS_SETTINGS_TIME_ZONE_BUTTON}, + {"timeZoneSubpageTitle", IDS_SETTINGS_TIME_ZONE_SUBPAGE_TITLE}, + {"setTimeZoneAutomaticallyDisabled", + IDS_SETTINGS_TIME_ZONE_DETECTION_MODE_DISABLED}, + {"setTimeZoneAutomaticallyOn", + IDS_SETTINGS_TIME_ZONE_DETECTION_SET_AUTOMATICALLY}, + {"setTimeZoneAutomaticallyOff", + IDS_SETTINGS_TIME_ZONE_DETECTION_CHOOSE_FROM_LIST}, + {"setTimeZoneAutomaticallyIpOnlyDefault", + IDS_SETTINGS_TIME_ZONE_DETECTION_MODE_IP_ONLY_DEFAULT}, + {"setTimeZoneAutomaticallyWithWiFiAccessPointsData", + IDS_SETTINGS_TIME_ZONE_DETECTION_MODE_SEND_WIFI_AP}, + {"setTimeZoneAutomaticallyWithAllLocationInfo", + IDS_SETTINGS_TIME_ZONE_DETECTION_MODE_SEND_ALL_INFO}, + {"use24HourClock", IDS_SETTINGS_USE_24_HOUR_CLOCK}, + {"setDateTime", IDS_SETTINGS_SET_DATE_TIME}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + html_source->AddString( + "timeZoneSettingsLearnMoreURL", + base::ASCIIToUTF16(base::StringPrintf( + chrome::kTimeZoneSettingsLearnMoreURL, + g_browser_process->GetApplicationLocale().c_str()))); +} + +void AddAboutStrings(content::WebUIDataSource* html_source, Profile* profile) { + // Top level About page strings. + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"aboutProductLogoAlt", IDS_SHORT_PRODUCT_LOGO_ALT_TEXT}, +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) + {"aboutReportAnIssue", IDS_SETTINGS_ABOUT_PAGE_REPORT_AN_ISSUE}, +#endif + {"aboutRelaunch", IDS_SETTINGS_ABOUT_PAGE_RELAUNCH}, + {"aboutUpgradeCheckStarted", IDS_SETTINGS_ABOUT_UPGRADE_CHECK_STARTED}, + {"aboutUpgradeRelaunch", IDS_SETTINGS_UPGRADE_SUCCESSFUL_RELAUNCH}, + {"aboutUpgradeUpdating", IDS_SETTINGS_UPGRADE_UPDATING}, + {"aboutUpgradeUpdatingPercent", IDS_SETTINGS_UPGRADE_UPDATING_PERCENT}, + {"aboutGetHelpUsingChrome", IDS_SETTINGS_GET_HELP_USING_CHROME}, + {"aboutPageTitle", IDS_SETTINGS_ABOUT_PROGRAM}, + {"aboutProductTitle", IDS_PRODUCT_NAME}, + + {"aboutEndOfLifeTitle", IDS_SETTINGS_ABOUT_PAGE_END_OF_LIFE_TITLE}, + {"aboutRelaunchAndPowerwash", + IDS_SETTINGS_ABOUT_PAGE_RELAUNCH_AND_POWERWASH}, + {"aboutRollbackInProgress", IDS_SETTINGS_UPGRADE_ROLLBACK_IN_PROGRESS}, + {"aboutRollbackSuccess", IDS_SETTINGS_UPGRADE_ROLLBACK_SUCCESS}, + {"aboutUpgradeUpdatingChannelSwitch", + IDS_SETTINGS_UPGRADE_UPDATING_CHANNEL_SWITCH}, + {"aboutUpgradeSuccessChannelSwitch", + IDS_SETTINGS_UPGRADE_SUCCESSFUL_CHANNEL_SWITCH}, + {"aboutTPMFirmwareUpdateTitle", + IDS_SETTINGS_ABOUT_TPM_FIRMWARE_UPDATE_TITLE}, + {"aboutTPMFirmwareUpdateDescription", + IDS_SETTINGS_ABOUT_TPM_FIRMWARE_UPDATE_DESCRIPTION}, + + // About page, channel switcher dialog. + {"aboutChangeChannel", IDS_SETTINGS_ABOUT_PAGE_CHANGE_CHANNEL}, + {"aboutChangeChannelAndPowerwash", + IDS_SETTINGS_ABOUT_PAGE_CHANGE_CHANNEL_AND_POWERWASH}, + {"aboutDelayedWarningMessage", + IDS_SETTINGS_ABOUT_PAGE_DELAYED_WARNING_MESSAGE}, + {"aboutDelayedWarningTitle", IDS_SETTINGS_ABOUT_PAGE_DELAYED_WARNING_TITLE}, + {"aboutPowerwashWarningMessage", + IDS_SETTINGS_ABOUT_PAGE_POWERWASH_WARNING_MESSAGE}, + {"aboutPowerwashWarningTitle", + IDS_SETTINGS_ABOUT_PAGE_POWERWASH_WARNING_TITLE}, + {"aboutUnstableWarningMessage", + IDS_SETTINGS_ABOUT_PAGE_UNSTABLE_WARNING_MESSAGE}, + {"aboutUnstableWarningTitle", + IDS_SETTINGS_ABOUT_PAGE_UNSTABLE_WARNING_TITLE}, + {"aboutChannelDialogBeta", IDS_SETTINGS_ABOUT_PAGE_DIALOG_CHANNEL_BETA}, + {"aboutChannelDialogDev", IDS_SETTINGS_ABOUT_PAGE_DIALOG_CHANNEL_DEV}, + {"aboutChannelDialogStable", IDS_SETTINGS_ABOUT_PAGE_DIALOG_CHANNEL_STABLE}, + + // About page, update warning dialog. + {"aboutUpdateWarningMessage", + IDS_SETTINGS_ABOUT_PAGE_UPDATE_WARNING_MESSAGE}, + {"aboutUpdateWarningTitle", IDS_SETTINGS_ABOUT_PAGE_UPDATE_WARNING_TITLE}, + + // Detailed build information + {"aboutBuildDetailsTitle", IDS_OS_SETTINGS_ABOUT_PAGE_BUILD_DETAILS}, + {"aboutChannelBeta", IDS_SETTINGS_ABOUT_PAGE_CURRENT_CHANNEL_BETA}, + {"aboutChannelCanary", IDS_SETTINGS_ABOUT_PAGE_CURRENT_CHANNEL_CANARY}, + {"aboutChannelDev", IDS_SETTINGS_ABOUT_PAGE_CURRENT_CHANNEL_DEV}, + {"aboutChannelLabel", IDS_SETTINGS_ABOUT_PAGE_CHANNEL}, + {"aboutChannelStable", IDS_SETTINGS_ABOUT_PAGE_CURRENT_CHANNEL_STABLE}, + {"aboutCheckForUpdates", IDS_SETTINGS_ABOUT_PAGE_CHECK_FOR_UPDATES}, + {"aboutCurrentlyOnChannel", IDS_SETTINGS_ABOUT_PAGE_CURRENT_CHANNEL}, + {"aboutDetailedBuildInfo", IDS_SETTINGS_ABOUT_PAGE_DETAILED_BUILD_INFO}, + {version_ui::kApplicationLabel, IDS_PRODUCT_NAME}, + {version_ui::kPlatform, IDS_PLATFORM_LABEL}, + {version_ui::kFirmwareVersion, IDS_VERSION_UI_FIRMWARE_VERSION}, + {version_ui::kARC, IDS_ARC_LABEL}, + {"aboutBuildDetailsCopyTooltipLabel", + IDS_OS_SETTINGS_ABOUT_PAGE_BUILD_DETAILS_COPY_TOOLTIP_LABEL}, + {"aboutIsArcStatusTitle", IDS_OS_SETTINGS_ABOUT_ARC_STATUS_TITLE}, + {"aboutIsDeveloperModeTitle", IDS_OS_SETTINGS_ABOUT_DEVELOPER_MODE}, + {"isEnterpriseManagedTitle", + IDS_OS_SETTINGS_ABOUT_PAGE_ENTERPRISE_ENNROLLED_TITLE}, + {"aboutOsPageTitle", IDS_SETTINGS_ABOUT_OS}, + {"aboutGetHelpUsingChromeOs", IDS_SETTINGS_GET_HELP_USING_CHROME_OS}, + {"aboutOsProductTitle", IDS_PRODUCT_OS_NAME}, + {"aboutReleaseNotesOffline", IDS_SETTINGS_ABOUT_PAGE_RELEASE_NOTES}, + {"aboutShowReleaseNotes", IDS_SETTINGS_ABOUT_PAGE_SHOW_RELEASE_NOTES}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + html_source->AddString("aboutTPMFirmwareUpdateLearnMoreURL", + chrome::kTPMFirmwareUpdateLearnMoreURL); + html_source->AddString( + "aboutUpgradeUpToDate", + ui::SubstituteChromeOSDeviceType(IDS_SETTINGS_UPGRADE_UP_TO_DATE)); + html_source->AddString("managementPage", + ManagementUI::GetManagementPageSubtitle(profile)); +} + +void AddResetStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"resetPageTitle", IDS_SETTINGS_RESET}, + {"powerwashTitle", IDS_SETTINGS_FACTORY_RESET}, + {"powerwashDialogTitle", IDS_SETTINGS_FACTORY_RESET_HEADING}, + {"powerwashDialogButton", IDS_SETTINGS_RESTART}, + {"powerwashButton", IDS_SETTINGS_FACTORY_RESET_BUTTON_LABEL}, + {"powerwashDialogExplanation", IDS_SETTINGS_FACTORY_RESET_WARNING}, + {"powerwashLearnMoreUrl", IDS_FACTORY_RESET_HELP_URL}, + {"powerwashButtonRoleDescription", + IDS_SETTINGS_FACTORY_RESET_BUTTON_ROLE}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + html_source->AddString( + "powerwashDescription", + l10n_util::GetStringFUTF16(IDS_SETTINGS_FACTORY_RESET_DESCRIPTION, + l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); +} + +void AddSearchStrings(content::WebUIDataSource* html_source, Profile* profile) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"osSearchEngineLabel", IDS_OS_SETTINGS_SEARCH_ENGINE_LABEL}, + {"searchGoogleAssistant", IDS_SETTINGS_SEARCH_GOOGLE_ASSISTANT}, + {"searchGoogleAssistantEnabled", + IDS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_ENABLED}, + {"searchGoogleAssistantDisabled", + IDS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_DISABLED}, + {"searchGoogleAssistantOn", IDS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_ON}, + {"searchGoogleAssistantOff", IDS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_OFF}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + // NOTE: This will be false when the flag is disabled. + const bool is_assistant_allowed = + ::assistant::IsAssistantAllowedForProfile(profile) == + ash::mojom::AssistantAllowedState::ALLOWED; + html_source->AddBoolean("isAssistantAllowed", is_assistant_allowed); + html_source->AddLocalizedString("osSearchPageTitle", + is_assistant_allowed + ? IDS_SETTINGS_SEARCH_AND_ASSISTANT + : IDS_SETTINGS_SEARCH); + html_source->AddString("searchExplanation", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_SEARCH_EXPLANATION, + base::ASCIIToUTF16(chrome::kOmniboxLearnMoreURL))); + html_source->AddString( + "osSearchEngineTooltip", + ui::SubstituteChromeOSDeviceType(IDS_OS_SETTINGS_SEARCH_ENGINE_TOOLTIP)); +} + +void AddPrivacyStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"privacyPageTitle", IDS_SETTINGS_PRIVACY}, + {"enableLogging", IDS_SETTINGS_ENABLE_LOGGING_PREF}, + {"enableLoggingDesc", IDS_SETTINGS_ENABLE_LOGGING_PREF_DESC}, + {"wakeOnWifi", IDS_SETTINGS_WAKE_ON_WIFI_DESCRIPTION}, + {"enableContentProtectionAttestation", + IDS_SETTINGS_ENABLE_CONTENT_PROTECTION_ATTESTATION}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + html_source->AddString("syncAndGoogleServicesLearnMoreURL", + chrome::kSyncAndGoogleServicesLearnMoreURL); + ::settings::AddPersonalizationOptionsStrings(html_source); +} + +void AddPeoplePageStrings(content::WebUIDataSource* html_source, + Profile* profile) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"osPeoplePageTitle", IDS_OS_SETTINGS_PEOPLE}, + {"accountManagerSubMenuLabel", + IDS_SETTINGS_ACCOUNT_MANAGER_SUBMENU_LABEL}, + {"accountManagerPageTitle", IDS_SETTINGS_ACCOUNT_MANAGER_PAGE_TITLE}, + {"kerberosAccountsSubMenuLabel", + IDS_SETTINGS_KERBEROS_ACCOUNTS_SUBMENU_LABEL}, + {"accountManagerPageTitle", IDS_SETTINGS_ACCOUNT_MANAGER_PAGE_TITLE}, + {"kerberosAccountsPageTitle", IDS_SETTINGS_KERBEROS_ACCOUNTS_PAGE_TITLE}, + {"lockScreenFingerprintTitle", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_FINGERPRINT_SUBPAGE_TITLE}, + {"manageOtherPeople", IDS_SETTINGS_PEOPLE_MANAGE_OTHER_PEOPLE}, + {"osSyncPageTitle", IDS_OS_SETTINGS_SYNC_PAGE_TITLE}, + {"syncAndNonPersonalizedServices", + IDS_SETTINGS_SYNC_SYNC_AND_NON_PERSONALIZED_SERVICES}, + {"syncDisconnectConfirm", IDS_SETTINGS_SYNC_DISCONNECT_CONFIRM}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + // Toggles the Chrome OS Account Manager submenu in the People section. + html_source->AddBoolean("isAccountManagerEnabled", + chromeos::IsAccountManagerAvailable(profile)); + + if (chromeos::features::IsSplitSyncConsentEnabled()) { + static constexpr webui::LocalizedString kTurnOffStrings[] = { + {"syncDisconnect", IDS_SETTINGS_PEOPLE_SYNC_TURN_OFF}, + {"syncDisconnectTitle", + IDS_SETTINGS_TURN_OFF_SYNC_AND_SIGN_OUT_DIALOG_TITLE}, + }; + AddLocalizedStringsBulk(html_source, kTurnOffStrings); + } else { + static constexpr webui::LocalizedString kSignOutStrings[] = { + {"syncDisconnect", IDS_SETTINGS_PEOPLE_SIGN_OUT}, + {"syncDisconnectTitle", IDS_SETTINGS_SYNC_DISCONNECT_TITLE}, + }; + AddLocalizedStringsBulk(html_source, kSignOutStrings); + } + + std::string sync_dashboard_url = + google_util::AppendGoogleLocaleParam( + GURL(chrome::kSyncGoogleDashboardURL), + g_browser_process->GetApplicationLocale()) + .spec(); + + html_source->AddString( + "syncDisconnectExplanation", + l10n_util::GetStringFUTF8(IDS_SETTINGS_SYNC_DISCONNECT_EXPLANATION, + base::ASCIIToUTF16(sync_dashboard_url))); + + AddAccountManagerPageStrings(html_source); + AddKerberosAccountsPageStrings(html_source); + AddKerberosAddAccountDialogStrings(html_source); + AddLockScreenPageStrings(html_source); + AddFingerprintListStrings(html_source); + AddFingerprintStrings(html_source); + AddSetupFingerprintDialogStrings(html_source); + AddSetupPinDialogStrings(html_source); + AddSyncControlsStrings(html_source); + + ::settings::AddSyncControlsStrings(html_source); + ::settings::AddSyncAccountControlStrings(html_source); + ::settings::AddPasswordPromptDialogStrings(html_source); + ::settings::AddSyncPageStrings(html_source); +} + +void AddPageVisibilityStrings(content::WebUIDataSource* html_source) { + PrefService* local_state = g_browser_process->local_state(); + // Toggles the Chrome OS Kerberos Accounts submenu in the People section. + // Note that the handler is also dependent on this pref. + html_source->AddBoolean("isKerberosEnabled", + local_state->GetBoolean(prefs::kKerberosEnabled)); +} + +} // namespace + +OsSettingsLocalizedStringsProvider::OsSettingsLocalizedStringsProvider( + Profile* profile, + local_search_service::mojom::LocalSearchService* local_search_service) { + local_search_service->GetIndex( + local_search_service::mojom::LocalSearchService::IndexId::CROS_SETTINGS, + index_remote_.BindNewPipeAndPassReceiver()); + + // Add per-page string providers. + // TODO(khorimoto): Add providers for the remaining pages. + per_page_providers_.push_back( + std::make_unique<InternetStringsProvider>(profile, /*delegate=*/this)); +} + +OsSettingsLocalizedStringsProvider::~OsSettingsLocalizedStringsProvider() = + default; + +void OsSettingsLocalizedStringsProvider::AddOsLocalizedStrings( + content::WebUIDataSource* html_source, + Profile* profile) { + for (const auto& per_page_provider : per_page_providers_) + per_page_provider->AddUiStrings(html_source); + + // TODO(khorimoto): Migrate these to OsSettingsPerPageStringsProvider + // instances. + AddAboutStrings(html_source, profile); + AddA11yStrings(html_source); + AddAndroidAppStrings(html_source); + AddAppManagementStrings(html_source); + AddAppsStrings(html_source); + AddBluetoothStrings(html_source); + AddChromeOSUserStrings(html_source, profile); + AddCommonStrings(html_source, profile); + AddCrostiniStrings(html_source, profile); + AddDateTimeStrings(html_source); + AddDeviceStrings(html_source); + AddFilesStrings(html_source); + AddGoogleAssistantStrings(html_source, profile); + AddLanguagesStrings(html_source); + AddMultideviceStrings(html_source); + AddParentalControlStrings(html_source, profile); + AddPageVisibilityStrings(html_source); + AddPeoplePageStrings(html_source, profile); + AddPersonalizationStrings(html_source); + AddPluginVmStrings(html_source, profile); + AddPrintingStrings(html_source); + AddPrivacyStrings(html_source); + AddResetStrings(html_source); + AddSearchInSettingsStrings(html_source); + AddSearchStrings(html_source, profile); + AddUsersStrings(html_source); + + policy_indicator::AddLocalizedStrings(html_source); + + html_source->UseStringsJs(); +} + +const SearchConcept* +OsSettingsLocalizedStringsProvider::GetCanonicalTagMetadata( + int canonical_message_id) const { + const auto it = canonical_id_to_metadata_map_.find(canonical_message_id); + if (it == canonical_id_to_metadata_map_.end()) + return nullptr; + return it->second; +} + +void OsSettingsLocalizedStringsProvider::Shutdown() { + index_remote_.reset(); +} + +void OsSettingsLocalizedStringsProvider::AddSearchTags( + const std::vector<SearchConcept>& tags_group) { + index_remote_->AddOrUpdate(ConceptVectorToDataPtrVector(tags_group), + /*callback=*/base::DoNothing()); + + // Add each concept to the map. Note that it is safe to take the address of + // each concept because all concepts are allocated via static + // base::NoDestructor objects in the Get*SearchConcepts() helper functions. + for (const auto& concept : tags_group) + canonical_id_to_metadata_map_[concept.canonical_message_id] = &concept; +} + +void OsSettingsLocalizedStringsProvider::RemoveSearchTags( + const std::vector<SearchConcept>& tags_group) { + std::vector<std::string> ids; + for (const auto& concept : tags_group) { + canonical_id_to_metadata_map_.erase(concept.canonical_message_id); + ids.push_back(base::NumberToString(concept.canonical_message_id)); + } + + index_remote_->Delete(ids, /*callback=*/base::DoNothing()); +} + +} // namespace settings +} // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.h b/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.h new file mode 100644 index 00000000000..c0d8c5adcd2 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.h @@ -0,0 +1,91 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_OS_SETTINGS_LOCALIZED_STRINGS_PROVIDER_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_OS_SETTINGS_LOCALIZED_STRINGS_PROVIDER_H_ + +#include <memory> +#include <unordered_map> +#include <vector> + +#include "chrome/browser/ui/webui/settings/chromeos/os_settings_per_page_strings_provider.h" +#include "chrome/services/local_search_service/public/mojom/local_search_service.mojom.h" +#include "components/keyed_service/core/keyed_service.h" +#include "mojo/public/cpp/bindings/remote.h" + +class Profile; + +namespace content { +class WebUIDataSource; +} // namespace content + +namespace chromeos { +namespace settings { + +struct SearchConcept; + +// Provides two types of localized strings for OS settings: +// +// (1) UI strings: Strings displayed in the normal settings UI. This contains +// strings such as headers, labels, instructional notes, etc. These strings +// are added directly to the settings app's WebUIDataSource before the app +// starts up via the static AddOsLocalizedStrings() function and are +// accessible within settings via loadTimeData. +// +// (2) Search tags: Strings used as potential matches for user search queries +// within settings. These strings don't appear in the normal UI; instead, +// they specify actions which can be taken in settings. When a user types a +// search query in settings, we compare the query against these strings to +// look for potential matches. For each potential search result, there is a +// "canonical" tag which represents a common phrase, and zero or more +// alternate phrases (e.g., canonical: "Display settings", alternate: +// "Monitor settings"). +// +// Since some of the settings sections may be unavailable (e.g., we don't +// show Bluetooth settings unless the device has Bluetooth capabilities), +// these strings are added/removed according to the Add/Remove*SearchTags() +// instance functions. +class OsSettingsLocalizedStringsProvider + : public KeyedService, + public OsSettingsPerPageStringsProvider::Delegate { + public: + OsSettingsLocalizedStringsProvider( + Profile* profile, + local_search_service::mojom::LocalSearchService* local_search_service); + OsSettingsLocalizedStringsProvider( + const OsSettingsLocalizedStringsProvider& other) = delete; + OsSettingsLocalizedStringsProvider& operator=( + const OsSettingsLocalizedStringsProvider& other) = delete; + ~OsSettingsLocalizedStringsProvider() override; + + // Adds the strings needed by the OS settings page to |html_source| + // This function causes |html_source| to expose a strings.js file from its + // source which contains a mapping from string's name to its translated value. + void AddOsLocalizedStrings(content::WebUIDataSource* html_source, + Profile* profile); + + // Returns the tag metadata associated with |canonical_message_id|, which must + // be one of the canonical IDS_SETTINGS_TAG_* identifiers used for a search + // tag. If no metadata is available or if |canonical_message_id| instead + // refers to an alternate tag's ID, null is returned. + const SearchConcept* GetCanonicalTagMetadata(int canonical_message_id) const; + + private: + // KeyedService: + void Shutdown() override; + + // OsSettingsPerPageStringsProvider::Delegate: + void AddSearchTags(const std::vector<SearchConcept>& tags_group) override; + void RemoveSearchTags(const std::vector<SearchConcept>& tags_group) override; + + std::vector<std::unique_ptr<OsSettingsPerPageStringsProvider>> + per_page_providers_; + mojo::Remote<local_search_service::mojom::Index> index_remote_; + std::unordered_map<int, const SearchConcept*> canonical_id_to_metadata_map_; +}; + +} // namespace settings +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_OS_SETTINGS_LOCALIZED_STRINGS_PROVIDER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider_factory.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider_factory.cc new file mode 100644 index 00000000000..8375790e5ca --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider_factory.cc @@ -0,0 +1,66 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/chromeos/os_settings_localized_strings_provider_factory.h" + +#include "chrome/browser/local_search_service/local_search_service_proxy.h" +#include "chrome/browser/local_search_service/local_search_service_proxy_factory.h" +#include "chrome/browser/profiles/incognito_helpers.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" + +namespace chromeos { +namespace settings { + +// static +OsSettingsLocalizedStringsProvider* +OsSettingsLocalizedStringsProviderFactory::GetForProfile(Profile* profile) { + return static_cast<OsSettingsLocalizedStringsProvider*>( + OsSettingsLocalizedStringsProviderFactory::GetInstance() + ->GetServiceForBrowserContext(profile, /*create=*/true)); +} + +// static +OsSettingsLocalizedStringsProviderFactory* +OsSettingsLocalizedStringsProviderFactory::GetInstance() { + return base::Singleton<OsSettingsLocalizedStringsProviderFactory>::get(); +} + +OsSettingsLocalizedStringsProviderFactory:: + OsSettingsLocalizedStringsProviderFactory() + : BrowserContextKeyedServiceFactory( + "OsSettingsLocalizedStringsProvider", + BrowserContextDependencyManager::GetInstance()) { + DependsOn( + local_search_service::LocalSearchServiceProxyFactory::GetInstance()); +} + +OsSettingsLocalizedStringsProviderFactory:: + ~OsSettingsLocalizedStringsProviderFactory() = default; + +KeyedService* +OsSettingsLocalizedStringsProviderFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + Profile* profile = Profile::FromBrowserContext(context); + return new OsSettingsLocalizedStringsProvider( + profile, + local_search_service::LocalSearchServiceProxyFactory::GetForProfile( + Profile::FromBrowserContext(profile)) + ->GetLocalSearchService()); +} + +bool OsSettingsLocalizedStringsProviderFactory::ServiceIsNULLWhileTesting() + const { + return true; +} + +content::BrowserContext* +OsSettingsLocalizedStringsProviderFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return chrome::GetBrowserContextOwnInstanceInIncognito(context); +} + +} // namespace settings +} // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider_factory.h b/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider_factory.h new file mode 100644 index 00000000000..d1b7df331e2 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider_factory.h @@ -0,0 +1,47 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_OS_SETTINGS_LOCALIZED_STRINGS_PROVIDER_FACTORY_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_OS_SETTINGS_LOCALIZED_STRINGS_PROVIDER_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +class Profile; + +namespace chromeos { +namespace settings { + +class OsSettingsLocalizedStringsProvider; + +class OsSettingsLocalizedStringsProviderFactory + : public BrowserContextKeyedServiceFactory { + public: + static OsSettingsLocalizedStringsProvider* GetForProfile(Profile* profile); + static OsSettingsLocalizedStringsProviderFactory* GetInstance(); + + private: + friend struct base::DefaultSingletonTraits< + OsSettingsLocalizedStringsProviderFactory>; + + OsSettingsLocalizedStringsProviderFactory(); + ~OsSettingsLocalizedStringsProviderFactory() override; + + OsSettingsLocalizedStringsProviderFactory( + const OsSettingsLocalizedStringsProviderFactory&) = delete; + OsSettingsLocalizedStringsProviderFactory& operator=( + const OsSettingsLocalizedStringsProviderFactory&) = delete; + + // BrowserContextKeyedServiceFactory: + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; + bool ServiceIsNULLWhileTesting() const override; + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; +}; + +} // namespace settings +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_OS_SETTINGS_LOCALIZED_STRINGS_PROVIDER_FACTORY_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider_unittest.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider_unittest.cc new file mode 100644 index 00000000000..c8eb26b6746 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider_unittest.cc @@ -0,0 +1,104 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/chromeos/os_settings_localized_strings_provider.h" + +#include "base/run_loop.h" +#include "chrome/browser/ui/webui/settings/chromeos/search/search_concept.h" +#include "chrome/common/webui_url_constants.h" +#include "chrome/grit/generated_resources.h" +#include "chrome/services/local_search_service/local_search_service_impl.h" +#include "chrome/services/local_search_service/public/mojom/local_search_service.mojom-test-utils.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/testing_profile.h" +#include "chrome/test/base/testing_profile_manager.h" +#include "chromeos/network/network_state_test_helper.h" +#include "chromeos/services/network_config/public/cpp/cros_network_config_test_helper.h" +#include "content/public/test/browser_task_environment.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/cros_system_api/dbus/shill/dbus-constants.h" + +namespace chromeos { +namespace settings { + +class OsSettingsLocalizedStringsProviderTest : public testing::Test { + protected: + OsSettingsLocalizedStringsProviderTest() + : profile_manager_(TestingBrowserProcess::GetGlobal()) {} + ~OsSettingsLocalizedStringsProviderTest() override = default; + + // testing::Test: + void SetUp() override { + ASSERT_TRUE(profile_manager_.SetUp()); + + provider_ = std::make_unique<OsSettingsLocalizedStringsProvider>( + profile_manager_.CreateTestingProfile("TestingProfile"), + &local_search_service_); + + local_search_service_.GetIndex( + local_search_service::mojom::LocalSearchService::IndexId::CROS_SETTINGS, + index_remote_.BindNewPipeAndPassReceiver()); + + // Allow asynchronous networking code to complete (networking functionality + // is tested below). + base::RunLoop().RunUntilIdle(); + } + + content::BrowserTaskEnvironment task_environment_; + TestingProfileManager profile_manager_; + chromeos::network_config::CrosNetworkConfigTestHelper network_config_helper_; + mojo::Remote<local_search_service::mojom::Index> index_remote_; + local_search_service::LocalSearchServiceImpl local_search_service_; + std::unique_ptr<OsSettingsLocalizedStringsProvider> provider_; +}; + +// To prevent this from becoming a change-detector test, this test simply +// verifies that when the provider starts up, it adds *some* strings without +// checking the exact number. It also checks one specific canonical tag. +TEST_F(OsSettingsLocalizedStringsProviderTest, WifiTags) { + uint64_t initial_num_items = 0; + local_search_service::mojom::IndexAsyncWaiter(index_remote_.get()) + .GetSize(&initial_num_items); + EXPECT_GT(initial_num_items, 0u); + + const SearchConcept* network_settings_concept = + provider_->GetCanonicalTagMetadata(IDS_SETTINGS_TAG_NETWORK_SETTINGS); + ASSERT_TRUE(network_settings_concept); + EXPECT_EQ(chrome::kNetworksSubPage, + network_settings_concept->url_path_with_parameters); + EXPECT_EQ(mojom::SearchResultIcon::kWifi, network_settings_concept->icon); + + // Ethernet is not present by default, so no Ethernet concepts have yet been + // added. + const SearchConcept* ethernet_settings_concept = + provider_->GetCanonicalTagMetadata(IDS_SETTINGS_TAG_ETHERNET_SETTINGS); + ASSERT_FALSE(ethernet_settings_concept); + + // Add Ethernet and let asynchronous handlers run. This should cause Ethernet + // tags to be added. + network_config_helper_.network_state_helper().device_test()->AddDevice( + "/device/stub_eth_device", shill::kTypeEthernet, "stub_eth_device"); + base::RunLoop().RunUntilIdle(); + + uint64_t num_items_after_adding_ethernet = 0; + local_search_service::mojom::IndexAsyncWaiter(index_remote_.get()) + .GetSize(&num_items_after_adding_ethernet); + EXPECT_GT(num_items_after_adding_ethernet, initial_num_items); + + ethernet_settings_concept = + provider_->GetCanonicalTagMetadata(IDS_SETTINGS_TAG_ETHERNET_SETTINGS); + ASSERT_TRUE(ethernet_settings_concept); + EXPECT_EQ(chrome::kEthernetSettingsSubPage, + ethernet_settings_concept->url_path_with_parameters); + EXPECT_EQ(mojom::SearchResultIcon::kEthernet, + ethernet_settings_concept->icon); +} + +// Note that other tests do not need to be added for different group of tags, +// since these tests would only be verifying the contents of +// os_settings_localized_strings_provider.cc. + +} // namespace settings +} // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_per_page_strings_provider.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_per_page_strings_provider.cc new file mode 100644 index 00000000000..26ac31b8cf6 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_per_page_strings_provider.cc @@ -0,0 +1,32 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/chromeos/os_settings_per_page_strings_provider.h" + +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" +#include "base/system/sys_info.h" + +namespace chromeos { +namespace settings { + +// static +base::string16 OsSettingsPerPageStringsProvider::GetHelpUrlWithBoard( + const std::string& original_url) { + return base::ASCIIToUTF16(original_url + + "&b=" + base::SysInfo::GetLsbReleaseBoard()); +} + +OsSettingsPerPageStringsProvider::~OsSettingsPerPageStringsProvider() = default; + +OsSettingsPerPageStringsProvider::OsSettingsPerPageStringsProvider( + Profile* profile, + Delegate* delegate) + : profile_(profile), delegate_(delegate) { + DCHECK(profile); + DCHECK(delegate); +} + +} // namespace settings +} // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_per_page_strings_provider.h b/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_per_page_strings_provider.h new file mode 100644 index 00000000000..c2a6771c85b --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_per_page_strings_provider.h @@ -0,0 +1,73 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_OS_SETTINGS_PER_PAGE_STRINGS_PROVIDER_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_OS_SETTINGS_PER_PAGE_STRINGS_PROVIDER_H_ + +#include <string> +#include <vector> + +#include "base/strings/string16.h" +#include "chrome/browser/ui/webui/settings/chromeos/search/search_concept.h" + +class Profile; + +namespace content { +class WebUIDataSource; +} // namespace content + +namespace chromeos { +namespace settings { + +// Provides strings for an individual page in OS settings (i.e., each subpage is +// expected to have its own implementation. Responsible for two types of +// strings: +// +// (1) UI strings: Strings (e.g., headers, labels) displayed in the settings UI. +// Added to a WebUIDataSource via the pure virtual AddUiStrings() function. +// +// (2) Search tags: Strings used as potential matches for user search queries +// within settings. Added/removed via the {Add|Remove}SearchTagsGroup +// delegate functions. Tags which are always searchable should be added in +// the class' constructor; however, tags which apply to content which is +// dynamically shown/hidden should be added when that content is visible and +// removed when the content is no longer visible. +class OsSettingsPerPageStringsProvider { + public: + class Delegate { + public: + ~Delegate() = default; + virtual void AddSearchTags( + const std::vector<SearchConcept>& tags_group) = 0; + virtual void RemoveSearchTags( + const std::vector<SearchConcept>& tags_group) = 0; + }; + + virtual ~OsSettingsPerPageStringsProvider(); + + OsSettingsPerPageStringsProvider( + const OsSettingsPerPageStringsProvider& other) = delete; + OsSettingsPerPageStringsProvider& operator=( + const OsSettingsPerPageStringsProvider& other) = delete; + + // Adds strings to be displayed in the UI via loadTimeData. + virtual void AddUiStrings(content::WebUIDataSource* html_source) const = 0; + + protected: + static base::string16 GetHelpUrlWithBoard(const std::string& original_url); + + OsSettingsPerPageStringsProvider(Profile* profile, Delegate* delegate); + + Profile* profile() { return profile_; } + Delegate* delegate() { return delegate_; } + + private: + Profile* profile_; + Delegate* delegate_; +}; + +} // namespace settings +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_OS_SETTINGS_PER_PAGE_STRINGS_PROVIDER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc index a91606bde11..dd4edc8807a 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc @@ -11,14 +11,32 @@ #include <utility> #include <vector> +#include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/network_config_service.h" #include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h" +#include "ash/public/cpp/stylus_utils.h" #include "base/bind.h" +#include "base/bind_helpers.h" #include "base/feature_list.h" +#include "base/memory/ptr_util.h" +#include "base/metrics/histogram_functions.h" #include "build/build_config.h" -#include "chrome/browser/ui/web_applications/system_web_app_ui_utils.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/browser_process_platform_part.h" +#include "chrome/browser/chromeos/account_manager/account_manager_util.h" +#include "chrome/browser/chromeos/arc/arc_util.h" +#include "chrome/browser/chromeos/crostini/crostini_features.h" +#include "chrome/browser/chromeos/login/demo_mode/demo_session.h" +#include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h" +#include "chrome/browser/chromeos/multidevice_setup/multidevice_setup_client_factory.h" +#include "chrome/browser/chromeos/plugin_vm/plugin_vm_pref_names.h" +#include "chrome/browser/chromeos/plugin_vm/plugin_vm_util.h" +#include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/signin/identity_manager_factory.h" +#include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/webui/app_management/app_management.mojom.h" #include "chrome/browser/ui/webui/app_management/app_management_page_handler.h" +#include "chrome/browser/ui/webui/chromeos/smb_shares/smb_handler.h" #include "chrome/browser/ui/webui/chromeos/sync/os_sync_handler.h" #include "chrome/browser/ui/webui/managed_ui_handler.h" #include "chrome/browser/ui/webui/metrics_handler.h" @@ -26,7 +44,33 @@ #include "chrome/browser/ui/webui/settings/about_handler.h" #include "chrome/browser/ui/webui/settings/accessibility_main_handler.h" #include "chrome/browser/ui/webui/settings/browser_lifetime_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/account_manager_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/ambient_mode_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/android_apps_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/crostini_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/date_time_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/device_pointer_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/device_power_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/device_storage_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/fingerprint_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/internet_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/multidevice_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.h" +#include "chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider_factory.h" #include "chrome/browser/ui/webui/settings/chromeos/parental_controls_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/plugin_vm_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/pref_names.h" +#include "chrome/browser/ui/webui/settings/chromeos/quick_unlock_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/search/search_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/search/search_handler_factory.h" +#include "chrome/browser/ui/webui/settings/chromeos/search/settings_user_action_tracker.h" #include "chrome/browser/ui/webui/settings/chromeos/wallpaper_handler.h" #include "chrome/browser/ui/webui/settings/downloads_handler.h" #include "chrome/browser/ui/webui/settings/extension_control_handler.h" @@ -40,7 +84,9 @@ #include "chrome/browser/ui/webui/settings/settings_cookies_view_handler.h" #include "chrome/browser/ui/webui/settings/settings_localized_strings_provider.h" #include "chrome/browser/ui/webui/settings/settings_media_devices_selection_handler.h" -#include "chrome/browser/ui/webui/settings/settings_ui.h" +#include "chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.h" +#include "chrome/browser/ui/webui/settings/tts_handler.h" +#include "chrome/browser/ui/webui/webui_util.h" #include "chrome/browser/web_applications/system_web_app_manager.h" #include "chrome/common/chrome_features.h" #include "chrome/common/webui_url_constants.h" @@ -48,17 +94,36 @@ #include "chrome/grit/generated_resources.h" #include "chrome/grit/os_settings_resources.h" #include "chrome/grit/os_settings_resources_map.h" +#include "chromeos/components/account_manager/account_manager.h" +#include "chromeos/components/account_manager/account_manager_factory.h" +#include "chromeos/components/web_applications/manifest_request_filter.h" #include "chromeos/constants/chromeos_features.h" +#include "chromeos/constants/chromeos_pref_names.h" +#include "chromeos/login/auth/password_visibility_utils.h" +#include "chromeos/services/multidevice_setup/public/cpp/prefs.h" #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h" #include "components/password_manager/core/common/password_manager_features.h" +#include "components/pref_registry/pref_registry_syncable.h" +#include "components/prefs/pref_service.h" #include "content/public/browser/web_ui_data_source.h" +#include "media/base/media_switches.h" #include "mojo/public/cpp/bindings/pending_receiver.h" +#include "ui/base/webui/web_ui_util.h" +#include "ui/chromeos/resources/grit/ui_chromeos_resources.h" +#include "ui/resources/grit/webui_resources.h" namespace chromeos { namespace settings { +// static +void OSSettingsUI::RegisterProfilePrefs( + user_prefs::PrefRegistrySyncable* registry) { + registry->RegisterBooleanPref(prefs::kSyncOsWallpaper, false); +} + OSSettingsUI::OSSettingsUI(content::WebUI* web_ui) : ui::MojoWebUIController(web_ui, /*enable_chrome_send=*/true), + time_when_opened_(base::TimeTicks::Now()), webui_load_timer_(web_ui->GetWebContents(), "ChromeOS.Settings.LoadDocumentTime", "ChromeOS.Settings.LoadCompletedTime") { @@ -66,7 +131,7 @@ OSSettingsUI::OSSettingsUI(content::WebUI* web_ui) content::WebUIDataSource* html_source = content::WebUIDataSource::Create(chrome::kChromeUIOSSettingsHost); - ::settings::SettingsUI::InitOSWebUIHandlers(profile, web_ui, html_source); + InitOSWebUIHandlers(html_source); // This handler is for chrome://os-settings. html_source->AddBoolean("isOSSettings", true); @@ -78,6 +143,9 @@ OSSettingsUI::OSSettingsUI(content::WebUI* web_ui) html_source->AddBoolean( "showParentalControls", chromeos::settings::ShouldShowParentalControls(profile)); + html_source->AddBoolean( + "syncSetupFriendlySettings", + base::FeatureList::IsEnabled(::features::kSyncSetupFriendlySettings)); AddSettingsPageUIHandler( std::make_unique<::settings::AccessibilityMainHandler>()); @@ -103,19 +171,17 @@ OSSettingsUI::OSSettingsUI(content::WebUI* web_ui) std::make_unique<::settings::ProtocolHandlersHandler>()); AddSettingsPageUIHandler( std::make_unique<::settings::SearchEnginesHandler>(profile)); - AddSettingsPageUIHandler( - std::make_unique<chromeos::settings::WallpaperHandler>(web_ui)); html_source->AddBoolean("showAppManagement", base::FeatureList::IsEnabled( ::features::kAppManagement)); html_source->AddBoolean("splitSettingsSyncEnabled", chromeos::features::IsSplitSettingsSyncEnabled()); + html_source->AddBoolean("splitSyncConsent", + chromeos::features::IsSplitSyncConsentEnabled()); -#if defined(OS_CHROMEOS) html_source->AddBoolean( "isSupportedArcVersion", AppManagementPageHandler::IsCurrentArcVersionSupported(profile)); -#endif // OS_CHROMEOS AddSettingsPageUIHandler( base::WrapUnique(::settings::AboutHandler::Create(html_source, profile))); @@ -126,7 +192,6 @@ OSSettingsUI::OSSettingsUI(content::WebUI* web_ui) web_ui->AddMessageHandler(std::make_unique<MetricsHandler>()); // Add the System Web App resources for Settings. - // TODO(jamescook|calamity): Migrate to chromeos::settings::OSSettingsUI. if (web_app::SystemWebAppManager::IsEnabled()) { html_source->AddResourcePath("icon-192.png", IDR_SETTINGS_LOGO_192); html_source->AddResourcePath("pwa.html", IDR_PWA_HTML); @@ -151,18 +216,37 @@ OSSettingsUI::OSSettingsUI(content::WebUI* web_ui) #endif html_source->AddResourcePath("app-management/app_management.mojom-lite.js", - IDR_APP_MANAGEMENT_MOJO_LITE_JS); - html_source->AddResourcePath("app-management/types.mojom-lite.js", - IDR_APP_MANAGEMENT_TYPES_MOJO_LITE_JS); - html_source->AddResourcePath("app-management/bitmap.mojom-lite.js", - IDR_APP_MANAGEMENT_BITMAP_MOJO_LITE_JS); - html_source->AddResourcePath("app-management/image.mojom-lite.js", - IDR_APP_MANAGEMENT_IMAGE_MOJO_LITE_JS); - html_source->AddResourcePath("app-management/image_info.mojom-lite.js", - IDR_APP_MANAGEMENT_IMAGE_INFO_MOJO_LITE_JS); - - ::settings::AddLocalizedStrings(html_source, profile, - web_ui->GetWebContents()); + IDR_OS_SETTINGS_APP_MANAGEMENT_MOJO_LITE_JS); + html_source->AddResourcePath( + "app-management/types.mojom-lite.js", + IDR_OS_SETTINGS_APP_MANAGEMENT_TYPES_MOJO_LITE_JS); + html_source->AddResourcePath( + "app-management/bitmap.mojom-lite.js", + IDR_OS_SETTINGS_APP_MANAGEMENT_BITMAP_MOJO_LITE_JS); + html_source->AddResourcePath( + "app-management/file_path.mojom-lite.js", + IDR_OS_SETTINGS_APP_MANAGEMENT_FILE_PATH_MOJO_LITE_JS); + html_source->AddResourcePath( + "app-management/image.mojom-lite.js", + IDR_OS_SETTINGS_APP_MANAGEMENT_IMAGE_MOJO_LITE_JS); + html_source->AddResourcePath( + "app-management/image_info.mojom-lite.js", + IDR_OS_SETTINGS_APP_MANAGEMENT_IMAGE_INFO_MOJO_LITE_JS); + + html_source->AddResourcePath( + "search/user_action_recorder.mojom-lite.js", + IDR_OS_SETTINGS_USER_ACTION_RECORDER_MOJOM_LITE_JS); + html_source->AddResourcePath( + "search/search_result_icon.mojom-lite.js", + IDR_OS_SETTINGS_SEARCH_RESULT_ICON_MOJOM_LITE_JS); + html_source->AddResourcePath("search/search.mojom-lite.js", + IDR_OS_SETTINGS_SEARCH_MOJOM_LITE_JS); + + // AddOsLocalizedStrings must be added after AddBrowserLocalizedStrings + // as repeated keys used by the OS strings should override the same keys + // that may be used in the Browser string provider. + OsSettingsLocalizedStringsProviderFactory::GetForProfile(profile) + ->AddOsLocalizedStrings(html_source, profile); auto plural_string_handler = std::make_unique<PluralStringHandler>(); plural_string_handler->AddLocalizedString("profileLabel", @@ -173,16 +257,210 @@ OSSettingsUI::OSSettingsUI(content::WebUI* web_ui) content::WebUIDataSource::Add(web_ui->GetWebContents()->GetBrowserContext(), html_source); +} - AddHandlerToRegistry(base::BindRepeating(&OSSettingsUI::BindCrosNetworkConfig, - base::Unretained(this))); - - AddHandlerToRegistry( - base::BindRepeating(&OSSettingsUI::BindAppManagementPageHandlerFactory, - base::Unretained(this))); +OSSettingsUI::~OSSettingsUI() { + // Note: OSSettingsUI lifetime is tied to the lifetime of the browser window. + base::UmaHistogramCustomTimes("ChromeOS.Settings.WindowOpenDuration", + base::TimeTicks::Now() - time_when_opened_, + /*min=*/base::TimeDelta::FromMicroseconds(500), + /*max=*/base::TimeDelta::FromHours(1), + /*buckets=*/50); } -OSSettingsUI::~OSSettingsUI() = default; +void OSSettingsUI::InitOSWebUIHandlers(content::WebUIDataSource* html_source) { + Profile* profile = Profile::FromWebUI(web_ui()); + + // TODO(jamescook): Sort out how account management is split between Chrome OS + // and browser settings. + if (chromeos::IsAccountManagerAvailable(profile)) { + chromeos::AccountManagerFactory* factory = + g_browser_process->platform_part()->GetAccountManagerFactory(); + chromeos::AccountManager* account_manager = + factory->GetAccountManager(profile->GetPath().value()); + DCHECK(account_manager); + + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::AccountManagerUIHandler>( + account_manager, IdentityManagerFactory::GetForProfile(profile))); + html_source->AddBoolean( + "secondaryGoogleAccountSigninAllowed", + profile->GetPrefs()->GetBoolean( + chromeos::prefs::kSecondaryGoogleAccountSigninAllowed)); + html_source->AddBoolean("isEduCoexistenceEnabled", + features::IsEduCoexistenceEnabled()); + } + + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::ChangePictureHandler>()); + + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::AccessibilityHandler>(profile)); + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::AndroidAppsHandler>(profile)); + if (crostini::CrostiniFeatures::Get()->IsUIAllowed(profile, + /*check_policy=*/false)) { + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::CrostiniHandler>(profile)); + } + web_ui()->AddMessageHandler( + chromeos::settings::CupsPrintersHandler::Create(web_ui())); + web_ui()->AddMessageHandler(base::WrapUnique( + chromeos::settings::DateTimeHandler::Create(html_source))); + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::FingerprintHandler>(profile)); + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::GoogleAssistantHandler>(profile)); + + std::unique_ptr<chromeos::settings::KerberosAccountsHandler> + kerberos_accounts_handler = + chromeos::settings::KerberosAccountsHandler::CreateIfKerberosEnabled( + profile); + if (kerberos_accounts_handler) { + // Note that the UI is enabled only if Kerberos is enabled. + web_ui()->AddMessageHandler(std::move(kerberos_accounts_handler)); + } + + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::KeyboardHandler>()); + + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::WallpaperHandler>(web_ui())); + + // If |!allow_plugin_vm| we still want to |show_plugin_vm| if the VM image is + // on disk, so that users are still able to delete the image at will. + const bool allow_plugin_vm = plugin_vm::IsPluginVmAllowedForProfile(profile); + const bool show_plugin_vm = + allow_plugin_vm || + profile->GetPrefs()->GetBoolean(plugin_vm::prefs::kPluginVmImageExists); + + if (show_plugin_vm) { + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::PluginVmHandler>(profile)); + } + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::PointerHandler>()); + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::QuickUnlockHandler>()); + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::StorageHandler>(profile, + html_source)); + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::StylusHandler>()); + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::InternetHandler>(profile)); + web_ui()->AddMessageHandler(std::make_unique<::settings::TtsHandler>()); + web_ui()->AddMessageHandler( + std::make_unique<chromeos::smb_dialog::SmbHandler>(profile, + base::DoNothing())); + + if (!profile->IsGuestSession()) { + chromeos::android_sms::AndroidSmsService* android_sms_service = + chromeos::android_sms::AndroidSmsServiceFactory::GetForBrowserContext( + profile); + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::MultideviceHandler>( + profile->GetPrefs(), + chromeos::multidevice_setup::MultiDeviceSetupClientFactory:: + GetForProfile(profile), + android_sms_service + ? android_sms_service->android_sms_pairing_state_tracker() + : nullptr, + android_sms_service ? android_sms_service->android_sms_app_manager() + : nullptr)); + if (chromeos::settings::ShouldShowParentalControls(profile)) { + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::ParentalControlsHandler>( + profile)); + } + + if (chromeos::features::IsAmbientModeEnabled()) { + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::AmbientModeHandler>()); + } + } + + html_source->AddBoolean( + "privacySettingsRedesignEnabled", + base::FeatureList::IsEnabled(::features::kPrivacySettingsRedesign)); + + html_source->AddBoolean( + "multideviceAllowedByPolicy", + chromeos::multidevice_setup::AreAnyMultiDeviceFeaturesAllowed( + profile->GetPrefs())); + html_source->AddBoolean( + "quickUnlockEnabled", + chromeos::quick_unlock::IsPinEnabled(profile->GetPrefs())); + html_source->AddBoolean( + "quickUnlockDisabledByPolicy", + chromeos::quick_unlock::IsPinDisabledByPolicy(profile->GetPrefs())); + html_source->AddBoolean( + "userCannotManuallyEnterPassword", + !chromeos::password_visibility::AccountHasUserFacingPassword( + chromeos::ProfileHelper::Get() + ->GetUserByProfile(profile) + ->GetAccountId())); + const bool fingerprint_unlock_enabled = + chromeos::quick_unlock::IsFingerprintEnabled(profile); + html_source->AddBoolean("fingerprintUnlockEnabled", + fingerprint_unlock_enabled); + if (fingerprint_unlock_enabled) { + html_source->AddInteger( + "fingerprintReaderLocation", + static_cast<int32_t>(chromeos::quick_unlock::GetFingerprintLocation())); + + // To use lottie, the worker-src CSP needs to be updated for the web ui that + // is using it. Since as of now there are only a couple of webuis using + // lottie animations, this update has to be performed manually. As the usage + // increases, set this as the default so manual override is no longer + // required. + html_source->OverrideContentSecurityPolicyWorkerSrc( + "worker-src blob: 'self';"); + html_source->AddResourcePath("finger_print.json", + IDR_LOGIN_FINGER_PRINT_TABLET_ANIMATION); + } + html_source->AddBoolean("lockScreenNotificationsEnabled", + ash::features::IsLockScreenNotificationsEnabled()); + html_source->AddBoolean( + "lockScreenHideSensitiveNotificationsSupported", + ash::features::IsLockScreenHideSensitiveNotificationsSupported()); + html_source->AddBoolean("showTechnologyBadge", + !ash::features::IsSeparateNetworkIconsEnabled()); + html_source->AddBoolean("hasInternalStylus", + ash::stylus_utils::HasInternalStylus()); + + html_source->AddBoolean("showCrostini", + crostini::CrostiniFeatures::Get()->IsUIAllowed( + profile, /*check_policy=*/false)); + + html_source->AddBoolean( + "allowCrostini", crostini::CrostiniFeatures::Get()->IsUIAllowed(profile)); + + html_source->AddBoolean("allowPluginVm", allow_plugin_vm); + html_source->AddBoolean("showPluginVm", show_plugin_vm); + + html_source->AddBoolean("isDemoSession", + chromeos::DemoSession::IsDeviceInDemoMode()); + + // We have 2 variants of Android apps settings. Default case, when the Play + // Store app exists we show expandable section that allows as to + // enable/disable the Play Store and link to Android settings which is + // available once settings app is registered in the system. + // For AOSP images we don't have the Play Store app. In last case we Android + // apps settings consists only from root link to Android settings and only + // visible once settings app is registered. + html_source->AddBoolean("androidAppsVisible", + arc::IsArcAllowedForProfile(profile)); + html_source->AddBoolean("havePlayStoreApp", arc::IsPlayStoreAvailable()); + + html_source->AddBoolean("enablePowerSettings", true); + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::PowerHandler>(profile->GetPrefs())); + + html_source->AddBoolean( + "showParentalControlsSettings", + chromeos::settings::ShouldShowParentalControls(profile)); +} void OSSettingsUI::AddSettingsPageUIHandler( std::unique_ptr<content::WebUIMessageHandler> handler) { @@ -190,12 +468,24 @@ void OSSettingsUI::AddSettingsPageUIHandler( web_ui()->AddMessageHandler(std::move(handler)); } -void OSSettingsUI::BindCrosNetworkConfig( +void OSSettingsUI::BindInterface( mojo::PendingReceiver<network_config::mojom::CrosNetworkConfig> receiver) { ash::GetNetworkConfigService(std::move(receiver)); } -void OSSettingsUI::BindAppManagementPageHandlerFactory( +void OSSettingsUI::BindInterface( + mojo::PendingReceiver<mojom::UserActionRecorder> receiver) { + user_action_recorder_ = + std::make_unique<SettingsUserActionTracker>(std::move(receiver)); +} + +void OSSettingsUI::BindInterface( + mojo::PendingReceiver<mojom::SearchHandler> receiver) { + SearchHandlerFactory::GetForProfile(Profile::FromWebUI(web_ui())) + ->BindInterface(std::move(receiver)); +} + +void OSSettingsUI::BindInterface( mojo::PendingReceiver<app_management::mojom::PageHandlerFactory> receiver) { if (!app_management_page_handler_factory_) { app_management_page_handler_factory_ = @@ -205,5 +495,7 @@ void OSSettingsUI::BindAppManagementPageHandlerFactory( app_management_page_handler_factory_->Bind(std::move(receiver)); } +WEB_UI_CONTROLLER_TYPE_IMPL(OSSettingsUI) + } // namespace settings } // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.h b/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.h index ff325c20bc3..c72c6b57c22 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.h +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.h @@ -8,40 +8,75 @@ #include <memory> #include "base/macros.h" +#include "base/time/time.h" #include "chrome/browser/ui/webui/app_management/app_management.mojom-forward.h" #include "chrome/browser/ui/webui/settings/chromeos/app_management/app_management_page_handler_factory.h" +#include "chrome/browser/ui/webui/settings/chromeos/search/user_action_recorder.mojom-forward.h" #include "chrome/browser/ui/webui/webui_load_timer.h" #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom-forward.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "ui/webui/mojo_web_ui_controller.h" namespace content { +class WebUIDataSource; class WebUIMessageHandler; -} +} // namespace content + +namespace user_prefs { +class PrefRegistrySyncable; +} // namespace user_prefs namespace chromeos { namespace settings { +namespace mojom { +class SearchHandler; +} // namespace mojom + // The WebUI handler for chrome://os-settings. class OSSettingsUI : public ui::MojoWebUIController { public: + static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); + explicit OSSettingsUI(content::WebUI* web_ui); ~OSSettingsUI() override; - private: - void AddSettingsPageUIHandler( - std::unique_ptr<content::WebUIMessageHandler> handler); - void BindCrosNetworkConfig( + // Initializes the WebUI message handlers for OS-specific settings. + void InitOSWebUIHandlers(content::WebUIDataSource* html_source); + + // Instantiates implementor of the mojom::CrosNetworkConfig mojo interface + // passing the pending receiver that will be internally bound. + void BindInterface( mojo::PendingReceiver<network_config::mojom::CrosNetworkConfig> receiver); - void BindAppManagementPageHandlerFactory( + + // Instantiates implementor of the mojom::UserActionRecorder mojo interface + // passing the pending receiver that will be internally bound. + void BindInterface(mojo::PendingReceiver<mojom::UserActionRecorder> receiver); + + // Instantiates implementor of the mojom::SearchHandler mojo interface + // passing the pending receiver that will be internally bound. + void BindInterface(mojo::PendingReceiver<mojom::SearchHandler> receiver); + + // Instantiates implementor of the mojom::PageHandlerFactory mojo interface + // passing the pending receiver that will be internally bound. + void BindInterface( mojo::PendingReceiver<app_management::mojom::PageHandlerFactory> receiver); + private: + void AddSettingsPageUIHandler( + std::unique_ptr<content::WebUIMessageHandler> handler); + + base::TimeTicks time_when_opened_; + WebuiLoadTimer webui_load_timer_; + std::unique_ptr<mojom::UserActionRecorder> user_action_recorder_; std::unique_ptr<AppManagementPageHandlerFactory> app_management_page_handler_factory_; + WEB_UI_CONTROLLER_TYPE_DECL(); + DISALLOW_COPY_AND_ASSIGN(OSSettingsUI); }; diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/plugin_vm_handler.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/plugin_vm_handler.cc index 715782b0b11..db5d9d79e67 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/plugin_vm_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/plugin_vm_handler.cc @@ -12,6 +12,8 @@ #include "base/bind_helpers.h" #include "chrome/browser/chromeos/file_manager/path_util.h" #include "chrome/browser/chromeos/guest_os/guest_os_share_path.h" +#include "chrome/browser/chromeos/plugin_vm/plugin_vm_manager.h" +#include "chrome/browser/chromeos/plugin_vm/plugin_vm_util.h" #include "chrome/browser/profiles/profile.h" #include "content/public/browser/browser_thread.h" @@ -32,6 +34,14 @@ void PluginVmHandler::RegisterMessages() { "removePluginVmSharedPath", base::BindRepeating(&PluginVmHandler::HandleRemovePluginVmSharedPath, weak_ptr_factory_.GetWeakPtr())); + web_ui()->RegisterMessageCallback( + "removePluginVm", + base::BindRepeating(&PluginVmHandler::HandleRemovePluginVm, + weak_ptr_factory_.GetWeakPtr())); + web_ui()->RegisterMessageCallback( + "requestPluginVmInstallerView", + base::BindRepeating(&PluginVmHandler::HandleRequestPluginVmInstallerView, + weak_ptr_factory_.GetWeakPtr())); } void PluginVmHandler::HandleGetPluginVmSharedPathsDisplayText( @@ -68,5 +78,28 @@ void PluginVmHandler::HandleRemovePluginVmSharedPath( path)); } +void PluginVmHandler::HandleRemovePluginVm(const base::ListValue* args) { + CHECK_EQ(0U, args->GetSize()); + + auto* manager = plugin_vm::PluginVmManager::GetForProfile(profile_); + if (!manager) { + LOG(ERROR) << "removePluginVm called from an invalid profile."; + return; + } + manager->UninstallPluginVm(); +} + +void PluginVmHandler::HandleRequestPluginVmInstallerView( + const base::ListValue* args) { + CHECK(args->empty()); + + if (plugin_vm::IsPluginVmEnabled(profile_)) { + LOG(ERROR) << "requestPluginVmInstallerView called from a profile which " + "already has Plugin VM installed."; + return; + } + plugin_vm::ShowPluginVmInstallerView(profile_); +} + } // namespace settings } // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/plugin_vm_handler.h b/chromium/chrome/browser/ui/webui/settings/chromeos/plugin_vm_handler.h index d57b34da1db..b003a9e3e11 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/plugin_vm_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/plugin_vm_handler.h @@ -32,6 +32,10 @@ class PluginVmHandler : public ::settings::SettingsPageUIHandler { void HandleGetPluginVmSharedPathsDisplayText(const base::ListValue* args); // Remove a specified path from being shared. void HandleRemovePluginVmSharedPath(const base::ListValue* args); + // Remove Plugin VM. + void HandleRemovePluginVm(const base::ListValue* args); + // Show the Plugin VM installer view if Plugin VM is not currently installed. + void HandleRequestPluginVmInstallerView(const base::ListValue* args); Profile* profile_; // weak_ptr_factory_ should always be last member. diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/pref_names.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/pref_names.cc new file mode 100644 index 00000000000..c36221f6270 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/pref_names.cc @@ -0,0 +1,20 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/chromeos/pref_names.h" + +namespace chromeos { +namespace settings { +namespace prefs { + +// Boolean specifying whether OS wallpaper sync is enabled. This is stored +// separately from the other OS sync preferences because it's an edge case; +// wallpaper does not have its own ModelType, so it cannot be part of +// UserSelectableOsType like the other OS sync types. +// TODO(https://crbug.com/967987): Break this dependency. +const char kSyncOsWallpaper[] = "sync.os_wallpaper"; + +} // namespace prefs +} // namespace settings +} // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/pref_names.h b/chromium/chrome/browser/ui/webui/settings/chromeos/pref_names.h new file mode 100644 index 00000000000..df2e7dce599 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/pref_names.h @@ -0,0 +1,18 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_PREF_NAMES_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_PREF_NAMES_H_ + +namespace chromeos { +namespace settings { +namespace prefs { + +extern const char kSyncOsWallpaper[]; + +} // namespace prefs +} // namespace settings +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_PREF_NAMES_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/quick_unlock_handler.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/quick_unlock_handler.cc new file mode 100644 index 00000000000..f74ec2b9c89 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/quick_unlock_handler.cc @@ -0,0 +1,38 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/chromeos/quick_unlock_handler.h" + +#include "base/bind.h" +#include "chrome/browser/chromeos/login/quick_unlock/pin_backend.h" +#include "content/public/browser/web_ui.h" + +namespace chromeos { +namespace settings { + +QuickUnlockHandler::QuickUnlockHandler() = default; + +QuickUnlockHandler::~QuickUnlockHandler() = default; + +void QuickUnlockHandler::RegisterMessages() { + web_ui()->RegisterMessageCallback( + "RequestPinLoginState", + base::BindRepeating(&QuickUnlockHandler::HandleRequestPinLoginState, + base::Unretained(this))); +} + +void QuickUnlockHandler::HandleRequestPinLoginState( + const base::ListValue* args) { + AllowJavascript(); + quick_unlock::PinBackend::GetInstance()->HasLoginSupport( + base::BindOnce(&QuickUnlockHandler::OnPinLoginAvailable, + weak_ptr_factory_.GetWeakPtr())); +} + +void QuickUnlockHandler::OnPinLoginAvailable(bool is_available) { + FireWebUIListener("pin-login-available-changed", base::Value(is_available)); +} + +} // namespace settings +} // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/quick_unlock_handler.h b/chromium/chrome/browser/ui/webui/settings/chromeos/quick_unlock_handler.h new file mode 100644 index 00000000000..4796c99ce3c --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/quick_unlock_handler.h @@ -0,0 +1,42 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_QUICK_UNLOCK_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_QUICK_UNLOCK_HANDLER_H_ + +#include "base/memory/weak_ptr.h" +#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" + +namespace base { +class ListValue; +} // namespace base + +namespace chromeos { +namespace settings { + +// Settings WebUI handler for quick unlock settings. +class QuickUnlockHandler : public ::settings::SettingsPageUIHandler { + public: + QuickUnlockHandler(); + QuickUnlockHandler(const QuickUnlockHandler&) = delete; + QuickUnlockHandler& operator=(const QuickUnlockHandler&) = delete; + ~QuickUnlockHandler() override; + + // SettingsPageUIHandler: + void RegisterMessages() override; + void OnJavascriptAllowed() override {} + void OnJavascriptDisallowed() override {} + + private: + void HandleRequestPinLoginState(const base::ListValue* args); + + void OnPinLoginAvailable(bool is_available); + + base::WeakPtrFactory<QuickUnlockHandler> weak_ptr_factory_{this}; +}; + +} // namespace settings +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_QUICK_UNLOCK_HANDLER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/search/BUILD.gn b/chromium/chrome/browser/ui/webui/settings/chromeos/search/BUILD.gn new file mode 100644 index 00000000000..b4554acf90b --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/search/BUILD.gn @@ -0,0 +1,17 @@ +# Copyright 2020 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//mojo/public/tools/bindings/mojom.gni") + +assert(is_chromeos) + +mojom("mojo_bindings") { + sources = [ + "search.mojom", + "search_result_icon.mojom", + "user_action_recorder.mojom", + ] + + public_deps = [ "//mojo/public/mojom/base" ] +} diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/search/OWNERS b/chromium/chrome/browser/ui/webui/settings/chromeos/search/OWNERS new file mode 100644 index 00000000000..2d3d2668edc --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/search/OWNERS @@ -0,0 +1,7 @@ +khorimoto@chromium.org +zentaro@chromium.org + +per-file *.mojom=set noparent +per-file *.mojom=file://ipc/SECURITY_OWNERS + +# COMPONENT: OS>Systems>Settings diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/search/search.mojom b/chromium/chrome/browser/ui/webui/settings/chromeos/search/search.mojom new file mode 100644 index 00000000000..d319e8d1079 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/search/search.mojom @@ -0,0 +1,33 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module chromeos.settings.mojom; + +import "chrome/browser/ui/webui/settings/chromeos/search/search_result_icon.mojom"; +import "mojo/public/mojom/base/string16.mojom"; + +// Search result metadata. +struct SearchResult { + // String to be displayed as a result in the UI. Meant to be displayed + // directly (i.e., not an ID but rather the actual text). + mojo_base.mojom.String16 result_text; + + // The URL path containing the relevant setting, which may or may not contain + // URL parameters. For example, the Wi-Fi list settings page is + // chrome://os-settings/networks?type=WiFi, so the field would be + // "networks?type=WiFi" for this page. + string url_path_with_parameters; + + // Icon to display for the search result. + SearchResultIcon icon; +}; + +// Provides settings search results. Implemented in the browser process; +// intended to be called from settings JS and Launcher C++. +interface SearchHandler { + // Searches settings for the given query and returns a list of results, sorted + // from most relevant to least relevant. An empty array indicates no relevant + // results. + Search(mojo_base.mojom.String16 query) => (array<SearchResult> results); +}; diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_concept.h b/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_concept.h new file mode 100644 index 00000000000..f6dc3b8c6f6 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_concept.h @@ -0,0 +1,62 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SEARCH_SEARCH_CONCEPT_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SEARCH_SEARCH_CONCEPT_H_ + +#include "chrome/browser/ui/webui/settings/chromeos/search/search_result_icon.mojom.h" + +namespace chromeos { +namespace settings { + +// Represents a potential search result. In this context, "concept" refers to +// the fact that this search result represents an idea which may be described +// by more than just one phrase. For example, a concept of "Display settings" +// may also be described as "Monitor settings". +// +// Each concept has a canonical description search tag as well as up to +// |kMaxAltTagsPerConcept| alternate descriptions search tags. +struct SearchConcept { + static constexpr size_t kMaxAltTagsPerConcept = 4; + static constexpr int kAltTagEnd = 0; + + SearchConcept(const SearchConcept& other) = default; + SearchConcept& operator=(const SearchConcept& other) = default; + + // Message ID (from os_settings_search_tag_strings.grdp) corresponding to the + // canonical search tag for this concept. + int canonical_message_id; + + // URL path corresponding to the settings subpage at which the user can + // change a setting associated with the tag. This string can also contain + // URL parameters. + // + // Example 1 - Display settings (chrome://os-settings/device/display): + // ==> "device/display". + // Example 2 - Wi-Fi settings (chrome://os-settings/networks?type=WiFi): + // ==> "networks?type=WiFi" + const char* url_path_with_parameters; + + // Icon to display for search results associated with this concept. + mojom::SearchResultIcon icon; + + // Alternate message IDs (from os_settings_search_tag_strings.grdp) + // corresponding to this concept. These IDs refer to messages which represent + // an alternate way of describing the same concept (e.g., "Monitor settings" + // is an alternate phrase for "Display settings"). + // + // This field provides up to |kMaxAltTagsPerConcept| alternate tags, but not + // all concepts will require this many. A value of kAltTagEnd is used to + // indicate that there are no further tags. + // + // Example 1 - Four alternate tags: [1234, 1235, 1236, 1237] + // Example 2 - Two alternate tags: [1234, 1235, kAltTagEnd, _] + // Example 3 - Zero alternate tags: [kAltTagEnd, _, _, _] + int alt_tag_ids[kMaxAltTagsPerConcept] = {kAltTagEnd}; +}; + +} // namespace settings +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SEARCH_SEARCH_CONCEPT_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_handler.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_handler.cc new file mode 100644 index 00000000000..a94db926427 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_handler.cc @@ -0,0 +1,107 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/chromeos/search/search_handler.h" + +#include "base/strings/string_number_conversions.h" +#include "chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.h" +#include "chrome/browser/ui/webui/settings/chromeos/search/search_concept.h" +#include "chrome/browser/ui/webui/settings/chromeos/search/search_result_icon.mojom.h" +#include "chrome/services/local_search_service/local_search_service_impl.h" +#include "chrome/services/local_search_service/public/mojom/types.mojom.h" +#include "ui/base/l10n/l10n_util.h" + +namespace chromeos { +namespace settings { +namespace { + +const int32_t kLocalSearchServiceMaxResults = 10; + +} // namespace + +// static +const size_t SearchHandler::kNumMaxResults = 5; + +SearchHandler::SearchHandler( + OsSettingsLocalizedStringsProvider* strings_provider, + local_search_service::LocalSearchServiceImpl* local_search_service) + : strings_provider_(strings_provider), + index_(local_search_service->GetIndexImpl( + local_search_service::IndexId::kCrosSettings)) {} + +SearchHandler::~SearchHandler() = default; + +void SearchHandler::BindInterface( + mojo::PendingReceiver<mojom::SearchHandler> pending_receiver) { + receivers_.Add(this, std::move(pending_receiver)); +} + +std::vector<mojom::SearchResultPtr> SearchHandler::Search( + const base::string16& query) { + std::vector<local_search_service::Result> local_search_service_results; + local_search_service::ResponseStatus response_status = index_->Find( + query, kLocalSearchServiceMaxResults, &local_search_service_results); + + if (response_status != local_search_service::ResponseStatus::kSuccess) { + LOG(ERROR) << "Cannot search; LocalSearchService returned " + << static_cast<int>(response_status) + << ". Returning empty results array."; + return {}; + } + + return GenerateSearchResultsArray(local_search_service_results); +} + +void SearchHandler::Search(const base::string16& query, + SearchCallback callback) { + std::move(callback).Run(Search(query)); +} + +std::vector<mojom::SearchResultPtr> SearchHandler::GenerateSearchResultsArray( + const std::vector<local_search_service::Result>& + local_search_service_results) { + std::vector<mojom::SearchResultPtr> search_results; + for (const auto& result : local_search_service_results) { + mojom::SearchResultPtr result_ptr = ResultToSearchResult(result); + if (result_ptr) + search_results.push_back(std::move(result_ptr)); + + // Limit the number of results to return. + if (search_results.size() == kNumMaxResults) + break; + } + + return search_results; +} + +mojom::SearchResultPtr SearchHandler::ResultToSearchResult( + const local_search_service::Result& result) { + int message_id; + + // The result's ID is expected to be a stringified int. + if (!base::StringToInt(result.id, &message_id)) + return nullptr; + + const SearchConcept* concept = + strings_provider_->GetCanonicalTagMetadata(message_id); + + // If the concept was not registered, no metadata is available. This can occur + // if the search tag was dynamically unregistered during the asynchronous + // Find() call. + if (!concept) + return nullptr; + + return mojom::SearchResult::New(l10n_util::GetStringUTF16(message_id), + concept->url_path_with_parameters, + concept->icon); +} + +void SearchHandler::Shutdown() { + strings_provider_ = nullptr; + index_ = nullptr; + receivers_.Clear(); +} + +} // namespace settings +} // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_handler.h b/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_handler.h new file mode 100644 index 00000000000..36df7ed4bb2 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_handler.h @@ -0,0 +1,77 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SEARCH_SEARCH_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SEARCH_SEARCH_HANDLER_H_ + +#include <vector> + +#include "base/optional.h" +#include "chrome/browser/ui/webui/settings/chromeos/search/search.mojom.h" +#include "chrome/services/local_search_service/index_impl.h" +#include "components/keyed_service/core/keyed_service.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/receiver_set.h" +#include "mojo/public/cpp/bindings/remote.h" + +namespace local_search_service { +class LocalSearchServiceImpl; +} // namespace local_search_service + +namespace chromeos { +namespace settings { + +class OsSettingsLocalizedStringsProvider; + +// Handles search queries for Chrome OS settings. Search() is expected to be +// invoked by the settings UI as well as the the Launcher search UI. Search +// results are obtained by matching the provided query against search tags +// indexed in the LocalSearchService and cross-referencing results with +// OsSettingsLocalizedStringsProvider. +// +// SearchHandler returns at most |kNumMaxResults| results; searches which do not +// provide any matches result in an empty results array. +class SearchHandler : public mojom::SearchHandler, public KeyedService { + public: + // Maximum number of results returned by a Search() call. + static const size_t kNumMaxResults; + + SearchHandler( + OsSettingsLocalizedStringsProvider* strings_provider, + local_search_service::LocalSearchServiceImpl* local_search_service); + ~SearchHandler() override; + + SearchHandler(const SearchHandler& other) = delete; + SearchHandler& operator=(const SearchHandler& other) = delete; + + void BindInterface( + mojo::PendingReceiver<mojom::SearchHandler> pending_receiver); + + // Synchronous search implementation (for in-process clients). + std::vector<mojom::SearchResultPtr> Search(const base::string16& query); + + // mojom::SearchHandler: + void Search(const base::string16& query, SearchCallback callback) override; + + private: + // KeyedService: + void Shutdown() override; + + std::vector<mojom::SearchResultPtr> GenerateSearchResultsArray( + const std::vector<local_search_service::Result>& + local_search_service_results); + mojom::SearchResultPtr ResultToSearchResult( + const local_search_service::Result& result); + + OsSettingsLocalizedStringsProvider* strings_provider_; + local_search_service::IndexImpl* index_; + + // Note: Expected to have multiple clients, so a ReceiverSet is used. + mojo::ReceiverSet<mojom::SearchHandler> receivers_; +}; + +} // namespace settings +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SEARCH_SEARCH_HANDLER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_handler_factory.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_handler_factory.cc new file mode 100644 index 00000000000..fba87783738 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_handler_factory.cc @@ -0,0 +1,61 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/chromeos/search/search_handler_factory.h" + +#include "chrome/browser/local_search_service/local_search_service_proxy.h" +#include "chrome/browser/local_search_service/local_search_service_proxy_factory.h" +#include "chrome/browser/profiles/incognito_helpers.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider_factory.h" +#include "chrome/browser/ui/webui/settings/chromeos/search/search_handler.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" + +namespace chromeos { +namespace settings { + +// static +SearchHandler* SearchHandlerFactory::GetForProfile(Profile* profile) { + return static_cast<SearchHandler*>( + SearchHandlerFactory::GetInstance()->GetServiceForBrowserContext( + profile, /*create=*/true)); +} + +// static +SearchHandlerFactory* SearchHandlerFactory::GetInstance() { + return base::Singleton<SearchHandlerFactory>::get(); +} + +SearchHandlerFactory::SearchHandlerFactory() + : BrowserContextKeyedServiceFactory( + "SearchHandler", + BrowserContextDependencyManager::GetInstance()) { + DependsOn( + local_search_service::LocalSearchServiceProxyFactory::GetInstance()); + DependsOn(OsSettingsLocalizedStringsProviderFactory::GetInstance()); +} + +SearchHandlerFactory::~SearchHandlerFactory() = default; + +KeyedService* SearchHandlerFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + Profile* profile = Profile::FromBrowserContext(context); + return new SearchHandler( + OsSettingsLocalizedStringsProviderFactory::GetForProfile(profile), + local_search_service::LocalSearchServiceProxyFactory::GetForProfile( + Profile::FromBrowserContext(profile)) + ->GetLocalSearchServiceImpl()); +} + +bool SearchHandlerFactory::ServiceIsNULLWhileTesting() const { + return true; +} + +content::BrowserContext* SearchHandlerFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return chrome::GetBrowserContextOwnInstanceInIncognito(context); +} + +} // namespace settings +} // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_handler_factory.h b/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_handler_factory.h new file mode 100644 index 00000000000..9b69e5f161c --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_handler_factory.h @@ -0,0 +1,45 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SEARCH_SEARCH_HANDLER_FACTORY_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SEARCH_SEARCH_HANDLER_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +class Profile; + +namespace chromeos { +namespace settings { + +class SearchHandler; + +// Factory for SearchHandler; available for incognito and multi-profile cases to +// support settings search in those contexts. +class SearchHandlerFactory : public BrowserContextKeyedServiceFactory { + public: + static SearchHandler* GetForProfile(Profile* profile); + static SearchHandlerFactory* GetInstance(); + + private: + friend struct base::DefaultSingletonTraits<SearchHandlerFactory>; + + SearchHandlerFactory(); + ~SearchHandlerFactory() override; + + SearchHandlerFactory(const SearchHandlerFactory&) = delete; + SearchHandlerFactory& operator=(const SearchHandlerFactory&) = delete; + + // BrowserContextKeyedServiceFactory: + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; + bool ServiceIsNULLWhileTesting() const override; + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; +}; + +} // namespace settings +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SEARCH_SEARCH_HANDLER_FACTORY_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_handler_unittest.cc new file mode 100644 index 00000000000..cc04fb87193 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_handler_unittest.cc @@ -0,0 +1,78 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/chromeos/search/search_handler.h" + +#include "base/run_loop.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.h" +#include "chrome/browser/ui/webui/settings/chromeos/search/search.mojom-test-utils.h" +#include "chrome/common/webui_url_constants.h" +#include "chrome/services/local_search_service/local_search_service_impl.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/testing_profile.h" +#include "chrome/test/base/testing_profile_manager.h" +#include "chromeos/services/network_config/public/cpp/cros_network_config_test_helper.h" +#include "content/public/test/browser_task_environment.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace chromeos { +namespace settings { + +class SearchHandlerTest : public testing::Test { + protected: + SearchHandlerTest() : profile_manager_(TestingBrowserProcess::GetGlobal()) {} + ~SearchHandlerTest() override = default; + + // testing::Test: + void SetUp() override { + ASSERT_TRUE(profile_manager_.SetUp()); + + provider_ = std::make_unique<OsSettingsLocalizedStringsProvider>( + profile_manager_.CreateTestingProfile("TestingProfile"), + &local_search_service_); + + handler_ = std::make_unique<SearchHandler>(provider_.get(), + &local_search_service_); + handler_->BindInterface(handler_remote_.BindNewPipeAndPassReceiver()); + + // Allow asynchronous networking code to complete; specifically, let code + // which adds Wi-Fi to the system run so that Wi-Fi search tags can be + // queried below. + base::RunLoop().RunUntilIdle(); + } + + content::BrowserTaskEnvironment task_environment_; + TestingProfileManager profile_manager_; + chromeos::network_config::CrosNetworkConfigTestHelper network_config_helper_; + mojo::Remote<mojom::SearchHandler> handler_remote_; + local_search_service::LocalSearchServiceImpl local_search_service_; + std::unique_ptr<OsSettingsLocalizedStringsProvider> provider_; + std::unique_ptr<SearchHandler> handler_; +}; + +TEST_F(SearchHandlerTest, Success) { + // Search for "Wi-Fi". + std::vector<mojom::SearchResultPtr> search_results; + mojom::SearchHandlerAsyncWaiter(handler_remote_.get()) + .Search(base::ASCIIToUTF16("Wi-Fi"), &search_results); + + // Multiple results should be available, and they should have Wi-Fi metadata. + EXPECT_GT(search_results.size(), 0u); + for (const auto& result : search_results) { + EXPECT_EQ(chrome::kWiFiSettingsSubPage, result->url_path_with_parameters); + EXPECT_EQ(mojom::SearchResultIcon::kWifi, result->icon); + } +} + +TEST_F(SearchHandlerTest, NoResults) { + std::vector<mojom::SearchResultPtr> search_results; + mojom::SearchHandlerAsyncWaiter(handler_remote_.get()) + .Search(base::ASCIIToUTF16("QueryWithNoResults"), &search_results); + EXPECT_TRUE(search_results.empty()); +} + +} // namespace settings +} // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_result_icon.mojom b/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_result_icon.mojom new file mode 100644 index 00000000000..ea4605ed09f --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/search/search_result_icon.mojom @@ -0,0 +1,14 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module chromeos.settings.mojom; + +// Icon types associated with a settings search result. +enum SearchResultIcon { + kCellular, + kEthernet, + // Note: Wi-Fi icon is used by default for networking tasks which may not be + // specifically tied to Wi-Fi. + kWifi +};
\ No newline at end of file diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/search/settings_user_action_tracker.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/search/settings_user_action_tracker.cc new file mode 100644 index 00000000000..49b774039a7 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/search/settings_user_action_tracker.cc @@ -0,0 +1,131 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/chromeos/search/settings_user_action_tracker.h" + +#include "base/metrics/histogram_functions.h" + +namespace chromeos { +namespace settings { + +namespace { + +// The maximum amount of time that the settings window can be blurred to be +// considered short enough for the "first change" metric. +constexpr base::TimeDelta kShortBlurTimeLimit = base::TimeDelta::FromMinutes(1); + +// The minimum amount of time between a setting change and a subsequent setting +// change. If two changes occur les than this amount of time from each other, +// they are ignored by metrics. See https://crbug.com/1073714 for details. +constexpr base::TimeDelta kMinSubsequentChange = + base::TimeDelta::FromMilliseconds(200); + +// Min/max values for the duration metrics. Note that these values are tied to +// the metrics defined below; if these ever change, the metric names must also +// be updated. +constexpr base::TimeDelta kMinDurationMetric = + base::TimeDelta::FromMilliseconds(100); +constexpr base::TimeDelta kMaxDurationMetric = base::TimeDelta::FromMinutes(10); + +void LogDurationMetric(const char* metric_name, base::TimeDelta duration) { + base::UmaHistogramCustomTimes(metric_name, duration, kMinDurationMetric, + kMaxDurationMetric, /*buckets=*/50); +} + +} // namespace + +SettingsUserActionTracker::SettingsUserActionTracker( + mojo::PendingReceiver<mojom::UserActionRecorder> pending_receiver) + : SettingsUserActionTracker() { + receiver_.Bind(std::move(pending_receiver)); +} + +SettingsUserActionTracker::SettingsUserActionTracker() + : metric_start_time_(base::TimeTicks::Now()) {} + +SettingsUserActionTracker::~SettingsUserActionTracker() = default; + +void SettingsUserActionTracker::RecordPageFocus() { + if (last_blur_timestamp_.is_null()) + return; + + // Log the duration of being blurred. + const base::TimeDelta blurred_duration = + base::TimeTicks::Now() - last_blur_timestamp_; + LogDurationMetric("ChromeOS.Settings.BlurredWindowDuration", + blurred_duration); + + // If the window was blurred for more than |kShortBlurTimeLimit|, + // the user was away from the window for long enough that we consider the + // user coming back to the window a new session for the purpose of metrics. + if (blurred_duration >= kShortBlurTimeLimit) { + ResetMetricsCountersAndTimestamp(); + last_record_setting_changed_timestamp_ = base::TimeTicks(); + } +} + +void SettingsUserActionTracker::RecordPageBlur() { + last_blur_timestamp_ = base::TimeTicks::Now(); +} + +void SettingsUserActionTracker::RecordClick() { + ++num_clicks_since_start_time_; +} + +void SettingsUserActionTracker::RecordNavigation() { + ++num_navigations_since_start_time_; +} + +void SettingsUserActionTracker::RecordSearch() { + ++num_searches_since_start_time_; +} + +void SettingsUserActionTracker::RecordSettingChange() { + base::TimeTicks now = base::TimeTicks::Now(); + + if (!last_record_setting_changed_timestamp_.is_null()) { + // If it has been less than |kMinSubsequentChange| since the last recorded + // setting change, this change is discarded. See https://crbug.com/1073714 + // for details. + if (now - last_record_setting_changed_timestamp_ < kMinSubsequentChange) + return; + + base::UmaHistogramCounts1000( + "ChromeOS.Settings.NumClicksUntilChange.SubsequentChange", + num_clicks_since_start_time_); + base::UmaHistogramCounts1000( + "ChromeOS.Settings.NumNavigationsUntilChange.SubsequentChange", + num_navigations_since_start_time_); + base::UmaHistogramCounts1000( + "ChromeOS.Settings.NumSearchesUntilChange.SubsequentChange", + num_searches_since_start_time_); + LogDurationMetric("ChromeOS.Settings.TimeUntilChange.SubsequentChange", + now - metric_start_time_); + } else { + base::UmaHistogramCounts1000( + "ChromeOS.Settings.NumClicksUntilChange.FirstChange", + num_clicks_since_start_time_); + base::UmaHistogramCounts1000( + "ChromeOS.Settings.NumNavigationsUntilChange.FirstChange", + num_navigations_since_start_time_); + base::UmaHistogramCounts1000( + "ChromeOS.Settings.NumSearchesUntilChange.FirstChange", + num_searches_since_start_time_); + LogDurationMetric("ChromeOS.Settings.TimeUntilChange.FirstChange", + now - metric_start_time_); + } + + ResetMetricsCountersAndTimestamp(); + last_record_setting_changed_timestamp_ = now; +} + +void SettingsUserActionTracker::ResetMetricsCountersAndTimestamp() { + metric_start_time_ = base::TimeTicks::Now(); + num_clicks_since_start_time_ = 0u; + num_navigations_since_start_time_ = 0u; + num_searches_since_start_time_ = 0u; +} + +} // namespace settings +} // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/search/settings_user_action_tracker.h b/chromium/chrome/browser/ui/webui/settings/chromeos/search/settings_user_action_tracker.h new file mode 100644 index 00000000000..f355bcd524e --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/search/settings_user_action_tracker.h @@ -0,0 +1,74 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SEARCH_SETTINGS_USER_ACTION_TRACKER_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SEARCH_SETTINGS_USER_ACTION_TRACKER_H_ + +#include "base/time/time.h" +#include "chrome/browser/ui/webui/settings/chromeos/search/user_action_recorder.mojom.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/receiver.h" + +namespace chromeos { +namespace settings { + +// Records user actions which measure the effort required to change a setting. +// This class is only meant to track actions from an individual settings +// session; if the settings window is closed and reopened again, a new instance +// should be created for that new session. +class SettingsUserActionTracker : public mojom::UserActionRecorder { + public: + explicit SettingsUserActionTracker( + mojo::PendingReceiver<mojom::UserActionRecorder> pending_receiver); + SettingsUserActionTracker(const SettingsUserActionTracker& other) = delete; + SettingsUserActionTracker& operator=(const SettingsUserActionTracker& other) = + delete; + ~SettingsUserActionTracker() override; + + // mojom::UserActionRecorder: + void RecordPageFocus() override; + void RecordPageBlur() override; + void RecordClick() override; + void RecordNavigation() override; + void RecordSearch() override; + void RecordSettingChange() override; + + private: + friend class SettingsUserActionTrackerTest; + + // For unit tests. + SettingsUserActionTracker(); + + void ResetMetricsCountersAndTimestamp(); + + // Time at which the last setting change metric was recorded since the window + // has been focused, or null if no setting change has been recorded since the + // window has been focused. Note that if the user blurs the window then + // refocuses it in less than a minute, this value remains non-null; i.e., it + // flips back to null only when the user has blurred the window for over a + // minute. + base::TimeTicks last_record_setting_changed_timestamp_; + + // Time at which recording the current metric has started. If + // |has_changed_setting_| is true, we're currently measuring the "subsequent + // setting change" metric; otherwise, we're measuring the "first setting + // change" metric. + base::TimeTicks metric_start_time_; + + // Counters associated with the current metric. + size_t num_clicks_since_start_time_ = 0u; + size_t num_navigations_since_start_time_ = 0u; + size_t num_searches_since_start_time_ = 0u; + + // The last time at which a page blur event was received; if no blur events + // have been received, this field is_null(). + base::TimeTicks last_blur_timestamp_; + + mojo::Receiver<mojom::UserActionRecorder> receiver_{this}; +}; + +} // namespace settings +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SEARCH_SETTINGS_USER_ACTION_TRACKER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/search/settings_user_action_tracker_unittest.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/search/settings_user_action_tracker_unittest.cc new file mode 100644 index 00000000000..74a0c9cb0b2 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/search/settings_user_action_tracker_unittest.cc @@ -0,0 +1,176 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/chromeos/search/settings_user_action_tracker.h" + +#include "base/test/metrics/histogram_tester.h" +#include "base/test/task_environment.h" +#include "base/time/time.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace chromeos { +namespace settings { + +class SettingsUserActionTrackerTest : public testing::Test { + protected: + SettingsUserActionTrackerTest() = default; + ~SettingsUserActionTrackerTest() override = default; + + base::test::TaskEnvironment task_environment_{ + base::test::TaskEnvironment::TimeSource::MOCK_TIME}; + base::HistogramTester histogram_tester_; + SettingsUserActionTracker tracker_; +}; + +TEST_F(SettingsUserActionTrackerTest, TestRecordMetrics) { + // Focus the page, perform some tasks, and change a setting. + tracker_.RecordPageFocus(); + tracker_.RecordClick(); + tracker_.RecordNavigation(); + tracker_.RecordSearch(); + task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10)); + tracker_.RecordSettingChange(); + + // The "first change" metrics should have been logged. + histogram_tester_.ExpectTotalCount( + "ChromeOS.Settings.NumClicksUntilChange.FirstChange", + /*count=*/1); + histogram_tester_.ExpectTotalCount( + "ChromeOS.Settings.NumNavigationsUntilChange.FirstChange", + /*count=*/1); + histogram_tester_.ExpectTotalCount( + "ChromeOS.Settings.NumSearchesUntilChange.FirstChange", + /*count=*/1); + histogram_tester_.ExpectTimeBucketCount( + "ChromeOS.Settings.TimeUntilChange.FirstChange", + /*sample=*/base::TimeDelta::FromSeconds(10), + /*count=*/1); + + // Without leaving the page, perform some more tasks, and change another + // setting. + tracker_.RecordClick(); + tracker_.RecordNavigation(); + tracker_.RecordSearch(); + task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10)); + tracker_.RecordSettingChange(); + + // The "subsequent change" metrics should have been logged. + histogram_tester_.ExpectTotalCount( + "ChromeOS.Settings.NumClicksUntilChange.SubsequentChange", + /*count=*/1); + histogram_tester_.ExpectTotalCount( + "ChromeOS.Settings.NumNavigationsUntilChange.SubsequentChange", + /*count=*/1); + histogram_tester_.ExpectTotalCount( + "ChromeOS.Settings.NumSearchesUntilChange.SubsequentChange", + /*count=*/1); + histogram_tester_.ExpectTimeBucketCount( + "ChromeOS.Settings.TimeUntilChange.SubsequentChange", + /*sample=*/base::TimeDelta::FromSeconds(10), + /*count=*/1); + + // Repeat this, but only after 100ms. This is lower than the minimum value + // required for this metric, so it should be ignored. + tracker_.RecordClick(); + tracker_.RecordNavigation(); + tracker_.RecordSearch(); + task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(100)); + tracker_.RecordSettingChange(); + + // No additional logging should have occurred, so make the same verifications + // as above. + histogram_tester_.ExpectTotalCount( + "ChromeOS.Settings.NumClicksUntilChange.SubsequentChange", + /*count=*/1); + histogram_tester_.ExpectTotalCount( + "ChromeOS.Settings.NumNavigationsUntilChange.SubsequentChange", + /*count=*/1); + histogram_tester_.ExpectTotalCount( + "ChromeOS.Settings.NumSearchesUntilChange.SubsequentChange", + /*count=*/1); + histogram_tester_.ExpectTimeBucketCount( + "ChromeOS.Settings.TimeUntilChange.SubsequentChange", + /*sample=*/base::TimeDelta::FromSeconds(10), + /*count=*/1); + + // Repeat this once more, and verify that the counts increased. + tracker_.RecordClick(); + tracker_.RecordNavigation(); + tracker_.RecordSearch(); + task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10)); + tracker_.RecordSettingChange(); + + // The "subsequent change" metrics should have been logged. + histogram_tester_.ExpectTotalCount( + "ChromeOS.Settings.NumClicksUntilChange.SubsequentChange", + /*count=*/2); + histogram_tester_.ExpectTotalCount( + "ChromeOS.Settings.NumNavigationsUntilChange.SubsequentChange", + /*count=*/2); + histogram_tester_.ExpectTotalCount( + "ChromeOS.Settings.NumSearchesUntilChange.SubsequentChange", + /*count=*/2); + histogram_tester_.ExpectTimeBucketCount( + "ChromeOS.Settings.TimeUntilChange.SubsequentChange", + /*sample=*/base::TimeDelta::FromSeconds(10), + /*count=*/2); +} + +TEST_F(SettingsUserActionTrackerTest, TestBlurAndFocus) { + // Focus the page, click, and change a setting. + tracker_.RecordPageFocus(); + tracker_.RecordClick(); + task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1)); + tracker_.RecordSettingChange(); + histogram_tester_.ExpectTotalCount( + "ChromeOS.Settings.NumClicksUntilChange.FirstChange", + /*count=*/1); + histogram_tester_.ExpectTimeBucketCount( + "ChromeOS.Settings.TimeUntilChange.FirstChange", + /*sample=*/base::TimeDelta::FromSeconds(1), + /*count=*/1); + + // Blur for 59 seconds (not quite a minute), click, and change a setting. + // Since the blur was under a minute, this should count for the "subsequent + // change" metrics. + tracker_.RecordPageBlur(); + task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(59)); + tracker_.RecordPageFocus(); + tracker_.RecordClick(); + tracker_.RecordSettingChange(); + histogram_tester_.ExpectTimeBucketCount( + "ChromeOS.Settings.BlurredWindowDuration", + /*sample=*/base::TimeDelta::FromSeconds(59), + /*count=*/1); + histogram_tester_.ExpectTotalCount( + "ChromeOS.Settings.NumClicksUntilChange.SubsequentChange", + /*count=*/1); + histogram_tester_.ExpectTimeBucketCount( + "ChromeOS.Settings.TimeUntilChange.SubsequentChange", + /*sample=*/base::TimeDelta::FromSeconds(59), + /*count=*/1); + + // Now, blur for a full minute, click, and change a setting. Since the blur + // was a full minute, this should count for the "first change" metrics. + tracker_.RecordPageBlur(); + task_environment_.FastForwardBy(base::TimeDelta::FromMinutes(1)); + tracker_.RecordPageFocus(); + task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(5)); + tracker_.RecordClick(); + tracker_.RecordSettingChange(); + histogram_tester_.ExpectTimeBucketCount( + "ChromeOS.Settings.BlurredWindowDuration", + /*sample=*/base::TimeDelta::FromMinutes(1), + /*count=*/2); + histogram_tester_.ExpectTotalCount( + "ChromeOS.Settings.NumClicksUntilChange.FirstChange", + /*count=*/2); + histogram_tester_.ExpectTimeBucketCount( + "ChromeOS.Settings.TimeUntilChange.FirstChange", + /*sample=*/base::TimeDelta::FromSeconds(5), + /*count=*/1); +} + +} // namespace settings. +} // namespace chromeos. diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/search/user_action_recorder.mojom b/chromium/chrome/browser/ui/webui/settings/chromeos/search/user_action_recorder.mojom new file mode 100644 index 00000000000..1f151fc028d --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/search/user_action_recorder.mojom @@ -0,0 +1,28 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module chromeos.settings.mojom; + +// Records user actions within OS settings. Implemented in the browser process; +// intended to be called from settings JS. +interface UserActionRecorder { + // Records that the settings window has been focused. + RecordPageFocus(); + + // Records that the settings window has been blurred (i.e., no longer + // focused). + RecordPageBlur(); + + // Records that the user has clicked within the settings page. + RecordClick(); + + // Records that the user has navigated to a settings subpage. + RecordNavigation(); + + // Records that the user has completed a search attempt. + RecordSearch(); + + // Records that the user has changed a setting. + RecordSettingChange(); +}; diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/server_printer_url_util.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/server_printer_url_util.cc new file mode 100644 index 00000000000..005d006a42c --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/server_printer_url_util.cc @@ -0,0 +1,73 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/chromeos/server_printer_url_util.h" + +#include "url/gurl.h" + +namespace { + +// Returns an updated |gurl| with the specified components from the params. If +// |scheme| is not empty, returns an updated GURL with the specified scheme. If +// |replace_port| is true, returns an updated GURL with 631 as the port. 631 is +// the default port for IPP. +GURL UpdateServerPrinterGURL(const GURL& gurl, + const std::string& scheme, + bool replace_ipp_port) { + GURL::Replacements replacement; + if (!scheme.empty()) + replacement.SetSchemeStr(scheme); + if (replace_ipp_port) + replacement.SetPortStr("631"); + return gurl.ReplaceComponents(replacement); +} + +} // namespace + +namespace chromeos { +namespace settings { + +bool HasValidServerPrinterScheme(const GURL& gurl) { + return gurl.SchemeIsHTTPOrHTTPS() || gurl.SchemeIs("ipp") || + gurl.SchemeIs("ipps"); +} + +base::Optional<GURL> GenerateServerPrinterUrlWithValidScheme( + const std::string& url) { + base::Optional<GURL> gurl = base::make_optional(GURL(url)); + if (!HasValidServerPrinterScheme(*gurl)) { + // If we're missing a valid scheme, try querying with IPPS first. + gurl = GURL("ipps://" + url); + } + + if (!gurl->is_valid()) + return base::nullopt; + + // Replaces IPP/IPPS by HTTP/HTTPS. IPP standard describes protocol built + // on top of HTTP, so both types of addresses have the same meaning in the + // context of IPP interface. Moreover, the URL must have HTTP/HTTPS scheme + // to pass IsStandard() test from GURL library (see "Validation of the URL + // address" below). + if (gurl->SchemeIs("ipp")) { + gurl = UpdateServerPrinterGURL(*gurl, "http", + /*replace_ipp_port=*/false); + // The default port for IPP is 631. If the schema IPP is replaced by HTTP + // and the port is not explicitly defined in the URL, we have to overwrite + // the default HTTP port with the default IPP port. For IPPS we do nothing + // because implementers use the same port for IPPS and HTTPS. + if (gurl->IntPort() == url::PORT_UNSPECIFIED) { + gurl = UpdateServerPrinterGURL(*gurl, /*scheme=*/"", + /*replace_ipp_port=*/true); + } + } else if (gurl->SchemeIs("ipps")) { + gurl = UpdateServerPrinterGURL(*gurl, "https", + /*replace_ipp_port=*/false); + } + + // Check validation of the URL address and return |gurl| if valid. + return gurl->IsStandard() ? gurl : base::nullopt; +} + +} // namespace settings +} // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/server_printer_url_util.h b/chromium/chrome/browser/ui/webui/settings/chromeos/server_printer_url_util.h new file mode 100644 index 00000000000..ad118c14f4b --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/server_printer_url_util.h @@ -0,0 +1,30 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SERVER_PRINTER_URL_UTIL_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SERVER_PRINTER_URL_UTIL_H_ + +#include <string> + +#include "base/optional.h" + +class GURL; + +namespace chromeos { +namespace settings { + +// Returns true if |gurl| has any the following scheme: HTTP, HTTPS, IPP, or +// IPPS. Returns false for an empty or any other scheme. +bool HasValidServerPrinterScheme(const GURL& gurl); + +// Returns a GURL from the input |url|. Returns base::nullopt if +// either |url| is invalid or constructing the GURL failed. This will also +// default the server printer URI to use HTTPS if it detects a missing scheme. +base::Optional<GURL> GenerateServerPrinterUrlWithValidScheme( + const std::string& url); + +} // namespace settings +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SERVER_PRINTER_URL_UTIL_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/server_printer_url_util_unittest.cc b/chromium/chrome/browser/ui/webui/settings/chromeos/server_printer_url_util_unittest.cc new file mode 100644 index 00000000000..26e2ec17433 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/server_printer_url_util_unittest.cc @@ -0,0 +1,89 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/chromeos/server_printer_url_util.h" + +#include <string> + +#include "base/optional.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace chromeos { +namespace settings { + +class ServerPrinterUrlUtilTest : public testing::Test { + public: + ServerPrinterUrlUtilTest() = default; + ~ServerPrinterUrlUtilTest() override = default; +}; + +TEST_F(ServerPrinterUrlUtilTest, IsValidScheme) { + GURL gurl1("ipp://123.123.11.11:123"); + ASSERT_TRUE(HasValidServerPrinterScheme(gurl1)); + + GURL gurl2("http://123.123.11.11:123"); + ASSERT_TRUE(HasValidServerPrinterScheme(gurl2)); + + GURL gurl3("ipps://123.123.11.11:123"); + ASSERT_TRUE(HasValidServerPrinterScheme(gurl3)); + + GURL gurl4("https://123.123.11.11:123"); + ASSERT_TRUE(HasValidServerPrinterScheme(gurl4)); + + // Missing scheme. + GURL gurl5("123.123.11.11:123"); + ASSERT_FALSE(HasValidServerPrinterScheme(gurl5)); + + // Invalid scheme. + GURL gurl6("test://123.123.11.11:123"); + ASSERT_FALSE(HasValidServerPrinterScheme(gurl6)); +} + +TEST_F(ServerPrinterUrlUtilTest, ConvertToGURL) { + // Test that a GURL is created with |gurl1| as its source. + std::string url1("http://123.123.11.11:631"); + base::Optional<GURL> gurl1 = GenerateServerPrinterUrlWithValidScheme(url1); + DCHECK(gurl1); + ASSERT_EQ("http://123.123.11.11:631/", gurl1->spec()); + ASSERT_EQ("http", gurl1->scheme()); + ASSERT_EQ("631", gurl1->port()); + + // Test that HTTPS is the default scheme if a scheme is not provided. + std::string url2("123.123.11.11:631"); + base::Optional<GURL> gurl2 = GenerateServerPrinterUrlWithValidScheme(url2); + DCHECK(gurl2); + ASSERT_EQ("https", gurl2->scheme()); + ASSERT_EQ("https://123.123.11.11:631/", gurl2->spec()); + + // Test that if a URL has IPP as its scheme, it will create a new GURL with + // HTTP as its scheme and 631 as its port. + std::string url3("ipp://123.123.11.11"); + base::Optional<GURL> gurl3 = GenerateServerPrinterUrlWithValidScheme(url3); + DCHECK(gurl3); + ASSERT_EQ("http", gurl3->scheme()); + ASSERT_EQ("631", gurl3->port()); + ASSERT_EQ("http://123.123.11.11:631/", gurl3->spec()); + + // Test that if a URL has IPP as its scheme and a specified port, it will + // create a new GURL with HTTP as the scheme and keeps the same port. + std::string url4("ipp://123.123.11.11:321"); + base::Optional<GURL> gurl4 = GenerateServerPrinterUrlWithValidScheme(url4); + DCHECK(gurl4); + ASSERT_EQ("http", gurl4->scheme()); + ASSERT_EQ("321", gurl4->port()); + ASSERT_EQ("http://123.123.11.11:321/", gurl4->spec()); + + // Test that if a URL has IPPS as its scheme and a specified port, a new GURL + // is created with the scheme as HTTPS and keeps the same port. + std::string url5("ipps://123.123.11.11:555"); + base::Optional<GURL> gurl5 = GenerateServerPrinterUrlWithValidScheme(url5); + DCHECK(gurl5); + ASSERT_EQ("https", gurl5->scheme()); + ASSERT_EQ("555", gurl5->port()); + ASSERT_EQ("https://123.123.11.11:555/", gurl5->spec()); +} + +} // namespace settings +} // namespace chromeos diff --git a/chromium/chrome/browser/ui/webui/settings/font_handler.cc b/chromium/chrome/browser/ui/webui/settings/font_handler.cc index 062eb45fb0f..8fac7613e07 100644 --- a/chromium/chrome/browser/ui/webui/settings/font_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/font_handler.cc @@ -13,28 +13,17 @@ #include "base/bind_helpers.h" #include "base/i18n/rtl.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/extensions/extension_service.h" -#include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" #include "content/public/browser/font_list_async.h" #include "content/public/browser/web_ui.h" -#include "extensions/browser/extension_system.h" -#include "extensions/common/extension_urls.h" #if defined(OS_MACOSX) #include "chrome/browser/ui/webui/settings_utils.h" #endif -namespace { - -const char kAdvancedFontSettingsExtensionId[] = - "caclkomlalccbpcdllchkeecicepbmbm"; - -} // namespace - namespace settings { FontHandler::FontHandler(content::WebUI* webui) @@ -51,78 +40,23 @@ void FontHandler::RegisterMessages() { web_ui()->RegisterMessageCallback( "fetchFontsData", base::BindRepeating(&FontHandler::HandleFetchFontsData, base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "observeAdvancedFontExtensionAvailable", - base::BindRepeating( - &FontHandler::HandleObserveAdvancedFontExtensionAvailable, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "openAdvancedFontSettings", - base::BindRepeating(&FontHandler::HandleOpenAdvancedFontSettings, - base::Unretained(this))); } -void FontHandler::OnJavascriptAllowed() { - extension_registry_observer_.Add( - extensions::ExtensionRegistry::Get(profile_)); -} +void FontHandler::OnJavascriptAllowed() {} -void FontHandler::OnJavascriptDisallowed() { - extension_registry_observer_.RemoveAll(); -} +void FontHandler::OnJavascriptDisallowed() {} void FontHandler::HandleFetchFontsData(const base::ListValue* args) { CHECK_EQ(1U, args->GetSize()); std::string callback_id; CHECK(args->GetString(0, &callback_id)); + AllowJavascript(); content::GetFontListAsync(base::Bind(&FontHandler::FontListHasLoaded, weak_ptr_factory_.GetWeakPtr(), callback_id)); } -void FontHandler::HandleObserveAdvancedFontExtensionAvailable( - const base::ListValue* /*args*/) { - AllowJavascript(); - NotifyAdvancedFontSettingsAvailability(); -} - -void FontHandler::HandleOpenAdvancedFontSettings( - const base::ListValue* /*args*/) { - const extensions::Extension* extension = GetAdvancedFontSettingsExtension(); - if (!extension) - return; - extensions::ExtensionTabUtil::OpenOptionsPage( - extension, - chrome::FindBrowserWithWebContents(web_ui()->GetWebContents())); -} - -const extensions::Extension* FontHandler::GetAdvancedFontSettingsExtension() { - extensions::ExtensionService* service = - extensions::ExtensionSystem::Get(profile_)->extension_service(); - if (!service->IsExtensionEnabled(kAdvancedFontSettingsExtensionId)) - return nullptr; - extensions::ExtensionRegistry* registry = - extensions::ExtensionRegistry::Get(profile_); - return registry->GetInstalledExtension(kAdvancedFontSettingsExtensionId); -} - -void FontHandler::NotifyAdvancedFontSettingsAvailability() { - FireWebUIListener("advanced-font-settings-installed", - base::Value(GetAdvancedFontSettingsExtension() != nullptr)); -} - -void FontHandler::OnExtensionLoaded(content::BrowserContext*, - const extensions::Extension*) { - NotifyAdvancedFontSettingsAvailability(); -} - -void FontHandler::OnExtensionUnloaded(content::BrowserContext*, - const extensions::Extension*, - extensions::UnloadedExtensionReason) { - NotifyAdvancedFontSettingsAvailability(); -} - void FontHandler::FontListHasLoaded(std::string callback_id, std::unique_ptr<base::ListValue> list) { // Font list. Selects the directionality for the fonts in the given list. @@ -142,11 +76,6 @@ void FontHandler::FontListHasLoaded(std::string callback_id, base::DictionaryValue response; response.Set("fontList", std::move(list)); - GURL extension_url(extension_urls::GetWebstoreItemDetailURLPrefix()); - response.SetString( - "extensionUrl", - extension_url.Resolve(kAdvancedFontSettingsExtensionId).spec()); - ResolveJavascriptCallback(base::Value(callback_id), response); } diff --git a/chromium/chrome/browser/ui/webui/settings/font_handler.h b/chromium/chrome/browser/ui/webui/settings/font_handler.h index 3c0a284ca9e..6864cb5381c 100644 --- a/chromium/chrome/browser/ui/webui/settings/font_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/font_handler.h @@ -12,8 +12,6 @@ #include "base/memory/weak_ptr.h" #include "base/scoped_observer.h" #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" -#include "extensions/browser/extension_registry.h" -#include "extensions/browser/extension_registry_observer.h" namespace base { class ListValue; @@ -23,17 +21,12 @@ namespace content { class WebUI; } -namespace extensions { -class Extension; -} - class Profile; namespace settings { // Handle OS font list and font preference settings. -class FontHandler : public SettingsPageUIHandler, - public extensions::ExtensionRegistryObserver { +class FontHandler : public SettingsPageUIHandler { public: explicit FontHandler(content::WebUI* webui); ~FontHandler() override; @@ -43,36 +36,14 @@ class FontHandler : public SettingsPageUIHandler, void OnJavascriptAllowed() override; void OnJavascriptDisallowed() override; - // ExtensionRegistryObserver implementation. - void OnExtensionLoaded(content::BrowserContext* browser_context, - const extensions::Extension* extension) override; - void OnExtensionUnloaded(content::BrowserContext* browser_context, - const extensions::Extension* extension, - extensions::UnloadedExtensionReason reason) override; - private: // Handler for script asking for font information. void HandleFetchFontsData(const base::ListValue* args); - // Listen for changes to whether the advanced font extension is available. - // An initial update will be sent when observation begins. - void HandleObserveAdvancedFontExtensionAvailable(const base::ListValue* args); - - // Open the advanced font settings page. - void HandleOpenAdvancedFontSettings(const base::ListValue* args); - // Callback to handle fonts loading. void FontListHasLoaded(std::string callback_id, std::unique_ptr<base::ListValue> list); - const extensions::Extension* GetAdvancedFontSettingsExtension(); - - void NotifyAdvancedFontSettingsAvailability(); - - ScopedObserver<extensions::ExtensionRegistry, - extensions::ExtensionRegistryObserver> - extension_registry_observer_{this}; - Profile* profile_; // Weak pointer. base::WeakPtrFactory<FontHandler> weak_ptr_factory_{this}; diff --git a/chromium/chrome/browser/ui/webui/settings/hats_handler.cc b/chromium/chrome/browser/ui/webui/settings/hats_handler.cc new file mode 100644 index 00000000000..74723f1b870 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/hats_handler.cc @@ -0,0 +1,37 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/hats_handler.h" + +#include "base/bind.h" +#include "base/threading/sequenced_task_runner_handle.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/hats/hats_service.h" +#include "chrome/browser/ui/hats/hats_service_factory.h" +#include "content/public/browser/visibility.h" +#include "content/public/browser/web_contents.h" + +namespace settings { + +HatsHandler::HatsHandler() = default; + +HatsHandler::~HatsHandler() = default; + +void HatsHandler::RegisterMessages() { + web_ui()->RegisterMessageCallback( + "tryShowHatsSurvey", + base::BindRepeating(&HatsHandler::HandleTryShowHatsSurvey, + base::Unretained(this))); +} + +void HatsHandler::HandleTryShowHatsSurvey(const base::ListValue* args) { + HatsService* hats_service = HatsServiceFactory::GetForProfile( + Profile::FromWebUI(web_ui()), /* create_if_necessary = */ true); + if (hats_service) { + hats_service->LaunchDelayedSurveyForWebContents( + kHatsSurveyTriggerSettingsPrivacy, web_ui()->GetWebContents(), 20000); + } +} + +} // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/hats_handler.h b/chromium/chrome/browser/ui/webui/settings/hats_handler.h new file mode 100644 index 00000000000..f2e22b4a0c5 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/hats_handler.h @@ -0,0 +1,39 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_HATS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_HATS_HANDLER_H_ + +#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" + +namespace settings { + +// Settings page UI handler that shows HaTS surveys. +class HatsHandler : public SettingsPageUIHandler { + public: + HatsHandler(); + + // Not copyable or movable + HatsHandler(const HatsHandler&) = delete; + HatsHandler& operator=(const HatsHandler&) = delete; + + ~HatsHandler() override; + + // WebUIMessageHandler implementation. + void RegisterMessages() override; + + void HandleTryShowHatsSurvey(const base::ListValue* args); + + private: + friend class HatsHandlerTest; + FRIEND_TEST_ALL_PREFIXES(HatsHandlerTest, HandleTryShowHatsSurvey); + + // SettingsPageUIHandler implementation. + void OnJavascriptAllowed() override {} + void OnJavascriptDisallowed() override {} +}; + +} // namespace settings + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_HATS_HANDLER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/hats_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/hats_handler_unittest.cc new file mode 100644 index 00000000000..dc459945792 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/hats_handler_unittest.cc @@ -0,0 +1,65 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/hats_handler.h" + +#include <memory> +#include <string> + +#include "base/values.h" +#include "chrome/browser/ui/hats/hats_service.h" +#include "chrome/browser/ui/hats/hats_service_factory.h" +#include "chrome/browser/ui/hats/mock_hats_service.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "content/public/test/test_web_ui.h" +#include "testing/gmock/include/gmock/gmock.h" + +class Profile; + +namespace settings { + +class HatsHandlerTest : public ChromeRenderViewHostTestHarness { + public: + void SetUp() override { + ChromeRenderViewHostTestHarness::SetUp(); + + web_ui_ = std::make_unique<content::TestWebUI>(); + web_ui_->set_web_contents(web_contents()); + handler_ = std::make_unique<HatsHandler>(); + handler_->set_web_ui(web_ui()); + handler_->AllowJavascript(); + web_ui_->ClearTrackedCalls(); + + mock_hats_service_ = static_cast<MockHatsService*>( + HatsServiceFactory::GetInstance()->SetTestingFactoryAndUse( + profile(), base::BindRepeating(&BuildMockHatsService))); + } + + void TearDown() override { + handler_->set_web_ui(nullptr); + handler_.reset(); + web_ui_.reset(); + + ChromeRenderViewHostTestHarness::TearDown(); + } + + content::TestWebUI* web_ui() { return web_ui_.get(); } + HatsHandler* handler() { return handler_.get(); } + MockHatsService* mock_hats_service_; + + private: + std::unique_ptr<content::TestWebUI> web_ui_; + std::unique_ptr<HatsHandler> handler_; +}; + +TEST_F(HatsHandlerTest, HandleTryShowHatsSurvey) { + EXPECT_CALL(*mock_hats_service_, + LaunchDelayedSurveyForWebContents( + kHatsSurveyTriggerSettingsPrivacy, web_contents(), 20000)); + base::ListValue args; + handler()->HandleTryShowHatsSurvey(&args); + task_environment()->RunUntilIdle(); +} + +} // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/settings_import_data_handler.cc b/chromium/chrome/browser/ui/webui/settings/import_data_handler.cc index b2e78bd722b..1637dc014a7 100644 --- a/chromium/chrome/browser/ui/webui/settings/settings_import_data_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/import_data_handler.cc @@ -2,7 +2,7 @@ // 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_import_data_handler.h" +#include "chrome/browser/ui/webui/settings/import_data_handler.h" #include <stddef.h> @@ -38,10 +38,10 @@ namespace { const char kImportStatusInProgress[] = "inProgress"; const char kImportStatusSucceeded[] = "succeeded"; const char kImportStatusFailed[] = "failed"; -} +} // namespace ImportDataHandler::ImportDataHandler() - : importer_host_(NULL), import_did_succeed_(false) { + : importer_host_(nullptr), import_did_succeed_(false) { DCHECK_CURRENTLY_ON(BrowserThread::UI); } @@ -49,7 +49,7 @@ ImportDataHandler::~ImportDataHandler() { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (importer_host_) - importer_host_->set_observer(NULL); + importer_host_->set_observer(nullptr); if (select_file_dialog_.get()) select_file_dialog_->ListenerDestroyed(); @@ -60,14 +60,14 @@ void ImportDataHandler::RegisterMessages() { web_ui()->RegisterMessageCallback( "initializeImportDialog", - base::BindRepeating(&ImportDataHandler::InitializeDialog, + base::BindRepeating(&ImportDataHandler::HandleInitializeImportDialog, base::Unretained(this))); web_ui()->RegisterMessageCallback( - "importData", base::BindRepeating(&ImportDataHandler::ImportData, + "importData", base::BindRepeating(&ImportDataHandler::HandleImportData, base::Unretained(this))); web_ui()->RegisterMessageCallback( "importFromBookmarksFile", - base::BindRepeating(&ImportDataHandler::HandleChooseBookmarksFile, + base::BindRepeating(&ImportDataHandler::HandleImportFromBookmarksFile, base::Unretained(this))); } @@ -77,7 +77,7 @@ void ImportDataHandler::OnJavascriptDisallowed() { // Stops listening to updates from any ongoing imports. if (importer_host_) - importer_host_->set_observer(NULL); + importer_host_->set_observer(nullptr); } void ImportDataHandler::StartImport( @@ -90,7 +90,7 @@ void ImportDataHandler::StartImport( // If another import is already ongoing, let it finish silently. if (importer_host_) - importer_host_->set_observer(NULL); + importer_host_->set_observer(nullptr); FireWebUIListener("import-data-status-changed", base::Value(kImportStatusInProgress)); @@ -99,32 +99,32 @@ void ImportDataHandler::StartImport( importer_host_ = new ExternalProcessImporterHost(); importer_host_->set_observer(this); Profile* profile = Profile::FromWebUI(web_ui()); - importer_host_->StartImportSettings(source_profile, profile, - imported_items, + importer_host_->StartImportSettings(source_profile, profile, imported_items, new ProfileWriter(profile)); importer::LogImporterUseToMetrics("ImportDataHandler", source_profile.importer_type); } -void ImportDataHandler::ImportData(const base::ListValue* args) { +void ImportDataHandler::HandleImportData(const base::ListValue* args) { DCHECK_CURRENTLY_ON(BrowserThread::UI); int browser_index; CHECK(args->GetInteger(0, &browser_index)); - PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs(); + const base::DictionaryValue* types = nullptr; + CHECK(args->GetDictionary(1, &types)); uint16_t selected_items = importer::NONE; - if (prefs->GetBoolean(prefs::kImportDialogAutofillFormData)) + if (*types->FindBoolKey(prefs::kImportDialogAutofillFormData)) selected_items |= importer::AUTOFILL_FORM_DATA; - if (prefs->GetBoolean(prefs::kImportDialogBookmarks)) + if (*types->FindBoolKey(prefs::kImportDialogBookmarks)) selected_items |= importer::FAVORITES; - if (prefs->GetBoolean(prefs::kImportDialogHistory)) + if (*types->FindBoolKey(prefs::kImportDialogHistory)) selected_items |= importer::HISTORY; - if (prefs->GetBoolean(prefs::kImportDialogSavedPasswords)) + if (*types->FindBoolKey(prefs::kImportDialogSavedPasswords)) selected_items |= importer::PASSWORDS; - if (prefs->GetBoolean(prefs::kImportDialogSearchEngine)) + if (*types->FindBoolKey(prefs::kImportDialogSearchEngine)) selected_items |= importer::SEARCH_ENGINES; const importer::SourceProfile& source_profile = @@ -136,11 +136,12 @@ void ImportDataHandler::ImportData(const base::ListValue* args) { StartImport(source_profile, imported_items); } else { LOG(WARNING) << "There were no settings to import from '" - << source_profile.importer_name << "'."; + << source_profile.importer_name << "'."; } } -void ImportDataHandler::InitializeDialog(const base::ListValue* args) { +void ImportDataHandler::HandleInitializeImportDialog( + const base::ListValue* args) { AllowJavascript(); CHECK_EQ(1U, args->GetSize()); @@ -155,6 +156,28 @@ void ImportDataHandler::InitializeDialog(const base::ListValue* args) { base::Unretained(this), callback_id)); } +void ImportDataHandler::HandleImportFromBookmarksFile( + const base::ListValue* args) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + DCHECK(args && args->empty()); + select_file_dialog_ = ui::SelectFileDialog::Create( + this, + std::make_unique<ChromeSelectFilePolicy>(web_ui()->GetWebContents())); + + ui::SelectFileDialog::FileTypeInfo file_type_info; + file_type_info.extensions.resize(1); + file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("html")); + + Browser* browser = + chrome::FindBrowserWithWebContents(web_ui()->GetWebContents()); + + select_file_dialog_->SelectFile( + ui::SelectFileDialog::SELECT_OPEN_FILE, base::string16(), + base::FilePath(), &file_type_info, 0, base::FilePath::StringType(), + browser->window()->GetNativeWindow(), nullptr); +} + void ImportDataHandler::SendBrowserProfileData(const std::string& callback_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -168,14 +191,15 @@ void ImportDataHandler::SendBrowserProfileData(const std::string& callback_id) { new base::DictionaryValue()); browser_profile->SetString("name", source_profile.importer_name); browser_profile->SetInteger("index", i); + browser_profile->SetString("profileName", source_profile.profile); browser_profile->SetBoolean("history", - (browser_services & importer::HISTORY) != 0); + (browser_services & importer::HISTORY) != 0); browser_profile->SetBoolean("favorites", - (browser_services & importer::FAVORITES) != 0); + (browser_services & importer::FAVORITES) != 0); browser_profile->SetBoolean("passwords", - (browser_services & importer::PASSWORDS) != 0); - browser_profile->SetBoolean("search", - (browser_services & importer::SEARCH_ENGINES) != 0); + (browser_services & importer::PASSWORDS) != 0); + browser_profile->SetBoolean( + "search", (browser_services & importer::SEARCH_ENGINES) != 0); browser_profile->SetBoolean( "autofillFormData", (browser_services & importer::AUTOFILL_FORM_DATA) != 0); @@ -206,8 +230,8 @@ void ImportDataHandler::ImportItemEnded(importer::ImportItem item) { void ImportDataHandler::ImportEnded() { DCHECK_CURRENTLY_ON(BrowserThread::UI); - importer_host_->set_observer(NULL); - importer_host_ = NULL; + importer_host_->set_observer(nullptr); + importer_host_ = nullptr; FireWebUIListener("import-data-status-changed", base::Value(import_did_succeed_ ? kImportStatusSucceeded @@ -226,29 +250,4 @@ void ImportDataHandler::FileSelected(const base::FilePath& path, StartImport(source_profile, importer::FAVORITES); } -void ImportDataHandler::HandleChooseBookmarksFile(const base::ListValue* args) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - DCHECK(args && args->empty()); - select_file_dialog_ = ui::SelectFileDialog::Create( - this, - std::make_unique<ChromeSelectFilePolicy>(web_ui()->GetWebContents())); - - ui::SelectFileDialog::FileTypeInfo file_type_info; - file_type_info.extensions.resize(1); - file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("html")); - - Browser* browser = - chrome::FindBrowserWithWebContents(web_ui()->GetWebContents()); - - select_file_dialog_->SelectFile(ui::SelectFileDialog::SELECT_OPEN_FILE, - base::string16(), - base::FilePath(), - &file_type_info, - 0, - base::FilePath::StringType(), - browser->window()->GetNativeWindow(), - NULL); -} - } // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/settings_import_data_handler.h b/chromium/chrome/browser/ui/webui/settings/import_data_handler.h index 68c9c7519e5..6ee9d1a99a8 100644 --- a/chromium/chrome/browser/ui/webui/settings/settings_import_data_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/import_data_handler.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_IMPORT_DATA_HANDLER_H_ -#define CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_IMPORT_DATA_HANDLER_H_ +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_IMPORT_DATA_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_IMPORT_DATA_HANDLER_H_ #include <stdint.h> @@ -38,9 +38,18 @@ class ImportDataHandler : public SettingsPageUIHandler, void StartImport(const importer::SourceProfile& source_profile, uint16_t imported_items); - void ImportData(const base::ListValue* args); + // Handler for the "importData" message. First argument is the selected + // browser index, and second argument is the types of data to import. + void HandleImportData(const base::ListValue* args); + + // Handler for the "initializeImportDialog" message. First argument is a + // callback id. + void HandleInitializeImportDialog(const base::ListValue* args); + + // Handler for the "importFromBookmarksFile" message. Opens a file selection + // dialog to choose the bookmarks HTML file. + void HandleImportFromBookmarksFile(const base::ListValue* args); - void InitializeDialog(const base::ListValue* args); void SendBrowserProfileData(const std::string& callback_id); // importer::ImporterProgressObserver: @@ -54,9 +63,6 @@ class ImportDataHandler : public SettingsPageUIHandler, int index, void* params) override; - // Opens a file selection dialog to choose the bookmarks HTML file. - void HandleChooseBookmarksFile(const base::ListValue* args); - std::unique_ptr<ImporterList> importer_list_; // If non-null it means importing is in progress. ImporterHost takes care @@ -72,4 +78,4 @@ class ImportDataHandler : public SettingsPageUIHandler, } // namespace settings -#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_IMPORT_DATA_HANDLER_H_ +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_IMPORT_DATA_HANDLER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/people_handler.cc b/chromium/chrome/browser/ui/webui/settings/people_handler.cc index 6dc8e03ca5a..57cd1e34ebb 100644 --- a/chromium/chrome/browser/ui/webui/settings/people_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/people_handler.cc @@ -18,11 +18,13 @@ #include "build/build_config.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_avatar_icon_util.h" #include "chrome/browser/profiles/profile_metrics.h" #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/browser/signin/signin_error_controller_factory.h" #include "chrome/browser/signin/signin_promo.h" #include "chrome/browser/signin/signin_ui_util.h" +#include "chrome/browser/signin/signin_util.h" #include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/browser/sync/sync_ui_util.h" #include "chrome/browser/ui/browser_finder.h" @@ -32,6 +34,7 @@ #include "chrome/browser/ui/webui/signin/login_ui_service.h" #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" #include "chrome/common/url_constants.h" +#include "chrome/common/webui_url_constants.h" #include "chrome/grit/generated_resources.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/prefs/pref_service.h" @@ -39,6 +42,7 @@ #include "components/signin/public/base/signin_metrics.h" #include "components/signin/public/base/signin_pref_names.h" #include "components/signin/public/identity_manager/accounts_mutator.h" +#include "components/signin/public/identity_manager/consent_level.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "components/signin/public/identity_manager/primary_account_mutator.h" #include "components/strings/grit/components_strings.h" @@ -51,26 +55,23 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_delegate.h" #include "google_apis/gaia/gaia_auth_util.h" +#include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/webui/web_ui_util.h" +#include "ui/gfx/image/image.h" -#if defined(OS_CHROMEOS) -#include "chrome/browser/chromeos/login/quick_unlock/pin_backend.h" -#else -#include "chrome/browser/signin/signin_util.h" +#if !defined(OS_CHROMEOS) #include "chrome/browser/ui/webui/profile_helper.h" #endif #if BUILDFLAG(ENABLE_DICE_SUPPORT) -#include "chrome/browser/profiles/profile_avatar_icon_util.h" #include "chrome/browser/signin/account_consistency_mode_manager.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "ui/gfx/image/image.h" #endif using content::WebContents; using l10n_util::GetStringFUTF16; using l10n_util::GetStringUTF16; +using signin::ConsentLevel; namespace { @@ -88,11 +89,7 @@ struct SyncConfigInfo { }; bool IsSyncSubpage(const GURL& current_url) { - return (current_url == chrome::GetSettingsUrl(chrome::kSyncSetupSubPage) -#if defined(OS_CHROMEOS) - || current_url == chrome::GetOSSettingsUrl(chrome::kSyncSetupSubPage) -#endif // defined(OS_CHROMEOS) - ); + return current_url == chrome::GetSettingsUrl(chrome::kSyncSetupSubPage); } SyncConfigInfo::SyncConfigInfo() @@ -182,7 +179,6 @@ std::string GetSyncErrorAction(sync_ui_util::ActionType action_type) { } } -#if BUILDFLAG(ENABLE_DICE_SUPPORT) // Returns the base::Value associated with the account, to use in the stored // accounts list. base::Value GetAccountValue(const AccountInfo& account) { @@ -198,7 +194,6 @@ base::Value GetAccountValue(const AccountInfo& account) { } return dictionary; } -#endif // BUILDFLAG(ENABLE_DICE_SUPPORT) base::string16 GetEnterPassphraseBody(syncer::PassphraseType passphrase_type, base::Time passphrase_time) { @@ -254,9 +249,7 @@ base::string16 GetFullEncryptionBody(syncer::PassphraseType passphrase_type, namespace settings { // static -const char PeopleHandler::kSpinnerPageStatus[] = "spinner"; const char PeopleHandler::kConfigurePageStatus[] = "configure"; -const char PeopleHandler::kTimeoutPageStatus[] = "timeout"; const char PeopleHandler::kDonePageStatus[] = "done"; const char PeopleHandler::kPassphraseFailedPageStatus[] = "passphraseFailed"; @@ -308,9 +301,11 @@ void PeopleHandler::RegisterMessages() { base::BindRepeating(&PeopleHandler::HandleAttemptUserExit, base::Unretained(this))); web_ui()->RegisterMessageCallback( - "RequestPinLoginState", - base::BindRepeating(&PeopleHandler::HandleRequestPinLoginState, - base::Unretained(this))); + "TurnOnSync", base::BindRepeating(&PeopleHandler::HandleTurnOnSync, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "TurnOffSync", base::BindRepeating(&PeopleHandler::HandleTurnOffSync, + base::Unretained(this))); #else web_ui()->RegisterMessageCallback( "SyncSetupSignout", base::BindRepeating(&PeopleHandler::HandleSignout, @@ -323,7 +318,6 @@ void PeopleHandler::RegisterMessages() { base::BindRepeating(&PeopleHandler::HandleStartSignin, base::Unretained(this))); #endif -#if BUILDFLAG(ENABLE_DICE_SUPPORT) web_ui()->RegisterMessageCallback( "SyncSetupGetStoredAccounts", base::BindRepeating(&PeopleHandler::HandleGetStoredAccounts, @@ -332,7 +326,6 @@ void PeopleHandler::RegisterMessages() { "SyncSetupStartSyncingWithEmail", base::BindRepeating(&PeopleHandler::HandleStartSyncingWithEmail, base::Unretained(this))); -#endif web_ui()->RegisterMessageCallback( "SyncStartKeyRetrieval", base::BindRepeating(&PeopleHandler::HandleStartKeyRetrieval, @@ -415,12 +408,6 @@ void PeopleHandler::DisplayGaiaLoginInNewTabOrWindow( } #endif -#if defined(OS_CHROMEOS) -void PeopleHandler::OnPinLoginAvailable(bool is_available) { - FireWebUIListener("pin-login-available-changed", base::Value(is_available)); -} -#endif - void PeopleHandler::OnDidClosePage(const base::ListValue* args) { // Don't mark setup as complete if "didAbort" is true, or if authentication // is still needed. @@ -432,7 +419,7 @@ void PeopleHandler::OnDidClosePage(const base::ListValue* args) { } syncer::SyncService* PeopleHandler::GetSyncService() const { - return profile_->IsSyncAllowed() + return ProfileSyncServiceFactory::IsSyncAllowed(profile_) ? ProfileSyncServiceFactory::GetForProfile(profile_) : nullptr; } @@ -457,6 +444,11 @@ void PeopleHandler::HandleSetDatatypes(const base::ListValue* args) { return; } + // Don't enable non-registered types (for example, kApps may not be registered + // on Chrome OS). + configuration.selected_types.RetainAll( + service->GetUserSettings()->GetRegisteredSelectableTypes()); + service->GetUserSettings()->SetSelectedTypes(configuration.sync_everything, configuration.selected_types); @@ -468,8 +460,8 @@ void PeopleHandler::HandleSetDatatypes(const base::ListValue* args) { ProfileMetrics::LogProfileSyncInfo(ProfileMetrics::SYNC_CHOOSE); } -#if BUILDFLAG(ENABLE_DICE_SUPPORT) void PeopleHandler::HandleGetStoredAccounts(const base::ListValue* args) { + AllowJavascript(); CHECK_EQ(1U, args->GetSize()); const base::Value* callback_id; CHECK(args->Get(0, &callback_id)); @@ -487,30 +479,33 @@ void PeopleHandler::OnExtendedAccountInfoRemoved(const AccountInfo& info) { base::Value PeopleHandler::GetStoredAccountsList() { base::Value accounts(base::Value::Type::LIST); - const bool dice_enabled = - AccountConsistencyModeManager::IsDiceEnabledForProfile(profile_); - - if (dice_enabled) { +#if BUILDFLAG(ENABLE_DICE_SUPPORT) + if (AccountConsistencyModeManager::IsDiceEnabledForProfile(profile_)) { // If dice is enabled, show all the accounts. - for (auto const& account : + for (const auto& account : signin_ui_util::GetAccountsForDicePromos(profile_)) { accounts.Append(GetAccountValue(account)); } - } else { - // If dice is disabled (and unified consent enabled), show only the primary - // account. - auto* identity_manager = IdentityManagerFactory::GetForProfile(profile_); - base::Optional<AccountInfo> primary_account_info = - identity_manager->FindExtendedAccountInfoForAccountWithRefreshToken( - identity_manager->GetPrimaryAccountInfo()); - if (primary_account_info.has_value()) - accounts.Append(GetAccountValue(primary_account_info.value())); + return accounts; } - +#endif + // Guest mode does not have a primary account (or an IdentityManager). + if (profile_->IsGuestSession()) + return base::ListValue(); + // If DICE is disabled for this profile or unsupported on this platform (e.g. + // Chrome OS), then show only the primary account, whether or not that account + // has consented to sync. + auto* identity_manager = IdentityManagerFactory::GetForProfile(profile_); + base::Optional<AccountInfo> primary_account_info = + identity_manager->FindExtendedAccountInfoForAccountWithRefreshToken( + identity_manager->GetPrimaryAccountInfo(ConsentLevel::kNotRequired)); + if (primary_account_info.has_value()) + accounts.Append(GetAccountValue(primary_account_info.value())); return accounts; } void PeopleHandler::HandleStartSyncingWithEmail(const base::ListValue* args) { +#if BUILDFLAG(ENABLE_DICE_SUPPORT) DCHECK(AccountConsistencyModeManager::IsDiceEnabledForProfile(profile_)); const base::Value* email; const base::Value* is_default_promo_account; @@ -530,8 +525,11 @@ void PeopleHandler::HandleStartSyncingWithEmail(const base::ListValue* args) { maybe_account.has_value() ? maybe_account.value() : AccountInfo(), signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS, is_default_promo_account->GetBool()); -} +#else + // TODO(jamescook): Enable sync on non-DICE platforms (e.g. Chrome OS). + NOTIMPLEMENTED(); #endif +} void PeopleHandler::HandleSetEncryption(const base::ListValue* args) { SyncConfigInfo configuration; @@ -577,6 +575,11 @@ void PeopleHandler::HandleSetEncryption(const base::ListValue* args) { // data types. passphrase_failed = !service->GetUserSettings()->SetDecryptionPassphrase( configuration.passphrase); + } else if (service->GetUserSettings()->IsTrustedVaultKeyRequired()) { + // There are pending keys due to trusted vault keys being required, likely + // because something changed since the UI was displayed. A passphrase + // cannot be set in such circumstances. + passphrase_failed = true; } else { // OK, the user sent us a passphrase, but we don't have pending keys. So // it either means that the pending keys were resolved somehow since the @@ -646,13 +649,22 @@ void PeopleHandler::HandleAttemptUserExit(const base::ListValue* args) { chrome::AttemptUserExit(); } -void PeopleHandler::HandleRequestPinLoginState(const base::ListValue* args) { - AllowJavascript(); - chromeos::quick_unlock::PinBackend::GetInstance()->HasLoginSupport( - base::BindOnce(&PeopleHandler::OnPinLoginAvailable, - weak_factory_.GetWeakPtr())); +void PeopleHandler::HandleTurnOnSync(const base::ListValue* args) { + // TODO(https://crbug.com/1050677) + NOTIMPLEMENTED(); } -#endif + +void PeopleHandler::HandleTurnOffSync(const base::ListValue* args) { + auto* identity_manager = IdentityManagerFactory::GetForProfile(profile_); + DCHECK(identity_manager->HasPrimaryAccount(ConsentLevel::kSync)); + DCHECK(signin_util::IsUserSignoutAllowedForProfile(profile_)); + + if (GetSyncService()) + syncer::RecordSyncEvent(syncer::STOP_FROM_OPTIONS); + + identity_manager->GetPrimaryAccountMutator()->RevokeSyncConsent(); +} +#endif // defined(OS_CHROMEOS) #if !defined(OS_CHROMEOS) void PeopleHandler::HandleStartSignin(const base::ListValue* args) { @@ -807,6 +819,10 @@ void PeopleHandler::InitializeSyncBlocker() { if (!service) return; + // The user opened settings directly to the syncSetup sub-page, because they + // clicked "Settings" in the browser sync consent dialog or because they + // clicked "Review sync options" in the Chrome OS out-of-box experience. + // Don't start syncing until they finish setup. if (IsSyncSubpage(web_contents->GetVisibleURL())) { sync_blocker_ = service->GetSetupInProgressHandle(); } @@ -860,7 +876,6 @@ std::unique_ptr<base::DictionaryValue> PeopleHandler::GetSyncStatusDictionary() if (profile_->IsGuestSession()) { // Cannot display signin status when running in guest mode on chromeos // because there is no IdentityManager. - sync_status->SetBoolean("signinAllowed", false); return sync_status; } @@ -870,7 +885,6 @@ std::unique_ptr<base::DictionaryValue> PeopleHandler::GetSyncStatusDictionary() auto* identity_manager = IdentityManagerFactory::GetForProfile(profile_); DCHECK(identity_manager); -#if !defined(OS_CHROMEOS) // Signout is not allowed if the user has policy (crbug.com/172204). if (!signin_util::IsUserSignoutAllowedForProfile(profile_)) { std::string username = identity_manager->GetPrimaryAccountInfo().email; @@ -880,7 +894,6 @@ std::unique_ptr<base::DictionaryValue> PeopleHandler::GetSyncStatusDictionary() if (!username.empty()) sync_status->SetString("domain", gaia::ExtractDomainName(username)); } -#endif // This is intentionally not using GetSyncService(), in order to access more // nuanced information, since GetSyncService() returns nullptr if anything @@ -890,8 +903,6 @@ std::unique_ptr<base::DictionaryValue> PeopleHandler::GetSyncStatusDictionary() bool disallowed_by_policy = service && service->HasDisableReason( syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY); - sync_status->SetBoolean( - "signinAllowed", profile_->GetPrefs()->GetBoolean(prefs::kSigninAllowed)); sync_status->SetBoolean("syncSystemEnabled", (service != nullptr)); sync_status->SetBoolean( "firstSetupInProgress", @@ -906,7 +917,7 @@ std::unique_ptr<base::DictionaryValue> PeopleHandler::GetSyncStatusDictionary() sync_status->SetString("statusText", GetStringUTF16(status_labels.status_label_string_id)); sync_status->SetString("statusActionText", - GetStringUTF16(status_labels.link_label_string_id)); + GetStringUTF16(status_labels.button_string_id)); sync_status->SetBoolean( "hasError", status_labels.message_type == sync_ui_util::SYNC_ERROR || status_labels.message_type == @@ -921,6 +932,8 @@ std::unique_ptr<base::DictionaryValue> PeopleHandler::GetSyncStatusDictionary() sync_status->SetBoolean( "disabled", !service || disallowed_by_policy || !service->GetUserSettings()->IsSyncAllowedByPlatform()); + // NOTE: This means signed-in for *sync*. It can be false when the user is + // signed-in to the content area or to the browser. sync_status->SetBoolean("signedIn", identity_manager->HasPrimaryAccount()); sync_status->SetString("signedInUsername", signin_ui_util::GetAuthenticatedUsername(profile_)); @@ -964,13 +977,10 @@ void PeopleHandler::PushSyncPrefs() { sync_user_settings->GetRegisteredSelectableTypes(); const syncer::UserSelectableTypeSet selected_types = sync_user_settings->GetSelectedTypes(); - const syncer::UserSelectableTypeSet enforced_types = - sync_user_settings->GetForcedTypes(); for (syncer::UserSelectableType type : syncer::UserSelectableTypeSet::All()) { const std::string type_name = syncer::GetUserSelectableTypeName(type); args.SetBoolean(type_name + "Registered", registered_types.Has(type)); args.SetBoolean(type_name + "Synced", selected_types.Has(type)); - args.SetBoolean(type_name + "Enforced", enforced_types.Has(type)); } args.SetBoolean("syncAllDataTypes", sync_user_settings->IsSyncEverythingEnabled()); @@ -988,9 +998,10 @@ void PeopleHandler::PushSyncPrefs() { args.SetBoolean("passphraseRequired", sync_user_settings->IsPassphraseRequired()); - args.SetBoolean( - "trustedVaultKeysRequired", - sync_user_settings->IsTrustedVaultKeyRequiredForPreferredDataTypes()); + // Same as above, we call IsTrustedVaultKeyRequired() here instead of. + // IsTrustedVaultKeyRequiredForPreferredDataTypes(). + args.SetBoolean("trustedVaultKeysRequired", + sync_user_settings->IsTrustedVaultKeyRequired()); syncer::PassphraseType passphrase_type = sync_user_settings->GetPassphraseType(); diff --git a/chromium/chrome/browser/ui/webui/settings/people_handler.h b/chromium/chrome/browser/ui/webui/settings/people_handler.h index 1573a3ce552..50093e129c3 100644 --- a/chromium/chrome/browser/ui/webui/settings/people_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/people_handler.h @@ -47,13 +47,9 @@ class PeopleHandler : public SettingsPageUIHandler, public: // TODO(tommycli): Remove these strings and instead use WebUIListener events. // These string constants are used from JavaScript (sync_browser_proxy.js). - static const char kSpinnerPageStatus[]; static const char kConfigurePageStatus[]; - static const char kTimeoutPageStatus[]; static const char kDonePageStatus[]; static const char kPassphraseFailedPageStatus[]; - // TODO(crbug.com/): Remove kSpinnerPageStatus and kTimeoutPageStatus (plus - // their JS-side handling); they're unused. explicit PeopleHandler(Profile* profile); ~PeopleHandler() override; @@ -89,6 +85,7 @@ class PeopleHandler : public SettingsPageUIHandler, FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, ShowSyncSetup); FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, TestSyncEverything); FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, TestSyncAllManually); + FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, NonRegisteredType); FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, TestPassphraseStillRequired); FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, TestSyncIndividualTypes); FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, @@ -97,10 +94,10 @@ class PeopleHandler : public SettingsPageUIHandler, FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, EnterWrongExistingPassphrase); FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, EnterBlankExistingPassphrase); FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, TurnOnEncryptAllDisallowed); - FRIEND_TEST_ALL_PREFIXES(PeopleHandlerNonCrosTest, + FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, UnrecoverableErrorInitializingSync); - FRIEND_TEST_ALL_PREFIXES(PeopleHandlerNonCrosTest, GaiaErrorInitializingSync); - FRIEND_TEST_ALL_PREFIXES(PeopleHandlerFirstSigninTest, DisplayBasicLogin); + FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, GaiaErrorInitializingSync); + FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, DisplayBasicLogin); FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, AcquireSyncBlockerWhenLoadingSyncSettingsSubpage); FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, RestartSyncAfterDashboardClear); @@ -113,6 +110,9 @@ class PeopleHandler : public SettingsPageUIHandler, DashboardClearWhileSettingsOpen_ConfirmLater); FRIEND_TEST_ALL_PREFIXES(PeopleHandlerDiceUnifiedConsentTest, StoredAccountsList); + FRIEND_TEST_ALL_PREFIXES(PeopleHandlerGuestModeTest, GetStoredAccountsList); + FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, TurnOffSync); + FRIEND_TEST_ALL_PREFIXES(PeopleHandlerTest, GetStoredAccountsList); // SettingsPageUIHandler implementation. void RegisterMessages() override; @@ -127,10 +127,8 @@ class PeopleHandler : public SettingsPageUIHandler, const CoreAccountInfo& primary_account_info) override; void OnPrimaryAccountCleared( const CoreAccountInfo& previous_primary_account_info) override; -#if BUILDFLAG(ENABLE_DICE_SUPPORT) void OnExtendedAccountInfoUpdated(const AccountInfo& info) override; void OnExtendedAccountInfoRemoved(const AccountInfo& info) override; -#endif // syncer::SyncServiceObserver implementation. void OnStateChanged(syncer::SyncService* sync) override; @@ -155,10 +153,11 @@ class PeopleHandler : public SettingsPageUIHandler, void HandleSetDatatypes(const base::ListValue* args); void HandleSetEncryption(const base::ListValue* args); void HandleShowSetupUI(const base::ListValue* args); - void HandleAttemptUserExit(const base::ListValue* args); void HandleSyncPrefsDispatch(const base::ListValue* args); #if defined(OS_CHROMEOS) - void HandleRequestPinLoginState(const base::ListValue* args); + void HandleAttemptUserExit(const base::ListValue* args); + void HandleTurnOnSync(const base::ListValue* args); + void HandleTurnOffSync(const base::ListValue* args); #endif #if !defined(OS_CHROMEOS) void HandleStartSignin(const base::ListValue* args); @@ -178,15 +177,9 @@ class PeopleHandler : public SettingsPageUIHandler, signin_metrics::AccessPoint access_point); #endif -#if defined(OS_CHROMEOS) - void OnPinLoginAvailable(bool is_available); -#endif - -#if BUILDFLAG(ENABLE_DICE_SUPPORT) void HandleGetStoredAccounts(const base::ListValue* args); void HandleStartSyncingWithEmail(const base::ListValue* args); base::Value GetStoredAccountsList(); -#endif // Pushes the updated sync prefs to JavaScript. void PushSyncPrefs(); @@ -233,9 +226,7 @@ class PeopleHandler : public SettingsPageUIHandler, ScopedObserver<syncer::SyncService, syncer::SyncServiceObserver> sync_service_observer_{this}; -#if defined(OS_CHROMEOS) base::WeakPtrFactory<PeopleHandler> weak_factory_{this}; -#endif DISALLOW_COPY_AND_ASSIGN(PeopleHandler); }; diff --git a/chromium/chrome/browser/ui/webui/settings/people_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/people_handler_unittest.cc index 60c758ab17d..f2ecedd6377 100644 --- a/chromium/chrome/browser/ui/webui/settings/people_handler_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/people_handler_unittest.cc @@ -14,6 +14,7 @@ #include "base/json/json_writer.h" #include "base/macros.h" #include "base/stl_util.h" +#include "base/test/mock_callback.h" #include "base/values.h" #include "build/build_config.h" #include "chrome/browser/defaults.h" @@ -35,9 +36,11 @@ #include "chrome/test/base/testing_profile.h" #include "components/prefs/pref_service.h" #include "components/signin/public/identity_manager/accounts_mutator.h" +#include "components/signin/public/identity_manager/consent_level.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "components/signin/public/identity_manager/identity_test_utils.h" #include "components/sync/base/passphrase_enums.h" +#include "components/sync/base/user_selectable_type.h" #include "components/sync/driver/mock_sync_service.h" #include "components/sync/driver/sync_user_settings_impl.h" #include "components/sync/driver/sync_user_settings_mock.h" @@ -50,6 +53,7 @@ #include "content/public/test/web_contents_tester.h" #include "testing/gtest/include/gtest/gtest.h" +using signin::ConsentLevel; using ::testing::_; using ::testing::ByMove; using ::testing::Const; @@ -211,19 +215,15 @@ class TestWebUIProvider class PeopleHandlerTest : public ChromeRenderViewHostTestHarness { public: - PeopleHandlerTest() {} + PeopleHandlerTest() = default; + ~PeopleHandlerTest() override = default; void SetUp() override { ChromeRenderViewHostTestHarness::SetUp(); - // Sign in the user. identity_test_env_adaptor_ = std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile()); - std::string username = GetTestUser(); - if (!username.empty()) - identity_test_env()->SetPrimaryAccount(username); - mock_sync_service_ = static_cast<syncer::MockSyncService*>( ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse( profile(), base::BindRepeating(&BuildMockSyncService))); @@ -241,13 +241,7 @@ class PeopleHandlerTest : public ChromeRenderViewHostTestHarness { ON_CALL(*mock_sync_service_, GetSetupInProgressHandle()) .WillByDefault( Return(ByMove(std::make_unique<syncer::SyncSetupInProgressHandle>( - base::BindRepeating( - &PeopleHandlerTest::OnSetupInProgressHandleDestroyed, - base::Unretained(this)))))); - - handler_ = std::make_unique<TestingPeopleHandler>(&web_ui_, profile()); - handler_->AllowJavascript(); - web_ui_.set_web_contents(web_contents()); + mock_on_setup_in_progress_handle_destroyed_.Get())))); } void TearDown() override { @@ -262,10 +256,18 @@ class PeopleHandlerTest : public ChromeRenderViewHostTestHarness { GetIdentityTestEnvironmentFactories(); } + void SigninUser() { identity_test_env()->SetPrimaryAccount(kTestUser); } + + void CreatePeopleHandler() { + handler_ = std::make_unique<TestingPeopleHandler>(&web_ui_, profile()); + handler_->AllowJavascript(); + web_ui_.set_web_contents(web_contents()); + } + // Setup the expectations for calls made when displaying the config page. void SetDefaultExpectationsForConfigPage() { ON_CALL(*mock_sync_service_, GetDisableReasons()) - .WillByDefault(Return(syncer::SyncService::DISABLE_REASON_NONE)); + .WillByDefault(Return(syncer::SyncService::DisableReasonSet())); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsSyncRequested()) .WillByDefault(Return(true)); ON_CALL(*mock_sync_service_->GetMockUserSettings(), @@ -305,17 +307,6 @@ class PeopleHandlerTest : public ChromeRenderViewHostTestHarness { EXPECT_EQ(expected_status, status); } - void ExpectPageStatusChanged(const std::string& expected_status) { - auto& data = *web_ui_.call_data().back(); - EXPECT_EQ("cr.webUIListenerCallback", data.function_name()); - std::string event; - ASSERT_TRUE(data.arg1()->GetAsString(&event)); - EXPECT_EQ("page-status-changed", event); - std::string status; - ASSERT_TRUE(data.arg2()->GetAsString(&status)); - EXPECT_EQ(expected_status, status); - } - const base::DictionaryValue* ExpectSyncPrefsChanged() { const content::TestWebUI::CallData& data1 = *web_ui_.call_data().back(); EXPECT_EQ("cr.webUIListenerCallback", data1.function_name()); @@ -329,20 +320,33 @@ class PeopleHandlerTest : public ChromeRenderViewHostTestHarness { return dictionary; } - void NotifySyncStateChanged() { - handler_->OnStateChanged(mock_sync_service_); + const base::DictionaryValue* ExpectSyncStatusChanged() { + const content::TestWebUI::CallData& data = *web_ui_.call_data().back(); + EXPECT_EQ("cr.webUIListenerCallback", data.function_name()); + + std::string event; + EXPECT_TRUE(data.arg1()->GetAsString(&event)); + EXPECT_EQ(event, "sync-status-changed"); + + const base::DictionaryValue* dictionary = nullptr; + EXPECT_TRUE(data.arg2()->GetAsDictionary(&dictionary)); + return dictionary; } - virtual std::string GetTestUser() { - return std::string(kTestUser); + void NotifySyncStateChanged() { + handler_->OnStateChanged(mock_sync_service_); } signin::IdentityTestEnvironment* identity_test_env() { return identity_test_env_adaptor_->identity_test_env(); } - MOCK_METHOD0(OnSetupInProgressHandleDestroyed, void()); + signin::IdentityManager* identity_manager() { + return identity_test_env()->identity_manager(); + } + testing::NiceMock<base::MockCallback<base::RepeatingClosure>> + mock_on_setup_in_progress_handle_destroyed_; syncer::MockSyncService* mock_sync_service_; std::unique_ptr<IdentityTestEnvironmentProfileAdaptor> identity_test_env_adaptor_; @@ -354,12 +358,11 @@ class PeopleHandlerTest : public ChromeRenderViewHostTestHarness { DISALLOW_COPY_AND_ASSIGN(PeopleHandlerTest); }; -class PeopleHandlerFirstSigninTest : public PeopleHandlerTest { - std::string GetTestUser() override { return std::string(); } -}; - #if !defined(OS_CHROMEOS) -TEST_F(PeopleHandlerFirstSigninTest, DisplayBasicLogin) { +TEST_F(PeopleHandlerTest, DisplayBasicLogin) { + ASSERT_FALSE(identity_test_env()->identity_manager()->HasPrimaryAccount( + ConsentLevel::kSync)); + CreatePeopleHandler(); // Test that the HandleStartSignin call enables JavaScript. handler_->DisallowJavascript(); @@ -374,22 +377,24 @@ TEST_F(PeopleHandlerFirstSigninTest, DisplayBasicLogin) { // Sync setup hands off control to the gaia login tab. EXPECT_EQ( - NULL, + nullptr, LoginUIServiceFactory::GetForProfile(profile())->current_login_ui()); ASSERT_FALSE(handler_->is_configuring_sync()); handler_->CloseSyncSetup(); EXPECT_EQ( - NULL, + nullptr, LoginUIServiceFactory::GetForProfile(profile())->current_login_ui()); } #endif // !defined(OS_CHROMEOS) TEST_F(PeopleHandlerTest, DisplayConfigureWithEngineDisabledAndCancel) { + SigninUser(); + CreatePeopleHandler(); ON_CALL(*mock_sync_service_, GetDisableReasons()) - .WillByDefault(Return(syncer::SyncService::DISABLE_REASON_NONE)); + .WillByDefault(Return(syncer::SyncService::DisableReasonSet())); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsSyncRequested()) .WillByDefault(Return(true)); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsFirstSetupComplete()) @@ -414,7 +419,7 @@ TEST_F(PeopleHandlerTest, DisplayConfigureWithEngineDisabledAndCancel) { handler_->CloseSyncSetup(); EXPECT_EQ( - NULL, + nullptr, LoginUIServiceFactory::GetForProfile(profile())->current_login_ui()); } @@ -422,10 +427,12 @@ TEST_F(PeopleHandlerTest, DisplayConfigureWithEngineDisabledAndCancel) { // initialized. TEST_F(PeopleHandlerTest, DisplayConfigureWithEngineDisabledAndSyncStartupCompleted) { + SigninUser(); + CreatePeopleHandler(); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsFirstSetupComplete()) .WillByDefault(Return(false)); ON_CALL(*mock_sync_service_, GetDisableReasons()) - .WillByDefault(Return(syncer::SyncService::DISABLE_REASON_NONE)); + .WillByDefault(Return(syncer::SyncService::DisableReasonSet())); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsSyncRequested()) .WillByDefault(Return(true)); // Sync engine is stopped initially, and will start up. @@ -463,8 +470,10 @@ TEST_F(PeopleHandlerTest, // initialized. TEST_F(PeopleHandlerTest, DisplayConfigureWithEngineDisabledAndCancelAfterSigninSuccess) { + SigninUser(); + CreatePeopleHandler(); ON_CALL(*mock_sync_service_, GetDisableReasons()) - .WillByDefault(Return(syncer::SyncService::DISABLE_REASON_NONE)); + .WillByDefault(Return(syncer::SyncService::DisableReasonSet())); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsSyncRequested()) .WillByDefault(Return(true)); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsFirstSetupComplete()) @@ -484,15 +493,17 @@ TEST_F(PeopleHandlerTest, // tell it we're through with the setup progress. testing::InSequence seq; EXPECT_CALL(*mock_sync_service_, StopAndClear()); - EXPECT_CALL(*this, OnSetupInProgressHandleDestroyed()); + EXPECT_CALL(mock_on_setup_in_progress_handle_destroyed_, Run()); handler_->CloseSyncSetup(); EXPECT_EQ( - NULL, + nullptr, LoginUIServiceFactory::GetForProfile(profile())->current_login_ui()); } TEST_F(PeopleHandlerTest, RestartSyncAfterDashboardClear) { + SigninUser(); + CreatePeopleHandler(); // Clearing sync from the dashboard results in DISABLE_REASON_USER_CHOICE // being set. ON_CALL(*mock_sync_service_, GetDisableReasons()) @@ -507,7 +518,7 @@ TEST_F(PeopleHandlerTest, RestartSyncAfterDashboardClear) { // SetSyncRequested(true) clears DISABLE_REASON_USER_CHOICE, and // immediately starts initializing the engine. ON_CALL(*mock_sync_service_, GetDisableReasons()) - .WillByDefault(Return(syncer::SyncService::DISABLE_REASON_NONE)); + .WillByDefault(Return(syncer::SyncService::DisableReasonSet())); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsSyncRequested()) .WillByDefault(Return(true)); ON_CALL(*mock_sync_service_, GetTransportState()) @@ -523,6 +534,8 @@ TEST_F(PeopleHandlerTest, RestartSyncAfterDashboardClear) { TEST_F(PeopleHandlerTest, RestartSyncAfterDashboardClearWithStandaloneTransport) { + SigninUser(); + CreatePeopleHandler(); // Clearing sync from the dashboard results in DISABLE_REASON_USER_CHOICE // being set. However, the sync engine has restarted in standalone transport // mode. @@ -538,7 +551,7 @@ TEST_F(PeopleHandlerTest, // SetSyncRequested(true) clears DISABLE_REASON_USER_CHOICE. Since the // engine is already running, it just gets reconfigured. ON_CALL(*mock_sync_service_, GetDisableReasons()) - .WillByDefault(Return(syncer::SyncService::DISABLE_REASON_NONE)); + .WillByDefault(Return(syncer::SyncService::DisableReasonSet())); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsSyncRequested()) .WillByDefault(Return(true)); ON_CALL(*mock_sync_service_, GetTransportState()) @@ -555,6 +568,8 @@ TEST_F(PeopleHandlerTest, // Tests that signals not related to user intention to configure sync don't // trigger sync engine start. TEST_F(PeopleHandlerTest, OnlyStartEngineWhenConfiguringSync) { + SigninUser(); + CreatePeopleHandler(); ON_CALL(*mock_sync_service_, GetTransportState()) .WillByDefault(Return(syncer::SyncService::TransportState::INITIALIZING)); EXPECT_CALL(*mock_sync_service_->GetMockUserSettings(), @@ -564,6 +579,8 @@ TEST_F(PeopleHandlerTest, OnlyStartEngineWhenConfiguringSync) { } TEST_F(PeopleHandlerTest, AcquireSyncBlockerWhenLoadingSyncSettingsSubpage) { + SigninUser(); + CreatePeopleHandler(); // We set up a factory override here to prevent a new web ui from being // created when we navigate to a page that would normally create one. test_factory_ = std::make_unique<TestChromeWebUIControllerFactory>(); @@ -584,15 +601,9 @@ TEST_F(PeopleHandlerTest, AcquireSyncBlockerWhenLoadingSyncSettingsSubpage) { EXPECT_TRUE(handler_->sync_blocker_); } -#if !defined(OS_CHROMEOS) - -class PeopleHandlerNonCrosTest : public PeopleHandlerTest { - public: - PeopleHandlerNonCrosTest() {} -}; - -// TODO(kochi): We need equivalent tests for ChromeOS. -TEST_F(PeopleHandlerNonCrosTest, UnrecoverableErrorInitializingSync) { +TEST_F(PeopleHandlerTest, UnrecoverableErrorInitializingSync) { + SigninUser(); + CreatePeopleHandler(); ON_CALL(*mock_sync_service_, GetDisableReasons()) .WillByDefault( Return(syncer::SyncService::DISABLE_REASON_UNRECOVERABLE_ERROR)); @@ -604,7 +615,9 @@ TEST_F(PeopleHandlerNonCrosTest, UnrecoverableErrorInitializingSync) { ASSERT_FALSE(handler_->is_configuring_sync()); } -TEST_F(PeopleHandlerNonCrosTest, GaiaErrorInitializingSync) { +TEST_F(PeopleHandlerTest, GaiaErrorInitializingSync) { + SigninUser(); + CreatePeopleHandler(); ON_CALL(*mock_sync_service_, GetDisableReasons()) .WillByDefault(Return(syncer::SyncService::DISABLE_REASON_NOT_SIGNED_IN)); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsFirstSetupComplete()) @@ -615,11 +628,11 @@ TEST_F(PeopleHandlerNonCrosTest, GaiaErrorInitializingSync) { ASSERT_FALSE(handler_->is_configuring_sync()); } -#endif // #if !defined(OS_CHROMEOS) - TEST_F(PeopleHandlerTest, TestSyncEverything) { - std::string args = GetConfiguration( - NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(), ENCRYPT_PASSWORDS); + SigninUser(); + CreatePeopleHandler(); + std::string args = GetConfiguration(nullptr, SYNC_ALL_DATA, GetAllTypes(), + std::string(), ENCRYPT_PASSWORDS); base::ListValue list_args; list_args.AppendString(kTestCallbackId); list_args.AppendString(args); @@ -637,8 +650,10 @@ TEST_F(PeopleHandlerTest, TestSyncEverything) { } TEST_F(PeopleHandlerTest, TestPassphraseStillRequired) { - std::string args = GetConfiguration( - NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(), ENCRYPT_PASSWORDS); + SigninUser(); + CreatePeopleHandler(); + std::string args = GetConfiguration(nullptr, SYNC_ALL_DATA, GetAllTypes(), + std::string(), ENCRYPT_PASSWORDS); base::ListValue list_args; list_args.AppendString(kTestCallbackId); list_args.AppendString(args); @@ -659,6 +674,8 @@ TEST_F(PeopleHandlerTest, TestPassphraseStillRequired) { } TEST_F(PeopleHandlerTest, EnterExistingFrozenImplicitPassword) { + SigninUser(); + CreatePeopleHandler(); base::DictionaryValue dict; dict.SetBoolean("setNewPassphrase", false); std::string args = GetConfiguration(&dict, SYNC_ALL_DATA, GetAllTypes(), @@ -687,6 +704,8 @@ TEST_F(PeopleHandlerTest, EnterExistingFrozenImplicitPassword) { } TEST_F(PeopleHandlerTest, SetNewCustomPassphrase) { + SigninUser(); + CreatePeopleHandler(); base::DictionaryValue dict; dict.SetBoolean("setNewPassphrase", true); std::string args = GetConfiguration(&dict, SYNC_ALL_DATA, GetAllTypes(), @@ -714,6 +733,8 @@ TEST_F(PeopleHandlerTest, SetNewCustomPassphrase) { } TEST_F(PeopleHandlerTest, EnterWrongExistingPassphrase) { + SigninUser(); + CreatePeopleHandler(); base::DictionaryValue dict; dict.SetBoolean("setNewPassphrase", false); std::string args = GetConfiguration(&dict, SYNC_ALL_DATA, GetAllTypes(), @@ -742,6 +763,8 @@ TEST_F(PeopleHandlerTest, EnterWrongExistingPassphrase) { } TEST_F(PeopleHandlerTest, EnterBlankExistingPassphrase) { + SigninUser(); + CreatePeopleHandler(); base::DictionaryValue dict; dict.SetBoolean("setNewPassphrase", false); std::string args = GetConfiguration(&dict, @@ -772,14 +795,15 @@ TEST_F(PeopleHandlerTest, EnterBlankExistingPassphrase) { // Walks through each user selectable type, and tries to sync just that single // data type. TEST_F(PeopleHandlerTest, TestSyncIndividualTypes) { + SigninUser(); + CreatePeopleHandler(); + SetDefaultExpectationsForConfigPage(); for (syncer::UserSelectableType type : GetAllTypes()) { syncer::UserSelectableTypeSet type_to_set; type_to_set.Put(type); - std::string args = GetConfiguration(NULL, - CHOOSE_WHAT_TO_SYNC, - type_to_set, - std::string(), - ENCRYPT_PASSWORDS); + std::string args = + GetConfiguration(nullptr, CHOOSE_WHAT_TO_SYNC, type_to_set, + std::string(), ENCRYPT_PASSWORDS); base::ListValue list_args; list_args.AppendString(kTestCallbackId); list_args.AppendString(args); @@ -799,11 +823,12 @@ TEST_F(PeopleHandlerTest, TestSyncIndividualTypes) { } TEST_F(PeopleHandlerTest, TestSyncAllManually) { - std::string args = GetConfiguration(NULL, - CHOOSE_WHAT_TO_SYNC, - GetAllTypes(), - std::string(), - ENCRYPT_PASSWORDS); + SigninUser(); + CreatePeopleHandler(); + SetDefaultExpectationsForConfigPage(); + std::string args = + GetConfiguration(nullptr, CHOOSE_WHAT_TO_SYNC, GetAllTypes(), + std::string(), ENCRYPT_PASSWORDS); base::ListValue list_args; list_args.AppendString(kTestCallbackId); list_args.AppendString(args); @@ -820,7 +845,37 @@ TEST_F(PeopleHandlerTest, TestSyncAllManually) { ExpectPageStatusResponse(PeopleHandler::kConfigurePageStatus); } +TEST_F(PeopleHandlerTest, NonRegisteredType) { + SigninUser(); + CreatePeopleHandler(); + SetDefaultExpectationsForConfigPage(); + + // Simulate apps not being registered. + syncer::UserSelectableTypeSet registered_types = GetAllTypes(); + registered_types.Remove(syncer::UserSelectableType::kApps); + ON_CALL(*mock_sync_service_->GetMockUserSettings(), + GetRegisteredSelectableTypes()) + .WillByDefault(Return(registered_types)); + SetupInitializedSyncService(); + + // Simulate "Sync everything" being turned off, but all individual + // toggles left on. + std::string config = + GetConfiguration(/*extra_values=*/nullptr, CHOOSE_WHAT_TO_SYNC, + GetAllTypes(), std::string(), ENCRYPT_PASSWORDS); + base::ListValue list_args; + list_args.AppendString(kTestCallbackId); + list_args.AppendString(config); + + // Only the registered types are selected. + EXPECT_CALL(*mock_sync_service_->GetMockUserSettings(), + SetSelectedTypes(/*sync_everything=*/false, registered_types)); + handler_->HandleSetDatatypes(&list_args); +} + TEST_F(PeopleHandlerTest, ShowSyncSetup) { + SigninUser(); + CreatePeopleHandler(); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsPassphraseRequired()) .WillByDefault(Return(false)); ON_CALL(*mock_sync_service_->GetMockUserSettings(), @@ -835,6 +890,8 @@ TEST_F(PeopleHandlerTest, ShowSyncSetup) { } TEST_F(PeopleHandlerTest, ShowSetupSyncEverything) { + SigninUser(); + CreatePeopleHandler(); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsPassphraseRequired()) .WillByDefault(Return(false)); ON_CALL(*mock_sync_service_->GetMockUserSettings(), @@ -863,6 +920,8 @@ TEST_F(PeopleHandlerTest, ShowSetupSyncEverything) { } TEST_F(PeopleHandlerTest, ShowSetupManuallySyncAll) { + SigninUser(); + CreatePeopleHandler(); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsPassphraseRequired()) .WillByDefault(Return(false)); ON_CALL(*mock_sync_service_->GetMockUserSettings(), @@ -880,6 +939,8 @@ TEST_F(PeopleHandlerTest, ShowSetupManuallySyncAll) { } TEST_F(PeopleHandlerTest, ShowSetupSyncForAllTypesIndividually) { + SigninUser(); + CreatePeopleHandler(); for (syncer::UserSelectableType type : GetAllTypes()) { ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsPassphraseRequired()) .WillByDefault(Return(false)); @@ -911,6 +972,8 @@ TEST_F(PeopleHandlerTest, ShowSetupSyncForAllTypesIndividually) { } TEST_F(PeopleHandlerTest, ShowSetupOldGaiaPassphraseRequired) { + SigninUser(); + CreatePeopleHandler(); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsPassphraseRequired()) .WillByDefault(Return(true)); ON_CALL(*mock_sync_service_->GetMockUserSettings(), GetPassphraseType()) @@ -927,6 +990,8 @@ TEST_F(PeopleHandlerTest, ShowSetupOldGaiaPassphraseRequired) { } TEST_F(PeopleHandlerTest, ShowSetupCustomPassphraseRequired) { + SigninUser(); + CreatePeopleHandler(); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsPassphraseRequired()) .WillByDefault(Return(true)); ON_CALL(*mock_sync_service_->GetMockUserSettings(), GetPassphraseType()) @@ -943,8 +1008,10 @@ TEST_F(PeopleHandlerTest, ShowSetupCustomPassphraseRequired) { } TEST_F(PeopleHandlerTest, ShowSetupTrustedVaultKeysRequired) { + SigninUser(); + CreatePeopleHandler(); ON_CALL(*mock_sync_service_->GetMockUserSettings(), - IsTrustedVaultKeyRequiredForPreferredDataTypes()) + IsTrustedVaultKeyRequired()) .WillByDefault(Return(true)); ON_CALL(*mock_sync_service_->GetMockUserSettings(), GetPassphraseType()) .WillByDefault(Return(syncer::PassphraseType::kTrustedVaultPassphrase)); @@ -958,11 +1025,11 @@ TEST_F(PeopleHandlerTest, ShowSetupTrustedVaultKeysRequired) { CheckBool(dictionary, "passphraseRequired", false); CheckBool(dictionary, "trustedVaultKeysRequired", true); EXPECT_FALSE(dictionary->FindKey("enterPassphraseBody")); - // TODO: See how to verify the appropriate action, once it's actually - // implemented. } TEST_F(PeopleHandlerTest, ShowSetupEncryptAll) { + SigninUser(); + CreatePeopleHandler(); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsPassphraseRequired()) .WillByDefault(Return(false)); ON_CALL(*mock_sync_service_->GetMockUserSettings(), @@ -982,6 +1049,8 @@ TEST_F(PeopleHandlerTest, ShowSetupEncryptAll) { } TEST_F(PeopleHandlerTest, ShowSetupEncryptAllDisallowed) { + SigninUser(); + CreatePeopleHandler(); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsPassphraseRequired()) .WillByDefault(Return(false)); ON_CALL(*mock_sync_service_->GetMockUserSettings(), @@ -1002,6 +1071,8 @@ TEST_F(PeopleHandlerTest, ShowSetupEncryptAllDisallowed) { } TEST_F(PeopleHandlerTest, TurnOnEncryptAllDisallowed) { + SigninUser(); + CreatePeopleHandler(); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsPassphraseRequiredForPreferredDataTypes()) .WillByDefault(Return(false)); @@ -1033,6 +1104,8 @@ TEST_F(PeopleHandlerTest, TurnOnEncryptAllDisallowed) { } TEST_F(PeopleHandlerTest, DashboardClearWhileSettingsOpen_ConfirmSoon) { + SigninUser(); + CreatePeopleHandler(); // Sync starts out fully enabled. SetDefaultExpectationsForConfigPage(); @@ -1062,7 +1135,7 @@ TEST_F(PeopleHandlerTest, DashboardClearWhileSettingsOpen_ConfirmSoon) { // SetSyncRequested(true) clears DISABLE_REASON_USER_CHOICE, and // immediately starts initializing the engine. ON_CALL(*mock_sync_service_, GetDisableReasons()) - .WillByDefault(Return(syncer::SyncService::DISABLE_REASON_NONE)); + .WillByDefault(Return(syncer::SyncService::DisableReasonSet())); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsSyncRequested()) .WillByDefault(Return(true)); ON_CALL(*mock_sync_service_, GetTransportState()) @@ -1086,6 +1159,8 @@ TEST_F(PeopleHandlerTest, DashboardClearWhileSettingsOpen_ConfirmSoon) { } TEST_F(PeopleHandlerTest, DashboardClearWhileSettingsOpen_ConfirmLater) { + SigninUser(); + CreatePeopleHandler(); // Sync starts out fully enabled. SetDefaultExpectationsForConfigPage(); @@ -1128,7 +1203,7 @@ TEST_F(PeopleHandlerTest, DashboardClearWhileSettingsOpen_ConfirmLater) { // SetSyncRequested(true) clears DISABLE_REASON_USER_CHOICE, and // immediately starts initializing the engine. ON_CALL(*mock_sync_service_, GetDisableReasons()) - .WillByDefault(Return(syncer::SyncService::DISABLE_REASON_NONE)); + .WillByDefault(Return(syncer::SyncService::DisableReasonSet())); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsSyncRequested()) .WillByDefault(Return(true)); ON_CALL(*mock_sync_service_, GetTransportState()) @@ -1195,7 +1270,44 @@ TEST(PeopleHandlerDiceUnifiedConsentTest, StoredAccountsList) { EXPECT_EQ("a@gmail.com", accounts_list[0].FindKey("email")->GetString()); EXPECT_EQ("b@gmail.com", accounts_list[1].FindKey("email")->GetString()); } - #endif // BUILDFLAG(ENABLE_DICE_SUPPORT) +#if defined(OS_CHROMEOS) +// Regression test for crash in guest mode. https://crbug.com/1040476 +TEST(PeopleHandlerGuestModeTest, GetStoredAccountsList) { + content::BrowserTaskEnvironment task_environment; + TestingProfile::Builder builder; + builder.SetGuestSession(); + std::unique_ptr<Profile> profile = builder.Build(); + + PeopleHandler handler(profile.get()); + base::Value accounts = handler.GetStoredAccountsList(); + EXPECT_TRUE(accounts.GetList().empty()); +} + +TEST_F(PeopleHandlerTest, TurnOffSync) { + // Simulate a user who previously turned on sync. + identity_test_env()->MakePrimaryAccountAvailable("user@gmail.com"); + ASSERT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); + + CreatePeopleHandler(); + handler_->HandleTurnOffSync(nullptr); + EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); + const base::DictionaryValue* status = ExpectSyncStatusChanged(); + CheckBool(status, "signedIn", false); +} + +TEST_F(PeopleHandlerTest, GetStoredAccountsList) { + // Chrome OS sets an unconsented primary account on login. + identity_test_env()->MakeUnconsentedPrimaryAccountAvailable("user@gmail.com"); + ASSERT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); + + CreatePeopleHandler(); + base::Value accounts = handler_->GetStoredAccountsList(); + base::Value::ListView accounts_list = accounts.GetList(); + ASSERT_EQ(1u, accounts_list.size()); + EXPECT_EQ("user@gmail.com", accounts_list[0].FindKey("email")->GetString()); +} +#endif // defined(OS_CHROMEOS) + } // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/profile_info_handler.cc b/chromium/chrome/browser/ui/webui/settings/profile_info_handler.cc index 139f2034b19..922bfc02a41 100644 --- a/chromium/chrome/browser/ui/webui/settings/profile_info_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/profile_info_handler.cc @@ -150,10 +150,7 @@ ProfileInfoHandler::GetAccountNameAndIcon() const { if (g_browser_process->profile_manager() ->GetProfileAttributesStorage() .GetProfileAttributesWithPath(profile_->GetPath(), &entry)) { - name = base::UTF16ToUTF8( - ProfileAttributesEntry::ShouldConcatenateGaiaAndProfileName() - ? entry->GetLocalProfileName() - : entry->GetName()); + name = base::UTF16ToUTF8(entry->GetLocalProfileName()); // TODO(crbug.com/710660): return chrome://theme/IDR_PROFILE_AVATAR_* // and update theme_source.cc to get high res avatar icons. This does less // work here, sends less over IPC, and is more stable with returned results. diff --git a/chromium/chrome/browser/ui/webui/settings/safe_browsing_handler.cc b/chromium/chrome/browser/ui/webui/settings/safe_browsing_handler.cc new file mode 100644 index 00000000000..7403e565a5a --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/safe_browsing_handler.cc @@ -0,0 +1,130 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/safe_browsing_handler.h" + +#include "components/prefs/pref_change_registrar.h" +#include "components/prefs/pref_service.h" +#include "components/safe_browsing/core/common/safe_browsing_prefs.h" +#include "components/safe_browsing/core/features.h" + +namespace settings { + +SafeBrowsingHandler::SafeBrowsingHandler(Profile* profile) + : profile_(profile) {} +SafeBrowsingHandler::~SafeBrowsingHandler() = default; + +void SafeBrowsingHandler::RegisterMessages() { + web_ui()->RegisterMessageCallback( + "getSafeBrowsingRadioManagedState", + base::BindRepeating( + &SafeBrowsingHandler::HandleGetSafeBrowsingRadioManagedState, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "validateSafeBrowsingEnhanced", + base::BindRepeating( + &SafeBrowsingHandler::HandleValidateSafeBrowsingEnhanced, + base::Unretained(this))); +} + +void SafeBrowsingHandler::HandleGetSafeBrowsingRadioManagedState( + const base::ListValue* args) { + AllowJavascript(); + CHECK_EQ(1U, args->GetList().size()); + std::string callback_id = args->GetList()[0].GetString(); + + auto state = GetSafeBrowsingRadioManagedState(profile_); + + base::Value result(base::Value::Type::DICTIONARY); + // TODO(crbug.com/1063265): Move managed state functions out of site_settings. + result.SetKey(kSafeBrowsingEnhanced, + site_settings::GetValueForManagedState(state.enhanced)); + result.SetKey(kSafeBrowsingStandard, + site_settings::GetValueForManagedState(state.standard)); + result.SetKey(kSafeBrowsingDisabled, + site_settings::GetValueForManagedState(state.disabled)); + + ResolveJavascriptCallback(base::Value(callback_id), result); +} + +void SafeBrowsingHandler::HandleValidateSafeBrowsingEnhanced( + const base::ListValue* args) { + // TODO(crbug.com/1074499) Remove this logic when Enhanced protection is + // considered stable. + if (!base::FeatureList::IsEnabled(safe_browsing::kEnhancedProtection)) + profile_->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnhanced, false); +} + +SafeBrowsingRadioManagedState +SafeBrowsingHandler::GetSafeBrowsingRadioManagedState(Profile* profile) { + // Create a default managed state that is updated based on preferences. + SafeBrowsingRadioManagedState managed_state; + + // Computing the effective Safe Browsing managed state requires inspecting + // three different preferences. It is possible that these may be in + // temporarily conflicting managed states. The enabled preference is always + // taken as the canonical source of management. + const PrefService::Preference* enabled_pref = + profile->GetPrefs()->FindPreference(prefs::kSafeBrowsingEnabled); + const bool enabled_enforced = !enabled_pref->IsUserModifiable(); + const bool enabled_recommended = + (enabled_pref && enabled_pref->GetRecommendedValue()); + const bool enabled_recommended_on = + enabled_recommended && enabled_pref->GetRecommendedValue()->GetBool(); + const auto enabled_policy_indicator = + site_settings::GetPolicyIndicatorFromPref(enabled_pref); + + // The enhanced preference may have a recommended setting. This only takes + // effect if the enabled preference also has a recommended setting. + const PrefService::Preference* enhanced_pref = + profile->GetPrefs()->FindPreference(prefs::kSafeBrowsingEnhanced); + const bool enhanced_recommended_on = + enhanced_pref->GetRecommendedValue() && + enhanced_pref->GetRecommendedValue()->GetBool(); + + // A forcefully disabled reporting preference will disallow enhanced from + // being selected and thus it must also be considered. + const PrefService::Preference* reporting_pref = + profile->GetPrefs()->FindPreference( + prefs::kSafeBrowsingScoutReportingEnabled); + const bool reporting_on = reporting_pref->GetValue()->GetBool(); + const bool reporting_enforced = !reporting_pref->IsUserModifiable(); + const auto reporting_policy_indicator = + site_settings::GetPolicyIndicatorFromPref(reporting_pref); + + if (!enabled_enforced && !enabled_recommended && !reporting_enforced) { + // No relevant policies are applied, return the default state. + return managed_state; + } + if (enabled_enforced) { + // All radio controls are managed. + managed_state.enhanced.disabled = true; + managed_state.enhanced.indicator = enabled_policy_indicator; + managed_state.standard.disabled = true; + managed_state.standard.indicator = enabled_policy_indicator; + managed_state.disabled.disabled = true; + managed_state.disabled.indicator = enabled_policy_indicator; + return managed_state; + } + if (enabled_recommended) { + if (enhanced_recommended_on) { + managed_state.enhanced.indicator = enabled_policy_indicator; + } else if (enabled_recommended_on) { + managed_state.standard.indicator = enabled_policy_indicator; + } else { + managed_state.disabled.indicator = enabled_policy_indicator; + } + return managed_state; + } + if (reporting_enforced && !reporting_on) { + // Disable enhanced protection when reporting has been enforced off. + managed_state.enhanced.disabled = true; + managed_state.enhanced.indicator = reporting_policy_indicator; + return managed_state; + } + + return managed_state; +} + +} // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/safe_browsing_handler.h b/chromium/chrome/browser/ui/webui/settings/safe_browsing_handler.h new file mode 100644 index 00000000000..4c27dae0c27 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/safe_browsing_handler.h @@ -0,0 +1,62 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_SAFE_BROWSING_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_SAFE_BROWSING_HANDLER_H_ + +#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" +#include "chrome/browser/ui/webui/site_settings_helper.h" + +#include "chrome/browser/profiles/profile.h" + +namespace settings { + +constexpr char kSafeBrowsingEnhanced[] = "enhanced"; +constexpr char kSafeBrowsingStandard[] = "standard"; +constexpr char kSafeBrowsingDisabled[] = "disabled"; + +struct SafeBrowsingRadioManagedState { + site_settings::ManagedState enhanced; + site_settings::ManagedState standard; + site_settings::ManagedState disabled; +}; + +// Settings page UI handler that provides representation of Safe Browsing +// settings. +class SafeBrowsingHandler : public SettingsPageUIHandler { + public: + explicit SafeBrowsingHandler(Profile* profile); + ~SafeBrowsingHandler() override; + + // WebUIMessageHandler implementation. + void RegisterMessages() override; + + // Calculate and return the current Safe Browsing radio buttons. + void HandleGetSafeBrowsingRadioManagedState(const base::ListValue* args); + + // Confirm that the current Safe Browsing Enhanced preference is appropriate + // for the currently enabled features, updating it if required. + void HandleValidateSafeBrowsingEnhanced(const base::ListValue* args); + + private: + friend class SafeBrowsingHandlerTest; + FRIEND_TEST_ALL_PREFIXES(SafeBrowsingHandlerTest, GenerateRadioManagedState); + FRIEND_TEST_ALL_PREFIXES(SafeBrowsingHandlerTest, ProvideRadioManagedState); + + // SettingsPageUIHandler implementation. + void OnJavascriptAllowed() override {} + void OnJavascriptDisallowed() override {} + + // Calculate the current Safe Browsing control state for the provided profile. + static SafeBrowsingRadioManagedState GetSafeBrowsingRadioManagedState( + Profile* profile); + + Profile* profile_; + + DISALLOW_COPY_AND_ASSIGN(SafeBrowsingHandler); +}; + +} // namespace settings + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_SAFE_BROWSING_HANDLER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/safe_browsing_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/safe_browsing_handler_unittest.cc new file mode 100644 index 00000000000..3065bc295e2 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/safe_browsing_handler_unittest.cc @@ -0,0 +1,248 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/safe_browsing_handler.h" + +#include <memory> +#include <string> + +#include "base/test/scoped_feature_list.h" +#include "base/values.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "chrome/test/base/testing_profile.h" +#include "components/prefs/pref_service.h" +#include "components/safe_browsing/core/common/safe_browsing_prefs.h" +#include "components/safe_browsing/core/features.h" +#include "components/sync_preferences/testing_pref_service_syncable.h" +#include "content/public/test/browser_task_environment.h" +#include "content/public/test/test_web_ui.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace settings { + +class SafeBrowsingHandlerTest : public testing::Test { + public: + void SetUp() override { + handler_ = std::make_unique<SafeBrowsingHandler>(profile()); + handler()->set_web_ui(web_ui()); + handler()->AllowJavascript(); + web_ui()->ClearTrackedCalls(); + } + + TestingProfile* profile() { return &profile_; } + content::TestWebUI* web_ui() { return &web_ui_; } + SafeBrowsingHandler* handler() { return handler_.get(); } + + private: + content::BrowserTaskEnvironment task_environment_; + std::unique_ptr<SafeBrowsingHandler> handler_; + TestingProfile profile_; + content::TestWebUI web_ui_; +}; + +// All of the possible managed states for a boolean preference that can be +// both enforced and recommended. +// TODO(crbug.com/1063265): Remove duplication with site_settings_helper. +enum class PrefSetting { + kEnforcedOff, + kEnforcedOn, + kRecommendedOff, + kRecommendedOn, + kNotSet, +}; + +// Possible preference sources supported by TestingPrefService. +// TODO(crbug.com/1063265): Remove duplication with site_settings_helper. +enum class PrefSource { + kExtension, + kDevicePolicy, + kRecommended, + kNone, +}; + +void AssertRadioManagedStateEqual(const SafeBrowsingRadioManagedState& a, + const SafeBrowsingRadioManagedState& b) { + ASSERT_EQ(a.enhanced.disabled, b.enhanced.disabled); + ASSERT_EQ(a.enhanced.indicator, b.enhanced.indicator); + ASSERT_EQ(a.standard.disabled, b.standard.disabled); + ASSERT_EQ(a.standard.indicator, b.standard.indicator); + ASSERT_EQ(a.disabled.disabled, b.disabled.disabled); + ASSERT_EQ(a.disabled.indicator, b.disabled.indicator); +} + +struct RadioManagedStateTestCase { + PrefSetting safe_browsing_enhanced; + PrefSetting safe_browsing_enabled; + PrefSetting safe_browsing_reporting; + PrefSource preference_source; + SafeBrowsingRadioManagedState expected_result; +}; + +const std::vector<RadioManagedStateTestCase> test_cases = { + {PrefSetting::kNotSet, + PrefSetting::kNotSet, + PrefSetting::kNotSet, + PrefSource::kNone, + {{false, site_settings::PolicyIndicatorType::kNone}, + {false, site_settings::PolicyIndicatorType::kNone}, + {false, site_settings::PolicyIndicatorType::kNone}}}, + {PrefSetting::kEnforcedOn, + PrefSetting::kEnforcedOn, + PrefSetting::kNotSet, + PrefSource::kExtension, + {{true, site_settings::PolicyIndicatorType::kExtension}, + {true, site_settings::PolicyIndicatorType::kExtension}, + {true, site_settings::PolicyIndicatorType::kExtension}}}, + {PrefSetting::kEnforcedOff, + PrefSetting::kEnforcedOff, + PrefSetting::kNotSet, + PrefSource::kDevicePolicy, + {{true, site_settings::PolicyIndicatorType::kDevicePolicy}, + {true, site_settings::PolicyIndicatorType::kDevicePolicy}, + {true, site_settings::PolicyIndicatorType::kDevicePolicy}}}, + {PrefSetting::kEnforcedOff, + PrefSetting::kEnforcedOn, + PrefSetting::kNotSet, + PrefSource::kExtension, + {{true, site_settings::PolicyIndicatorType::kExtension}, + {true, site_settings::PolicyIndicatorType::kExtension}, + {true, site_settings::PolicyIndicatorType::kExtension}}}, + {PrefSetting::kRecommendedOn, + PrefSetting::kRecommendedOn, + PrefSetting::kNotSet, + PrefSource::kRecommended, + {{false, site_settings::PolicyIndicatorType::kRecommended}, + {false, site_settings::PolicyIndicatorType::kNone}, + {false, site_settings::PolicyIndicatorType::kNone}}}, + {PrefSetting::kRecommendedOff, + PrefSetting::kRecommendedOn, + PrefSetting::kNotSet, + PrefSource::kRecommended, + {{false, site_settings::PolicyIndicatorType::kNone}, + {false, site_settings::PolicyIndicatorType::kRecommended}, + {false, site_settings::PolicyIndicatorType::kNone}}}, + {PrefSetting::kRecommendedOff, + PrefSetting::kRecommendedOff, + PrefSetting::kNotSet, + PrefSource::kRecommended, + {{false, site_settings::PolicyIndicatorType::kNone}, + {false, site_settings::PolicyIndicatorType::kNone}, + {false, site_settings::PolicyIndicatorType::kRecommended}}}, + {PrefSetting::kNotSet, + PrefSetting::kNotSet, + PrefSetting::kEnforcedOff, + PrefSource::kDevicePolicy, + {{true, site_settings::PolicyIndicatorType::kDevicePolicy}, + {false, site_settings::PolicyIndicatorType::kNone}, + {false, site_settings::PolicyIndicatorType::kNone}}}}; + +void SetupTestConditions(TestingProfile* profile, + const RadioManagedStateTestCase& test_case) { + sync_preferences::TestingPrefServiceSyncable* prefs = + profile->GetTestingPrefService(); + const std::map<const char*, PrefSetting> pref_to_setting = { + {prefs::kSafeBrowsingEnhanced, test_case.safe_browsing_enhanced}, + {prefs::kSafeBrowsingEnabled, test_case.safe_browsing_enabled}, + {prefs::kSafeBrowsingScoutReportingEnabled, + test_case.safe_browsing_reporting}}; + + for (const auto& pref_setting : pref_to_setting) { + if (pref_setting.second == PrefSetting::kNotSet) { + continue; + } + auto pref_value = std::make_unique<base::Value>( + pref_setting.second == PrefSetting::kRecommendedOn || + pref_setting.second == PrefSetting::kEnforcedOn); + if (test_case.preference_source == PrefSource::kExtension) { + prefs->SetExtensionPref(pref_setting.first, std::move(pref_value)); + } else if (test_case.preference_source == PrefSource::kDevicePolicy) { + prefs->SetManagedPref(pref_setting.first, std::move(pref_value)); + } else if (test_case.preference_source == PrefSource::kRecommended) { + prefs->SetRecommendedPref(pref_setting.first, std::move(pref_value)); + } + } +} + +TEST_F(SafeBrowsingHandlerTest, GenerateRadioManagedState) { + int count = 0; + for (const auto& test_case : test_cases) { + TestingProfile profile; + SCOPED_TRACE(base::StringPrintf("Test case %d", count++)); + SetupTestConditions(&profile, test_case); + AssertRadioManagedStateEqual( + handler()->GetSafeBrowsingRadioManagedState(&profile), + test_case.expected_result); + } +} + +TEST_F(SafeBrowsingHandlerTest, ProvideRadioManagedState) { + // Test that the handler correctly wraps the generated result. + const std::string kNone = "none"; + const std::string kDevicePolicy = "devicePolicy"; + const std::string kCallbackId = "callback"; + const std::vector<std::string> kRadioNames = {"enhanced", "standard", + "disabled"}; + + // Check that the default radio state is handled correctly. + base::ListValue get_args; + get_args.AppendString(kCallbackId); + handler()->HandleGetSafeBrowsingRadioManagedState(&get_args); + { + const content::TestWebUI::CallData& data = *web_ui()->call_data().back(); + EXPECT_EQ("cr.webUIResponse", data.function_name()); + EXPECT_EQ(kCallbackId, data.arg1()->GetString()); + ASSERT_TRUE(data.arg2()->GetBool()); + for (const auto& control_name : kRadioNames) { + auto* control_state = data.arg3()->FindPath(control_name); + ASSERT_FALSE(control_state->FindKey("disabled")->GetBool()); + ASSERT_EQ(kNone, control_state->FindKey("indicator")->GetString()); + } + } + + // Create a fully managed state and check it is returned correctly. + sync_preferences::TestingPrefServiceSyncable* pref_service = + profile()->GetTestingPrefService(); + pref_service->SetManagedPref(prefs::kSafeBrowsingEnhanced, + std::make_unique<base::Value>(true)); + pref_service->SetManagedPref(prefs::kSafeBrowsingEnabled, + std::make_unique<base::Value>(true)); + + handler()->HandleGetSafeBrowsingRadioManagedState(&get_args); + { + const content::TestWebUI::CallData& data = *web_ui()->call_data().back(); + EXPECT_EQ("cr.webUIResponse", data.function_name()); + EXPECT_EQ(kCallbackId, data.arg1()->GetString()); + ASSERT_TRUE(data.arg2()->GetBool()); + for (const auto& control_name : kRadioNames) { + auto* control_state = data.arg3()->FindPath(control_name); + ASSERT_TRUE(control_state->FindKey("disabled")->GetBool()); + ASSERT_EQ(kDevicePolicy, + control_state->FindKey("indicator")->GetString()); + } + } +} + +TEST_F(SafeBrowsingHandlerTest, ValidateSafeBrowsingPrefs) { + base::ListValue args; + base::test::ScopedFeatureList scoped_feature_list_; + sync_preferences::TestingPrefServiceSyncable* pref_service = + profile()->GetTestingPrefService(); + + pref_service->SetBoolean(prefs::kSafeBrowsingEnhanced, true); + + // Ensure the preference is not changed when the Enhanced feature is enabled. + scoped_feature_list_.InitWithFeatures({safe_browsing::kEnhancedProtection}, + {}); + handler()->HandleValidateSafeBrowsingEnhanced(&args); + EXPECT_TRUE(pref_service->GetBoolean(prefs::kSafeBrowsingEnhanced)); + scoped_feature_list_.Reset(); + + // Ensure the preference is disabled when the Enhanced feature is disabled. + scoped_feature_list_.InitWithFeatures({}, + {safe_browsing::kEnhancedProtection}); + handler()->HandleValidateSafeBrowsingEnhanced(&args); + EXPECT_FALSE(pref_service->GetBoolean(prefs::kSafeBrowsingEnhanced)); +} + +} // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/safety_check_handler.cc b/chromium/chrome/browser/ui/webui/settings/safety_check_handler.cc index be365ff4489..8e954398304 100644 --- a/chromium/chrome/browser/ui/webui/settings/safety_check_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/safety_check_handler.cc @@ -5,23 +5,238 @@ #include "chrome/browser/ui/webui/settings/safety_check_handler.h" #include "base/bind.h" +#include "base/i18n/number_formatting.h" +#include "base/metrics/histogram_functions.h" +#include "base/metrics/user_metrics.h" +#include "base/metrics/user_metrics_action.h" +#include "base/strings/string16.h" +#include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" +#include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h" +#include "chrome/browser/password_manager/bulk_leak_check_service_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/channel_info.h" +#include "chrome/common/url_constants.h" +#include "chrome/grit/chromium_strings.h" +#include "chrome/grit/generated_resources.h" +#include "components/prefs/pref_service.h" +#include "components/safe_browsing/core/common/safe_browsing_prefs.h" +#include "components/strings/grit/components_strings.h" +#include "components/version_info/version_info.h" +#include "extensions/browser/extension_prefs_factory.h" +#include "extensions/browser/extension_system.h" +#include "extensions/common/extension_id.h" +#include "ui/base/l10n/l10n_util.h" + +#if defined(OS_CHROMEOS) +#include "ui/chromeos/devicetype_utils.h" +#endif + +namespace { + +// Constants for communication with JS. +constexpr char kUpdatesEvent[] = "safety-check-updates-status-changed"; +constexpr char kPasswordsEvent[] = "safety-check-passwords-status-changed"; +constexpr char kSafeBrowsingEvent[] = + "safety-check-safe-browsing-status-changed"; +constexpr char kExtensionsEvent[] = "safety-check-extensions-status-changed"; +constexpr char kPerformSafetyCheck[] = "performSafetyCheck"; +constexpr char kGetParentRanDisplayString[] = "getSafetyCheckRanDisplayString"; +constexpr char kNewState[] = "newState"; +constexpr char kDisplayString[] = "displayString"; +constexpr char kButtonString[] = "buttonString"; +constexpr char kPasswordsCompromised[] = "passwordsCompromised"; +constexpr char kExtensionsReenabledByUser[] = "extensionsReenabledByUser"; +constexpr char kExtensionsReenabledByAdmin[] = "extensionsReenabledByAdmin"; + +// Converts the VersionUpdater::Status to the UpdateStatus enum to be passed +// to the safety check frontend. Note: if the VersionUpdater::Status gets +// changed, this will fail to compile. That is done intentionally to ensure +// that the states of the safety check are always in sync with the +// VersionUpdater ones. +SafetyCheckHandler::UpdateStatus ConvertToUpdateStatus( + VersionUpdater::Status status) { + switch (status) { + case VersionUpdater::CHECKING: + return SafetyCheckHandler::UpdateStatus::kChecking; + case VersionUpdater::UPDATED: + return SafetyCheckHandler::UpdateStatus::kUpdated; + case VersionUpdater::UPDATING: + return SafetyCheckHandler::UpdateStatus::kUpdating; + case VersionUpdater::NEED_PERMISSION_TO_UPDATE: + case VersionUpdater::NEARLY_UPDATED: + return SafetyCheckHandler::UpdateStatus::kRelaunch; + case VersionUpdater::DISABLED_BY_ADMIN: + return SafetyCheckHandler::UpdateStatus::kDisabledByAdmin; + // The disabled state can only be returned on non Chrome-branded browsers. + case VersionUpdater::DISABLED: + return SafetyCheckHandler::UpdateStatus::kUnknown; + case VersionUpdater::FAILED: + case VersionUpdater::FAILED_CONNECTION_TYPE_DISALLOWED: + return SafetyCheckHandler::UpdateStatus::kFailed; + case VersionUpdater::FAILED_OFFLINE: + return SafetyCheckHandler::UpdateStatus::kFailedOffline; + } +} +} // namespace SafetyCheckHandler::SafetyCheckHandler() = default; SafetyCheckHandler::~SafetyCheckHandler() = default; void SafetyCheckHandler::PerformSafetyCheck() { - version_updater_.reset(VersionUpdater::Create(web_ui()->GetWebContents())); - CheckUpdates(version_updater_.get(), - base::Bind(&SafetyCheckHandler::OnUpdateCheckResult, - base::Unretained(this))); + AllowJavascript(); + + if (!version_updater_) { + version_updater_.reset(VersionUpdater::Create(web_ui()->GetWebContents())); + } + DCHECK(version_updater_); + CheckUpdates(); + + CheckSafeBrowsing(); + + if (!leak_service_) { + leak_service_ = BulkLeakCheckServiceFactory::GetForProfile( + Profile::FromWebUI(web_ui())); + } + DCHECK(leak_service_); + if (!passwords_delegate_) { + passwords_delegate_ = + extensions::PasswordsPrivateDelegateFactory::GetForBrowserContext( + Profile::FromWebUI(web_ui()), true); + } + DCHECK(passwords_delegate_); + CheckPasswords(); + + if (!extension_prefs_) { + extension_prefs_ = extensions::ExtensionPrefsFactory::GetForBrowserContext( + Profile::FromWebUI(web_ui())); + } + DCHECK(extension_prefs_); + if (!extension_service_) { + extension_service_ = + extensions::ExtensionSystem::Get(Profile::FromWebUI(web_ui())) + ->extension_service(); + } + DCHECK(extension_service_); + CheckExtensions(); } -void SafetyCheckHandler::CheckUpdates( - VersionUpdater* version_updater, - const VersionUpdater::StatusCallback& update_callback) { - version_updater->CheckForUpdate(update_callback, - VersionUpdater::PromoteCallback()); +SafetyCheckHandler::SafetyCheckHandler( + std::unique_ptr<VersionUpdater> version_updater, + password_manager::BulkLeakCheckService* leak_service, + extensions::PasswordsPrivateDelegate* passwords_delegate, + extensions::ExtensionPrefs* extension_prefs, + extensions::ExtensionServiceInterface* extension_service) + : version_updater_(std::move(version_updater)), + leak_service_(leak_service), + passwords_delegate_(passwords_delegate), + extension_prefs_(extension_prefs), + extension_service_(extension_service) {} + +void SafetyCheckHandler::HandlePerformSafetyCheck(const base::ListValue* args) { + PerformSafetyCheck(); +} + +void SafetyCheckHandler::HandleGetParentRanDisplayString( + const base::ListValue* args) { + const base::Value* callback_id; + double timestampRanDouble; + CHECK(args->Get(0, &callback_id)); + CHECK(args->GetDouble(1, ×tampRanDouble)); + + ResolveJavascriptCallback( + *callback_id, base::Value(GetStringForParentRan(timestampRanDouble))); +} + +void SafetyCheckHandler::CheckUpdates() { + // Usage of base::Unretained(this) is safe, because we own `version_updater_`. + version_updater_->CheckForUpdate( + base::Bind(&SafetyCheckHandler::OnUpdateCheckResult, + base::Unretained(this)), + VersionUpdater::PromoteCallback()); +} + +void SafetyCheckHandler::CheckSafeBrowsing() { + PrefService* pref_service = Profile::FromWebUI(web_ui())->GetPrefs(); + const PrefService::Preference* pref = + pref_service->FindPreference(prefs::kSafeBrowsingEnabled); + SafeBrowsingStatus status; + if (pref_service->GetBoolean(prefs::kSafeBrowsingEnabled)) { + status = SafeBrowsingStatus::kEnabled; + } else if (pref->IsManaged()) { + status = SafeBrowsingStatus::kDisabledByAdmin; + } else if (pref->IsExtensionControlled()) { + status = SafeBrowsingStatus::kDisabledByExtension; + } else { + status = SafeBrowsingStatus::kDisabled; + } + OnSafeBrowsingCheckResult(status); +} + +void SafetyCheckHandler::CheckPasswords() { + // Remove |this| as an existing observer for BulkLeakCheck if it is + // registered. This takes care of an edge case when safety check starts twice + // on the same page. Normally this should not happen, but if it does, the + // browser should not crash. + observed_leak_check_.RemoveAll(); + observed_leak_check_.Add(leak_service_); + passwords_delegate_->StartPasswordCheck(base::BindOnce( + &SafetyCheckHandler::OnStateChanged, weak_ptr_factory_.GetWeakPtr())); +} + +void SafetyCheckHandler::CheckExtensions() { + extensions::ExtensionIdList extensions; + extension_prefs_->GetExtensions(&extensions); + int blocklisted = 0; + int reenabled_by_user = 0; + int reenabled_by_admin = 0; + for (auto extension_id : extensions) { + extensions::BlacklistState state = + extension_prefs_->GetExtensionBlacklistState(extension_id); + if (state == extensions::BLACKLISTED_UNKNOWN) { + // If any of the extensions are in the unknown blacklist state, that means + // there was an error the last time the blacklist was fetched. That means + // the results cannot be relied upon. + OnExtensionsCheckResult(ExtensionsStatus::kError, Blocklisted(0), + ReenabledUser(0), ReenabledAdmin(0)); + return; + } + if (state == extensions::NOT_BLACKLISTED) { + continue; + } + ++blocklisted; + if (!extension_service_->IsExtensionEnabled(extension_id)) { + continue; + } + if (extension_service_->UserCanDisableInstalledExtension(extension_id)) { + ++reenabled_by_user; + } else { + ++reenabled_by_admin; + } + } + if (blocklisted == 0) { + OnExtensionsCheckResult(ExtensionsStatus::kNoneBlocklisted, Blocklisted(0), + ReenabledUser(0), ReenabledAdmin(0)); + } else if (reenabled_by_user == 0 && reenabled_by_admin == 0) { + OnExtensionsCheckResult(ExtensionsStatus::kBlocklistedAllDisabled, + Blocklisted(blocklisted), ReenabledUser(0), + ReenabledAdmin(0)); + } else if (reenabled_by_user > 0 && reenabled_by_admin == 0) { + OnExtensionsCheckResult(ExtensionsStatus::kBlocklistedReenabledAllByUser, + Blocklisted(blocklisted), + ReenabledUser(reenabled_by_user), + ReenabledAdmin(0)); + } else if (reenabled_by_admin > 0 && reenabled_by_user == 0) { + OnExtensionsCheckResult(ExtensionsStatus::kBlocklistedReenabledAllByAdmin, + Blocklisted(blocklisted), ReenabledUser(0), + ReenabledAdmin(reenabled_by_admin)); + } else { + OnExtensionsCheckResult(ExtensionsStatus::kBlocklistedReenabledSomeByUser, + Blocklisted(blocklisted), + ReenabledUser(reenabled_by_user), + ReenabledAdmin(reenabled_by_admin)); + } } void SafetyCheckHandler::OnUpdateCheckResult(VersionUpdater::Status status, @@ -30,5 +245,370 @@ void SafetyCheckHandler::OnUpdateCheckResult(VersionUpdater::Status status, const std::string& version, int64_t update_size, const base::string16& message) { - NOTIMPLEMENTED(); + UpdateStatus update_status = ConvertToUpdateStatus(status); + base::DictionaryValue event; + event.SetIntKey(kNewState, + static_cast<int>(update_status != UpdateStatus::kUnknown + ? update_status + : UpdateStatus::kFailedOffline)); + event.SetStringKey(kDisplayString, GetStringForUpdates(update_status)); + FireWebUIListener(kUpdatesEvent, event); + if (update_status != UpdateStatus::kChecking) { + base::UmaHistogramEnumeration("Settings.SafetyCheck.UpdatesResult", + update_status); + } +} + +void SafetyCheckHandler::OnSafeBrowsingCheckResult( + SafetyCheckHandler::SafeBrowsingStatus status) { + base::DictionaryValue event; + event.SetIntKey(kNewState, static_cast<int>(status)); + event.SetStringKey(kDisplayString, GetStringForSafeBrowsing(status)); + FireWebUIListener(kSafeBrowsingEvent, event); + if (status != SafeBrowsingStatus::kChecking) { + base::UmaHistogramEnumeration("Settings.SafetyCheck.SafeBrowsingResult", + status); + } +} + +void SafetyCheckHandler::OnPasswordsCheckResult(PasswordsStatus status, + Compromised compromised, + Done done, + Total total) { + base::DictionaryValue event; + event.SetIntKey(kNewState, static_cast<int>(status)); + if (status == PasswordsStatus::kCompromisedExist) { + event.SetIntKey(kPasswordsCompromised, compromised.value()); + event.SetStringKey( + kButtonString, + l10n_util::GetPluralStringFUTF16( + IDS_SETTINGS_SAFETY_CHECK_PASSWORDS_BUTTON, compromised.value())); + } + event.SetStringKey(kDisplayString, + GetStringForPasswords(status, compromised, done, total)); + FireWebUIListener(kPasswordsEvent, event); + if (status != PasswordsStatus::kChecking) { + base::UmaHistogramEnumeration("Settings.SafetyCheck.PasswordsResult", + status); + } +} + +void SafetyCheckHandler::OnExtensionsCheckResult( + ExtensionsStatus status, + Blocklisted blocklisted, + ReenabledUser reenabled_user, + ReenabledAdmin reenabled_admin) { + base::DictionaryValue event; + event.SetIntKey(kNewState, static_cast<int>(status)); + if (status == ExtensionsStatus::kBlocklistedReenabledAllByUser || + status == ExtensionsStatus::kBlocklistedReenabledSomeByUser) { + event.SetIntKey(kExtensionsReenabledByUser, reenabled_user.value()); + } + if (status == ExtensionsStatus::kBlocklistedReenabledAllByAdmin || + status == ExtensionsStatus::kBlocklistedReenabledSomeByUser) { + event.SetIntKey(kExtensionsReenabledByAdmin, reenabled_admin.value()); + } + event.SetStringKey(kDisplayString, + GetStringForExtensions(status, Blocklisted(blocklisted), + reenabled_user, reenabled_admin)); + FireWebUIListener(kExtensionsEvent, event); + if (status != ExtensionsStatus::kChecking) { + base::UmaHistogramEnumeration("Settings.SafetyCheck.ExtensionsResult", + status); + } +} + +base::string16 SafetyCheckHandler::GetStringForUpdates(UpdateStatus status) { + switch (status) { + case UpdateStatus::kChecking: + return l10n_util::GetStringUTF16(IDS_SETTINGS_SAFETY_CHECK_RUNNING); + case UpdateStatus::kUpdated: +#if defined(OS_CHROMEOS) + return ui::SubstituteChromeOSDeviceType(IDS_SETTINGS_UPGRADE_UP_TO_DATE); +#else + return l10n_util::GetStringUTF16(IDS_SETTINGS_UPGRADE_UP_TO_DATE); +#endif + case UpdateStatus::kUpdating: + return l10n_util::GetStringUTF16(IDS_SETTINGS_UPGRADE_UPDATING); + case UpdateStatus::kRelaunch: + return l10n_util::GetStringUTF16( + IDS_SETTINGS_UPGRADE_SUCCESSFUL_RELAUNCH); + case UpdateStatus::kDisabledByAdmin: + return l10n_util::GetStringFUTF16( + IDS_SETTINGS_SAFETY_CHECK_UPDATES_DISABLED_BY_ADMIN, + base::ASCIIToUTF16(chrome::kWhoIsMyAdministratorHelpURL)); + case UpdateStatus::kFailedOffline: + return l10n_util::GetStringUTF16( + IDS_SETTINGS_SAFETY_CHECK_UPDATES_FAILED_OFFLINE); + case UpdateStatus::kFailed: + return l10n_util::GetStringFUTF16( + IDS_SETTINGS_SAFETY_CHECK_UPDATES_FAILED, + base::ASCIIToUTF16(chrome::kChromeFixUpdateProblems)); + case UpdateStatus::kUnknown: + return l10n_util::GetStringFUTF16( + IDS_SETTINGS_ABOUT_PAGE_BROWSER_VERSION, + base::UTF8ToUTF16(version_info::GetVersionNumber()), + l10n_util::GetStringUTF16(version_info::IsOfficialBuild() + ? IDS_VERSION_UI_OFFICIAL + : IDS_VERSION_UI_UNOFFICIAL), + base::UTF8ToUTF16(chrome::GetChannelName()), + l10n_util::GetStringUTF16(sizeof(void*) == 8 ? IDS_VERSION_UI_64BIT + : IDS_VERSION_UI_32BIT)); + } +} + +base::string16 SafetyCheckHandler::GetStringForSafeBrowsing( + SafeBrowsingStatus status) { + switch (status) { + case SafeBrowsingStatus::kChecking: + return l10n_util::GetStringUTF16(IDS_SETTINGS_SAFETY_CHECK_RUNNING); + case SafeBrowsingStatus::kEnabled: + return l10n_util::GetStringUTF16( + IDS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_ENABLED); + case SafeBrowsingStatus::kDisabled: + return l10n_util::GetStringUTF16( + IDS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_DISABLED); + case SafeBrowsingStatus::kDisabledByAdmin: + return l10n_util::GetStringFUTF16( + IDS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_DISABLED_BY_ADMIN, + base::ASCIIToUTF16(chrome::kWhoIsMyAdministratorHelpURL)); + case SafeBrowsingStatus::kDisabledByExtension: + return l10n_util::GetStringUTF16( + IDS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_DISABLED_BY_EXTENSION); + } +} + +base::string16 SafetyCheckHandler::GetStringForPasswords( + PasswordsStatus status, + Compromised compromised, + Done done, + Total total) { + const base::string16 short_product_name = + l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME); + switch (status) { + case PasswordsStatus::kChecking: { + // Unable to get progress for some reason. + if (total.value() == 0) { + return l10n_util::GetStringUTF16(IDS_SETTINGS_SAFETY_CHECK_RUNNING); + } + return l10n_util::GetStringFUTF16(IDS_SETTINGS_CHECK_PASSWORDS_PROGRESS, + base::FormatNumber(done.value()), + base::FormatNumber(total.value())); + } + case PasswordsStatus::kSafe: + return l10n_util::GetPluralStringFUTF16( + IDS_SETTINGS_COMPROMISED_PASSWORDS_COUNT, 0); + case PasswordsStatus::kCompromisedExist: + return l10n_util::GetPluralStringFUTF16( + IDS_SETTINGS_COMPROMISED_PASSWORDS_COUNT, compromised.value()); + case PasswordsStatus::kOffline: + return l10n_util::GetStringFUTF16( + IDS_SETTINGS_CHECK_PASSWORDS_ERROR_OFFLINE, short_product_name); + case PasswordsStatus::kNoPasswords: + return l10n_util::GetStringFUTF16( + IDS_SETTINGS_CHECK_PASSWORDS_ERROR_NO_PASSWORDS, short_product_name); + case PasswordsStatus::kSignedOut: + return l10n_util::GetStringUTF16( + IDS_SETTINGS_SAFETY_CHECK_PASSWORDS_SIGNED_OUT); + case PasswordsStatus::kQuotaLimit: + return l10n_util::GetStringFUTF16( + IDS_SETTINGS_CHECK_PASSWORDS_ERROR_QUOTA_LIMIT, short_product_name); + case PasswordsStatus::kError: + return l10n_util::GetStringFUTF16( + IDS_SETTINGS_CHECK_PASSWORDS_ERROR_GENERIC, short_product_name); + } +} + +base::string16 SafetyCheckHandler::GetStringForExtensions( + ExtensionsStatus status, + Blocklisted blocklisted, + ReenabledUser reenabled_user, + ReenabledAdmin reenabled_admin) { + switch (status) { + case ExtensionsStatus::kChecking: + return l10n_util::GetStringUTF16(IDS_SETTINGS_SAFETY_CHECK_RUNNING); + case ExtensionsStatus::kError: + return l10n_util::GetStringUTF16( + IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_ERROR); + case ExtensionsStatus::kNoneBlocklisted: + return l10n_util::GetStringUTF16( + IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_SAFE); + case ExtensionsStatus::kBlocklistedAllDisabled: + return l10n_util::GetPluralStringFUTF16( + IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_BLOCKLISTED_OFF, + blocklisted.value()); + case ExtensionsStatus::kBlocklistedReenabledAllByUser: + return l10n_util::GetPluralStringFUTF16( + IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_BLOCKLISTED_ON_USER, + reenabled_user.value()); + case ExtensionsStatus::kBlocklistedReenabledSomeByUser: + // TODO(crbug/1060625): Make string concatenation with a period + // internationalized (see go/i18n-concatenation). + return l10n_util::GetPluralStringFUTF16( + IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_BLOCKLISTED_ON_USER, + reenabled_user.value()) + + base::ASCIIToUTF16(". ") + + l10n_util::GetPluralStringFUTF16( + IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_BLOCKLISTED_ON_ADMIN, + reenabled_admin.value()) + + base::ASCIIToUTF16("."); + case ExtensionsStatus::kBlocklistedReenabledAllByAdmin: + return l10n_util::GetPluralStringFUTF16( + IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_BLOCKLISTED_ON_ADMIN, + reenabled_admin.value()); + } +} + +base::string16 SafetyCheckHandler::GetStringForParentRan(double timestamp_ran) { + return SafetyCheckHandler::GetStringForParentRan(timestamp_ran, + base::Time::Now()); +} + +base::string16 SafetyCheckHandler::GetStringForParentRan( + double timestamp_ran, + base::Time system_time) { + const base::Time timeRan = base::Time::FromJsTime(timestamp_ran); + base::Time::Exploded timeRanExploded; + timeRan.LocalExplode(&timeRanExploded); + + base::Time::Exploded systemTimeExploded; + system_time.LocalExplode(&systemTimeExploded); + + const base::Time timeYesterday = system_time - base::TimeDelta::FromDays(1); + base::Time::Exploded timeYesterdayExploded; + timeYesterday.LocalExplode(&timeYesterdayExploded); + + const auto timeDiff = system_time - timeRan; + if (timeRanExploded.year == systemTimeExploded.year && + timeRanExploded.month == systemTimeExploded.month && + timeRanExploded.day_of_month == systemTimeExploded.day_of_month) { + // Safety check ran today. + const int timeDiffInMinutes = timeDiff.InMinutes(); + if (timeDiffInMinutes == 0) { + return l10n_util::GetStringUTF16( + IDS_SETTINGS_SAFETY_CHECK_PARENT_PRIMARY_LABEL_AFTER); + } else if (timeDiffInMinutes < 60) { + return l10n_util::GetPluralStringFUTF16( + IDS_SETTINGS_SAFETY_CHECK_PARENT_PRIMARY_LABEL_AFTER_MINS, + timeDiffInMinutes); + } else { + return l10n_util::GetPluralStringFUTF16( + IDS_SETTINGS_SAFETY_CHECK_PARENT_PRIMARY_LABEL_AFTER_HOURS, + timeDiffInMinutes / 60); + } + } else if (timeRanExploded.year == timeYesterdayExploded.year && + timeRanExploded.month == timeYesterdayExploded.month && + timeRanExploded.day_of_month == + timeYesterdayExploded.day_of_month) { + // Safety check ran yesterday. + return l10n_util::GetStringUTF16( + IDS_SETTINGS_SAFETY_CHECK_PARENT_PRIMARY_LABEL_AFTER_YESTERDAY); + } else { + // Safety check ran longer ago than yesterday. + // TODO(crbug.com/1015841): While a minor issue, this is not be the ideal + // way to calculate the days passed since safety check ran. For example, + // <48 h might still be 2 days ago. + const int timeDiffInDays = timeDiff.InDays(); + return l10n_util::GetPluralStringFUTF16( + IDS_SETTINGS_SAFETY_CHECK_PARENT_PRIMARY_LABEL_AFTER_DAYS, + timeDiffInDays); + } +} + +void SafetyCheckHandler::DetermineIfNoPasswordsOrSafe( + const std::vector<extensions::api::passwords_private::PasswordUiEntry>& + passwords) { + OnPasswordsCheckResult(passwords.empty() ? PasswordsStatus::kNoPasswords + : PasswordsStatus::kSafe, + Compromised(0), Done(0), Total(0)); +} + +void SafetyCheckHandler::OnStateChanged( + password_manager::BulkLeakCheckService::State state) { + using password_manager::BulkLeakCheckService; + switch (state) { + case BulkLeakCheckService::State::kIdle: + case BulkLeakCheckService::State::kCanceled: { + size_t num_compromised = + passwords_delegate_->GetCompromisedCredentials().size(); + if (num_compromised == 0) { + passwords_delegate_->GetSavedPasswordsList( + base::BindOnce(&SafetyCheckHandler::DetermineIfNoPasswordsOrSafe, + base::Unretained(this))); + } else { + OnPasswordsCheckResult(PasswordsStatus::kCompromisedExist, + Compromised(num_compromised), Done(0), Total(0)); + } + break; + } + case BulkLeakCheckService::State::kRunning: + OnPasswordsCheckResult(PasswordsStatus::kChecking, Compromised(0), + Done(0), Total(0)); + // Non-terminal state, so nothing else needs to be done. + return; + case BulkLeakCheckService::State::kSignedOut: + OnPasswordsCheckResult(PasswordsStatus::kSignedOut, Compromised(0), + Done(0), Total(0)); + break; + case BulkLeakCheckService::State::kNetworkError: + OnPasswordsCheckResult(PasswordsStatus::kOffline, Compromised(0), Done(0), + Total(0)); + break; + case BulkLeakCheckService::State::kQuotaLimit: + OnPasswordsCheckResult(PasswordsStatus::kQuotaLimit, Compromised(0), + Done(0), Total(0)); + break; + case BulkLeakCheckService::State::kTokenRequestFailure: + case BulkLeakCheckService::State::kHashingFailure: + case BulkLeakCheckService::State::kServiceError: + OnPasswordsCheckResult(PasswordsStatus::kError, Compromised(0), Done(0), + Total(0)); + break; + } + + // Stop observing the leak service in all terminal states, if it's still being + // observed. + observed_leak_check_.RemoveAll(); +} + +void SafetyCheckHandler::OnCredentialDone( + const password_manager::LeakCheckCredential& credential, + password_manager::IsLeaked is_leaked) { + extensions::api::passwords_private::PasswordCheckStatus status = + passwords_delegate_->GetPasswordCheckStatus(); + // Send progress updates only if the check is still running. + if (status.state == + extensions::api::passwords_private::PASSWORD_CHECK_STATE_RUNNING && + status.already_processed && status.remaining_in_queue) { + Done done = Done(*(status.already_processed)); + Total total = Total(*(status.remaining_in_queue) + done.value()); + OnPasswordsCheckResult(PasswordsStatus::kChecking, Compromised(0), done, + total); + } +} + +void SafetyCheckHandler::OnJavascriptAllowed() {} + +void SafetyCheckHandler::OnJavascriptDisallowed() { + // Remove |this| as an observer for BulkLeakCheck. This takes care of an edge + // case when the page is reloaded while the password check is in progress and + // another safety check is started. Otherwise |observed_leak_check_| + // automatically calls RemoveAll() on destruction. + observed_leak_check_.RemoveAll(); + // Destroy the version updater to prevent getting a callback and firing a + // WebUI event, which would cause a crash. + version_updater_.reset(); +} + +void SafetyCheckHandler::RegisterMessages() { + // Usage of base::Unretained(this) is safe, because web_ui() owns `this` and + // won't release ownership until destruction. + web_ui()->RegisterMessageCallback( + kPerformSafetyCheck, + base::BindRepeating(&SafetyCheckHandler::HandlePerformSafetyCheck, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + kGetParentRanDisplayString, + base::BindRepeating(&SafetyCheckHandler::HandleGetParentRanDisplayString, + base::Unretained(this))); } diff --git a/chromium/chrome/browser/ui/webui/settings/safety_check_handler.h b/chromium/chrome/browser/ui/webui/settings/safety_check_handler.h index 6268c712010..0680927e4c8 100644 --- a/chromium/chrome/browser/ui/webui/settings/safety_check_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/safety_check_handler.h @@ -13,13 +13,75 @@ #include "base/callback_forward.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "base/scoped_observer.h" +#include "base/util/type_safety/strong_alias.h" +#include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/ui/webui/help/version_updater.h" #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" +#include "components/password_manager/core/browser/bulk_leak_check_service.h" +#include "extensions/browser/extension_prefs.h" +#include "extensions/browser/extension_registry.h" -// Settings page UI handler that checks four areas of browser safety: browser -// updates, password leaks, malicious extensions, and unwanted software. -class SafetyCheckHandler : public settings::SettingsPageUIHandler { +// Settings page UI handler that checks four areas of browser safety: +// browser updates, password leaks, malicious extensions, and unwanted +// software. +class SafetyCheckHandler + : public settings::SettingsPageUIHandler, + public password_manager::BulkLeakCheckService::Observer { public: + // The following enums represent the state of each component of the safety + // check and should be kept in sync with the JS frontend + // (safety_check_browser_proxy.js) and |SafetyCheck*| metrics enums in + // enums.xml. + enum class UpdateStatus { + kChecking = 0, + kUpdated = 1, + kUpdating = 2, + kRelaunch = 3, + kDisabledByAdmin = 4, + kFailedOffline = 5, + kFailed = 6, + // Non-Google branded browsers cannot check for updates using + // VersionUpdater. + kUnknown = 7, + // New enum values must go above here. + kMaxValue = kUnknown, + }; + enum class SafeBrowsingStatus { + kChecking = 0, + kEnabled = 1, + kDisabled = 2, + kDisabledByAdmin = 3, + kDisabledByExtension = 4, + // New enum values must go above here. + kMaxValue = kDisabledByExtension, + }; + enum class PasswordsStatus { + kChecking = 0, + kSafe = 1, + kCompromisedExist = 2, + kOffline = 3, + kNoPasswords = 4, + kSignedOut = 5, + kQuotaLimit = 6, + kError = 7, + // New enum values must go above here. + kMaxValue = kError, + }; + enum class ExtensionsStatus { + kChecking = 0, + kError = 1, + kNoneBlocklisted = 2, + kBlocklistedAllDisabled = 3, + kBlocklistedReenabledAllByUser = 4, + // In this case, at least one of the extensions was re-enabled by admin. + kBlocklistedReenabledSomeByUser = 5, + kBlocklistedReenabledAllByAdmin = 6, + // New enum values must go above here. + kMaxValue = kBlocklistedReenabledAllByAdmin, + }; + SafetyCheckHandler(); ~SafetyCheckHandler() override; @@ -28,18 +90,57 @@ class SafetyCheckHandler : public settings::SettingsPageUIHandler { // should only be called as a result of an explicit user action. void PerformSafetyCheck(); - // Each triggers a corresponding check and calls the provided callback on - // completion. - void CheckUpdates(VersionUpdater* updater, - const VersionUpdater::StatusCallback& update_callback); + // Constructs the 'safety check ran' display string by how long ago safety + // check ran. + base::string16 GetStringForParentRan(double timestamp_ran); + base::string16 GetStringForParentRan(double timestamp_ran, + base::Time systemTime); + + protected: + SafetyCheckHandler(std::unique_ptr<VersionUpdater> version_updater, + password_manager::BulkLeakCheckService* leak_service, + extensions::PasswordsPrivateDelegate* passwords_delegate, + extensions::ExtensionPrefs* extension_prefs, + extensions::ExtensionServiceInterface* extension_service); + + void SetVersionUpdaterForTesting( + std::unique_ptr<VersionUpdater> version_updater) { + version_updater_ = std::move(version_updater); + } private: - // SettingsPageUIHandler implementation. - void OnJavascriptAllowed() override {} - void OnJavascriptDisallowed() override {} + // These ensure integers are passed in the correct possitions in the extension + // check methods. + using Compromised = util::StrongAlias<class CompromisedTag, int>; + using Done = util::StrongAlias<class DoneTag, int>; + using Total = util::StrongAlias<class TotalTag, int>; + using Blocklisted = util::StrongAlias<class BlocklistedTag, int>; + using ReenabledUser = util::StrongAlias<class ReenabledUserTag, int>; + using ReenabledAdmin = util::StrongAlias<class ReenabledAdminTag, int>; - // WebUIMessageHandler implementation. - void RegisterMessages() override {} + // Handles triggering the safety check from the frontend (by user pressing a + // button). + void HandlePerformSafetyCheck(const base::ListValue* args); + + // Handles updating the safety check parent display string to show how long + // ago the safety check last ran. + void HandleGetParentRanDisplayString(const base::ListValue* args); + + // Triggers an update check and invokes OnUpdateCheckResult once results + // are available. + void CheckUpdates(); + + // Gets the status of Safe Browsing from the PrefService and invokes + // OnSafeBrowsingCheckResult with results. + void CheckSafeBrowsing(); + + // Triggers a bulk password leak check and invokes OnPasswordsCheckResult once + // results are available. + void CheckPasswords(); + + // Checks if any of the installed extensions are blocklisted, and in + // that case, if any of those were re-enabled. + void CheckExtensions(); // Callbacks that get triggered when each check completes. void OnUpdateCheckResult(VersionUpdater::Status status, @@ -48,10 +149,60 @@ class SafetyCheckHandler : public settings::SettingsPageUIHandler { const std::string& version, int64_t update_size, const base::string16& message); + void OnSafeBrowsingCheckResult(SafeBrowsingStatus status); + void OnPasswordsCheckResult(PasswordsStatus status, + Compromised compromised, + Done done, + Total total); + void OnExtensionsCheckResult(ExtensionsStatus status, + Blocklisted blocklisted, + ReenabledUser reenabled_user, + ReenabledAdmin reenabled_admin); - std::unique_ptr<VersionUpdater> version_updater_; + // Methods for building user-visible strings based on the safety check + // state. + base::string16 GetStringForUpdates(UpdateStatus status); + base::string16 GetStringForSafeBrowsing(SafeBrowsingStatus status); + base::string16 GetStringForPasswords(PasswordsStatus status, + Compromised compromised, + Done done, + Total total); + base::string16 GetStringForExtensions(ExtensionsStatus status, + Blocklisted blocklisted, + ReenabledUser reenabled_user, + ReenabledAdmin reenabled_admin); + + // Since the password check API does not distinguish between the cases of + // having no compromised passwords and not having any passwords at all, it is + // necessary to use this method as a callback for + // |PasswordsPrivateDelegate::GetSavedPasswordsList| to distinguish the two + // states here. + void DetermineIfNoPasswordsOrSafe( + const std::vector<extensions::api::passwords_private::PasswordUiEntry>& + passwords); - DISALLOW_COPY_AND_ASSIGN(SafetyCheckHandler); + // BulkLeakCheckService::Observer implementation. + void OnStateChanged( + password_manager::BulkLeakCheckService::State state) override; + void OnCredentialDone(const password_manager::LeakCheckCredential& credential, + password_manager::IsLeaked is_leaked) override; + + // SettingsPageUIHandler implementation. + void OnJavascriptAllowed() override; + void OnJavascriptDisallowed() override; + + // WebUIMessageHandler implementation. + void RegisterMessages() override; + + std::unique_ptr<VersionUpdater> version_updater_; + password_manager::BulkLeakCheckService* leak_service_ = nullptr; + extensions::PasswordsPrivateDelegate* passwords_delegate_ = nullptr; + extensions::ExtensionPrefs* extension_prefs_ = nullptr; + extensions::ExtensionServiceInterface* extension_service_ = nullptr; + ScopedObserver<password_manager::BulkLeakCheckService, + password_manager::BulkLeakCheckService::Observer> + observed_leak_check_{this}; + base::WeakPtrFactory<SafetyCheckHandler> weak_ptr_factory_{this}; }; #endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_SAFETY_CHECK_HANDLER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/safety_check_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/safety_check_handler_unittest.cc index 827d2dec6bd..cefb6e359d7 100644 --- a/chromium/chrome/browser/ui/webui/settings/safety_check_handler_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/safety_check_handler_unittest.cc @@ -4,43 +4,1040 @@ #include "chrome/browser/ui/webui/settings/safety_check_handler.h" +#include <string> +#include <unordered_map> + #include "base/bind.h" +#include "base/optional.h" +#include "base/strings/string16.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/metrics/histogram_tester.h" +#include "base/test/metrics/user_action_tester.h" +#include "base/util/type_safety/strong_alias.h" +#include "build/build_config.h" +#include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h" +#include "chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.h" +#include "chrome/browser/extensions/test_extension_service.h" #include "chrome/browser/ui/webui/help/test_version_updater.h" +#include "chrome/common/channel_info.h" +#include "chrome/common/extensions/api/passwords_private.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "components/crx_file/id_util.h" +#include "components/password_manager/core/browser/bulk_leak_check_service.h" +#include "components/password_manager/core/browser/leak_detection/bulk_leak_check.h" +#include "components/prefs/pref_service.h" +#include "components/safe_browsing/core/common/safe_browsing_prefs.h" +#include "components/sync_preferences/testing_pref_service_syncable.h" +#include "components/version_info/version_info.h" +#include "content/public/test/test_web_ui.h" +#include "extensions/browser/extension_prefs.h" +#include "extensions/common/extension.h" +#include "extensions/common/extension_builder.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" #include "testing/gtest/include/gtest/gtest.h" -class SafetyCheckHandlerTest : public ::testing::Test { +#if defined(OS_CHROMEOS) +#include "ui/chromeos/devicetype_utils.h" +#endif + +// Components for building event strings. +constexpr char kUpdates[] = "updates"; +constexpr char kPasswords[] = "passwords"; +constexpr char kSafeBrowsing[] = "safe-browsing"; +constexpr char kExtensions[] = "extensions"; + +namespace { +using Enabled = util::StrongAlias<class EnabledTag, bool>; +using UserCanDisable = util::StrongAlias<class UserCanDisableTag, bool>; + +class TestingSafetyCheckHandler : public SafetyCheckHandler { public: - void Callback(VersionUpdater::Status status, - int progress, - bool rollback, - const std::string& version, - int64_t update_size, - const base::string16& message) { - callback_invoked_ = true; - result_ = status; + using SafetyCheckHandler::AllowJavascript; + using SafetyCheckHandler::DisallowJavascript; + using SafetyCheckHandler::set_web_ui; + using SafetyCheckHandler::SetVersionUpdaterForTesting; + + TestingSafetyCheckHandler( + std::unique_ptr<VersionUpdater> version_updater, + password_manager::BulkLeakCheckService* leak_service, + extensions::PasswordsPrivateDelegate* passwords_delegate, + extensions::ExtensionPrefs* extension_prefs, + extensions::ExtensionServiceInterface* extension_service) + : SafetyCheckHandler(std::move(version_updater), + leak_service, + passwords_delegate, + extension_prefs, + extension_service) {} +}; + +class TestDestructionVersionUpdater : public TestVersionUpdater { + public: + ~TestDestructionVersionUpdater() override { destructor_invoked_ = true; } + + void CheckForUpdate(const StatusCallback& callback, + const PromoteCallback&) override {} + + static bool GetDestructorInvoked() { return destructor_invoked_; } + + private: + static bool destructor_invoked_; +}; + +bool TestDestructionVersionUpdater::destructor_invoked_ = false; + +class TestPasswordsDelegate : public extensions::TestPasswordsPrivateDelegate { + public: + void SetBulkLeakCheckService( + password_manager::BulkLeakCheckService* leak_service) { + leak_service_ = leak_service; + } + + void SetNumCompromisedCredentials(int compromised_password_count) { + compromised_password_count_ = compromised_password_count; } + void SetPasswordCheckState( + extensions::api::passwords_private::PasswordCheckState state) { + state_ = state; + } + + void SetProgress(int done, int total) { + done_ = done; + total_ = total; + } + + std::vector<extensions::api::passwords_private::CompromisedCredential> + GetCompromisedCredentials() override { + std::vector<extensions::api::passwords_private::CompromisedCredential> + compromised(compromised_password_count_); + for (int i = 0; i < compromised_password_count_; ++i) { + compromised[i].username = "test" + base::NumberToString(i); + } + return compromised; + } + + extensions::api::passwords_private::PasswordCheckStatus + GetPasswordCheckStatus() override { + extensions::api::passwords_private::PasswordCheckStatus status; + status.state = state_; + if (total_ != 0) { + status.already_processed = std::make_unique<int>(done_); + status.remaining_in_queue = std::make_unique<int>(total_ - done_); + } + return status; + } + + private: + password_manager::BulkLeakCheckService* leak_service_ = nullptr; + int compromised_password_count_ = 0; + int done_ = 0; + int total_ = 0; + extensions::api::passwords_private::PasswordCheckState state_ = + extensions::api::passwords_private::PASSWORD_CHECK_STATE_IDLE; +}; + +class TestSafetyCheckExtensionService : public TestExtensionService { + public: + void AddExtensionState(const std::string& extension_id, + Enabled enabled, + UserCanDisable user_can_disable) { + state_map_.emplace(extension_id, ExtensionState{enabled.value(), + user_can_disable.value()}); + } + + bool IsExtensionEnabled(const std::string& extension_id) const override { + auto it = state_map_.find(extension_id); + if (it == state_map_.end()) { + return false; + } + return it->second.enabled; + } + + bool UserCanDisableInstalledExtension( + const std::string& extension_id) override { + auto it = state_map_.find(extension_id); + if (it == state_map_.end()) { + return false; + } + return it->second.user_can_disable; + } + + private: + struct ExtensionState { + bool enabled; + bool user_can_disable; + }; + + std::unordered_map<std::string, ExtensionState> state_map_; +}; + +} // namespace + +class SafetyCheckHandlerTest : public ChromeRenderViewHostTestHarness { + public: + void SetUp() override; + + // Returns a |base::DictionaryValue| for safety check status update that + // has the specified |component| and |new_state| if it exists; nullptr + // otherwise. + const base::DictionaryValue* GetSafetyCheckStatusChangedWithDataIfExists( + const std::string& component, + int new_state); + + std::string GenerateExtensionId(char char_to_repeat); + + void VerifyDisplayString(const base::DictionaryValue* event, + const base::string16& expected); + void VerifyDisplayString(const base::DictionaryValue* event, + const std::string& expected); + void VerifyButtonString(const base::DictionaryValue* event, + const base::string16& expected); + void VerifyButtonString(const base::DictionaryValue* event, + const std::string& expected); + protected: - bool callback_invoked_ = false; - VersionUpdater::Status result_; - TestVersionUpdater version_updater_; - SafetyCheckHandler safety_check_; + TestVersionUpdater* version_updater_ = nullptr; + std::unique_ptr<password_manager::BulkLeakCheckService> test_leak_service_; + TestPasswordsDelegate test_passwords_delegate_; + extensions::ExtensionPrefs* test_extension_prefs_ = nullptr; + TestSafetyCheckExtensionService test_extension_service_; + content::TestWebUI test_web_ui_; + std::unique_ptr<TestingSafetyCheckHandler> safety_check_; + base::HistogramTester histogram_tester_; + + private: + // Replaces any instances of browser name (e.g. Google Chrome, Chromium, + // etc) with "browser" to make sure tests work both on Chromium and + // Google Chrome. + void ReplaceBrowserName(base::string16* s); }; -TEST_F(SafetyCheckHandlerTest, CheckUpdatesUpdated) { - version_updater_.SetReturnedStatus(VersionUpdater::Status::UPDATED); - safety_check_.CheckUpdates( - &version_updater_, - base::Bind(&SafetyCheckHandlerTest::Callback, base::Unretained(this))); - ASSERT_TRUE(callback_invoked_); - EXPECT_EQ(VersionUpdater::Status::UPDATED, result_); -} - -TEST_F(SafetyCheckHandlerTest, CheckUpdatesNotUpdated) { - version_updater_.SetReturnedStatus(VersionUpdater::Status::DISABLED); - safety_check_.CheckUpdates( - &version_updater_, - base::Bind(&SafetyCheckHandlerTest::Callback, base::Unretained(this))); - ASSERT_TRUE(callback_invoked_); - EXPECT_EQ(VersionUpdater::Status::DISABLED, result_); +void SafetyCheckHandlerTest::SetUp() { + ChromeRenderViewHostTestHarness::SetUp(); + + // The unique pointer to a TestVersionUpdater gets moved to + // SafetyCheckHandler, but a raw pointer is retained here to change its + // state. + auto version_updater = std::make_unique<TestVersionUpdater>(); + test_leak_service_ = std::make_unique<password_manager::BulkLeakCheckService>( + nullptr, nullptr); + test_passwords_delegate_.SetBulkLeakCheckService(test_leak_service_.get()); + version_updater_ = version_updater.get(); + test_web_ui_.set_web_contents(web_contents()); + test_extension_prefs_ = extensions::ExtensionPrefs::Get(profile()); + safety_check_ = std::make_unique<TestingSafetyCheckHandler>( + std::move(version_updater), test_leak_service_.get(), + &test_passwords_delegate_, test_extension_prefs_, + &test_extension_service_); + test_web_ui_.ClearTrackedCalls(); + safety_check_->set_web_ui(&test_web_ui_); + safety_check_->AllowJavascript(); +} + +const base::DictionaryValue* +SafetyCheckHandlerTest::GetSafetyCheckStatusChangedWithDataIfExists( + const std::string& component, + int new_state) { + // Return the latest update if multiple, so iterate from the end. + const std::vector<std::unique_ptr<content::TestWebUI::CallData>>& call_data = + test_web_ui_.call_data(); + for (int i = call_data.size() - 1; i >= 0; --i) { + const content::TestWebUI::CallData& data = *(call_data[i]); + if (data.function_name() != "cr.webUIListenerCallback") { + continue; + } + std::string event; + if ((!data.arg1()->GetAsString(&event)) || + event != "safety-check-" + component + "-status-changed") { + continue; + } + const base::DictionaryValue* dictionary = nullptr; + if (!data.arg2()->GetAsDictionary(&dictionary)) { + continue; + } + int cur_new_state; + if (dictionary->GetInteger("newState", &cur_new_state) && + cur_new_state == new_state) { + return dictionary; + } + } + return nullptr; +} + +std::string SafetyCheckHandlerTest::GenerateExtensionId(char char_to_repeat) { + return std::string(crx_file::id_util::kIdSize * 2, char_to_repeat); +} + +void SafetyCheckHandlerTest::VerifyDisplayString( + const base::DictionaryValue* event, + const base::string16& expected) { + base::string16 display; + ASSERT_TRUE(event->GetString("displayString", &display)); + ReplaceBrowserName(&display); + // Need to also replace any instances of Chrome and Chromium in the + // expected string due to an edge case on ChromeOS, where a device name + // is "Chrome", which gets replaced in the display string. + base::string16 expected_replaced = expected; + ReplaceBrowserName(&expected_replaced); + EXPECT_EQ(expected_replaced, display); +} + +void SafetyCheckHandlerTest::VerifyDisplayString( + const base::DictionaryValue* event, + const std::string& expected) { + VerifyDisplayString(event, base::ASCIIToUTF16(expected)); +} + +void SafetyCheckHandlerTest::VerifyButtonString( + const base::DictionaryValue* event, + const base::string16& expected) { + base::string16 button; + ASSERT_TRUE(event->GetString("buttonString", &button)); + EXPECT_EQ(expected, button); +} + +void SafetyCheckHandlerTest::VerifyButtonString( + const base::DictionaryValue* event, + const std::string& expected) { + VerifyButtonString(event, base::ASCIIToUTF16(expected)); +} + +void SafetyCheckHandlerTest::ReplaceBrowserName(base::string16* s) { + base::ReplaceSubstringsAfterOffset(s, 0, base::ASCIIToUTF16("Google Chrome"), + base::ASCIIToUTF16("Browser")); + base::ReplaceSubstringsAfterOffset(s, 0, base::ASCIIToUTF16("Chrome"), + base::ASCIIToUTF16("Browser")); + base::ReplaceSubstringsAfterOffset(s, 0, base::ASCIIToUTF16("Chromium"), + base::ASCIIToUTF16("Browser")); +} + +TEST_F(SafetyCheckHandlerTest, CheckUpdates_Checking) { + version_updater_->SetReturnedStatus(VersionUpdater::Status::CHECKING); + safety_check_->PerformSafetyCheck(); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kUpdates, + static_cast<int>(SafetyCheckHandler::UpdateStatus::kChecking)); + ASSERT_TRUE(event); + VerifyDisplayString(event, base::UTF8ToUTF16("Running…")); + // Checking state should not get recorded. + histogram_tester_.ExpectTotalCount("Settings.SafetyCheck.UpdatesResult", 0); +} + +TEST_F(SafetyCheckHandlerTest, CheckUpdates_Updated) { + version_updater_->SetReturnedStatus(VersionUpdater::Status::UPDATED); + safety_check_->PerformSafetyCheck(); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kUpdates, + static_cast<int>(SafetyCheckHandler::UpdateStatus::kUpdated)); + ASSERT_TRUE(event); +#if defined(OS_CHROMEOS) + base::string16 expected = base::ASCIIToUTF16("Your ") + + ui::GetChromeOSDeviceName() + + base::ASCIIToUTF16(" is up to date"); + VerifyDisplayString(event, expected); +#else + VerifyDisplayString(event, "Browser is up to date"); +#endif + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.UpdatesResult", + SafetyCheckHandler::UpdateStatus::kUpdated, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckUpdates_Updating) { + version_updater_->SetReturnedStatus(VersionUpdater::Status::UPDATING); + safety_check_->PerformSafetyCheck(); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kUpdates, + static_cast<int>(SafetyCheckHandler::UpdateStatus::kUpdating)); + ASSERT_TRUE(event); +#if defined(OS_CHROMEOS) + VerifyDisplayString(event, "Updating your device"); +#else + VerifyDisplayString(event, "Updating Browser"); +#endif + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.UpdatesResult", + SafetyCheckHandler::UpdateStatus::kUpdating, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckUpdates_Relaunch) { + version_updater_->SetReturnedStatus(VersionUpdater::Status::NEARLY_UPDATED); + safety_check_->PerformSafetyCheck(); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kUpdates, + static_cast<int>(SafetyCheckHandler::UpdateStatus::kRelaunch)); + ASSERT_TRUE(event); +#if defined(OS_CHROMEOS) + VerifyDisplayString( + event, "Nearly up to date! Restart your device to finish updating."); +#else + VerifyDisplayString(event, + "Nearly up to date! Relaunch Browser to finish " + "updating. Incognito windows won't reopen."); +#endif + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.UpdatesResult", + SafetyCheckHandler::UpdateStatus::kRelaunch, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckUpdates_Disabled) { + version_updater_->SetReturnedStatus(VersionUpdater::Status::DISABLED); + safety_check_->PerformSafetyCheck(); + // TODO(crbug/1072432): Since the UNKNOWN state is not present in JS in M83, + // use FAILED_OFFLINE, which uses the same icon. + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kUpdates, + static_cast<int>(SafetyCheckHandler::UpdateStatus::kFailedOffline)); + ASSERT_TRUE(event); + VerifyDisplayString( + event, "Version " + version_info::GetVersionNumber() + " (" + + (version_info::IsOfficialBuild() ? "Official Build" + : "Developer Build") + + ") " + chrome::GetChannelName() + + (sizeof(void*) == 8 ? " (64-bit)" : " (32-bit)")); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.UpdatesResult", + SafetyCheckHandler::UpdateStatus::kUnknown, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckUpdates_DisabledByAdmin) { + version_updater_->SetReturnedStatus( + VersionUpdater::Status::DISABLED_BY_ADMIN); + safety_check_->PerformSafetyCheck(); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kUpdates, + static_cast<int>(SafetyCheckHandler::UpdateStatus::kDisabledByAdmin)); + ASSERT_TRUE(event); + VerifyDisplayString( + event, + "Updates are managed by <a target=\"_blank\" " + "href=\"https://support.google.com/chrome?p=your_administrator\">your " + "administrator</a>"); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.UpdatesResult", + SafetyCheckHandler::UpdateStatus::kDisabledByAdmin, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckUpdates_FailedOffline) { + version_updater_->SetReturnedStatus(VersionUpdater::Status::FAILED_OFFLINE); + safety_check_->PerformSafetyCheck(); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kUpdates, + static_cast<int>(SafetyCheckHandler::UpdateStatus::kFailedOffline)); + ASSERT_TRUE(event); + VerifyDisplayString(event, + "Browser can't check for updates. Try checking your " + "internet connection."); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.UpdatesResult", + SafetyCheckHandler::UpdateStatus::kFailedOffline, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckUpdates_Failed) { + version_updater_->SetReturnedStatus(VersionUpdater::Status::FAILED); + safety_check_->PerformSafetyCheck(); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kUpdates, + static_cast<int>(SafetyCheckHandler::UpdateStatus::kFailed)); + ASSERT_TRUE(event); + VerifyDisplayString( + event, + "Browser didn't update, something went wrong. <a target=\"_blank\" " + "href=\"https://support.google.com/chrome?p=fix_chrome_updates\">Fix " + "Browser update problems and failed updates.</a>"); + histogram_tester_.ExpectBucketCount("Settings.SafetyCheck.UpdatesResult", + SafetyCheckHandler::UpdateStatus::kFailed, + 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckUpdates_DestroyedOnJavascriptDisallowed) { + EXPECT_FALSE(TestDestructionVersionUpdater::GetDestructorInvoked()); + safety_check_->SetVersionUpdaterForTesting( + std::make_unique<TestDestructionVersionUpdater>()); + safety_check_->PerformSafetyCheck(); + safety_check_->DisallowJavascript(); + EXPECT_TRUE(TestDestructionVersionUpdater::GetDestructorInvoked()); +} + +TEST_F(SafetyCheckHandlerTest, CheckSafeBrowsing_Enabled) { + Profile::FromWebUI(&test_web_ui_) + ->GetPrefs() + ->SetBoolean(prefs::kSafeBrowsingEnabled, true); + safety_check_->PerformSafetyCheck(); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kSafeBrowsing, + static_cast<int>(SafetyCheckHandler::SafeBrowsingStatus::kEnabled)); + ASSERT_TRUE(event); + VerifyDisplayString(event, + "Safe Browsing is on and protecting you from harmful " + "sites and downloads"); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.SafeBrowsingResult", + SafetyCheckHandler::SafeBrowsingStatus::kEnabled, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckSafeBrowsing_Disabled) { + Profile::FromWebUI(&test_web_ui_) + ->GetPrefs() + ->SetBoolean(prefs::kSafeBrowsingEnabled, false); + safety_check_->PerformSafetyCheck(); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kSafeBrowsing, + static_cast<int>(SafetyCheckHandler::SafeBrowsingStatus::kDisabled)); + ASSERT_TRUE(event); + VerifyDisplayString( + event, "Safe Browsing is off. Browser recommends turning it on."); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.SafeBrowsingResult", + SafetyCheckHandler::SafeBrowsingStatus::kDisabled, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckSafeBrowsing_DisabledByAdmin) { + TestingProfile::FromWebUI(&test_web_ui_) + ->AsTestingProfile() + ->GetTestingPrefService() + ->SetManagedPref(prefs::kSafeBrowsingEnabled, + std::make_unique<base::Value>(false)); + safety_check_->PerformSafetyCheck(); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kSafeBrowsing, + static_cast<int>( + SafetyCheckHandler::SafeBrowsingStatus::kDisabledByAdmin)); + ASSERT_TRUE(event); + VerifyDisplayString( + event, + "<a target=\"_blank\" " + "href=\"https://support.google.com/chrome?p=your_administrator\">Your " + "administrator</a> has turned off Safe Browsing"); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.SafeBrowsingResult", + SafetyCheckHandler::SafeBrowsingStatus::kDisabledByAdmin, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckSafeBrowsing_DisabledByExtension) { + TestingProfile::FromWebUI(&test_web_ui_) + ->AsTestingProfile() + ->GetTestingPrefService() + ->SetExtensionPref(prefs::kSafeBrowsingEnabled, + std::make_unique<base::Value>(false)); + safety_check_->PerformSafetyCheck(); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kSafeBrowsing, + static_cast<int>( + SafetyCheckHandler::SafeBrowsingStatus::kDisabledByExtension)); + ASSERT_TRUE(event); + VerifyDisplayString(event, "An extension has turned off Safe Browsing"); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.SafeBrowsingResult", + SafetyCheckHandler::SafeBrowsingStatus::kDisabledByExtension, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckPasswords_ObserverRemovedAfterError) { + safety_check_->PerformSafetyCheck(); + // First, a "running" change of state. + test_leak_service_->set_state_and_notify( + password_manager::BulkLeakCheckService::State::kRunning); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>(SafetyCheckHandler::PasswordsStatus::kChecking)); + ASSERT_TRUE(event); + VerifyDisplayString(event, base::UTF8ToUTF16("Running…")); + histogram_tester_.ExpectTotalCount("Settings.SafetyCheck.PasswordsResult", 0); + // Second, an "offline" state. + test_leak_service_->set_state_and_notify( + password_manager::BulkLeakCheckService::State::kNetworkError); + const base::DictionaryValue* event2 = + GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>(SafetyCheckHandler::PasswordsStatus::kOffline)); + ASSERT_TRUE(event2); + VerifyDisplayString(event2, + "Browser can't check your passwords. Try checking your " + "internet connection."); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.PasswordsResult", + SafetyCheckHandler::PasswordsStatus::kOffline, 1); + // Another error, but since the previous state is terminal, the handler + // should no longer be observing the BulkLeakCheckService state. + test_leak_service_->set_state_and_notify( + password_manager::BulkLeakCheckService::State::kServiceError); + const base::DictionaryValue* event3 = + GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>(SafetyCheckHandler::PasswordsStatus::kOffline)); + ASSERT_TRUE(event3); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.PasswordsResult", + SafetyCheckHandler::PasswordsStatus::kOffline, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckPasswords_InterruptedAndRefreshed) { + safety_check_->PerformSafetyCheck(); + // Password check running. + test_leak_service_->set_state_and_notify( + password_manager::BulkLeakCheckService::State::kRunning); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>(SafetyCheckHandler::PasswordsStatus::kChecking)); + ASSERT_TRUE(event); + VerifyDisplayString(event, base::UTF8ToUTF16("Running…")); + // The check gets interrupted and the page is refreshed. + safety_check_->DisallowJavascript(); + safety_check_->AllowJavascript(); + // Need to set the |TestVersionUpdater| instance again to prevent + // |PerformSafetyCheck()| from creating a real |VersionUpdater| instance. + safety_check_->SetVersionUpdaterForTesting( + std::make_unique<TestVersionUpdater>()); + // Another run of the safety check. + safety_check_->PerformSafetyCheck(); + test_leak_service_->set_state_and_notify( + password_manager::BulkLeakCheckService::State::kRunning); + const base::DictionaryValue* event2 = + GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>(SafetyCheckHandler::PasswordsStatus::kChecking)); + ASSERT_TRUE(event2); + test_leak_service_->set_state_and_notify( + password_manager::BulkLeakCheckService::State::kSignedOut); + const base::DictionaryValue* event3 = + GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>(SafetyCheckHandler::PasswordsStatus::kSignedOut)); + ASSERT_TRUE(event3); + VerifyDisplayString(event3, + "Browser can't check your passwords because you're not " + "signed in"); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.PasswordsResult", + SafetyCheckHandler::PasswordsStatus::kSignedOut, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckPasswords_StartedTwice) { + safety_check_->PerformSafetyCheck(); + safety_check_->PerformSafetyCheck(); + // First, a "running" change of state. + test_leak_service_->set_state_and_notify( + password_manager::BulkLeakCheckService::State::kRunning); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>(SafetyCheckHandler::PasswordsStatus::kChecking)); + ASSERT_TRUE(event); + // Then, a network error. + test_leak_service_->set_state_and_notify( + password_manager::BulkLeakCheckService::State::kNetworkError); + const base::DictionaryValue* event2 = + GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>(SafetyCheckHandler::PasswordsStatus::kOffline)); + EXPECT_TRUE(event2); + VerifyDisplayString(event2, + "Browser can't check your passwords. Try checking your " + "internet connection."); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.PasswordsResult", + SafetyCheckHandler::PasswordsStatus::kOffline, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckPasswords_ObserverNotifiedTwice) { + safety_check_->PerformSafetyCheck(); + EXPECT_TRUE(test_passwords_delegate_.StartPasswordCheckTriggered()); + static_cast<password_manager::BulkLeakCheckService::Observer*>( + safety_check_.get()) + ->OnStateChanged( + password_manager::BulkLeakCheckService::State::kServiceError); + // Another notification about the same state change. + static_cast<password_manager::BulkLeakCheckService::Observer*>( + safety_check_.get()) + ->OnStateChanged( + password_manager::BulkLeakCheckService::State::kServiceError); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>(SafetyCheckHandler::PasswordsStatus::kError)); + ASSERT_TRUE(event); +} + +TEST_F(SafetyCheckHandlerTest, CheckPasswords_Safe) { + safety_check_->PerformSafetyCheck(); + // First, a "running" change of state. + test_leak_service_->set_state_and_notify( + password_manager::BulkLeakCheckService::State::kRunning); + EXPECT_TRUE(GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>(SafetyCheckHandler::PasswordsStatus::kChecking))); + // Second, a "safe" state. + test_leak_service_->set_state_and_notify( + password_manager::BulkLeakCheckService::State::kIdle); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>(SafetyCheckHandler::PasswordsStatus::kSafe)); + EXPECT_TRUE(event); + VerifyDisplayString(event, "No compromised passwords found"); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.PasswordsResult", + SafetyCheckHandler::PasswordsStatus::kSafe, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckPasswords_CompromisedExist) { + constexpr int kCompromised = 7; + test_passwords_delegate_.SetNumCompromisedCredentials(kCompromised); + safety_check_->PerformSafetyCheck(); + // First, a "running" change of state. + test_leak_service_->set_state_and_notify( + password_manager::BulkLeakCheckService::State::kRunning); + EXPECT_TRUE(GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>(SafetyCheckHandler::PasswordsStatus::kChecking))); + // Compromised passwords found state. + test_leak_service_->set_state_and_notify( + password_manager::BulkLeakCheckService::State::kIdle); + const base::DictionaryValue* event2 = + GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>( + SafetyCheckHandler::PasswordsStatus::kCompromisedExist)); + ASSERT_TRUE(event2); + VerifyDisplayString( + event2, base::NumberToString(kCompromised) + " compromised passwords"); + VerifyButtonString(event2, "Change passwords"); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.PasswordsResult", + SafetyCheckHandler::PasswordsStatus::kCompromisedExist, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckPasswords_Error) { + safety_check_->PerformSafetyCheck(); + EXPECT_TRUE(test_passwords_delegate_.StartPasswordCheckTriggered()); + static_cast<password_manager::BulkLeakCheckService::Observer*>( + safety_check_.get()) + ->OnStateChanged( + password_manager::BulkLeakCheckService::State::kServiceError); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>(SafetyCheckHandler::PasswordsStatus::kError)); + ASSERT_TRUE(event); + VerifyDisplayString(event, + "Browser can't check your passwords. Try again " + "later."); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.PasswordsResult", + SafetyCheckHandler::PasswordsStatus::kError, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckPasswords_RunningOneCompromised) { + test_passwords_delegate_.SetNumCompromisedCredentials(1); + safety_check_->PerformSafetyCheck(); + EXPECT_TRUE(test_passwords_delegate_.StartPasswordCheckTriggered()); + static_cast<password_manager::BulkLeakCheckService::Observer*>( + safety_check_.get()) + ->OnStateChanged(password_manager::BulkLeakCheckService::State::kIdle); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>( + SafetyCheckHandler::PasswordsStatus::kCompromisedExist)); + ASSERT_TRUE(event); + VerifyDisplayString(event, "1 compromised password"); + VerifyButtonString(event, "Change password"); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.PasswordsResult", + SafetyCheckHandler::PasswordsStatus::kCompromisedExist, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckPasswords_NoPasswords) { + test_passwords_delegate_.ClearSavedPasswordsList(); + test_passwords_delegate_.SetStartPasswordCheckState( + password_manager::BulkLeakCheckService::State::kIdle); + safety_check_->PerformSafetyCheck(); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>(SafetyCheckHandler::PasswordsStatus::kNoPasswords)); + EXPECT_TRUE(event); + VerifyDisplayString(event, + "No saved passwords. Chrome can check your passwords " + "when you save them."); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.PasswordsResult", + SafetyCheckHandler::PasswordsStatus::kNoPasswords, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckPasswords_Progress) { + auto credential = password_manager::LeakCheckCredential( + base::UTF8ToUTF16("test"), base::UTF8ToUTF16("test")); + auto is_leaked = password_manager::IsLeaked(false); + safety_check_->PerformSafetyCheck(); + test_passwords_delegate_.SetPasswordCheckState( + extensions::api::passwords_private::PASSWORD_CHECK_STATE_RUNNING); + test_passwords_delegate_.SetProgress(1, 3); + static_cast<password_manager::BulkLeakCheckService::Observer*>( + safety_check_.get()) + ->OnCredentialDone(credential, is_leaked); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>(SafetyCheckHandler::PasswordsStatus::kChecking)); + EXPECT_TRUE(event); + VerifyDisplayString(event, base::UTF8ToUTF16("Checking passwords (1 of 3)…")); + + test_passwords_delegate_.SetProgress(2, 3); + static_cast<password_manager::BulkLeakCheckService::Observer*>( + safety_check_.get()) + ->OnCredentialDone(credential, is_leaked); + const base::DictionaryValue* event2 = + GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>(SafetyCheckHandler::PasswordsStatus::kChecking)); + EXPECT_TRUE(event2); + VerifyDisplayString(event2, + base::UTF8ToUTF16("Checking passwords (2 of 3)…")); + + // Final update comes after status change, so no new progress message should + // be present. + test_passwords_delegate_.SetPasswordCheckState( + extensions::api::passwords_private::PASSWORD_CHECK_STATE_IDLE); + test_passwords_delegate_.SetProgress(3, 3); + static_cast<password_manager::BulkLeakCheckService::Observer*>( + safety_check_.get()) + ->OnCredentialDone(credential, is_leaked); + const base::DictionaryValue* event3 = + GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>(SafetyCheckHandler::PasswordsStatus::kChecking)); + EXPECT_TRUE(event3); + // Still 2/3 event. + VerifyDisplayString(event3, + base::UTF8ToUTF16("Checking passwords (2 of 3)…")); +} + +TEST_F(SafetyCheckHandlerTest, CheckExtensions_NoExtensions) { + safety_check_->PerformSafetyCheck(); + EXPECT_TRUE(GetSafetyCheckStatusChangedWithDataIfExists( + kExtensions, + static_cast<int>( + SafetyCheckHandler::ExtensionsStatus::kNoneBlocklisted))); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.ExtensionsResult", + SafetyCheckHandler::ExtensionsStatus::kNoneBlocklisted, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckExtensions_NoneBlocklisted) { + std::string extension_id = GenerateExtensionId('a'); + scoped_refptr<const extensions::Extension> extension = + extensions::ExtensionBuilder(extension_id).Build(); + test_extension_prefs_->OnExtensionInstalled( + extension.get(), extensions::Extension::State::ENABLED, + syncer::StringOrdinal(), ""); + test_extension_prefs_->SetExtensionBlacklistState( + extension_id, extensions::NOT_BLACKLISTED); + safety_check_->PerformSafetyCheck(); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kExtensions, + static_cast<int>( + SafetyCheckHandler::ExtensionsStatus::kNoneBlocklisted)); + EXPECT_TRUE(event); + VerifyDisplayString(event, + "You're protected from potentially harmful extensions"); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.ExtensionsResult", + SafetyCheckHandler::ExtensionsStatus::kNoneBlocklisted, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckExtensions_BlocklistedAllDisabled) { + std::string extension_id = GenerateExtensionId('a'); + scoped_refptr<const extensions::Extension> extension = + extensions::ExtensionBuilder("test0").SetID(extension_id).Build(); + test_extension_prefs_->OnExtensionInstalled( + extension.get(), extensions::Extension::State::DISABLED, + syncer::StringOrdinal(), ""); + test_extension_prefs_->SetExtensionBlacklistState( + extension_id, extensions::BLACKLISTED_MALWARE); + test_extension_service_.AddExtensionState(extension_id, Enabled(false), + UserCanDisable(false)); + safety_check_->PerformSafetyCheck(); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kExtensions, + static_cast<int>( + SafetyCheckHandler::ExtensionsStatus::kBlocklistedAllDisabled)); + EXPECT_TRUE(event); + VerifyDisplayString( + event, "1 potentially harmful extension is off. You can also remove it."); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.ExtensionsResult", + SafetyCheckHandler::ExtensionsStatus::kBlocklistedAllDisabled, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckExtensions_BlocklistedReenabledAllByUser) { + std::string extension_id = GenerateExtensionId('a'); + scoped_refptr<const extensions::Extension> extension = + extensions::ExtensionBuilder("test0").SetID(extension_id).Build(); + test_extension_prefs_->OnExtensionInstalled( + extension.get(), extensions::Extension::State::ENABLED, + syncer::StringOrdinal(), ""); + test_extension_prefs_->SetExtensionBlacklistState( + extension_id, extensions::BLACKLISTED_POTENTIALLY_UNWANTED); + test_extension_service_.AddExtensionState(extension_id, Enabled(true), + UserCanDisable(true)); + safety_check_->PerformSafetyCheck(); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kExtensions, static_cast<int>(SafetyCheckHandler::ExtensionsStatus:: + kBlocklistedReenabledAllByUser)); + EXPECT_TRUE(event); + VerifyDisplayString(event, + "You turned 1 potentially harmful extension back on"); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.ExtensionsResult", + SafetyCheckHandler::ExtensionsStatus::kBlocklistedReenabledAllByUser, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckExtensions_BlocklistedReenabledAllByAdmin) { + std::string extension_id = GenerateExtensionId('a'); + scoped_refptr<const extensions::Extension> extension = + extensions::ExtensionBuilder("test0").SetID(extension_id).Build(); + test_extension_prefs_->OnExtensionInstalled( + extension.get(), extensions::Extension::State::ENABLED, + syncer::StringOrdinal(), ""); + test_extension_prefs_->SetExtensionBlacklistState( + extension_id, extensions::BLACKLISTED_POTENTIALLY_UNWANTED); + test_extension_service_.AddExtensionState(extension_id, Enabled(true), + UserCanDisable(false)); + safety_check_->PerformSafetyCheck(); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kExtensions, static_cast<int>(SafetyCheckHandler::ExtensionsStatus:: + kBlocklistedReenabledAllByAdmin)); + VerifyDisplayString(event, + "Your administrator turned 1 potentially harmful " + "extension back on"); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.ExtensionsResult", + SafetyCheckHandler::ExtensionsStatus::kBlocklistedReenabledAllByAdmin, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckExtensions_BlocklistedReenabledSomeByUser) { + std::string extension_id = GenerateExtensionId('a'); + scoped_refptr<const extensions::Extension> extension = + extensions::ExtensionBuilder("test0").SetID(extension_id).Build(); + test_extension_prefs_->OnExtensionInstalled( + extension.get(), extensions::Extension::State::ENABLED, + syncer::StringOrdinal(), ""); + test_extension_prefs_->SetExtensionBlacklistState( + extension_id, extensions::BLACKLISTED_POTENTIALLY_UNWANTED); + test_extension_service_.AddExtensionState(extension_id, Enabled(true), + UserCanDisable(true)); + + std::string extension2_id = GenerateExtensionId('b'); + scoped_refptr<const extensions::Extension> extension2 = + extensions::ExtensionBuilder("test1").SetID(extension2_id).Build(); + test_extension_prefs_->OnExtensionInstalled( + extension2.get(), extensions::Extension::State::ENABLED, + syncer::StringOrdinal(), ""); + test_extension_prefs_->SetExtensionBlacklistState( + extension2_id, extensions::BLACKLISTED_POTENTIALLY_UNWANTED); + test_extension_service_.AddExtensionState(extension2_id, Enabled(true), + UserCanDisable(false)); + + safety_check_->PerformSafetyCheck(); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kExtensions, static_cast<int>(SafetyCheckHandler::ExtensionsStatus:: + kBlocklistedReenabledSomeByUser)); + EXPECT_TRUE(event); + VerifyDisplayString(event, + "You turned 1 potentially harmful extension back " + "on. Your administrator " + "turned 1 potentially harmful extension back on."); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.ExtensionsResult", + SafetyCheckHandler::ExtensionsStatus::kBlocklistedReenabledSomeByUser, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckExtensions_Error) { + // One extension in the error state. + std::string extension_id = GenerateExtensionId('a'); + scoped_refptr<const extensions::Extension> extension = + extensions::ExtensionBuilder("test0").SetID(extension_id).Build(); + test_extension_prefs_->OnExtensionInstalled( + extension.get(), extensions::Extension::State::ENABLED, + syncer::StringOrdinal(), ""); + test_extension_prefs_->SetExtensionBlacklistState( + extension_id, extensions::BLACKLISTED_UNKNOWN); + test_extension_service_.AddExtensionState(extension_id, Enabled(true), + UserCanDisable(true)); + + // Another extension blocklisted. + std::string extension2_id = GenerateExtensionId('b'); + scoped_refptr<const extensions::Extension> extension2 = + extensions::ExtensionBuilder("test1").SetID(extension2_id).Build(); + test_extension_prefs_->OnExtensionInstalled( + extension2.get(), extensions::Extension::State::ENABLED, + syncer::StringOrdinal(), ""); + test_extension_prefs_->SetExtensionBlacklistState( + extension2_id, extensions::BLACKLISTED_POTENTIALLY_UNWANTED); + test_extension_service_.AddExtensionState(extension2_id, Enabled(true), + UserCanDisable(false)); + + safety_check_->PerformSafetyCheck(); + const base::DictionaryValue* event = + GetSafetyCheckStatusChangedWithDataIfExists( + kExtensions, + static_cast<int>(SafetyCheckHandler::ExtensionsStatus::kError)); + EXPECT_TRUE(event); + VerifyDisplayString(event, + "Browser can't check your extensions. Try again later."); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.ExtensionsResult", + SafetyCheckHandler::ExtensionsStatus::kError, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckParentRanDisplayString) { + // 1 second before midnight, so that -(24h-1s) is still on the same day. + const base::Time systemTime = + base::Time::Now().LocalMidnight() - base::TimeDelta::FromSeconds(1); + // Display strings for given time deltas in seconds. + std::vector<std::tuple<std::string, int>> tuples{ + std::make_tuple("Safety check ran a moment ago", 1), + std::make_tuple("Safety check ran a moment ago", 59), + std::make_tuple("Safety check ran 1 minute ago", 60), + std::make_tuple("Safety check ran 2 minutes ago", 60 * 2), + std::make_tuple("Safety check ran 59 minutes ago", 60 * 60 - 1), + std::make_tuple("Safety check ran 1 hour ago", 60 * 60), + std::make_tuple("Safety check ran 2 hours ago", 60 * 60 * 2), + std::make_tuple("Safety check ran 23 hours ago", 60 * 60 * 23), + std::make_tuple("Safety check ran yesterday", 60 * 60 * 24), + std::make_tuple("Safety check ran yesterday", 60 * 60 * 24 * 2 - 1), + std::make_tuple("Safety check ran 2 days ago", 60 * 60 * 24 * 2), + std::make_tuple("Safety check ran 2 days ago", 60 * 60 * 24 * 3 - 1), + std::make_tuple("Safety check ran 3 days ago", 60 * 60 * 24 * 3), + std::make_tuple("Safety check ran 3 days ago", 60 * 60 * 24 * 4 - 1)}; + // Test that above time deltas produce the corresponding display strings. + for (auto tuple : tuples) { + const base::Time time = + systemTime - base::TimeDelta::FromSeconds(std::get<1>(tuple)); + const base::string16 displayString = safety_check_->GetStringForParentRan( + time.ToJsTimeIgnoringNull(), systemTime); + EXPECT_EQ(base::UTF8ToUTF16(std::get<0>(tuple)), displayString); + } } diff --git a/chromium/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc b/chromium/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc index ed1e4d58c0b..7c2416bd30a 100644 --- a/chromium/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc @@ -18,6 +18,7 @@ #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h" #include "chrome/browser/browsing_data/counters/browsing_data_counter_factory.h" #include "chrome/browser/browsing_data/counters/browsing_data_counter_utils.h" +#include "chrome/browser/engagement/important_sites_util.h" #include "chrome/browser/history/web_history_service_factory.h" #include "chrome/browser/signin/account_reconcilor_factory.h" #include "chrome/browser/signin/identity_manager_factory.h" @@ -26,6 +27,7 @@ #include "chrome/common/channel_info.h" #include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" +#include "components/browsing_data/core/browsing_data_utils.h" #include "components/browsing_data/core/history_notice_utils.h" #include "components/browsing_data/core/pref_names.h" #include "components/feature_engagement/buildflags.h" @@ -48,6 +50,7 @@ using BrowsingDataType = browsing_data::BrowsingDataType; namespace { const int kMaxTimesHistoryNoticeShown = 1; +const int kMaxInstalledAppsToWarnOf = 5; // TODO(msramek): Get the list of deletion preferences from the JS side. const char* kCounterPrefsAdvanced[] = { @@ -66,14 +69,20 @@ const char* kCounterPrefsBasic[] = { browsing_data::prefs::kDeleteCacheBasic, }; +const char kRegisterableDomainField[] = "registerableDomain"; +const char kReasonBitfieldField[] = "reasonBitfield"; +const char kIsCheckedField[] = "isChecked"; +const char kAppName[] = "appName"; + } // namespace namespace settings { // ClearBrowsingDataHandler ---------------------------------------------------- -ClearBrowsingDataHandler::ClearBrowsingDataHandler(content::WebUI* webui) - : profile_(Profile::FromWebUI(webui)), +ClearBrowsingDataHandler::ClearBrowsingDataHandler(content::WebUI* webui, + Profile* profile) + : profile_(profile), sync_service_(ProfileSyncServiceFactory::GetForProfile(profile_)), sync_service_observer_(this), show_history_deletion_dialog_(false) {} @@ -83,6 +92,11 @@ ClearBrowsingDataHandler::~ClearBrowsingDataHandler() { void ClearBrowsingDataHandler::RegisterMessages() { web_ui()->RegisterMessageCallback( + "getInstalledApps", + base::BindRepeating( + &ClearBrowsingDataHandler::GetRecentlyLaunchedInstalledApps, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( "clearBrowsingData", base::BindRepeating(&ClearBrowsingDataHandler::HandleClearBrowsingData, base::Unretained(this))); @@ -137,16 +151,99 @@ void ClearBrowsingDataHandler::HandleClearBrowsingDataForTest() { std::make_unique<base::ListValue>(); data_types->AppendString("browser.clear_data.browsing_history"); + std::unique_ptr<base::ListValue> installed_apps = + std::make_unique<base::ListValue>(); + base::ListValue list_args; list_args.AppendString("webui_callback_id"); list_args.Append(std::move(data_types)); list_args.AppendInteger(1u); + list_args.Append(std::move(installed_apps)); HandleClearBrowsingData(&list_args); } +void ClearBrowsingDataHandler::GetRecentlyLaunchedInstalledApps( + const base::ListValue* args) { + CHECK_EQ(2U, args->GetSize()); + std::string webui_callback_id; + int period_selected; + CHECK(args->GetString(0, &webui_callback_id)); + + CHECK(args->GetInteger(1, &period_selected)); + browsing_data::TimePeriod time_period = + static_cast<browsing_data::TimePeriod>(period_selected); + + auto installed_apps = ImportantSitesUtil::GetInstalledRegisterableDomains( + time_period, profile_, kMaxInstalledAppsToWarnOf); + + OnGotInstalledApps(webui_callback_id, installed_apps); +} + +void ClearBrowsingDataHandler::OnGotInstalledApps( + const std::string& webui_callback_id, + const std::vector<ImportantSitesUtil::ImportantDomainInfo>& + installed_apps) { + base::ListValue installed_apps_list; + for (const auto& info : installed_apps) { + auto entry = std::make_unique<base::DictionaryValue>(); + // Used to get favicon in ClearBrowsingDataDialog and display URL next to + // app name in the dialog. + entry->SetString(kRegisterableDomainField, info.registerable_domain); + // The |reason_bitfield| is only passed to Javascript to be logged + // from |HandleClearBrowsingData|. + entry->SetInteger(kReasonBitfieldField, info.reason_bitfield); + // Initially all sites are selected for deletion. + entry->SetBoolean(kIsCheckedField, true); + // User friendly name for the installed app. + DCHECK(info.app_name); + entry->SetString(kAppName, info.app_name.value()); + installed_apps_list.Append(std::move(entry)); + } + ResolveJavascriptCallback(base::Value(webui_callback_id), + installed_apps_list); +} + +std::unique_ptr<content::BrowsingDataFilterBuilder> +ClearBrowsingDataHandler::ProcessInstalledApps( + const base::ListValue* installed_apps) { + std::vector<std::string> excluded_domains; + std::vector<int32_t> excluded_domain_reasons; + std::vector<std::string> ignored_domains; + std::vector<int32_t> ignored_domain_reasons; + for (const auto& item : *installed_apps) { + const base::DictionaryValue* site = nullptr; + CHECK(item.GetAsDictionary(&site)); + bool is_checked = false; + CHECK(site->GetBoolean(kIsCheckedField, &is_checked)); + std::string domain; + CHECK(site->GetString(kRegisterableDomainField, &domain)); + int domain_reason = -1; + CHECK(site->GetInteger(kReasonBitfieldField, &domain_reason)); + if (is_checked) { // Selected installed apps should be deleted. + ignored_domains.push_back(domain); + ignored_domain_reasons.push_back(domain_reason); + } else { // Unselected sites should be kept. + excluded_domains.push_back(domain); + excluded_domain_reasons.push_back(domain_reason); + } + } + if (!excluded_domains.empty() || !ignored_domains.empty()) { + ImportantSitesUtil::RecordBlacklistedAndIgnoredImportantSites( + profile_->GetOriginalProfile(), excluded_domains, + excluded_domain_reasons, ignored_domains, ignored_domain_reasons); + } + + std::unique_ptr<content::BrowsingDataFilterBuilder> filter_builder( + content::BrowsingDataFilterBuilder::Create( + content::BrowsingDataFilterBuilder::BLACKLIST)); + for (const std::string& domain : excluded_domains) + filter_builder->AddRegisterableDomain(domain); + return filter_builder; +} + void ClearBrowsingDataHandler::HandleClearBrowsingData( const base::ListValue* args) { - CHECK_EQ(3U, args->GetSize()); + CHECK_EQ(4U, args->GetSize()); std::string webui_callback_id; CHECK(args->GetString(0, &webui_callback_id)); @@ -261,6 +358,11 @@ void ClearBrowsingDataHandler::HandleClearBrowsingData( int period_selected; CHECK(args->GetInteger(2, &period_selected)); + const base::ListValue* installed_apps = nullptr; + CHECK(args->GetList(3, &installed_apps)); + std::unique_ptr<content::BrowsingDataFilterBuilder> filter_builder = + ProcessInstalledApps(installed_apps); + content::BrowsingDataRemover* remover = content::BrowserContext::GetBrowsingDataRemover(profile_); @@ -272,10 +374,8 @@ void ClearBrowsingDataHandler::HandleClearBrowsingData( static_cast<browsing_data::TimePeriod>(period_selected); browsing_data_important_sites_util::Remove( - remove_mask, origin_mask, time_period, - content::BrowsingDataFilterBuilder::Create( - content::BrowsingDataFilterBuilder::BLACKLIST), - remover, std::move(callback)); + remove_mask, origin_mask, time_period, std::move(filter_builder), remover, + std::move(callback)); #if BUILDFLAG(ENABLE_LEGACY_DESKTOP_IN_PRODUCT_HELP) feature_engagement::IncognitoWindowTrackerFactory::GetInstance() @@ -360,11 +460,10 @@ void ClearBrowsingDataHandler::RefreshHistoryNotice() { if (notice_shown_times < kMaxTimesHistoryNoticeShown) { browsing_data::ShouldPopupDialogAboutOtherFormsOfBrowsingHistory( - sync_service_, - WebHistoryServiceFactory::GetForProfile(profile_), + sync_service_, WebHistoryServiceFactory::GetForProfile(profile_), chrome::GetChannel(), - base::Bind(&ClearBrowsingDataHandler::UpdateHistoryDeletionDialog, - weak_ptr_factory_.GetWeakPtr())); + base::BindOnce(&ClearBrowsingDataHandler::UpdateHistoryDeletionDialog, + weak_ptr_factory_.GetWeakPtr())); } } diff --git a/chromium/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.h b/chromium/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.h index 9434c788871..784812552ef 100644 --- a/chromium/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.h @@ -12,6 +12,7 @@ #include "base/containers/flat_set.h" #include "base/macros.h" #include "base/scoped_observer.h" +#include "chrome/browser/engagement/important_sites_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" #include "components/browsing_data/core/browsing_data_utils.h" @@ -24,6 +25,7 @@ class ListValue; } namespace content { +class BrowsingDataFilterBuilder; class WebUI; } @@ -33,7 +35,7 @@ namespace settings { class ClearBrowsingDataHandler : public SettingsPageUIHandler, public syncer::SyncServiceObserver { public: - explicit ClearBrowsingDataHandler(content::WebUI* webui); + ClearBrowsingDataHandler(content::WebUI* webui, Profile* profile); ~ClearBrowsingDataHandler() override; // WebUIMessageHandler implementation. @@ -44,7 +46,24 @@ class ClearBrowsingDataHandler : public SettingsPageUIHandler, // Calls |HandleClearBrowsingData| with test data for browser test. void HandleClearBrowsingDataForTest(); + protected: + // Fetches a list of installed apps to be displayed in the clear browsing + // data confirmation dialog. Called by Javascript. + void GetRecentlyLaunchedInstalledApps(const base::ListValue* args); + private: + // Respond to the WebUI callback with the list of installed apps. + void OnGotInstalledApps( + const std::string& webui_callback_id, + const std::vector<ImportantSitesUtil::ImportantDomainInfo>& + installed_apps); + + // Build a filter of sites to include and exclude from site data removal + // based on whether installed apps were marked for deletion by the checkbox on + // the installed apps warning dialog. + std::unique_ptr<content::BrowsingDataFilterBuilder> ProcessInstalledApps( + const base::ListValue* installed_apps); + // Clears browsing data, called by Javascript. void HandleClearBrowsingData(const base::ListValue* value); diff --git a/chromium/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler_browsertest.cc b/chromium/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler_browsertest.cc new file mode 100644 index 00000000000..98dca3b412e --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler_browsertest.cc @@ -0,0 +1,110 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include <memory> + +#include "chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.h" + +#include "base/values.h" +#include "chrome/browser/ui/web_applications/web_app_controller_browsertest.h" +#include "chrome/common/webui_url_constants.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "content/public/browser/web_ui.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/test_web_ui.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace { + +constexpr char kGetInstalledApps[] = "getInstalledApps"; +constexpr char kWebUiFunctionName[] = "webUiCallbackName"; + +} // namespace + +namespace settings { + +class TestingClearBrowsingDataHandler : public ClearBrowsingDataHandler { + public: + TestingClearBrowsingDataHandler(content::WebUI* webui, Profile* profile) + : ClearBrowsingDataHandler(webui, profile) { + set_web_ui(webui); + } + TestingClearBrowsingDataHandler& operator=( + const TestingClearBrowsingDataHandler&) = delete; + TestingClearBrowsingDataHandler(const TestingClearBrowsingDataHandler&) = + delete; +}; + +class ClearBrowsingDataHandlerBrowserTest + : public web_app::WebAppControllerBrowserTest { + public: + ClearBrowsingDataHandlerBrowserTest() = default; + ~ClearBrowsingDataHandlerBrowserTest() = default; + + void SetUpOnMainThread() override { + WebAppControllerBrowserTest::SetUpOnMainThread(); + + handler_ = std::make_unique<TestingClearBrowsingDataHandler>( + web_ui(), browser()->profile()); + handler_->AllowJavascriptForTesting(); + handler_->RegisterMessages(); + } + + void TearDownOnMainThread() override { handler_.reset(); } + + protected: + web_app::AppId InstallAndLaunchApp(GURL& url) { + auto app_id = InstallPWA(url); + + ui_test_utils::UrlLoadObserver url_observer( + url, content::NotificationService::AllSources()); + + auto* app_browser = + ClearBrowsingDataHandlerBrowserTest::LaunchWebAppBrowser(app_id); + url_observer.Wait(); + DCHECK(app_browser); + DCHECK(app_browser != browser()); + + return app_id; + } + + ClearBrowsingDataHandler* handler() { return handler_.get(); } + content::TestWebUI* web_ui() { return &web_ui_; } + + private: + std::unique_ptr<ClearBrowsingDataHandler> handler_; + content::TestWebUI web_ui_; +}; + +IN_PROC_BROWSER_TEST_P(ClearBrowsingDataHandlerBrowserTest, GetInstalledApps) { + GURL url(https_server()->GetURL("/")); + InstallAndLaunchApp(url); + base::ListValue args; + args.AppendString(kWebUiFunctionName); + args.AppendInteger(1U); + + web_ui()->HandleReceivedMessage(kGetInstalledApps, &args); + const content::TestWebUI::CallData& call_data = *web_ui()->call_data().back(); + EXPECT_EQ("cr.webUIResponse", call_data.function_name()); + EXPECT_EQ(kWebUiFunctionName, call_data.arg1()->GetString()); + ASSERT_TRUE(call_data.arg2()->GetBool()); + + // Get results from JS callback. + const base::span<const base::Value> result = call_data.arg3()->GetList(); + ASSERT_EQ(1U, result.size()); + auto& installed_app = result.back(); + ASSERT_EQ(url.host(), *(installed_app.FindStringKey("registerableDomain"))); +} + +INSTANTIATE_TEST_SUITE_P( + All, + ClearBrowsingDataHandlerBrowserTest, + ::testing::Values( + web_app::ControllerType::kHostedAppController, + web_app::ControllerType::kUnifiedControllerWithBookmarkApp, + web_app::ControllerType::kUnifiedControllerWithWebApp), + web_app::ControllerTypeParamToString); + +} // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chromium/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc index 8dc520241ba..90189cf77f1 100644 --- a/chromium/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chromium/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc @@ -10,7 +10,6 @@ #include "base/feature_list.h" #include "base/i18n/number_formatting.h" #include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/win/windows_version.h" #include "build/branding_buildflags.h" @@ -28,8 +27,8 @@ #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h" #include "chrome/browser/ui/webui/management_ui.h" #include "chrome/browser/ui/webui/policy_indicator_localized_strings_provider.h" +#include "chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.h" #include "chrome/browser/ui/webui/webui_util.h" -#include "chrome/common/channel_info.h" #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/url_constants.h" @@ -50,18 +49,20 @@ #include "components/autofill/core/common/autofill_payments_features.h" #include "components/browsing_data/core/features.h" #include "components/content_settings/core/common/features.h" +#include "components/dom_distiller/core/dom_distiller_features.h" #include "components/google/core/common/google_util.h" #include "components/omnibox/common/omnibox_features.h" +#include "components/password_manager/core/browser/leak_detection_dialog_utils.h" #include "components/password_manager/core/browser/manage_passwords_referrer.h" #include "components/password_manager/core/common/password_manager_features.h" -#include "components/safe_browsing/common/safe_browsing_prefs.h" +#include "components/safe_browsing/core/common/safe_browsing_prefs.h" #include "components/signin/public/base/signin_buildflags.h" #include "components/strings/grit/components_strings.h" #include "components/subresource_filter/core/browser/subresource_filter_features.h" #include "components/sync/driver/sync_service.h" #include "components/sync/driver/sync_service_utils.h" #include "components/sync/driver/sync_user_settings.h" -#include "components/version_info/version_info.h" +#include "components/zoom/page_zoom_constants.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui_data_source.h" #include "content/public/common/content_features.h" @@ -74,42 +75,25 @@ #include "ui/accessibility/accessibility_switches.h" #include "ui/base/accelerators/accelerator.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/webui/web_ui_util.h" +#include "ui/strings/grit/ui_strings.h" #if defined(OS_CHROMEOS) -#include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/ash_switches.h" -#include "ash/public/mojom/assistant_state_controller.mojom.h" #include "base/system/sys_info.h" #include "chrome/browser/chromeos/account_manager/account_manager_util.h" -#include "chrome/browser/chromeos/arc/arc_util.h" #include "chrome/browser/chromeos/assistant/assistant_util.h" -#include "chrome/browser/chromeos/crostini/crostini_features.h" -#include "chrome/browser/chromeos/crostini/crostini_util.h" #include "chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h" #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h" #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h" #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" -#include "chrome/browser/policy/profile_policy_connector.h" -#include "chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.h" -#include "chrome/browser/ui/webui/chromeos/bluetooth_dialog_localized_strings_provider.h" -#include "chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.h" -#include "chrome/browser/ui/webui/chromeos/smb_shares/smb_shares_localized_strings_provider.h" #include "chrome/common/pref_names.h" #include "chrome/common/webui_url_constants.h" #include "chromeos/constants/chromeos_features.h" -#include "chromeos/constants/chromeos_switches.h" -#include "chromeos/services/assistant/public/features.h" -#include "chromeos/services/multidevice_setup/public/cpp/url_provider.h" -#include "chromeos/strings/grit/chromeos_strings.h" #include "components/prefs/pref_service.h" #include "components/user_manager/user_manager.h" -#include "device/bluetooth/strings/grit/bluetooth_strings.h" #include "ui/chromeos/devicetype_utils.h" -#include "ui/chromeos/events/keyboard_layout_util.h" -#include "ui/display/display_features.h" -#include "ui/display/display_switches.h" -#include "ui/display/manager/touch_device_manager.h" #else #include "chrome/browser/ui/webui/settings/system_handler.h" #endif @@ -129,7 +113,6 @@ #if defined(USE_NSS_CERTS) #include "chrome/browser/ui/webui/certificate_manager_localized_strings_provider.h" #endif - namespace settings { namespace { @@ -141,26 +124,6 @@ base::string16 GetHelpUrlWithBoard(const std::string& original_url) { return base::ASCIIToUTF16(original_url + "&b=" + base::SysInfo::GetLsbReleaseBoard()); } - -bool IsDeviceManaged() { - policy::BrowserPolicyConnectorChromeOS* connector = - g_browser_process->platform_part()->browser_policy_connector_chromeos(); - return connector->IsEnterpriseManaged(); -} - -bool IsProfileManaged(Profile* profile) { - return profile->GetProfilePolicyConnector()->IsManaged(); -} - -bool ShouldEnableArcAdbSideloading() { - // Only enable on supported devices per USE flag. - if (!base::FeatureList::IsEnabled( - chromeos::features::kArcAdbSideloadingFeature)) { - return false; - } - - return chrome::GetChannel() < version_info::Channel::BETA; -} #endif void AddCommonStrings(content::WebUIDataSource* html_source, Profile* profile) { @@ -175,11 +138,8 @@ void AddCommonStrings(content::WebUIDataSource* html_source, Profile* profile) { {"confirm", IDS_CONFIRM}, {"continue", IDS_SETTINGS_CONTINUE}, {"controlledByExtension", IDS_SETTINGS_CONTROLLED_BY_EXTENSION}, + {"custom", IDS_SETTINGS_CUSTOM}, {"delete", IDS_SETTINGS_DELETE}, -#if defined(OS_CHROMEOS) - {"deviceOff", IDS_SETTINGS_DEVICE_OFF}, - {"deviceOn", IDS_SETTINGS_DEVICE_ON}, -#endif {"disable", IDS_DISABLE}, {"done", IDS_DONE}, {"edit", IDS_SETTINGS_EDIT}, @@ -195,15 +155,24 @@ void AddCommonStrings(content::WebUIDataSource* html_source, Profile* profile) { #endif {"retry", IDS_SETTINGS_RETRY}, {"save", IDS_SAVE}, + {"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}, - {"toggleOn", IDS_SETTINGS_TOGGLE_ON}, - {"toggleOff", IDS_SETTINGS_TOGGLE_OFF}, {"notValid", IDS_SETTINGS_NOT_VALID}, {"notValidWebAddress", IDS_SETTINGS_NOT_VALID_WEB_ADDRESS}, {"notValidWebAddressForContentType", IDS_SETTINGS_NOT_VALID_WEB_ADDRESS_FOR_CONTENT_TYPE}, + + // Common font related strings shown in a11y and appearance sections. + {"quickBrownFox", IDS_SETTINGS_QUICK_BROWN_FOX}, + {"verySmall", IDS_SETTINGS_VERY_SMALL_FONT}, + {"small", IDS_SETTINGS_SMALL_FONT}, + {"medium", IDS_SETTINGS_MEDIUM_FONT}, + {"large", IDS_SETTINGS_LARGE_FONT}, + {"veryLarge", IDS_SETTINGS_VERY_LARGE_FONT}, }; AddLocalizedStringsBulk(html_source, kLocalizedStrings); @@ -221,327 +190,66 @@ void AddCommonStrings(content::WebUIDataSource* html_source, Profile* profile) { void AddA11yStrings(content::WebUIDataSource* html_source) { static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"moreFeaturesLink", IDS_SETTINGS_MORE_FEATURES_LINK}, {"a11yPageTitle", IDS_SETTINGS_ACCESSIBILITY}, {"a11yWebStore", IDS_SETTINGS_ACCESSIBILITY_WEB_STORE}, + {"moreFeaturesLinkDescription", + IDS_SETTINGS_MORE_FEATURES_LINK_DESCRIPTION}, {"accessibleImageLabelsTitle", IDS_SETTINGS_ACCESSIBLE_IMAGE_LABELS_TITLE}, {"accessibleImageLabelsSubtitle", IDS_SETTINGS_ACCESSIBLE_IMAGE_LABELS_SUBTITLE}, - {"moreFeaturesLink", IDS_SETTINGS_MORE_FEATURES_LINK}, - {"moreFeaturesLinkDescription", - IDS_SETTINGS_MORE_FEATURES_LINK_DESCRIPTION}, - {"captionsTitle", IDS_SETTINGS_CAPTIONS}, - {"captionsSettings", IDS_SETTINGS_CAPTIONS_SETTINGS}, - {"captionsPreview", IDS_SETTINGS_CAPTIONS_PREVIEW}, - {"captionsTextSize", IDS_SETTINGS_CAPTIONS_TEXT_SIZE}, - {"captionsTextFont", IDS_SETTINGS_CAPTIONS_TEXT_FONT}, - {"captionsTextColor", IDS_SETTINGS_CAPTIONS_TEXT_COLOR}, - {"captionsTextOpacity", IDS_SETTINGS_CAPTIONS_TEXT_OPACITY}, - {"captionsBackgroundOpacity", IDS_SETTINGS_CAPTIONS_BACKGROUND_OPACITY}, - {"captionsOpacityOpaque", IDS_SETTINGS_CAPTIONS_OPACITY_OPAQUE}, - {"captionsOpacitySemiTransparent", - IDS_SETTINGS_CAPTIONS_OPACITY_SEMI_TRANSPARENT}, - {"captionsOpacityTransparent", IDS_SETTINGS_CAPTIONS_OPACITY_TRANSPARENT}, - {"captionsTextShadow", IDS_SETTINGS_CAPTIONS_TEXT_SHADOW}, - {"captionsTextShadowNone", IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_NONE}, - {"captionsTextShadowRaised", IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_RAISED}, - {"captionsTextShadowDepressed", - IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_DEPRESSED}, - {"captionsTextShadowUniform", IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_UNIFORM}, - {"captionsTextShadowDropShadow", - IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_DROP_SHADOW}, - {"captionsBackgroundColor", IDS_SETTINGS_CAPTIONS_BACKGROUND_COLOR}, - {"captionsColorBlack", IDS_SETTINGS_CAPTIONS_COLOR_BLACK}, - {"captionsColorWhite", IDS_SETTINGS_CAPTIONS_COLOR_WHITE}, - {"captionsColorRed", IDS_SETTINGS_CAPTIONS_COLOR_RED}, - {"captionsColorGreen", IDS_SETTINGS_CAPTIONS_COLOR_GREEN}, - {"captionsColorBlue", IDS_SETTINGS_CAPTIONS_COLOR_BLUE}, - {"captionsColorYellow", IDS_SETTINGS_CAPTIONS_COLOR_YELLOW}, - {"captionsColorCyan", IDS_SETTINGS_CAPTIONS_COLOR_CYAN}, - {"captionsColorMagenta", IDS_SETTINGS_CAPTIONS_COLOR_MAGENTA}, - {"captionsDefaultSetting", IDS_SETTINGS_CAPTIONS_DEFAULT_SETTING}, {"settingsSliderRoleDescription", IDS_SETTINGS_SLIDER_MIN_MAX_ARIA_ROLE_DESCRIPTION}, + {"captionsEnableLiveCaptionTitle", + IDS_SETTINGS_CAPTIONS_ENABLE_LIVE_CAPTION_TITLE}, + {"captionsEnableLiveCaptionSubtitle", + IDS_SETTINGS_CAPTIONS_ENABLE_LIVE_CAPTION_SUBTITLE}, #if defined(OS_CHROMEOS) - {"optionsInMenuLabel", IDS_SETTINGS_OPTIONS_IN_MENU_LABEL}, - {"largeMouseCursorLabel", IDS_SETTINGS_LARGE_MOUSE_CURSOR_LABEL}, - {"largeMouseCursorSizeLabel", IDS_SETTINGS_LARGE_MOUSE_CURSOR_SIZE_LABEL}, - {"largeMouseCursorSizeDefaultLabel", - IDS_SETTINGS_LARGE_MOUSE_CURSOR_SIZE_DEFAULT_LABEL}, - {"largeMouseCursorSizeLargeLabel", - IDS_SETTINGS_LARGE_MOUSE_CURSOR_SIZE_LARGE_LABEL}, - {"highContrastLabel", IDS_SETTINGS_HIGH_CONTRAST_LABEL}, - {"stickyKeysLabel", IDS_SETTINGS_STICKY_KEYS_LABEL}, - {"chromeVoxLabel", IDS_SETTINGS_CHROMEVOX_LABEL}, - {"chromeVoxOptionsLabel", IDS_SETTINGS_CHROMEVOX_OPTIONS_LABEL}, - {"screenMagnifierLabel", IDS_SETTINGS_SCREEN_MAGNIFIER_LABEL}, - {"screenMagnifierZoomLabel", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_LABEL}, - {"dockedMagnifierLabel", IDS_SETTINGS_DOCKED_MAGNIFIER_LABEL}, - {"dockedMagnifierZoomLabel", IDS_SETTINGS_DOCKED_MAGNIFIER_ZOOM_LABEL}, - {"screenMagnifierZoom2x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_2_X}, - {"screenMagnifierZoom4x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_4_X}, - {"screenMagnifierZoom6x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_6_X}, - {"screenMagnifierZoom8x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_8_X}, - {"screenMagnifierZoom10x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_10_X}, - {"screenMagnifierZoom12x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_12_X}, - {"screenMagnifierZoom14x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_14_X}, - {"screenMagnifierZoom16x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_16_X}, - {"screenMagnifierZoom18x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_18_X}, - {"screenMagnifierZoom20x", IDS_SETTINGS_SCREEN_MAGNIFIER_ZOOM_20_X}, - {"tapDraggingLabel", IDS_SETTINGS_TAP_DRAGGING_LABEL}, - {"clickOnStopLabel", IDS_SETTINGS_CLICK_ON_STOP_LABEL}, - {"delayBeforeClickLabel", IDS_SETTINGS_DELAY_BEFORE_CLICK_LABEL}, - {"delayBeforeClickExtremelyShort", - IDS_SETTINGS_DELAY_BEFORE_CLICK_EXTREMELY_SHORT}, - {"delayBeforeClickVeryShort", IDS_SETTINGS_DELAY_BEFORE_CLICK_VERY_SHORT}, - {"delayBeforeClickShort", IDS_SETTINGS_DELAY_BEFORE_CLICK_SHORT}, - {"delayBeforeClickLong", IDS_SETTINGS_DELAY_BEFORE_CLICK_LONG}, - {"delayBeforeClickVeryLong", IDS_SETTINGS_DELAY_BEFORE_CLICK_VERY_LONG}, - {"autoclickRevertToLeftClick", IDS_SETTINGS_AUTOCLICK_REVERT_TO_LEFT_CLICK}, - {"autoclickStabilizeCursorPosition", - IDS_SETTINGS_AUTOCLICK_STABILIZE_CURSOR_POSITION}, - {"autoclickMovementThresholdLabel", - IDS_SETTINGS_AUTOCLICK_MOVEMENT_THRESHOLD_LABEL}, - {"autoclickMovementThresholdExtraSmall", - IDS_SETTINGS_AUTOCLICK_MOVEMENT_THRESHOLD_EXTRA_SMALL}, - {"autoclickMovementThresholdSmall", - IDS_SETTINGS_AUTOCLICK_MOVEMENT_THRESHOLD_SMALL}, - {"autoclickMovementThresholdDefault", - IDS_SETTINGS_AUTOCLICK_MOVEMENT_THRESHOLD_DEFAULT}, - {"autoclickMovementThresholdLarge", - IDS_SETTINGS_AUTOCLICK_MOVEMENT_THRESHOLD_LARGE}, - {"autoclickMovementThresholdExtraLarge", - IDS_SETTINGS_AUTOCLICK_MOVEMENT_THRESHOLD_EXTRA_LARGE}, - {"dictationDescription", IDS_SETTINGS_ACCESSIBILITY_DICTATION_DESCRIPTION}, - {"dictationLabel", IDS_SETTINGS_ACCESSIBILITY_DICTATION_LABEL}, - {"onScreenKeyboardLabel", IDS_SETTINGS_ON_SCREEN_KEYBOARD_LABEL}, - {"monoAudioLabel", IDS_SETTINGS_MONO_AUDIO_LABEL}, - {"startupSoundLabel", IDS_SETTINGS_STARTUP_SOUND_LABEL}, - {"a11yExplanation", IDS_SETTINGS_ACCESSIBILITY_EXPLANATION}, - {"caretHighlightLabel", - IDS_SETTINGS_ACCESSIBILITY_CARET_HIGHLIGHT_DESCRIPTION}, - {"cursorHighlightLabel", - IDS_SETTINGS_ACCESSIBILITY_CURSOR_HIGHLIGHT_DESCRIPTION}, - {"focusHighlightLabel", - IDS_SETTINGS_ACCESSIBILITY_FOCUS_HIGHLIGHT_DESCRIPTION}, - {"selectToSpeakTitle", IDS_SETTINGS_ACCESSIBILITY_SELECT_TO_SPEAK_TITLE}, - {"selectToSpeakDisabledDescription", - IDS_SETTINGS_ACCESSIBILITY_SELECT_TO_SPEAK_DISABLED_DESCRIPTION}, - {"selectToSpeakDescription", - IDS_SETTINGS_ACCESSIBILITY_SELECT_TO_SPEAK_DESCRIPTION}, - {"selectToSpeakDescriptionWithoutKeyboard", - IDS_SETTINGS_ACCESSIBILITY_SELECT_TO_SPEAK_DESCRIPTION_WITHOUT_KEYBOARD}, - {"selectToSpeakOptionsLabel", - IDS_SETTINGS_ACCESSIBILITY_SELECT_TO_SPEAK_OPTIONS_LABEL}, - {"switchAccessLabel", IDS_SETTINGS_ACCESSIBILITY_SWITCH_ACCESS_DESCRIPTION}, - {"switchAccessOptionsLabel", - IDS_SETTINGS_ACCESSIBILITY_SWITCH_ACCESS_OPTIONS_LABEL}, - {"manageSwitchAccessSettings", IDS_SETTINGS_MANAGE_SWITCH_ACCESS_SETTINGS}, - {"switchAssignmentHeading", IDS_SETTINGS_SWITCH_ASSIGNMENT_HEADING}, - {"switchAssignOptionNone", IDS_SETTINGS_SWITCH_ASSIGN_OPTION_NONE}, - {"switchAssignOptionSpace", IDS_SETTINGS_SWITCH_ASSIGN_OPTION_SPACE}, - {"switchAssignOptionEnter", IDS_SETTINGS_SWITCH_ASSIGN_OPTION_ENTER}, - {"assignSelectSwitchLabel", IDS_SETTINGS_ASSIGN_SELECT_SWITCH_LABEL}, - {"assignNextSwitchLabel", IDS_SETTINGS_ASSIGN_NEXT_SWITCH_LABEL}, - {"assignPreviousSwitchLabel", IDS_SETTINGS_ASSIGN_PREVIOUS_SWITCH_LABEL}, - {"switchAccessAutoScanHeading", - IDS_SETTINGS_SWITCH_ACCESS_AUTO_SCAN_HEADING}, - {"switchAccessAutoScanLabel", IDS_SETTINGS_SWITCH_ACCESS_AUTO_SCAN_LABEL}, - {"switchAccessAutoScanSpeedLabel", - IDS_SETTINGS_SWITCH_ACCESS_AUTO_SCAN_SPEED_LABEL}, - {"switchAccessAutoScanKeyboardSpeedLabel", - IDS_SETTINGS_SWITCH_ACCESS_AUTO_SCAN_KEYBOARD_SPEED_LABEL}, - {"durationInSeconds", IDS_SETTINGS_DURATION_IN_SECONDS}, {"manageAccessibilityFeatures", IDS_SETTINGS_ACCESSIBILITY_MANAGE_ACCESSIBILITY_FEATURES}, - {"textToSpeechHeading", IDS_SETTINGS_ACCESSIBILITY_TEXT_TO_SPEECH_HEADING}, - {"displayHeading", IDS_SETTINGS_ACCESSIBILITY_DISPLAY_HEADING}, - {"displaySettingsTitle", IDS_SETTINGS_ACCESSIBILITY_DISPLAY_SETTINGS_TITLE}, - {"displaySettingsDescription", - IDS_SETTINGS_ACCESSIBILITY_DISPLAY_SETTINGS_DESCRIPTION}, - {"appearanceSettingsTitle", - IDS_SETTINGS_ACCESSIBILITY_APPEARANCE_SETTINGS_TITLE}, - {"appearanceSettingsDescription", - IDS_SETTINGS_ACCESSIBILITY_APPEARANCE_SETTINGS_DESCRIPTION}, - {"keyboardAndTextInputHeading", - IDS_SETTINGS_ACCESSIBILITY_KEYBOARD_AND_TEXT_INPUT_HEADING}, - {"keyboardSettingsTitle", - IDS_SETTINGS_ACCESSIBILITY_KEYBOARD_SETTINGS_TITLE}, - {"keyboardSettingsDescription", - IDS_SETTINGS_ACCESSIBILITY_KEYBOARD_SETTINGS_DESCRIPTION}, - {"mouseAndTouchpadHeading", - IDS_SETTINGS_ACCESSIBILITY_MOUSE_AND_TOUCHPAD_HEADING}, - {"mouseSettingsTitle", IDS_SETTINGS_ACCESSIBILITY_MOUSE_SETTINGS_TITLE}, - {"mouseSettingsDescription", - IDS_SETTINGS_ACCESSIBILITY_MOUSE_SETTINGS_DESCRIPTION}, - {"audioAndCaptionsHeading", - IDS_SETTINGS_ACCESSIBILITY_AUDIO_AND_CAPTIONS_HEADING}, - {"additionalFeaturesTitle", - IDS_SETTINGS_ACCESSIBILITY_ADDITIONAL_FEATURES_TITLE}, - {"manageTtsSettings", IDS_SETTINGS_MANAGE_TTS_SETTINGS}, - {"ttsSettingsLinkDescription", IDS_SETTINGS_TTS_LINK_DESCRIPTION}, - {"textToSpeechVoices", IDS_SETTINGS_TEXT_TO_SPEECH_VOICES}, - {"textToSpeechNoVoicesMessage", - IDS_SETTINGS_TEXT_TO_SPEECH_NO_VOICES_MESSAGE}, - {"textToSpeechMoreLanguages", IDS_SETTINGS_TEXT_TO_SPEECH_MORE_LANGUAGES}, - {"textToSpeechProperties", IDS_SETTINGS_TEXT_TO_SPEECH_PROPERTIES}, - {"textToSpeechRate", IDS_SETTINGS_TEXT_TO_SPEECH_RATE}, - {"textToSpeechRateMinimumLabel", - IDS_SETTINGS_TEXT_TO_SPEECH_RATE_MINIMUM_LABEL}, - {"textToSpeechRateMaximumLabel", - IDS_SETTINGS_TEXT_TO_SPEECH_RATE_MAXIMUM_LABEL}, - {"textToSpeechPitch", IDS_SETTINGS_TEXT_TO_SPEECH_PITCH}, - {"textToSpeechPitchMinimumLabel", - IDS_SETTINGS_TEXT_TO_SPEECH_PITCH_MINIMUM_LABEL}, - {"textToSpeechPitchMaximumLabel", - IDS_SETTINGS_TEXT_TO_SPEECH_PITCH_MAXIMUM_LABEL}, - {"textToSpeechVolume", IDS_SETTINGS_TEXT_TO_SPEECH_VOLUME}, - {"textToSpeechVolumeMinimumLabel", - IDS_SETTINGS_TEXT_TO_SPEECH_VOLUME_MINIMUM_LABEL}, - {"textToSpeechVolumeMaximumLabel", - IDS_SETTINGS_TEXT_TO_SPEECH_VOLUME_MAXIMUM_LABEL}, - {"percentage", IDS_SETTINGS_PERCENTAGE}, - {"defaultPercentage", IDS_SETTINGS_DEFAULT_PERCENTAGE}, - {"textToSpeechPreviewHeading", IDS_SETTINGS_TEXT_TO_SPEECH_PREVIEW_HEADING}, - {"textToSpeechPreviewInputLabel", - IDS_SETTINGS_TEXT_TO_SPEECH_PREVIEW_INPUT_LABEL}, - {"textToSpeechPreviewInput", IDS_SETTINGS_TEXT_TO_SPEECH_PREVIEW_INPUT}, - {"textToSpeechPreviewVoice", IDS_SETTINGS_TEXT_TO_SPEECH_PREVIEW_VOICE}, - {"textToSpeechPreviewPlay", IDS_SETTINGS_TEXT_TO_SPEECH_PREVIEW_PLAY}, - {"textToSpeechEngines", IDS_SETTINGS_TEXT_TO_SPEECH_ENGINES}, + {"androidAppsManageAppLinks", IDS_SETTINGS_ANDROID_APPS_MANAGE_APP_LINKS}, #endif }; AddLocalizedStringsBulk(html_source, kLocalizedStrings); - html_source->AddBoolean( - "showExperimentalA11yLabels", - base::FeatureList::IsEnabled(features::kExperimentalAccessibilityLabels)); - - html_source->AddBoolean( - "enableCaptionSettings", - base::FeatureList::IsEnabled(features::kCaptionSettings)); - #if defined(OS_WIN) html_source->AddBoolean("isWindows10OrNewer", base::win::GetVersion() >= base::win::Version::WIN10); #endif - -#if defined(OS_CHROMEOS) - html_source->AddString("accountManagerLearnMoreUrl", - chrome::kAccountManagerLearnMoreURL); - html_source->AddString("a11yLearnMoreUrl", - chrome::kChromeAccessibilityHelpURL); - - base::CommandLine& cmd = *base::CommandLine::ForCurrentProcess(); html_source->AddBoolean( - "showExperimentalA11yFeatures", - cmd.HasSwitch(::switches::kEnableExperimentalAccessibilityFeatures)); + "showExperimentalA11yLabels", + base::FeatureList::IsEnabled(features::kExperimentalAccessibilityLabels)); - html_source->AddBoolean( - "showExperimentalAccessibilitySwitchAccess", - cmd.HasSwitch(::switches::kEnableExperimentalAccessibilitySwitchAccess)); + html_source->AddBoolean("enableLiveCaption", + base::FeatureList::IsEnabled(media::kLiveCaption)); - html_source->AddBoolean( - "showExperimentalAccessibilitySwitchAccessImprovedTextInput", - cmd.HasSwitch( - ::switches::kEnableExperimentalAccessibilitySwitchAccessText)); -#endif + AddCaptionSubpageStrings(html_source); } -void AddAboutStrings(content::WebUIDataSource* html_source) { +void AddAboutStrings(content::WebUIDataSource* html_source, Profile* profile) { + // Top level About Page strings. static constexpr webui::LocalizedString kLocalizedStrings[] = { {"aboutProductLogoAlt", IDS_SHORT_PRODUCT_LOGO_ALT_TEXT}, - #if BUILDFLAG(GOOGLE_CHROME_BRANDING) {"aboutReportAnIssue", IDS_SETTINGS_ABOUT_PAGE_REPORT_AN_ISSUE}, #endif - {"aboutRelaunch", IDS_SETTINGS_ABOUT_PAGE_RELAUNCH}, {"aboutUpgradeCheckStarted", IDS_SETTINGS_ABOUT_UPGRADE_CHECK_STARTED}, {"aboutUpgradeRelaunch", IDS_SETTINGS_UPGRADE_SUCCESSFUL_RELAUNCH}, {"aboutUpgradeUpdating", IDS_SETTINGS_UPGRADE_UPDATING}, {"aboutUpgradeUpdatingPercent", IDS_SETTINGS_UPGRADE_UPDATING_PERCENT}, - + {"aboutGetHelpUsingChrome", IDS_SETTINGS_GET_HELP_USING_CHROME}, + {"aboutPageTitle", IDS_SETTINGS_ABOUT_PROGRAM}, + {"aboutProductTitle", IDS_PRODUCT_NAME}, #if defined(OS_CHROMEOS) - {"aboutBuildDetailsTitle", IDS_OS_SETTINGS_ABOUT_PAGE_BUILD_DETAILS}, - {"aboutChannelBeta", IDS_SETTINGS_ABOUT_PAGE_CURRENT_CHANNEL_BETA}, - {"aboutChannelCanary", IDS_SETTINGS_ABOUT_PAGE_CURRENT_CHANNEL_CANARY}, - {"aboutChannelDev", IDS_SETTINGS_ABOUT_PAGE_CURRENT_CHANNEL_DEV}, - {"aboutChannelLabel", IDS_SETTINGS_ABOUT_PAGE_CHANNEL}, - {"aboutChannelStable", IDS_SETTINGS_ABOUT_PAGE_CURRENT_CHANNEL_STABLE}, - {"aboutCheckForUpdates", IDS_SETTINGS_ABOUT_PAGE_CHECK_FOR_UPDATES}, - {"aboutCurrentlyOnChannel", IDS_SETTINGS_ABOUT_PAGE_CURRENT_CHANNEL}, - {"aboutDetailedBuildInfo", IDS_SETTINGS_ABOUT_PAGE_DETAILED_BUILD_INFO}, - {"aboutEndOfLifeTitle", IDS_SETTINGS_ABOUT_PAGE_END_OF_LIFE_TITLE}, - {"aboutRelaunchAndPowerwash", - IDS_SETTINGS_ABOUT_PAGE_RELAUNCH_AND_POWERWASH}, - {"aboutRollbackInProgress", IDS_SETTINGS_UPGRADE_ROLLBACK_IN_PROGRESS}, - {"aboutRollbackSuccess", IDS_SETTINGS_UPGRADE_ROLLBACK_SUCCESS}, {"aboutUpdateOsSettingsLink", IDS_SETTINGS_ABOUT_SEE_OS_SETTINGS_FOR_UPDATE_MESSAGE}, - {"aboutUpgradeUpdatingChannelSwitch", - IDS_SETTINGS_UPGRADE_UPDATING_CHANNEL_SWITCH}, - {"aboutUpgradeSuccessChannelSwitch", - IDS_SETTINGS_UPGRADE_SUCCESSFUL_CHANNEL_SWITCH}, - {"aboutTPMFirmwareUpdateTitle", - IDS_SETTINGS_ABOUT_TPM_FIRMWARE_UPDATE_TITLE}, - {"aboutTPMFirmwareUpdateDescription", - IDS_SETTINGS_ABOUT_TPM_FIRMWARE_UPDATE_DESCRIPTION}, - - // About page, channel switcher dialog. - {"aboutChangeChannel", IDS_SETTINGS_ABOUT_PAGE_CHANGE_CHANNEL}, - {"aboutChangeChannelAndPowerwash", - IDS_SETTINGS_ABOUT_PAGE_CHANGE_CHANNEL_AND_POWERWASH}, - {"aboutDelayedWarningMessage", - IDS_SETTINGS_ABOUT_PAGE_DELAYED_WARNING_MESSAGE}, - {"aboutDelayedWarningTitle", IDS_SETTINGS_ABOUT_PAGE_DELAYED_WARNING_TITLE}, - {"aboutPowerwashWarningMessage", - IDS_SETTINGS_ABOUT_PAGE_POWERWASH_WARNING_MESSAGE}, - {"aboutPowerwashWarningTitle", - IDS_SETTINGS_ABOUT_PAGE_POWERWASH_WARNING_TITLE}, - {"aboutUnstableWarningMessage", - IDS_SETTINGS_ABOUT_PAGE_UNSTABLE_WARNING_MESSAGE}, - {"aboutUnstableWarningTitle", - IDS_SETTINGS_ABOUT_PAGE_UNSTABLE_WARNING_TITLE}, - {"aboutChannelDialogBeta", IDS_SETTINGS_ABOUT_PAGE_DIALOG_CHANNEL_BETA}, - {"aboutChannelDialogDev", IDS_SETTINGS_ABOUT_PAGE_DIALOG_CHANNEL_DEV}, - {"aboutChannelDialogStable", IDS_SETTINGS_ABOUT_PAGE_DIALOG_CHANNEL_STABLE}, - - // About page, update warning dialog. - {"aboutUpdateWarningMessage", - IDS_SETTINGS_ABOUT_PAGE_UPDATE_WARNING_MESSAGE}, - {"aboutUpdateWarningTitle", IDS_SETTINGS_ABOUT_PAGE_UPDATE_WARNING_TITLE}, -#endif // defined(OS_CHROMEOS) +#endif }; AddLocalizedStringsBulk(html_source, kLocalizedStrings); -#if defined(OS_CHROMEOS) - html_source->AddLocalizedString("aboutOsPageTitle", IDS_SETTINGS_ABOUT_OS); - html_source->AddLocalizedString("aboutGetHelpUsingChromeOs", - IDS_SETTINGS_GET_HELP_USING_CHROME_OS); - html_source->AddLocalizedString("aboutOsProductTitle", IDS_PRODUCT_OS_NAME); - html_source->AddLocalizedString("aboutReleaseNotesOffline", - IDS_SETTINGS_ABOUT_PAGE_RELEASE_NOTES); - html_source->AddLocalizedString("aboutShowReleaseNotes", - IDS_SETTINGS_ABOUT_PAGE_SHOW_RELEASE_NOTES); - if (base::FeatureList::IsEnabled(chromeos::features::kSplitSettings)) { - html_source->AddLocalizedString("aboutGetHelpUsingChrome", - IDS_SETTINGS_GET_HELP_USING_CHROME); - html_source->AddLocalizedString("aboutPageTitle", - IDS_SETTINGS_ABOUT_PROGRAM); - html_source->AddLocalizedString("aboutProductTitle", IDS_PRODUCT_NAME); - } else { - html_source->AddLocalizedString("aboutGetHelpUsingChrome", - IDS_SETTINGS_GET_HELP_USING_CHROME_OS); - html_source->AddLocalizedString("aboutPageTitle", IDS_SETTINGS_ABOUT_OS); - html_source->AddLocalizedString("aboutProductTitle", IDS_PRODUCT_OS_NAME); - } -#else - html_source->AddLocalizedString("aboutGetHelpUsingChrome", - IDS_SETTINGS_GET_HELP_USING_CHROME); - html_source->AddLocalizedString("aboutPageTitle", IDS_SETTINGS_ABOUT_PROGRAM); - html_source->AddLocalizedString("aboutProductTitle", IDS_PRODUCT_NAME); -#endif - + html_source->AddString("managementPage", + ManagementUI::GetManagementPageSubtitle(profile)); html_source->AddString( "aboutUpgradeUpToDate", #if defined(OS_CHROMEOS) @@ -549,200 +257,7 @@ void AddAboutStrings(content::WebUIDataSource* html_source) { #else l10n_util::GetStringUTF16(IDS_SETTINGS_UPGRADE_UP_TO_DATE)); #endif - -#if defined(OS_CHROMEOS) - html_source->AddString("aboutTPMFirmwareUpdateLearnMoreURL", - chrome::kTPMFirmwareUpdateLearnMoreURL); -#endif -} - -#if defined(OS_CHROMEOS) -void AddCrostiniStrings(content::WebUIDataSource* html_source, - Profile* profile) { - static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"crostiniPageTitle", IDS_SETTINGS_CROSTINI_TITLE}, - {"crostiniPageLabel", IDS_SETTINGS_CROSTINI_LABEL}, - {"crostiniEnable", IDS_SETTINGS_TURN_ON}, - {"crostiniSharedPaths", IDS_SETTINGS_CROSTINI_SHARED_PATHS}, - {"crostiniSharedPathsListHeading", - IDS_SETTINGS_CROSTINI_SHARED_PATHS_LIST_HEADING}, - {"crostiniSharedPathsInstructionsAdd", - IDS_SETTINGS_CROSTINI_SHARED_PATHS_INSTRUCTIONS_ADD}, - {"crostiniSharedPathsInstructionsRemove", - IDS_SETTINGS_CROSTINI_SHARED_PATHS_INSTRUCTIONS_REMOVE}, - {"crostiniSharedPathsRemoveSharing", - IDS_SETTINGS_CROSTINI_SHARED_PATHS_REMOVE_SHARING}, - {"crostiniExportImportTitle", IDS_SETTINGS_CROSTINI_EXPORT_IMPORT_TITLE}, - {"crostiniExport", IDS_SETTINGS_CROSTINI_EXPORT}, - {"crostiniExportLabel", IDS_SETTINGS_CROSTINI_EXPORT_LABEL}, - {"crostiniImport", IDS_SETTINGS_CROSTINI_IMPORT}, - {"crostiniImportLabel", IDS_SETTINGS_CROSTINI_IMPORT_LABEL}, - {"crostiniImportConfirmationDialogTitle", - IDS_SETTINGS_CROSTINI_CONFIRM_IMPORT_DIALOG_WINDOW_TITLE}, - {"crostiniImportConfirmationDialogMessage", - IDS_SETTINGS_CROSTINI_CONFIRM_IMPORT_DIALOG_WINDOW_MESSAGE}, - {"crostiniImportConfirmationDialogConfirmationButton", - IDS_SETTINGS_CROSTINI_IMPORT}, - {"crostiniRemoveButton", IDS_SETTINGS_CROSTINI_REMOVE_BUTTON}, - {"crostiniSharedUsbDevicesLabel", - IDS_SETTINGS_CROSTINI_SHARED_USB_DEVICES_LABEL}, - {"crostiniSharedUsbDevicesDescription", - IDS_SETTINGS_CROSTINI_SHARED_USB_DEVICES_DESCRIPTION}, - {"crostiniSharedUsbDevicesExtraDescription", - IDS_SETTINGS_CROSTINI_SHARED_USB_DEVICES_EXTRA_DESCRIPTION}, - {"crostiniSharedUsbDevicesListEmptyMessage", - IDS_SETTINGS_CROSTINI_SHARED_USB_DEVICES_LIST_EMPTY_MESSAGE}, - {"crostiniArcAdbTitle", IDS_SETTINGS_CROSTINI_ARC_ADB_TITLE}, - {"crostiniArcAdbDescription", IDS_SETTINGS_CROSTINI_ARC_ADB_DESCRIPTION}, - {"crostiniArcAdbLabel", IDS_SETTINGS_CROSTINI_ARC_ADB_LABEL}, - {"crostiniArcAdbRestartButton", - IDS_SETTINGS_CROSTINI_ARC_ADB_RESTART_BUTTON}, - {"crostiniArcAdbConfirmationTitleEnable", - IDS_SETTINGS_CROSTINI_ARC_ADB_CONFIRMATION_TITLE_ENABLE}, - {"crostiniArcAdbConfirmationTitleDisable", - IDS_SETTINGS_CROSTINI_ARC_ADB_CONFIRMATION_TITLE_DISABLE}, - }; - AddLocalizedStringsBulk(html_source, kLocalizedStrings); - html_source->AddString( - "crostiniSubtext", - l10n_util::GetStringFUTF16( - IDS_SETTINGS_CROSTINI_SUBTEXT, ui::GetChromeOSDeviceName(), - GetHelpUrlWithBoard(chrome::kLinuxAppsLearnMoreURL))); - // TODO(crbug.com/893332): replace with the final URL - html_source->AddString( - "crostiniArcAdbPowerwashRequiredSublabel", - l10n_util::GetStringFUTF16( - IDS_SETTINGS_CROSTINI_ARC_ADB_POWERWASH_REQUIRED_SUBLABEL, - GetHelpUrlWithBoard(chrome::kLinuxAppsLearnMoreURL))); - html_source->AddString("crostiniRemove", l10n_util::GetStringFUTF16( - IDS_SETTINGS_CROSTINI_REMOVE, - ui::GetChromeOSDeviceName())); - html_source->AddString( - "crostiniArcAdbConfirmationMessageEnable", - l10n_util::GetStringFUTF16( - IDS_SETTINGS_CROSTINI_ARC_ADB_CONFIRMATION_MESSAGE_ENABLE, - ui::GetChromeOSDeviceName())); - html_source->AddString( - "crostiniArcAdbConfirmationMessageDisable", - l10n_util::GetStringFUTF16( - IDS_SETTINGS_CROSTINI_ARC_ADB_CONFIRMATION_MESSAGE_DISABLE, - ui::GetChromeOSDeviceName())); - html_source->AddString( - "crostiniSharedPathsInstructionsLocate", - l10n_util::GetStringFUTF16( - IDS_SETTINGS_CROSTINI_SHARED_PATHS_INSTRUCTIONS_LOCATE, - base::ASCIIToUTF16( - crostini::ContainerChromeOSBaseDirectory().value()))); - html_source->AddBoolean( - "showCrostiniExportImport", - crostini::CrostiniFeatures::Get()->IsExportImportUIAllowed(profile)); - html_source->AddBoolean("ArcAdbSideloadingSupported", - ShouldEnableArcAdbSideloading()); - html_source->AddBoolean("isOwnerProfile", - chromeos::ProfileHelper::IsOwnerProfile(profile)); - html_source->AddBoolean("isEnterpriseManaged", - IsDeviceManaged() || IsProfileManaged(profile)); -} - -void AddPluginVmStrings(content::WebUIDataSource* html_source, - Profile* profile) { - static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"pluginVmPageTitle", IDS_SETTINGS_PLUGIN_VM_PAGE_TITLE}, - {"pluginVmPageLabel", IDS_SETTINGS_PLUGIN_VM_PAGE_LABEL}, - {"pluginVmPageSubtext", IDS_SETTINGS_PLUGIN_VM_PAGE_SUBTEXT}, - {"pluginVmPrinterAccess", IDS_SETTINGS_PLUGIN_VM_PRINTER_ACCESS}, - {"pluginVmSharedPaths", IDS_SETTINGS_PLUGIN_VM_SHARED_PATHS}, - {"pluginVmSharedPathsListHeading", - IDS_SETTINGS_PLUGIN_VM_SHARED_PATHS_LIST_HEADING}, - {"pluginVmSharedPathsInstructionsAdd", - IDS_SETTINGS_PLUGIN_VM_SHARED_PATHS_INSTRUCTIONS_ADD}, - {"pluginVmSharedPathsInstructionsRemove", - IDS_SETTINGS_PLUGIN_VM_SHARED_PATHS_INSTRUCTIONS_REMOVE}, - {"pluginVmSharedPathsRemoveSharing", - IDS_SETTINGS_PLUGIN_VM_SHARED_PATHS_REMOVE_SHARING}, - }; - AddLocalizedStringsBulk(html_source, kLocalizedStrings); -} - -void AddAndroidAppStrings(content::WebUIDataSource* html_source) { - static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"androidAppsPageLabel", IDS_SETTINGS_ANDROID_APPS_LABEL}, - {"androidAppsEnable", IDS_SETTINGS_TURN_ON}, - {"androidAppsManageApps", IDS_SETTINGS_ANDROID_APPS_MANAGE_APPS}, - {"androidAppsRemove", IDS_SETTINGS_ANDROID_APPS_REMOVE}, - {"androidAppsRemoveButton", IDS_SETTINGS_ANDROID_APPS_REMOVE_BUTTON}, - {"androidAppsDisableDialogTitle", - IDS_SETTINGS_ANDROID_APPS_DISABLE_DIALOG_TITLE}, - {"androidAppsDisableDialogMessage", - IDS_SETTINGS_ANDROID_APPS_DISABLE_DIALOG_MESSAGE}, - {"androidAppsDisableDialogRemove", - IDS_SETTINGS_ANDROID_APPS_DISABLE_DIALOG_REMOVE}, - {"androidAppsManageAppLinks", IDS_SETTINGS_ANDROID_APPS_MANAGE_APP_LINKS}, - }; - AddLocalizedStringsBulk(html_source, kLocalizedStrings); - html_source->AddLocalizedString("androidAppsPageTitle", - arc::IsPlayStoreAvailable() - ? IDS_SETTINGS_ANDROID_APPS_TITLE - : IDS_SETTINGS_ANDROID_SETTINGS_TITLE); - html_source->AddString( - "androidAppsSubtext", - l10n_util::GetStringFUTF16( - IDS_SETTINGS_ANDROID_APPS_SUBTEXT, ui::GetChromeOSDeviceName(), - GetHelpUrlWithBoard(chrome::kAndroidAppsLearnMoreURL))); -} - -void AddAppsStrings(content::WebUIDataSource* html_source) { - static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"appsPageTitle", IDS_SETTINGS_APPS_TITLE}, - {"appManagementTitle", IDS_SETTINGS_APPS_LINK_TEXT}, - }; - - AddLocalizedStringsBulk(html_source, kLocalizedStrings); -} - -void AddAppManagementStrings(content::WebUIDataSource* html_source) { - static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"appManagementAppInstalledByPolicyLabel", - IDS_APP_MANAGEMENT_POLICY_APP_POLICY_STRING}, - {"appManagementCameraPermissionLabel", IDS_APP_MANAGEMENT_CAMERA}, - {"appManagementContactsPermissionLabel", IDS_APP_MANAGEMENT_CONTACTS}, - {"appManagementLocationPermissionLabel", IDS_APP_MANAGEMENT_LOCATION}, - {"appManagementMicrophonePermissionLabel", IDS_APP_MANAGEMENT_MICROPHONE}, - {"appManagementMoreSettingsLabel", IDS_APP_MANAGEMENT_MORE_SETTINGS}, - {"appManagementNoAppsFound", IDS_APP_MANAGEMENT_NO_APPS_FOUND}, - {"appManagementNoPermissions", - IDS_APPLICATION_INFO_APP_NO_PERMISSIONS_TEXT}, - {"appManagementNotificationsLabel", IDS_APP_MANAGEMENT_NOTIFICATIONS}, - {"appManagementPermissionsLabel", IDS_APP_MANAGEMENT_PERMISSIONS}, - {"appManagementPinToShelfLabel", IDS_APP_MANAGEMENT_PIN_TO_SHELF}, - {"appManagementSearchPrompt", IDS_APP_MANAGEMENT_SEARCH_PROMPT}, - {"appManagementStoragePermissionLabel", IDS_APP_MANAGEMENT_STORAGE}, - {"appManagementUninstallLabel", IDS_APP_MANAGEMENT_UNINSTALL_APP}, - }; - AddLocalizedStringsBulk(html_source, kLocalizedStrings); -} -#endif - -#if defined(OS_CHROMEOS) -void AddParentalControlStrings(content::WebUIDataSource* html_source) { - html_source->AddBoolean( - "isChild", user_manager::UserManager::Get()->IsLoggedInAsChildUser()); - static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"parentalControlsPageTitle", IDS_SETTINGS_PARENTAL_CONTROLS_PAGE_TITLE}, - {"parentalControlsPageSetUpLabel", - IDS_SETTINGS_PARENTAL_CONTROLS_PAGE_SET_UP_LABEL}, - {"parentalControlsPageViewSettingsLabel", - IDS_SETTINGS_PARENTAL_CONTROLS_PAGE_VIEW_SETTINGS_LABEL}, - {"parentalControlsPageConnectToInternetLabel", - IDS_SETTINGS_PARENTAL_CONTROLS_PAGE_CONNECT_TO_INTERNET_LABEL}, - {"parentalControlsSetUpButtonLabel", - IDS_SETTINGS_PARENTAL_CONTROLS_SET_UP_BUTTON_LABEL}, - {"parentalControlsSetUpButtonRole", - IDS_SETTINGS_PARENTAL_CONTROLS_SET_UP_BUTTON_ROLE}, - }; - AddLocalizedStringsBulk(html_source, kLocalizedStrings); } -#endif void AddAppearanceStrings(content::WebUIDataSource* html_source, Profile* profile) { @@ -752,14 +267,6 @@ void AddAppearanceStrings(content::WebUIDataSource* html_source, {"enterCustomWebAddress", IDS_SETTINGS_ENTER_CUSTOM_WEB_ADDRESS}, {"homeButtonDisabled", IDS_SETTINGS_HOME_BUTTON_DISABLED}, {"themes", IDS_SETTINGS_THEMES}, -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) - {"systemTheme", IDS_SETTINGS_SYSTEM_THEME}, - {"useSystemTheme", IDS_SETTINGS_USE_SYSTEM_THEME}, - {"classicTheme", IDS_SETTINGS_CLASSIC_THEME}, - {"useClassicTheme", IDS_SETTINGS_USE_CLASSIC_THEME}, -#else - {"resetToDefaultTheme", IDS_SETTINGS_RESET_TO_DEFAULT_THEME}, -#endif {"chromeColors", IDS_SETTINGS_CHROME_COLORS}, {"showHomeButton", IDS_SETTINGS_SHOW_HOME_BUTTON}, {"showBookmarksBar", IDS_SETTINGS_SHOW_BOOKMARKS_BAR}, @@ -767,98 +274,39 @@ void AddAppearanceStrings(content::WebUIDataSource* html_source, {"changeHomePage", IDS_SETTINGS_CHANGE_HOME_PAGE}, {"themesGalleryUrl", IDS_THEMES_GALLERY_URL}, {"chooseFromWebStore", IDS_SETTINGS_WEB_STORE}, -#if defined(OS_CHROMEOS) - {"personalizationPageTitle", IDS_OS_SETTINGS_PERSONALIZATION}, - {"openWallpaperApp", IDS_OS_SETTINGS_OPEN_WALLPAPER_APP}, - {"setWallpaper", IDS_OS_SETTINGS_SET_WALLPAPER}, -#endif + {"pageZoom", IDS_SETTINGS_PAGE_ZOOM_LABEL}, + {"fontSize", IDS_SETTINGS_FONT_SIZE_LABEL}, + {"customizeFonts", IDS_SETTINGS_CUSTOMIZE_FONTS}, + {"fonts", IDS_SETTINGS_FONTS}, + {"standardFont", IDS_SETTINGS_STANDARD_FONT_LABEL}, + {"serifFont", IDS_SETTINGS_SERIF_FONT_LABEL}, + {"sansSerifFont", IDS_SETTINGS_SANS_SERIF_FONT_LABEL}, + {"fixedWidthFont", IDS_SETTINGS_FIXED_WIDTH_FONT_LABEL}, + {"minimumFont", IDS_SETTINGS_MINIMUM_FONT_SIZE_LABEL}, + {"tiny", IDS_SETTINGS_TINY_FONT_SIZE}, + {"huge", IDS_SETTINGS_HUGE_FONT_SIZE}, #if defined(OS_LINUX) && !defined(OS_CHROMEOS) + {"systemTheme", IDS_SETTINGS_SYSTEM_THEME}, + {"useSystemTheme", IDS_SETTINGS_USE_SYSTEM_THEME}, + {"classicTheme", IDS_SETTINGS_CLASSIC_THEME}, + {"useClassicTheme", IDS_SETTINGS_USE_CLASSIC_THEME}, {"showWindowDecorations", IDS_SHOW_WINDOW_DECORATIONS}, +#else + {"resetToDefaultTheme", IDS_SETTINGS_RESET_TO_DEFAULT_THEME}, #endif #if defined(OS_MACOSX) {"tabsToLinks", IDS_SETTINGS_TABS_TO_LINKS_PREF}, {"warnBeforeQuitting", IDS_SETTINGS_WARN_BEFORE_QUITTING_PREF}, #endif + {"readerMode", IDS_SETTINGS_READER_MODE}, + {"readerModeDescription", IDS_SETTINGS_READER_MODE_DESCRIPTION}, }; AddLocalizedStringsBulk(html_source, kLocalizedStrings); -#if defined(OS_CHROMEOS) - if (base::FeatureList::IsEnabled(chromeos::features::kSplitSettings)) { - html_source->AddLocalizedString("changePictureTitle", - IDS_OS_SETTINGS_CHANGE_PICTURE_TITLE); - } else { - html_source->AddLocalizedString("changePictureTitle", - IDS_SETTINGS_CHANGE_PICTURE_DIALOG_TITLE); - } -#endif -} - -#if defined(OS_CHROMEOS) -void AddBluetoothStrings(content::WebUIDataSource* html_source) { - static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"bluetoothConnected", IDS_SETTINGS_BLUETOOTH_CONNECTED}, - {"bluetoothConnectedWithBattery", - IDS_SETTINGS_BLUETOOTH_CONNECTED_WITH_BATTERY}, - {"bluetoothConnecting", IDS_SETTINGS_BLUETOOTH_CONNECTING}, - {"bluetoothDeviceListPaired", IDS_SETTINGS_BLUETOOTH_DEVICE_LIST_PAIRED}, - {"bluetoothDeviceListUnpaired", - IDS_SETTINGS_BLUETOOTH_DEVICE_LIST_UNPAIRED}, - {"bluetoothConnect", IDS_SETTINGS_BLUETOOTH_CONNECT}, - {"bluetoothDisconnect", IDS_SETTINGS_BLUETOOTH_DISCONNECT}, - {"bluetoothToggleA11yLabel", - IDS_SETTINGS_BLUETOOTH_TOGGLE_ACCESSIBILITY_LABEL}, - {"bluetoothExpandA11yLabel", - IDS_SETTINGS_BLUETOOTH_EXPAND_ACCESSIBILITY_LABEL}, - {"bluetoothNoDevices", IDS_SETTINGS_BLUETOOTH_NO_DEVICES}, - {"bluetoothNoDevicesFound", IDS_SETTINGS_BLUETOOTH_NO_DEVICES_FOUND}, - {"bluetoothNotConnected", IDS_SETTINGS_BLUETOOTH_NOT_CONNECTED}, - {"bluetoothPageTitle", IDS_SETTINGS_BLUETOOTH}, - {"bluetoothPairDevicePageTitle", - IDS_SETTINGS_BLUETOOTH_PAIR_DEVICE_TITLE}, - {"bluetoothRemove", IDS_SETTINGS_BLUETOOTH_REMOVE}, - {"bluetoothPrimaryUserControlled", - IDS_SETTINGS_BLUETOOTH_PRIMARY_USER_CONTROLLED}, - {"bluetoothDeviceType_computer", - IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_COMPUTER}, - {"bluetoothDeviceType_phone", - IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_PHONE}, - {"bluetoothDeviceType_modem", - IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_MODEM}, - {"bluetoothDeviceType_audio", - IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_AUDIO}, - {"bluetoothDeviceType_carAudio", - IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_CAR_AUDIO}, - {"bluetoothDeviceType_video", - IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_VIDEO}, - {"bluetoothDeviceType_peripheral", - IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_PERIPHERAL}, - {"bluetoothDeviceType_joystick", - IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_JOYSTICK}, - {"bluetoothDeviceType_gamepad", - IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_GAMEPAD}, - {"bluetoothDeviceType_keyboard", - IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_KEYBOARD}, - {"bluetoothDeviceType_mouse", - IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_MOUSE}, - {"bluetoothDeviceType_tablet", - IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_TABLET}, - {"bluetoothDeviceType_keyboardMouseCombo", - IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_KEYBOARD_MOUSE_COMBO}, - {"bluetoothDeviceType_unknown", - IDS_BLUETOOTH_ACCESSIBILITY_DEVICE_TYPE_UNKNOWN}, - }; - AddLocalizedStringsBulk(html_source, kLocalizedStrings); - chromeos::bluetooth_dialog::AddLocalizedStrings(html_source); -} -#endif - -void AddChangePasswordStrings(content::WebUIDataSource* html_source) { - static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"changePasswordPageTitle", IDS_SETTINGS_CHANGE_PASSWORD_TITLE}, - {"changePasswordPageDetails", IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS}, - {"changePasswordPageButton", IDS_SETTINGS_CHANGE_PASSWORD_BUTTON}, - }; - AddLocalizedStringsBulk(html_source, kLocalizedStrings); + html_source->AddString("presetZoomFactors", + zoom::GetPresetZoomFactorsAsJSON()); + html_source->AddBoolean("showReaderModeOption", + dom_distiller::OfferReaderModeInSettings()); } void AddClearBrowsingDataStrings(content::WebUIDataSource* html_source, @@ -895,6 +343,8 @@ void AddClearBrowsingDataStrings(content::WebUIDataSource* html_source, {"historyDeletionDialogTitle", IDS_CLEAR_BROWSING_DATA_HISTORY_NOTICE_TITLE}, {"historyDeletionDialogOK", IDS_CLEAR_BROWSING_DATA_HISTORY_NOTICE_OK}, + {"installedAppsConfirm", IDS_SETTINGS_CLEAR_INSTALLED_APPS_DATA_CONFIRM}, + {"installedAppsTitle", IDS_SETTINGS_CLEAR_INSTALLED_APPS_DATA_TITLE}, {"notificationWarning", IDS_SETTINGS_NOTIFICATION_WARNING}, }; @@ -933,288 +383,12 @@ void AddDefaultBrowserStrings(content::WebUIDataSource* html_source) { } #endif -#if defined(OS_CHROMEOS) -void AddDeviceStrings(content::WebUIDataSource* html_source) { - static constexpr webui::LocalizedString kDeviceStrings[] = { - {"devicePageTitle", IDS_SETTINGS_DEVICE_TITLE}, - {"scrollLabel", IDS_SETTINGS_SCROLL_LABEL}, - {"traditionalScrollLabel", IDS_SETTINGS_TRADITIONAL_SCROLL_LABEL}, - {"naturalScrollLabel", IDS_SETTINGS_NATURAL_SCROLL_LABEL}, - {"naturalScrollLearnMore", IDS_LEARN_MORE}, - }; - AddLocalizedStringsBulk(html_source, kDeviceStrings); - - static constexpr webui::LocalizedString kPointersStrings[] = { - {"mouseTitle", IDS_SETTINGS_MOUSE_TITLE}, - {"touchpadTitle", IDS_SETTINGS_TOUCHPAD_TITLE}, - {"mouseAndTouchpadTitle", IDS_SETTINGS_MOUSE_AND_TOUCHPAD_TITLE}, - {"touchpadTapToClickEnabledLabel", - IDS_SETTINGS_TOUCHPAD_TAP_TO_CLICK_ENABLED_LABEL}, - {"touchpadSpeed", IDS_SETTINGS_TOUCHPAD_SPEED_LABEL}, - {"pointerSlow", IDS_SETTINGS_POINTER_SPEED_SLOW_LABEL}, - {"pointerFast", IDS_SETTINGS_POINTER_SPEED_FAST_LABEL}, - {"mouseSpeed", IDS_SETTINGS_MOUSE_SPEED_LABEL}, - {"mouseSwapButtons", IDS_SETTINGS_MOUSE_SWAP_BUTTONS_LABEL}, - {"mouseReverseScroll", IDS_SETTINGS_MOUSE_REVERSE_SCROLL_LABEL}, - {"mouseAccelerationLabel", IDS_SETTINGS_MOUSE_ACCELERATION_LABEL}, - {"touchpadAccelerationLabel", IDS_SETTINGS_TOUCHPAD_ACCELERATION_LABEL}, - }; - AddLocalizedStringsBulk(html_source, kPointersStrings); - - static constexpr webui::LocalizedString keyboard_strings[] = { - {"keyboardTitle", IDS_SETTINGS_KEYBOARD_TITLE}, - {"keyboardKeyCtrl", IDS_SETTINGS_KEYBOARD_KEY_LEFT_CTRL}, - {"keyboardKeyAlt", IDS_SETTINGS_KEYBOARD_KEY_LEFT_ALT}, - {"keyboardKeyCapsLock", IDS_SETTINGS_KEYBOARD_KEY_CAPS_LOCK}, - {"keyboardKeyCommand", IDS_SETTINGS_KEYBOARD_KEY_COMMAND}, - {"keyboardKeyDiamond", IDS_SETTINGS_KEYBOARD_KEY_DIAMOND}, - {"keyboardKeyEscape", IDS_SETTINGS_KEYBOARD_KEY_ESCAPE}, - {"keyboardKeyBackspace", IDS_SETTINGS_KEYBOARD_KEY_BACKSPACE}, - {"keyboardKeyAssistant", IDS_SETTINGS_KEYBOARD_KEY_ASSISTANT}, - {"keyboardKeyDisabled", IDS_SETTINGS_KEYBOARD_KEY_DISABLED}, - {"keyboardKeyExternalCommand", - IDS_SETTINGS_KEYBOARD_KEY_EXTERNAL_COMMAND}, - {"keyboardKeyExternalMeta", IDS_SETTINGS_KEYBOARD_KEY_EXTERNAL_META}, - {"keyboardKeyMeta", IDS_SETTINGS_KEYBOARD_KEY_META}, - {"keyboardSendFunctionKeys", IDS_SETTINGS_KEYBOARD_SEND_FUNCTION_KEYS}, - {"keyboardEnableAutoRepeat", IDS_SETTINGS_KEYBOARD_AUTO_REPEAT_ENABLE}, - {"keyRepeatDelay", IDS_SETTINGS_KEYBOARD_AUTO_REPEAT_DELAY}, - {"keyRepeatDelayLong", IDS_SETTINGS_KEYBOARD_AUTO_REPEAT_DELAY_LONG}, - {"keyRepeatDelayShort", IDS_SETTINGS_KEYBOARD_AUTO_REPEAT_DELAY_SHORT}, - {"keyRepeatRate", IDS_SETTINGS_KEYBOARD_AUTO_REPEAT_RATE}, - {"keyRepeatRateSlow", IDS_SETTINGS_KEYBOARD_AUTO_REPEAT_RATE_SLOW}, - {"keyRepeatRateFast", IDS_SETTINGS_KEYBOARD_AUTO_REPEAT_FAST}, - {"showKeyboardShortcutViewer", - IDS_SETTINGS_KEYBOARD_SHOW_SHORTCUT_VIEWER}, - {"keyboardShowLanguageAndInput", - IDS_SETTINGS_KEYBOARD_SHOW_LANGUAGE_AND_INPUT}, - }; - AddLocalizedStringsBulk(html_source, keyboard_strings); - html_source->AddLocalizedString("keyboardKeySearch", - ui::DeviceUsesKeyboardLayout2() - ? IDS_SETTINGS_KEYBOARD_KEY_LAUNCHER - : IDS_SETTINGS_KEYBOARD_KEY_SEARCH); - html_source->AddLocalizedString( - "keyboardSendFunctionKeysDescription", - ui::DeviceUsesKeyboardLayout2() - ? IDS_SETTINGS_KEYBOARD_SEND_FUNCTION_KEYS_LAYOUT2_DESCRIPTION - : IDS_SETTINGS_KEYBOARD_SEND_FUNCTION_KEYS_DESCRIPTION); - - static constexpr webui::LocalizedString kStylusStrings[] = { - {"stylusTitle", IDS_SETTINGS_STYLUS_TITLE}, - {"stylusEnableStylusTools", IDS_SETTINGS_STYLUS_ENABLE_STYLUS_TOOLS}, - {"stylusAutoOpenStylusTools", IDS_SETTINGS_STYLUS_AUTO_OPEN_STYLUS_TOOLS}, - {"stylusFindMoreAppsPrimary", IDS_SETTINGS_STYLUS_FIND_MORE_APPS_PRIMARY}, - {"stylusFindMoreAppsSecondary", - IDS_SETTINGS_STYLUS_FIND_MORE_APPS_SECONDARY}, - {"stylusNoteTakingApp", IDS_SETTINGS_STYLUS_NOTE_TAKING_APP_LABEL}, - {"stylusNoteTakingAppEnabledOnLockScreen", - IDS_SETTINGS_STYLUS_NOTE_TAKING_APP_LOCK_SCREEN_CHECKBOX}, - {"stylusNoteTakingAppKeepsLastNoteOnLockScreen", - IDS_SETTINGS_STYLUS_NOTE_TAKING_APP_KEEP_LATEST_NOTE}, - {"stylusNoteTakingAppLockScreenSettingsHeader", - IDS_SETTINGS_STYLUS_LOCK_SCREEN_NOTES_TITLE}, - {"stylusNoteTakingAppNoneAvailable", - IDS_SETTINGS_STYLUS_NOTE_TAKING_APP_NONE_AVAILABLE}, - {"stylusNoteTakingAppWaitingForAndroid", - IDS_SETTINGS_STYLUS_NOTE_TAKING_APP_WAITING_FOR_ANDROID}}; - AddLocalizedStringsBulk(html_source, kStylusStrings); - - static constexpr webui::LocalizedString kDisplayStrings[] = { - {"displayTitle", IDS_SETTINGS_DISPLAY_TITLE}, - {"displayArrangementText", IDS_SETTINGS_DISPLAY_ARRANGEMENT_TEXT}, - {"displayArrangementTitle", IDS_SETTINGS_DISPLAY_ARRANGEMENT_TITLE}, - {"displayMirror", IDS_SETTINGS_DISPLAY_MIRROR}, - {"displayMirrorDisplayName", IDS_SETTINGS_DISPLAY_MIRROR_DISPLAY_NAME}, - {"displayAmbientColorTitle", IDS_SETTINGS_DISPLAY_AMBIENT_COLOR_TITLE}, - {"displayAmbientColorSubtitle", - IDS_SETTINGS_DISPLAY_AMBIENT_COLOR_SUBTITLE}, - {"displayNightLightLabel", IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_LABEL}, - {"displayNightLightOnAtSunset", - IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_ON_AT_SUNSET}, - {"displayNightLightOffAtSunrise", - IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_OFF_AT_SUNRISE}, - {"displayNightLightScheduleCustom", - IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_SCHEDULE_CUSTOM}, - {"displayNightLightScheduleLabel", - IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_SCHEDULE_LABEL}, - {"displayNightLightScheduleNever", - IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_SCHEDULE_NEVER}, - {"displayNightLightScheduleSunsetToSunRise", - IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_SCHEDULE_SUNSET_TO_SUNRISE}, - {"displayNightLightStartTime", - IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_START_TIME}, - {"displayNightLightStopTime", IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_STOP_TIME}, - {"displayNightLightText", IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_TEXT}, - {"displayNightLightTemperatureLabel", - IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_TEMPERATURE_LABEL}, - {"displayNightLightTempSliderMaxLabel", - IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_TEMP_SLIDER_MAX_LABEL}, - {"displayNightLightTempSliderMinLabel", - IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_TEMP_SLIDER_MIN_LABEL}, - {"displayUnifiedDesktop", IDS_SETTINGS_DISPLAY_UNIFIED_DESKTOP}, - {"displayResolutionTitle", IDS_SETTINGS_DISPLAY_RESOLUTION_TITLE}, - {"displayResolutionText", IDS_SETTINGS_DISPLAY_RESOLUTION_TEXT}, - {"displayResolutionTextBest", IDS_SETTINGS_DISPLAY_RESOLUTION_TEXT_BEST}, - {"displayResolutionTextNative", - IDS_SETTINGS_DISPLAY_RESOLUTION_TEXT_NATIVE}, - {"displayResolutionSublabel", IDS_SETTINGS_DISPLAY_RESOLUTION_SUBLABEL}, - {"displayResolutionMenuItem", IDS_SETTINGS_DISPLAY_RESOLUTION_MENU_ITEM}, - {"displayResolutionInterlacedMenuItem", - IDS_SETTINGS_DISPLAY_RESOLUTION_INTERLACED_MENU_ITEM}, - {"displayZoomTitle", IDS_SETTINGS_DISPLAY_ZOOM_TITLE}, - {"displayZoomSublabel", IDS_SETTINGS_DISPLAY_ZOOM_SUBLABEL}, - {"displayZoomValue", IDS_SETTINGS_DISPLAY_ZOOM_VALUE}, - {"displayZoomLogicalResolutionText", - IDS_SETTINGS_DISPLAY_ZOOM_LOGICAL_RESOLUTION_TEXT}, - {"displayZoomNativeLogicalResolutionNativeText", - IDS_SETTINGS_DISPLAY_ZOOM_LOGICAL_RESOLUTION_NATIVE_TEXT}, - {"displayZoomLogicalResolutionDefaultText", - IDS_SETTINGS_DISPLAY_ZOOM_LOGICAL_RESOLUTION_DEFAULT_TEXT}, - {"displaySizeSliderMinLabel", IDS_SETTINGS_DISPLAY_ZOOM_SLIDER_MINIMUM}, - {"displaySizeSliderMaxLabel", IDS_SETTINGS_DISPLAY_ZOOM_SLIDER_MAXIMUM}, - {"displayScreenTitle", IDS_SETTINGS_DISPLAY_SCREEN}, - {"displayScreenExtended", IDS_SETTINGS_DISPLAY_SCREEN_EXTENDED}, - {"displayScreenPrimary", IDS_SETTINGS_DISPLAY_SCREEN_PRIMARY}, - {"displayOrientation", IDS_SETTINGS_DISPLAY_ORIENTATION}, - {"displayOrientationStandard", IDS_SETTINGS_DISPLAY_ORIENTATION_STANDARD}, - {"displayOrientationAutoRotate", - IDS_SETTINGS_DISPLAY_ORIENTATION_AUTO_ROTATE}, - {"displayOverscanPageText", IDS_SETTINGS_DISPLAY_OVERSCAN_TEXT}, - {"displayOverscanPageTitle", IDS_SETTINGS_DISPLAY_OVERSCAN_TITLE}, - {"displayOverscanSubtitle", IDS_SETTINGS_DISPLAY_OVERSCAN_SUBTITLE}, - {"displayOverscanInstructions", - IDS_SETTINGS_DISPLAY_OVERSCAN_INSTRUCTIONS}, - {"displayOverscanResize", IDS_SETTINGS_DISPLAY_OVERSCAN_RESIZE}, - {"displayOverscanPosition", IDS_SETTINGS_DISPLAY_OVERSCAN_POSITION}, - {"displayOverscanReset", IDS_SETTINGS_DISPLAY_OVERSCAN_RESET}, - {"displayTouchCalibrationTitle", - IDS_SETTINGS_DISPLAY_TOUCH_CALIBRATION_TITLE}, - {"displayTouchCalibrationText", - IDS_SETTINGS_DISPLAY_TOUCH_CALIBRATION_TEXT}}; - AddLocalizedStringsBulk(html_source, kDisplayStrings); - base::CommandLine& cmd = *base::CommandLine::ForCurrentProcess(); - html_source->AddBoolean("unifiedDesktopAvailable", - cmd.HasSwitch(::switches::kEnableUnifiedDesktop)); - - html_source->AddBoolean("listAllDisplayModes", - display::features::IsListAllDisplayModesEnabled()); - - html_source->AddBoolean("deviceSupportsAmbientColor", - ash::features::IsAllowAmbientEQEnabled()); - - html_source->AddBoolean( - "enableTouchCalibrationSetting", - cmd.HasSwitch(chromeos::switches::kEnableTouchCalibrationSetting)); - - html_source->AddBoolean("hasExternalTouchDevice", - display::HasExternalTouchscreenDevice()); - - html_source->AddBoolean( - "allowDisableMouseAcceleration", - base::FeatureList::IsEnabled(features::kAllowDisableMouseAcceleration)); - - static constexpr webui::LocalizedString kStorageStrings[] = { - {"storageTitle", IDS_SETTINGS_STORAGE_TITLE}, - {"storageItemInUse", IDS_SETTINGS_STORAGE_ITEM_IN_USE}, - {"storageItemAvailable", IDS_SETTINGS_STORAGE_ITEM_AVAILABLE}, - {"storageItemDownloads", IDS_SETTINGS_STORAGE_ITEM_DOWNLOADS}, - {"storageItemBrowsingData", IDS_SETTINGS_STORAGE_ITEM_BROWSING_DATA}, - {"storageItemAndroid", IDS_SETTINGS_STORAGE_ITEM_ANDROID}, - {"storageItemCrostini", IDS_SETTINGS_STORAGE_ITEM_CROSTINI}, - {"storageItemOtherUsers", IDS_SETTINGS_STORAGE_ITEM_OTHER_USERS}, - {"storageSizeComputing", IDS_SETTINGS_STORAGE_SIZE_CALCULATING}, - {"storageSizeUnknown", IDS_SETTINGS_STORAGE_SIZE_UNKNOWN}, - {"storageSpaceLowMessageTitle", - IDS_SETTINGS_STORAGE_SPACE_LOW_MESSAGE_TITLE}, - {"storageSpaceLowMessageLine1", - IDS_SETTINGS_STORAGE_SPACE_LOW_MESSAGE_LINE_1}, - {"storageSpaceLowMessageLine2", - IDS_SETTINGS_STORAGE_SPACE_LOW_MESSAGE_LINE_2}, - {"storageSpaceCriticallyLowMessageTitle", - IDS_SETTINGS_STORAGE_SPACE_CRITICALLY_LOW_MESSAGE_TITLE}, - {"storageSpaceCriticallyLowMessageLine1", - IDS_SETTINGS_STORAGE_SPACE_CRITICALLY_LOW_MESSAGE_LINE_1}, - {"storageSpaceCriticallyLowMessageLine2", - IDS_SETTINGS_STORAGE_SPACE_CRITICALLY_LOW_MESSAGE_LINE_2}, - {"storageExternal", IDS_SETTINGS_STORAGE_EXTERNAL}, - {"storageExternalStorageEmptyListHeader", - IDS_SETTINGS_STORAGE_EXTERNAL_STORAGE_EMPTY_LIST_HEADER}, - {"storageExternalStorageListHeader", - IDS_SETTINGS_STORAGE_EXTERNAL_STORAGE_LIST_HEADER}, - {"storageOverviewAriaLabel", IDS_SETTINGS_STORAGE_OVERVIEW_ARIA_LABEL}}; - - AddLocalizedStringsBulk(html_source, kStorageStrings); - - html_source->AddString( - "storageAndroidAppsExternalDrivesNote", - l10n_util::GetStringFUTF16( - IDS_SETTINGS_STORAGE_ANDROID_APPS_ACCESS_EXTERNAL_DRIVES_NOTE, - base::ASCIIToUTF16(chrome::kArcExternalStorageLearnMoreURL))); - - static constexpr webui::LocalizedString kPowerStrings[] = { - {"powerTitle", IDS_SETTINGS_POWER_TITLE}, - {"powerSourceLabel", IDS_SETTINGS_POWER_SOURCE_LABEL}, - {"powerSourceBattery", IDS_SETTINGS_POWER_SOURCE_BATTERY}, - {"powerSourceAcAdapter", IDS_SETTINGS_POWER_SOURCE_AC_ADAPTER}, - {"powerSourceLowPowerCharger", - IDS_SETTINGS_POWER_SOURCE_LOW_POWER_CHARGER}, - {"calculatingPower", IDS_SETTINGS_POWER_SOURCE_CALCULATING}, - {"powerIdleLabel", IDS_SETTINGS_POWER_IDLE_LABEL}, - {"powerIdleDisplayOffSleep", IDS_SETTINGS_POWER_IDLE_DISPLAY_OFF_SLEEP}, - {"powerIdleDisplayOff", IDS_SETTINGS_POWER_IDLE_DISPLAY_OFF}, - {"powerIdleDisplayOn", IDS_SETTINGS_POWER_IDLE_DISPLAY_ON}, - {"powerIdleOther", IDS_SETTINGS_POWER_IDLE_OTHER}, - {"powerLidSleepLabel", IDS_SETTINGS_POWER_LID_CLOSED_SLEEP_LABEL}, - {"powerLidSignOutLabel", IDS_SETTINGS_POWER_LID_CLOSED_SIGN_OUT_LABEL}, - {"powerLidShutDownLabel", IDS_SETTINGS_POWER_LID_CLOSED_SHUT_DOWN_LABEL}, - }; - AddLocalizedStringsBulk(html_source, kPowerStrings); - - html_source->AddString("naturalScrollLearnMoreLink", - GetHelpUrlWithBoard(chrome::kNaturalScrollHelpURL)); -} - -void AddFilesStrings(content::WebUIDataSource* html_source) { - static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"filesPageTitle", IDS_OS_SETTINGS_FILES}, - {"smbSharesTitle", IDS_SETTINGS_DOWNLOADS_SMB_SHARES}, - {"smbSharesLearnMoreLabel", - IDS_SETTINGS_DOWNLOADS_SMB_SHARES_LEARN_MORE_LABEL}, - {"addSmbShare", IDS_SETTINGS_DOWNLOADS_SMB_SHARES_ADD_SHARE}, - {"smbShareAddedSuccessfulMessage", - IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_SUCCESS_MESSAGE}, - {"smbShareAddedErrorMessage", - IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_ERROR_MESSAGE}, - {"smbShareAddedAuthFailedMessage", - IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_AUTH_FAILED_MESSAGE}, - {"smbShareAddedNotFoundMessage", - IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_NOT_FOUND_MESSAGE}, - {"smbShareAddedUnsupportedDeviceMessage", - IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_UNSUPPORTED_DEVICE_MESSAGE}, - {"smbShareAddedMountExistsMessage", - IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_MOUNT_EXISTS_MESSAGE}, - {"smbShareAddedInvalidURLMessage", - IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_MOUNT_INVALID_URL_MESSAGE}, - {"smbShareAddedInvalidSSOURLMessage", - IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_MOUNT_INVALID_SSO_URL_MESSAGE}, - }; - AddLocalizedStringsBulk(html_source, kLocalizedStrings); - - chromeos::smb_dialog::AddLocalizedStrings(html_source); - - html_source->AddString("smbSharesLearnMoreURL", - GetHelpUrlWithBoard(chrome::kSmbSharesLearnMoreURL)); -} -#endif // defined(OS_CHROMEOS) - void AddDownloadsStrings(content::WebUIDataSource* html_source) { static constexpr webui::LocalizedString kLocalizedStrings[] = { {"downloadsPageTitle", IDS_SETTINGS_DOWNLOADS}, {"downloadLocation", IDS_SETTINGS_DOWNLOAD_LOCATION}, {"changeDownloadLocation", IDS_SETTINGS_CHANGE_DOWNLOAD_LOCATION}, {"promptForDownload", IDS_SETTINGS_PROMPT_FOR_DOWNLOAD}, - {"disconnectGoogleDriveAccount", IDS_SETTINGS_DISCONNECT_GOOGLE_DRIVE}, {"openFileTypesAutomatically", IDS_SETTINGS_OPEN_FILE_TYPES_AUTOMATICALLY}, }; @@ -1364,15 +538,7 @@ void AddResetStrings(content::WebUIDataSource* html_source) { {"triggeredResetPageTitle", IDS_TRIGGERED_RESET_PROFILE_SETTINGS_TITLE}, {"resetDialogCommit", IDS_SETTINGS_RESET}, {"resetPageFeedback", IDS_SETTINGS_RESET_PROFILE_FEEDBACK}, -#if defined(OS_CHROMEOS) - {"powerwashTitle", IDS_SETTINGS_FACTORY_RESET}, - {"powerwashDialogTitle", IDS_SETTINGS_FACTORY_RESET_HEADING}, - {"powerwashDialogExplanation", IDS_SETTINGS_FACTORY_RESET_WARNING}, - {"powerwashDialogButton", IDS_SETTINGS_RESTART}, - {"powerwashLearnMoreUrl", IDS_FACTORY_RESET_HELP_URL}, - {"powerwashButton", IDS_SETTINGS_FACTORY_RESET_BUTTON_LABEL}, - {"powerwashButtonRoleDescription", IDS_SETTINGS_FACTORY_RESET_BUTTON_ROLE}, -#endif + // Automatic reset banner (now a dialog). {"resetAutomatedDialogTitle", IDS_SETTINGS_RESET_AUTOMATED_DIALOG_TITLE}, {"resetProfileBannerButton", IDS_SETTINGS_RESET_BANNER_RESET_BUTTON_TEXT}, @@ -1388,12 +554,6 @@ void AddResetStrings(content::WebUIDataSource* html_source) { chrome::kResetProfileSettingsLearnMoreURL); html_source->AddString("resetProfileBannerLearnMoreUrl", chrome::kAutomaticSettingsResetLearnMoreURL); -#if defined(OS_CHROMEOS) - html_source->AddString( - "powerwashDescription", - l10n_util::GetStringFUTF16(IDS_SETTINGS_FACTORY_RESET_DESCRIPTION, - l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); -#endif } #if !defined(OS_CHROMEOS) @@ -1418,242 +578,20 @@ void AddImportDataStrings(content::WebUIDataSource* html_source) { } #endif -#if defined(OS_CHROMEOS) -void AddDateTimeStrings(content::WebUIDataSource* html_source) { - static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"dateTimePageTitle", IDS_SETTINGS_DATE_TIME}, - {"timeZone", IDS_SETTINGS_TIME_ZONE}, - {"selectTimeZoneResolveMethod", - IDS_SETTINGS_SELECT_TIME_ZONE_RESOLVE_METHOD}, - {"timeZoneGeolocation", IDS_SETTINGS_TIME_ZONE_GEOLOCATION}, - {"timeZoneButton", IDS_SETTINGS_TIME_ZONE_BUTTON}, - {"timeZoneSubpageTitle", IDS_SETTINGS_TIME_ZONE_SUBPAGE_TITLE}, - {"setTimeZoneAutomaticallyDisabled", - IDS_SETTINGS_TIME_ZONE_DETECTION_MODE_DISABLED}, - {"setTimeZoneAutomaticallyOn", - IDS_SETTINGS_TIME_ZONE_DETECTION_SET_AUTOMATICALLY}, - {"setTimeZoneAutomaticallyOff", - IDS_SETTINGS_TIME_ZONE_DETECTION_CHOOSE_FROM_LIST}, - {"setTimeZoneAutomaticallyIpOnlyDefault", - IDS_SETTINGS_TIME_ZONE_DETECTION_MODE_IP_ONLY_DEFAULT}, - {"setTimeZoneAutomaticallyWithWiFiAccessPointsData", - IDS_SETTINGS_TIME_ZONE_DETECTION_MODE_SEND_WIFI_AP}, - {"setTimeZoneAutomaticallyWithAllLocationInfo", - IDS_SETTINGS_TIME_ZONE_DETECTION_MODE_SEND_ALL_INFO}, - {"use24HourClock", IDS_SETTINGS_USE_24_HOUR_CLOCK}, - {"setDateTime", IDS_SETTINGS_SET_DATE_TIME}, - }; - AddLocalizedStringsBulk(html_source, kLocalizedStrings); - html_source->AddString( - "timeZoneSettingsLearnMoreURL", - base::ASCIIToUTF16(base::StringPrintf( - chrome::kTimeZoneSettingsLearnMoreURL, - g_browser_process->GetApplicationLocale().c_str()))); -} - -void AddEasyUnlockStrings(content::WebUIDataSource* html_source) { - static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"easyUnlockSectionTitle", IDS_SETTINGS_EASY_UNLOCK_SECTION_TITLE}, - {"easyUnlockUnlockDeviceOnly", - IDS_SETTINGS_EASY_UNLOCK_UNLOCK_DEVICE_ONLY}, - {"easyUnlockUnlockDeviceAndAllowSignin", - IDS_SETTINGS_EASY_UNLOCK_UNLOCK_DEVICE_AND_ALLOW_SIGNIN}, - }; - AddLocalizedStringsBulk(html_source, kLocalizedStrings); -} - -void AddFingerprintStrings(content::WebUIDataSource* html_source) { - int instruction_id, aria_label_id; - using FingerprintLocation = chromeos::quick_unlock::FingerprintLocation; - switch (chromeos::quick_unlock::GetFingerprintLocation()) { - case FingerprintLocation::TABLET_POWER_BUTTON: - instruction_id = - IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_LOCATE_SCANNER_POWER_BUTTON; - aria_label_id = - IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_LOCATE_SCANNER_POWER_BUTTON_ARIA_LABEL; - break; - case FingerprintLocation::KEYBOARD_TOP_RIGHT: - instruction_id = - IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_LOCATE_SCANNER_KEYBOARD; - aria_label_id = - IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_LOCATE_SCANNER_KEYBOARD_TOP_RIGHT_ARIA_LABEL; - break; - case FingerprintLocation::KEYBOARD_BOTTOM_RIGHT: - instruction_id = - IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_LOCATE_SCANNER_KEYBOARD; - aria_label_id = - IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_LOCATE_SCANNER_KEYBOARD_BOTTOM_RIGHT_ARIA_LABEL; - break; - } - html_source->AddLocalizedString( - "configureFingerprintInstructionLocateScannerStep", instruction_id); - html_source->AddLocalizedString("configureFingerprintScannerStepAriaLabel", - aria_label_id); -} - -void AddInternetStrings(content::WebUIDataSource* html_source) { - static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"internetAddConnection", IDS_SETTINGS_INTERNET_ADD_CONNECTION}, - {"internetAddConnectionExpandA11yLabel", - IDS_SETTINGS_INTERNET_ADD_CONNECTION_EXPAND_ACCESSIBILITY_LABEL}, - {"internetAddConnectionNotAllowed", - IDS_SETTINGS_INTERNET_ADD_CONNECTION_NOT_ALLOWED}, - {"internetAddThirdPartyVPN", IDS_SETTINGS_INTERNET_ADD_THIRD_PARTY_VPN}, - {"internetAddVPN", IDS_SETTINGS_INTERNET_ADD_VPN}, - {"internetAddWiFi", IDS_SETTINGS_INTERNET_ADD_WIFI}, - {"internetConfigName", IDS_SETTINGS_INTERNET_CONFIG_NAME}, - {"internetDetailPageTitle", IDS_SETTINGS_INTERNET_DETAIL}, - {"internetDeviceEnabling", IDS_SETTINGS_INTERNET_DEVICE_ENABLING}, - {"internetDeviceInitializing", IDS_SETTINGS_INTERNET_DEVICE_INITIALIZING}, - {"internetJoinType", IDS_SETTINGS_INTERNET_JOIN_TYPE}, - {"internetKnownNetworksPageTitle", IDS_SETTINGS_INTERNET_KNOWN_NETWORKS}, - {"internetMobileSearching", IDS_SETTINGS_INTERNET_MOBILE_SEARCH}, - {"internetNoNetworks", IDS_SETTINGS_INTERNET_NO_NETWORKS}, - {"internetPageTitle", IDS_SETTINGS_INTERNET}, - {"internetSummaryButtonA11yLabel", - IDS_SETTINGS_INTERNET_SUMMARY_BUTTON_ACCESSIBILITY_LABEL}, - {"internetToggleMobileA11yLabel", - IDS_SETTINGS_INTERNET_TOGGLE_MOBILE_ACCESSIBILITY_LABEL}, - {"internetToggleTetherLabel", IDS_SETTINGS_INTERNET_TOGGLE_TETHER_LABEL}, - {"internetToggleTetherSubtext", - IDS_SETTINGS_INTERNET_TOGGLE_TETHER_SUBTEXT}, - {"internetToggleWiFiA11yLabel", - IDS_SETTINGS_INTERNET_TOGGLE_WIFI_ACCESSIBILITY_LABEL}, - {"knownNetworksAll", IDS_SETTINGS_INTERNET_KNOWN_NETWORKS_ALL}, - {"knownNetworksButton", IDS_SETTINGS_INTERNET_KNOWN_NETWORKS_BUTTON}, - {"knownNetworksMessage", IDS_SETTINGS_INTERNET_KNOWN_NETWORKS_MESSAGE}, - {"knownNetworksPreferred", - IDS_SETTINGS_INTERNET_KNOWN_NETWORKS_PREFFERED}, - {"knownNetworksMenuAddPreferred", - IDS_SETTINGS_INTERNET_KNOWN_NETWORKS_MENU_ADD_PREFERRED}, - {"knownNetworksMenuRemovePreferred", - IDS_SETTINGS_INTERNET_KNOWN_NETWORKS_MENU_REMOVE_PREFERRED}, - {"knownNetworksMenuForget", - IDS_SETTINGS_INTERNET_KNOWN_NETWORKS_MENU_FORGET}, - {"networkAllowDataRoaming", - IDS_SETTINGS_SETTINGS_NETWORK_ALLOW_DATA_ROAMING}, - {"networkAllowDataRoamingEnabledHome", - IDS_SETTINGS_SETTINGS_NETWORK_ALLOW_DATA_ROAMING_ENABLED_HOME}, - {"networkAllowDataRoamingEnabledRoaming", - IDS_SETTINGS_SETTINGS_NETWORK_ALLOW_DATA_ROAMING_ENABLED_ROAMING}, - {"networkAllowDataRoamingDisabled", - IDS_SETTINGS_SETTINGS_NETWORK_ALLOW_DATA_ROAMING_DISABLED}, - {"networkAlwaysOnVpn", IDS_SETTINGS_INTERNET_NETWORK_ALWAYS_ON_VPN}, - {"networkAutoConnect", IDS_SETTINGS_INTERNET_NETWORK_AUTO_CONNECT}, - {"networkAutoConnectCellular", - IDS_SETTINGS_INTERNET_NETWORK_AUTO_CONNECT_CELLULAR}, - {"networkButtonActivate", IDS_SETTINGS_INTERNET_BUTTON_ACTIVATE}, - {"networkButtonConfigure", IDS_SETTINGS_INTERNET_BUTTON_CONFIGURE}, - {"networkButtonConnect", IDS_SETTINGS_INTERNET_BUTTON_CONNECT}, - {"networkButtonDisconnect", IDS_SETTINGS_INTERNET_BUTTON_DISCONNECT}, - {"networkButtonForget", IDS_SETTINGS_INTERNET_BUTTON_FORGET}, - {"networkButtonViewAccount", IDS_SETTINGS_INTERNET_BUTTON_VIEW_ACCOUNT}, - {"networkConnectNotAllowed", IDS_SETTINGS_INTERNET_CONNECT_NOT_ALLOWED}, - {"networkIPAddress", IDS_SETTINGS_INTERNET_NETWORK_IP_ADDRESS}, - {"networkIPConfigAuto", IDS_SETTINGS_INTERNET_NETWORK_IP_CONFIG_AUTO}, - {"networkNameserversLearnMore", IDS_LEARN_MORE}, - {"networkPrefer", IDS_SETTINGS_INTERNET_NETWORK_PREFER}, - {"networkPrimaryUserControlled", - IDS_SETTINGS_INTERNET_NETWORK_PRIMARY_USER_CONTROLLED}, - {"networkScanningLabel", IDS_NETWORK_SCANNING_MESSAGE}, - {"networkSectionAdvanced", - IDS_SETTINGS_INTERNET_NETWORK_SECTION_ADVANCED}, - {"networkSectionAdvancedA11yLabel", - IDS_SETTINGS_INTERNET_NETWORK_SECTION_ADVANCED_ACCESSIBILITY_LABEL}, - {"networkSectionNetwork", IDS_SETTINGS_INTERNET_NETWORK_SECTION_NETWORK}, - {"networkSectionNetworkExpandA11yLabel", - IDS_SETTINGS_INTERNET_NETWORK_SECTION_NETWORK_ACCESSIBILITY_LABEL}, - {"networkSectionProxy", IDS_SETTINGS_INTERNET_NETWORK_SECTION_PROXY}, - {"networkSectionProxyExpandA11yLabel", - IDS_SETTINGS_INTERNET_NETWORK_SECTION_PROXY_ACCESSIBILITY_LABEL}, - {"networkShared", IDS_SETTINGS_INTERNET_NETWORK_SHARED}, - {"networkVpnBuiltin", IDS_NETWORK_TYPE_VPN_BUILTIN}, - {"networkOutOfRange", IDS_SETTINGS_INTERNET_WIFI_NETWORK_OUT_OF_RANGE}, - {"cellularContactSpecificCarrier", - IDS_SETTINGS_INTERNET_CELLULAR_CONTACT_SPECIFIC_CARRIER}, - {"cellularContactDefaultCarrier", - IDS_SETTINGS_INTERNET_CELLULAR_CONTACT_DEFAULT_CARRIER}, - {"tetherPhoneOutOfRange", - IDS_SETTINGS_INTERNET_TETHER_PHONE_OUT_OF_RANGE}, - {"gmscoreNotificationsTitle", - IDS_SETTINGS_INTERNET_GMSCORE_NOTIFICATIONS_TITLE}, - {"gmscoreNotificationsOneDeviceSubtitle", - IDS_SETTINGS_INTERNET_GMSCORE_NOTIFICATIONS_ONE_DEVICE_SUBTITLE}, - {"gmscoreNotificationsTwoDevicesSubtitle", - IDS_SETTINGS_INTERNET_GMSCORE_NOTIFICATIONS_TWO_DEVICES_SUBTITLE}, - {"gmscoreNotificationsManyDevicesSubtitle", - IDS_SETTINGS_INTERNET_GMSCORE_NOTIFICATIONS_MANY_DEVICES_SUBTITLE}, - {"gmscoreNotificationsFirstStep", - IDS_SETTINGS_INTERNET_GMSCORE_NOTIFICATIONS_FIRST_STEP}, - {"gmscoreNotificationsSecondStep", - IDS_SETTINGS_INTERNET_GMSCORE_NOTIFICATIONS_SECOND_STEP}, - {"gmscoreNotificationsThirdStep", - IDS_SETTINGS_INTERNET_GMSCORE_NOTIFICATIONS_THIRD_STEP}, - {"gmscoreNotificationsFourthStep", - IDS_SETTINGS_INTERNET_GMSCORE_NOTIFICATIONS_FOURTH_STEP}, - {"tetherConnectionDialogTitle", - IDS_SETTINGS_INTERNET_TETHER_CONNECTION_DIALOG_TITLE}, - {"tetherConnectionAvailableDeviceTitle", - IDS_SETTINGS_INTERNET_TETHER_CONNECTION_AVAILABLE_DEVICE_TITLE}, - {"tetherConnectionBatteryPercentage", - IDS_SETTINGS_INTERNET_TETHER_CONNECTION_BATTERY_PERCENTAGE}, - {"tetherConnectionExplanation", - IDS_SETTINGS_INTERNET_TETHER_CONNECTION_EXPLANATION}, - {"tetherConnectionCarrierWarning", - IDS_SETTINGS_INTERNET_TETHER_CONNECTION_CARRIER_WARNING}, - {"tetherConnectionDescriptionTitle", - IDS_SETTINGS_INTERNET_TETHER_CONNECTION_DESCRIPTION_TITLE}, - {"tetherConnectionDescriptionMobileData", - IDS_SETTINGS_INTERNET_TETHER_CONNECTION_DESCRIPTION_MOBILE_DATA}, - {"tetherConnectionDescriptionBattery", - IDS_SETTINGS_INTERNET_TETHER_CONNECTION_DESCRIPTION_BATTERY}, - {"tetherConnectionDescriptionWiFi", - IDS_SETTINGS_INTERNET_TETHER_CONNECTION_DESCRIPTION_WIFI}, - {"tetherConnectionNotNowButton", - IDS_SETTINGS_INTERNET_TETHER_CONNECTION_NOT_NOW_BUTTON}, - {"tetherConnectionConnectButton", - IDS_SETTINGS_INTERNET_TETHER_CONNECTION_CONNECT_BUTTON}, - {"tetherEnableBluetooth", IDS_ENABLE_BLUETOOTH}, - }; - AddLocalizedStringsBulk(html_source, kLocalizedStrings); - - html_source->AddString("networkGoogleNameserversLearnMoreUrl", - chrome::kGoogleNameserversLearnMoreURL); - html_source->AddString( - "internetNoNetworksMobileData", - l10n_util::GetStringFUTF16( - IDS_SETTINGS_INTERNET_LOOKING_FOR_MOBILE_NETWORK, - GetHelpUrlWithBoard(chrome::kInstantTetheringLearnMoreURL))); -} -#endif - -void AddLanguagesStrings(content::WebUIDataSource* html_source) { +void AddLanguagesStrings(content::WebUIDataSource* html_source, + Profile* profile) { static constexpr webui::LocalizedString kLocalizedStrings[] = { {"languagesListTitle", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_TITLE}, {"searchLanguages", IDS_SETTINGS_LANGUAGE_SEARCH}, {"languagesExpandA11yLabel", IDS_SETTINGS_LANGUAGES_EXPAND_ACCESSIBILITY_LABEL}, - {"orderLanguagesInstructions", - IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_ORDERING_INSTRUCTIONS}, + {"orderBrowserLanguagesInstructions", + IDS_SETTINGS_LANGUAGES_BROWSER_LANGUAGES_LIST_ORDERING_INSTRUCTIONS}, {"moveToTop", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_TO_TOP}, {"moveUp", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_UP}, {"moveDown", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_DOWN}, {"removeLanguage", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_REMOVE}, {"addLanguages", IDS_SETTINGS_LANGUAGES_LANGUAGES_ADD}, -#if defined(OS_CHROMEOS) - {"osLanguagesPageTitle", IDS_OS_SETTINGS_LANGUAGES_AND_INPUT_PAGE_TITLE}, - {"osLanguagesListTitle", IDS_OS_SETTINGS_LANGUAGES_LIST_TITLE}, - {"inputMethodsListTitle", IDS_SETTINGS_LANGUAGES_INPUT_METHODS_LIST_TITLE}, - {"inputMethodEnabled", IDS_SETTINGS_LANGUAGES_INPUT_METHOD_ENABLED}, - {"inputMethodsExpandA11yLabel", - IDS_SETTINGS_LANGUAGES_INPUT_METHODS_EXPAND_ACCESSIBILITY_LABEL}, - {"inputMethodsManagedbyPolicy", - IDS_SETTINGS_LANGUAGES_INPUT_METHODS_MANAGED_BY_POLICY}, - {"manageInputMethods", IDS_SETTINGS_LANGUAGES_INPUT_METHODS_MANAGE}, - {"manageInputMethodsPageTitle", - IDS_SETTINGS_LANGUAGES_MANAGE_INPUT_METHODS_TITLE}, - {"showImeMenu", IDS_SETTINGS_LANGUAGES_SHOW_IME_MENU}, -#endif {"addLanguagesDialogTitle", IDS_SETTINGS_LANGUAGES_MANAGE_LANGUAGES_TITLE}, {"allLanguages", IDS_SETTINGS_LANGUAGES_ALL_LANGUAGES}, {"enabledLanguages", IDS_SETTINGS_LANGUAGES_ENABLED_LANGUAGES}, @@ -1704,18 +642,23 @@ void AddLanguagesStrings(content::WebUIDataSource* html_source) { html_source->AddString( "languagesLearnMoreURL", base::ASCIIToUTF16(chrome::kLanguageSettingsLearnMoreUrl)); - // TODO(hsuregan): Remove once OS Browser split settings is complete. html_source->AddString( "languagesPageTitle", - l10n_util::GetStringUTF16( - base::FeatureList::IsEnabled(chromeos::features::kSplitSettings) - ? IDS_SETTINGS_LANGUAGES_PAGE_TITLE - : IDS_OS_SETTINGS_LANGUAGES_AND_INPUT_PAGE_TITLE)); + l10n_util::GetStringUTF16(IDS_SETTINGS_LANGUAGES_PAGE_TITLE)); #else html_source->AddString( "languagesPageTitle", l10n_util::GetStringUTF16(IDS_SETTINGS_LANGUAGES_PAGE_TITLE)); #endif +#if defined(OS_CHROMEOS) + user_manager::UserManager* user_manager = user_manager::UserManager::Get(); + const user_manager::User* user = + chromeos::ProfileHelper::Get()->GetUserByProfile(profile); + const user_manager::User* primary_user = user_manager->GetPrimaryUser(); + html_source->AddBoolean( + "isSecondaryUser", + user && user->GetAccountId() != primary_user->GetAccountId()); +#endif // defined(OS_CHROMEOS) } #if defined(OS_CHROMEOS) @@ -1723,34 +666,13 @@ void AddChromeOSUserStrings(content::WebUIDataSource* html_source, Profile* profile) { user_manager::UserManager* user_manager = user_manager::UserManager::Get(); - const user_manager::User* user = - chromeos::ProfileHelper::Get()->GetUserByProfile(profile); const user_manager::User* primary_user = user_manager->GetPrimaryUser(); std::string primary_user_email = primary_user->GetAccountId().GetUserEmail(); - html_source->AddString("primaryUserEmail", primary_user_email); - html_source->AddBoolean( - "isSecondaryUser", - user && user->GetAccountId() != primary_user->GetAccountId()); - html_source->AddString( - "secondaryUserBannerText", - l10n_util::GetStringFUTF16(IDS_SETTINGS_SECONDARY_USER_BANNER, - base::ASCIIToUTF16(primary_user_email))); - html_source->AddString("browserSettingsBannerText", - l10n_util::GetStringFUTF16( - IDS_SETTINGS_BROWSER_SETTINGS_BANNER, - base::ASCIIToUTF16(chrome::kChromeUISettingsURL))); html_source->AddString( "osSettingsBannerText", l10n_util::GetStringFUTF16( IDS_SETTINGS_OS_SETTINGS_BANNER, base::ASCIIToUTF16(chrome::kChromeUIOSSettingsURL))); - html_source->AddBoolean("isActiveDirectoryUser", - user && user->IsActiveDirectoryUser()); - - if (!IsDeviceManaged() && !user_manager->IsCurrentUserOwner()) { - html_source->AddString("ownerEmail", - user_manager->GetOwnerAccountId().GetUserEmail()); - } } #endif @@ -1809,8 +731,42 @@ void AddAutofillStrings(content::WebUIDataSource* html_source, static constexpr webui::LocalizedString kLocalizedStrings[] = { {"autofillPageTitle", IDS_SETTINGS_AUTOFILL}, {"passwords", IDS_SETTINGS_PASSWORDS}, + {"checkPasswords", IDS_SETTINGS_CHECK_PASSWORDS}, + {"checkPasswordsCanceled", IDS_SETTINGS_CHECK_PASSWORDS_CANCELED}, + {"checkedPasswords", IDS_SETTINGS_CHECKED_PASSWORDS}, + {"checkPasswordsDescription", IDS_SETTINGS_CHECK_PASSWORDS_DESCRIPTION}, + {"checkPasswordsAgain", IDS_SETTINGS_CHECK_PASSWORDS_AGAIN}, + {"checkPasswordsAgainAfterError", + IDS_SETTINGS_CHECK_PASSWORDS_AGAIN_AFTER_ERROR}, + {"checkPasswordsProgress", IDS_SETTINGS_CHECK_PASSWORDS_PROGRESS}, + {"checkPasswordsStop", IDS_SETTINGS_CHECK_PASSWORDS_STOP}, + {"compromisedPasswords", IDS_SETTINGS_COMPROMISED_PASSWORDS}, + {"compromisedPasswordsDescription", + IDS_SETTINGS_COMPROMISED_PASSWORDS_ADVICE}, + {"changePasswordButton", IDS_SETTINGS_CHANGE_PASSWORD_BUTTON}, + {"changePasswordInApp", IDS_SETTINGS_CHANGE_PASSWORD_IN_APP_LABEL}, + {"leakedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_REASON_LEAKED}, + {"phishedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_REASON_PHISHED}, + {"phishedAndLeakedPassword", + IDS_SETTINGS_COMPROMISED_PASSWORD_REASON_PHISHED_AND_LEAKED}, + {"showCompromisedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_SHOW}, + {"hideCompromisedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_HIDE}, + {"editCompromisedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_EDIT}, + {"removeCompromisedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_REMOVE}, + {"removeCompromisedPasswordConfirmationTitle", + IDS_SETTINGS_REMOVE_COMPROMISED_PASSWORD_CONFIRMATION_TITLE}, + {"removeCompromisedPasswordConfirmationDescription", + IDS_SETTINGS_REMOVE_COMPROMISED_PASSWORD_CONFIRMATION_DESCRIPTION}, + {"editCompromisedPasswordTitle", + IDS_SETTINGS_COMPROMISED_EDIT_PASSWORD_TITLE}, + {"editCompromisedPasswordFootnote", + IDS_SETTINGS_COMPROMISED_EDIT_PASSWORD_FOOTNOTE}, + {"editCompromisedPasswordSite", + IDS_SETTINGS_COMPROMISED_EDIT_PASSWORD_SITE}, + {"editCompromisedPasswordApp", + IDS_SETTINGS_COMPROMISED_EDIT_PASSWORD_APP}, {"creditCards", IDS_AUTOFILL_PAYMENT_METHODS}, - {"noCreditCardsFound", IDS_SETTINGS_PAYMENT_METHODS_NONE}, + {"noPaymentMethodsFound", IDS_SETTINGS_PAYMENT_METHODS_NONE}, {"googlePayments", IDS_SETTINGS_GOOGLE_PAYMENTS}, {"googlePaymentsCached", IDS_SETTINGS_GOOGLE_PAYMENTS_CACHED}, {"enableProfilesLabel", IDS_AUTOFILL_ENABLE_PROFILES_TOGGLE_LABEL}, @@ -1844,6 +800,8 @@ void AddAutofillStrings(content::WebUIDataSource* html_source, {"migratableCardsInfoSingle", IDS_SETTINGS_SINGLE_MIGRATABLE_CARD_INFO}, {"migratableCardsInfoMultiple", IDS_SETTINGS_MULTIPLE_MIGRATABLE_CARDS_INFO}, + {"upiIdLabel", IDS_SETTINGS_UPI_ID_LABEL}, + {"upiIdExpirationNever", IDS_SETTINGS_UPI_ID_EXPIRATION_NEVER}, {"canMakePaymentToggleLabel", IDS_SETTINGS_CAN_MAKE_PAYMENT_TOGGLE_LABEL}, {"autofillDetail", IDS_SETTINGS_AUTOFILL_DETAIL}, {"passwordsSavePasswordsLabel", @@ -1854,6 +812,8 @@ void AddAutofillStrings(content::WebUIDataSource* html_source, IDS_SETTINGS_PASSWORDS_AUTOSIGNIN_CHECKBOX_DESC}, {"passwordsLeakDetectionLabel", IDS_SETTINGS_PASSWORDS_LEAK_DETECTION_LABEL}, + {"passwordsLeakDetectionGeneralDescription", + IDS_PASSWORD_MANAGER_LEAK_HELP_MESSAGE}, {"passwordsLeakDetectionSignedOutEnabledDescription", IDS_SETTINGS_PASSWORDS_LEAK_DETECTION_SIGNED_OUT_ENABLED_DESC}, {"savedPasswordsHeading", IDS_SETTINGS_PASSWORDS_SAVED_HEADING}, @@ -1865,6 +825,7 @@ void AddAutofillStrings(content::WebUIDataSource* html_source, {"hidePassword", IDS_SETTINGS_PASSWORD_HIDE}, {"passwordDetailsTitle", IDS_SETTINGS_PASSWORDS_VIEW_DETAILS_TITLE}, {"passwordViewDetails", IDS_SETTINGS_PASSWORD_DETAILS}, + {"copyPassword", IDS_SETTINGS_PASSWORD_COPY}, {"editPasswordWebsiteLabel", IDS_SETTINGS_PASSWORDS_WEBSITE}, {"editPasswordUsernameLabel", IDS_SETTINGS_PASSWORDS_USERNAME}, {"editPasswordPasswordLabel", IDS_SETTINGS_PASSWORDS_PASSWORD}, @@ -1873,6 +834,10 @@ void AddAutofillStrings(content::WebUIDataSource* html_source, {"noExceptionsFound", IDS_SETTINGS_PASSWORDS_EXCEPTIONS_NONE}, {"import", IDS_PASSWORD_MANAGER_IMPORT_BUTTON}, {"exportMenuItem", IDS_SETTINGS_PASSWORDS_EXPORT_MENU_ITEM}, + {"optInAccountStorageLabel", + IDS_SETTINGS_PASSWORDS_OPT_IN_ACCOUNT_STORAGE_LABEL}, + {"optOutAccountStorageLabel", + IDS_SETTINGS_PASSWORDS_OPT_OUT_ACCOUNT_STORAGE_LABEL}, {"undoRemovePassword", IDS_SETTINGS_PASSWORD_UNDO}, {"passwordDeleted", IDS_SETTINGS_PASSWORD_DELETED_PASSWORD}, {"passwordRowMoreActionsButton", IDS_SETTINGS_PASSWORD_ROW_MORE_ACTIONS}, @@ -1894,6 +859,33 @@ void AddAutofillStrings(content::WebUIDataSource* html_source, {"savedToThisDeviceOnly", IDS_SETTINGS_PAYMENTS_SAVED_TO_THIS_DEVICE_ONLY}}; + const base::string16 short_product_name = + l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME); + html_source->AddString( + "checkPasswordsErrorOffline", + l10n_util::GetStringFUTF16(IDS_SETTINGS_CHECK_PASSWORDS_ERROR_OFFLINE, + short_product_name)); + html_source->AddString( + "checkPasswordsErrorSignedOut", + l10n_util::GetStringFUTF16(IDS_SETTINGS_CHECK_PASSWORDS_ERROR_SIGNED_OUT, + short_product_name)); + html_source->AddString( + "checkPasswordsErrorNoPasswords", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_CHECK_PASSWORDS_ERROR_NO_PASSWORDS, short_product_name)); + html_source->AddString( + "checkPasswordsErrorQuota", + l10n_util::GetStringFUTF16(IDS_SETTINGS_CHECK_PASSWORDS_ERROR_QUOTA_LIMIT, + short_product_name)); + html_source->AddString( + "checkPasswordsErrorGeneric", + l10n_util::GetStringFUTF16(IDS_SETTINGS_CHECK_PASSWORDS_ERROR_GENERIC, + short_product_name)); + html_source->AddString( + "noCompromisedCredentials", + l10n_util::GetStringFUTF16(IDS_SETTINGS_NO_COMPROMISED_CREDENTIALS_LABEL, + short_product_name)); + GURL google_password_manager_url = GetGooglePasswordManagerURL( password_manager::ManagePasswordsReferrer::kChromeSettings); @@ -1902,8 +894,19 @@ void AddAutofillStrings(content::WebUIDataSource* html_source, l10n_util::GetStringFUTF16( IDS_SETTINGS_PASSWORDS_MANAGE_PASSWORDS, base::UTF8ToUTF16(google_password_manager_url.spec()))); + html_source->AddString( + "checkPasswordsErrorQuotaGoogleAccount", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_CHECK_PASSWORDS_ERROR_QUOTA_LIMIT_GOOGLE_ACCOUNT, + short_product_name, + base::UTF8ToUTF16( + password_manager::GetPasswordCheckupURL( + password_manager::PasswordCheckupReferrer::kPasswordCheck) + .spec()))); html_source->AddString("googlePasswordManagerUrl", google_password_manager_url.spec()); + html_source->AddString("passwordCheckLearnMoreURL", + chrome::kPasswordCheckLearnMoreURL); html_source->AddString("passwordManagerLearnMoreURL", chrome::kPasswordManagerLearnMoreURL); html_source->AddString("manageAddressesUrl", @@ -1937,397 +940,119 @@ void AddAutofillStrings(content::WebUIDataSource* html_source, "fidoAuthenticationAvailableForAutofill", IsFidoAuthenticationAvailable(personal_data, web_contents)); - html_source->AddBoolean( - "passwordsLeakDetectionEnabled", - base::FeatureList::IsEnabled(password_manager::features::kLeakDetection)); - ui::Accelerator undo_accelerator(ui::VKEY_Z, ui::EF_PLATFORM_ACCELERATOR); html_source->AddString( "undoDescription", l10n_util::GetStringFUTF16(IDS_UNDO_DESCRIPTION, undo_accelerator.GetShortcutText())); + html_source->AddBoolean("showUpiIdSettings", + base::FeatureList::IsEnabled( + autofill::features::kAutofillSaveAndFillVPA)); + AddLocalizedStringsBulk(html_source, kLocalizedStrings); } -void AddPeopleStrings(content::WebUIDataSource* html_source, Profile* profile) { - static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"peoplePageTitle", IDS_SETTINGS_PEOPLE}, - {"manageOtherPeople", IDS_SETTINGS_PEOPLE_MANAGE_OTHER_PEOPLE}, +void AddSignOutDialogStrings(content::WebUIDataSource* html_source, + Profile* profile) { #if defined(OS_CHROMEOS) - {"accountManagerDescription", IDS_SETTINGS_ACCOUNT_MANAGER_DESCRIPTION}, - {"accountManagerPageTitle", IDS_SETTINGS_ACCOUNT_MANAGER_PAGE_TITLE}, - {"accountManagerSubMenuLabel", IDS_SETTINGS_ACCOUNT_MANAGER_SUBMENU_LABEL}, - {"accountListHeader", IDS_SETTINGS_ACCOUNT_MANAGER_LIST_HEADER}, - {"addAccountLabel", IDS_SETTINGS_ACCOUNT_MANAGER_ADD_ACCOUNT_LABEL}, - {"removeAccountLabel", IDS_SETTINGS_ACCOUNT_MANAGER_REMOVE_ACCOUNT_LABEL}, - {"accountManagerPrimaryAccountTooltip", - IDS_SETTINGS_ACCOUNT_MANAGER_PRIMARY_ACCOUNT_TOOLTIP}, - {"accountManagerSecondaryAccountsDisabledText", - IDS_SETTINGS_ACCOUNT_MANAGER_SECONDARY_ACCOUNTS_DISABLED_TEXT}, - {"accountManagerSecondaryAccountsDisabledChildText", - IDS_SETTINGS_ACCOUNT_MANAGER_SECONDARY_ACCOUNTS_DISABLED_CHILD_TEXT}, - {"accountManagerSignedOutAccountName", - IDS_SETTINGS_ACCOUNT_MANAGER_SIGNED_OUT_ACCOUNT_PLACEHOLDER}, - {"accountManagerUnmigratedAccountName", - IDS_SETTINGS_ACCOUNT_MANAGER_UNMIGRATED_ACCOUNT_PLACEHOLDER}, - {"accountManagerMigrationLabel", - IDS_SETTINGS_ACCOUNT_MANAGER_MIGRATION_LABEL}, - {"accountManagerReauthenticationLabel", - IDS_SETTINGS_ACCOUNT_MANAGER_REAUTHENTICATION_LABEL}, - {"accountManagerMigrationTooltip", - IDS_SETTINGS_ACCOUNT_MANAGER_MIGRATION_TOOLTIP}, - {"accountManagerReauthenticationTooltip", - IDS_SETTINGS_ACCOUNT_MANAGER_REAUTHENTICATION_TOOLTIP}, - {"accountManagerMoreActionsTooltip", - IDS_SETTINGS_ACCOUNT_MANAGER_MORE_ACTIONS_TOOLTIP}, - {"accountManagerManagedLabel", - IDS_SETTINGS_ACCOUNT_MANAGER_MANAGEMENT_STATUS_MANAGED_ACCOUNT}, - {"accountManagerUnmanagedLabel", - IDS_SETTINGS_ACCOUNT_MANAGER_MANAGEMENT_STATUS_UNMANAGED_ACCOUNT}, - {"configureFingerprintTitle", IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_TITLE}, - {"configureFingerprintInstructionReadyStep", - IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_READY}, - {"configureFingerprintLiftFinger", - IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_LIFT_FINGER}, - {"configureFingerprintTryAgain", - IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_TRY_AGAIN}, - {"configureFingerprintImmobile", - IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_FINGER_IMMOBILE}, - {"configureFingerprintAddAnotherButton", - IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_ADD_ANOTHER_BUTTON}, - {"configurePinChoosePinTitle", - IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_CHOOSE_PIN_TITLE}, - {"configurePinConfirmPinTitle", - IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_CONFIRM_PIN_TITLE}, - {"configurePinMismatched", IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_MISMATCHED}, - {"configurePinTooShort", IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_TOO_SHORT}, - {"configurePinTooLong", IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_TOO_LONG}, - {"configurePinWeakPin", IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_WEAK_PIN}, - {"enableScreenlock", IDS_SETTINGS_PEOPLE_ENABLE_SCREENLOCK}, - {"kerberosAccountsSubMenuLabel", - IDS_SETTINGS_KERBEROS_ACCOUNTS_SUBMENU_LABEL}, - {"kerberosAccountsPageTitle", IDS_SETTINGS_KERBEROS_ACCOUNTS_PAGE_TITLE}, - {"kerberosAccountsListHeader", IDS_SETTINGS_KERBEROS_ACCOUNTS_LIST_HEADER}, - {"kerberosAccountsAddAccountLabel", - IDS_SETTINGS_KERBEROS_ACCOUNTS_ADD_ACCOUNT_LABEL}, - {"kerberosAccountsRefreshNowLabel", - IDS_SETTINGS_KERBEROS_ACCOUNTS_REFRESH_NOW_LABEL}, - {"kerberosAccountsSetAsActiveAccountLabel", - IDS_SETTINGS_KERBEROS_ACCOUNTS_SET_AS_ACTIVE_ACCOUNT_LABEL}, - {"kerberosAccountsRemoveAccountLabel", - IDS_SETTINGS_KERBEROS_ACCOUNTS_REMOVE_ACCOUNT_LABEL}, - {"kerberosAccountsAccountRemovedTip", - IDS_SETTINGS_KERBEROS_ACCOUNTS_ACCOUNT_REMOVED_TIP}, - {"kerberosAccountsAccountRefreshedTip", - IDS_SETTINGS_KERBEROS_ACCOUNTS_ACCOUNT_REFRESHED_TIP}, - {"kerberosAccountsSignedIn", IDS_SETTINGS_KERBEROS_ACCOUNTS_SIGNED_IN}, - {"kerberosAccountsSignedOut", IDS_SETTINGS_KERBEROS_ACCOUNTS_SIGNED_OUT}, - {"kerberosAccountsReauthenticationLabel", - IDS_SETTINGS_KERBEROS_ACCOUNTS_REAUTHENTICATION_LABEL}, - {"kerberosAccountsTicketActive", - IDS_SETTINGS_KERBEROS_ACCOUNTS_TICKET_ACTIVE}, - {"addKerberosAccount", IDS_SETTINGS_ADD_KERBEROS_ACCOUNT}, - {"refreshKerberosAccount", IDS_SETTINGS_REFRESH_KERBEROS_ACCOUNT}, - {"addKerberosAccountDescription", - IDS_SETTINGS_ADD_KERBEROS_ACCOUNT_DESCRIPTION}, - {"addKerberosAccountRememberPassword", - IDS_SETTINGS_ADD_KERBEROS_ACCOUNT_REMEMBER_PASSWORD}, - {"addKerberosAccountRefreshButtonLabel", - IDS_SETTINGS_ADD_KERBEROS_ACCOUNT_REFRESH_BUTTON_LABEL}, - {"kerberosUsername", IDS_SETTINGS_KERBEROS_USERNAME}, - {"kerberosPassword", IDS_SETTINGS_KERBEROS_PASSWORD}, - {"kerberosAccountsAdvancedConfigLabel", - IDS_SETTINGS_KERBEROS_ACCOUNTS_ADVANCED_CONFIG_LABEL}, - {"kerberosAdvancedConfigTitle", - IDS_SETTINGS_KERBEROS_ADVANCED_CONFIG_TITLE}, - {"kerberosAdvancedConfigDesc", IDS_SETTINGS_KERBEROS_ADVANCED_CONFIG_DESC}, - {"kerberosErrorNetworkProblem", - IDS_SETTINGS_KERBEROS_ERROR_NETWORK_PROBLEM}, - {"kerberosErrorUsernameInvalid", - IDS_SETTINGS_KERBEROS_ERROR_USERNAME_INVALID}, - {"kerberosErrorUsernameUnknown", - IDS_SETTINGS_KERBEROS_ERROR_USERNAME_UNKNOWN}, - {"kerberosErrorDuplicatePrincipalName", - IDS_SETTINGS_KERBEROS_ERROR_DUPLICATE_PRINCIPAL_NAME}, - {"kerberosErrorContactingServer", - IDS_SETTINGS_KERBEROS_ERROR_CONTACTING_SERVER}, - {"kerberosErrorPasswordInvalid", - IDS_SETTINGS_KERBEROS_ERROR_PASSWORD_INVALID}, - {"kerberosErrorPasswordExpired", - IDS_SETTINGS_KERBEROS_ERROR_PASSWORD_EXPIRED}, - {"kerberosErrorKdcEncType", IDS_SETTINGS_KERBEROS_ERROR_KDC_ENC_TYPE}, - {"kerberosErrorGeneral", IDS_SETTINGS_KERBEROS_ERROR_GENERAL}, - {"kerberosConfigErrorSectionNestedInGroup", - IDS_SETTINGS_KERBEROS_CONFIG_ERROR_SECTION_NESTED_IN_GROUP}, - {"kerberosConfigErrorSectionSyntax", - IDS_SETTINGS_KERBEROS_CONFIG_ERROR_SECTION_SYNTAX}, - {"kerberosConfigErrorExpectedOpeningCurlyBrace", - IDS_SETTINGS_KERBEROS_CONFIG_ERROR_EXPECTED_OPENING_CURLY_BRACE}, - {"kerberosConfigErrorExtraCurlyBrace", - IDS_SETTINGS_KERBEROS_CONFIG_ERROR_EXTRA_CURLY_BRACE}, - {"kerberosConfigErrorRelationSyntax", - IDS_SETTINGS_KERBEROS_CONFIG_ERROR_RELATION_SYNTAX_ERROR}, - {"kerberosConfigErrorKeyNotSupported", - IDS_SETTINGS_KERBEROS_CONFIG_ERROR_KEY_NOT_SUPPORTED}, - {"kerberosConfigErrorSectionNotSupported", - IDS_SETTINGS_KERBEROS_CONFIG_ERROR_SECTION_NOT_SUPPORTED}, - {"kerberosConfigErrorKrb5FailedToParse", - IDS_SETTINGS_KERBEROS_CONFIG_ERROR_KRB5_FAILED_TO_PARSE}, - {"lockScreenAddFingerprint", - IDS_SETTINGS_PEOPLE_LOCK_SCREEN_ADD_FINGERPRINT_BUTTON}, - {"lockScreenChangePinButton", - IDS_SETTINGS_PEOPLE_LOCK_SCREEN_CHANGE_PIN_BUTTON}, - {"lockScreenEditFingerprints", - IDS_SETTINGS_PEOPLE_LOCK_SCREEN_EDIT_FINGERPRINTS}, - {"lockScreenEditFingerprintsDescription", - IDS_SETTINGS_PEOPLE_LOCK_SCREEN_EDIT_FINGERPRINTS_DESCRIPTION}, - {"lockScreenSetupFingerprintButton", - IDS_SETTINGS_PEOPLE_LOCK_SCREEN_FINGERPRINT_SETUP_BUTTON}, - {"lockScreenNumberFingerprints", - IDS_SETTINGS_PEOPLE_LOCK_SCREEN_NUM_FINGERPRINTS}, - {"lockScreenNone", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_NONE}, - {"lockScreenFingerprintNewName", - IDS_SETTINGS_PEOPLE_LOCK_SCREEN_NEW_FINGERPRINT_DEFAULT_NAME}, - {"lockScreenFingerprintTitle", - IDS_SETTINGS_PEOPLE_LOCK_SCREEN_FINGERPRINT_SUBPAGE_TITLE}, - {"lockScreenFingerprintWarning", - IDS_SETTINGS_PEOPLE_LOCK_SCREEN_FINGERPRINT_LESS_SECURE}, - {"lockScreenDeleteFingerprintLabel", - IDS_SETTINGS_PEOPLE_LOCK_SCREEN_DELETE_FINGERPRINT_ARIA_LABEL}, - {"lockScreenNotificationHide", - IDS_ASH_SETTINGS_LOCK_SCREEN_NOTIFICATION_HIDE}, - {"lockScreenNotificationHideSensitive", - IDS_ASH_SETTINGS_LOCK_SCREEN_NOTIFICATION_HIDE_SENSITIVE}, - {"lockScreenNotificationShow", - IDS_ASH_SETTINGS_LOCK_SCREEN_NOTIFICATION_SHOW}, - {"lockScreenNotificationTitle", - IDS_ASH_SETTINGS_LOCK_SCREEN_NOTIFICATION_TITLE}, - {"lockScreenOptionsLock", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_OPTIONS_LOCK}, - {"lockScreenOptionsLoginLock", - IDS_SETTINGS_PEOPLE_LOCK_SCREEN_OPTIONS_LOGIN_LOCK}, - {"lockScreenPasswordOnly", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_PASSWORD_ONLY}, - {"lockScreenPinOrPassword", - IDS_SETTINGS_PEOPLE_LOCK_SCREEN_PIN_OR_PASSWORD}, - {"lockScreenRegisteredFingerprints", - IDS_SETTINGS_PEOPLE_LOCK_SCREEN_REGISTERED_FINGERPRINTS_LABEL}, - {"lockScreenSetupPinButton", - IDS_SETTINGS_PEOPLE_LOCK_SCREEN_SETUP_PIN_BUTTON}, - {"lockScreenTitleLock", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_TITLE_LOCK}, - {"lockScreenTitleLoginLock", - IDS_SETTINGS_PEOPLE_LOCK_SCREEN_TITLE_LOGIN_LOCK}, - {"passwordPromptEnterPasswordLock", - IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_ENTER_PASSWORD_LOCK}, - {"passwordPromptEnterPasswordLoginLock", - IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_ENTER_PASSWORD_LOGIN_LOCK}, - {"passwordPromptInvalidPassword", - IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_INVALID_PASSWORD}, - {"passwordPromptPasswordLabel", - IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_PASSWORD_LABEL}, - {"passwordPromptTitle", IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_TITLE}, - {"pinKeyboardPlaceholderPin", IDS_PIN_KEYBOARD_HINT_TEXT_PIN}, - {"pinKeyboardPlaceholderPinPassword", - IDS_PIN_KEYBOARD_HINT_TEXT_PIN_PASSWORD}, - {"pinKeyboardDeleteAccessibleName", - IDS_PIN_KEYBOARD_DELETE_ACCESSIBLE_NAME}, - {"changePicturePageDescription", IDS_SETTINGS_CHANGE_PICTURE_DIALOG_TEXT}, - {"takePhoto", IDS_SETTINGS_CHANGE_PICTURE_TAKE_PHOTO}, - {"captureVideo", IDS_SETTINGS_CHANGE_PICTURE_CAPTURE_VIDEO}, - {"discardPhoto", IDS_SETTINGS_CHANGE_PICTURE_DISCARD_PHOTO}, - {"switchModeToCamera", IDS_SETTINGS_CHANGE_PICTURE_SWITCH_MODE_TO_CAMERA}, - {"switchModeToVideo", IDS_SETTINGS_CHANGE_PICTURE_SWITCH_MODE_TO_VIDEO}, - {"chooseFile", IDS_SETTINGS_CHANGE_PICTURE_CHOOSE_FILE}, - {"profilePhoto", IDS_SETTINGS_CHANGE_PICTURE_PROFILE_PHOTO}, - {"oldPhoto", IDS_SETTINGS_CHANGE_PICTURE_OLD_PHOTO}, - {"oldVideo", IDS_SETTINGS_CHANGE_PICTURE_OLD_VIDEO}, - {"previewAltText", IDS_SETTINGS_CHANGE_PICTURE_PREVIEW_ALT}, - {"authorCreditText", IDS_SETTINGS_CHANGE_PICTURE_AUTHOR_CREDIT_TEXT}, - {"photoCaptureAccessibleText", IDS_SETTINGS_PHOTO_CAPTURE_ACCESSIBLE_TEXT}, - {"photoDiscardAccessibleText", IDS_SETTINGS_PHOTO_DISCARD_ACCESSIBLE_TEXT}, - {"photoModeAccessibleText", IDS_SETTINGS_PHOTO_MODE_ACCESSIBLE_TEXT}, - {"syncOsAppsCheckboxLabel", IDS_OS_SETTINGS_SYNC_OS_APPS_CHECKBOX_LABEL}, - {"syncOsSettingsCheckboxLabel", - IDS_OS_SETTINGS_SYNC_OS_SETTINGS_CHECKBOX_LABEL}, - {"syncPrintersCheckboxLabel", IDS_OS_SETTINGS_SYNC_PRINTERS_CHECKBOX_LABEL}, - {"videoModeAccessibleText", IDS_SETTINGS_VIDEO_MODE_ACCESSIBLE_TEXT}, - {"wifiConfigurationsCheckboxLabel", - IDS_SETTINGS_WIFI_CONFIGURATIONS_CHECKBOX_LABEL}, -#else // !defined(OS_CHROMEOS) - {"domainManagedProfile", IDS_SETTINGS_PEOPLE_DOMAIN_MANAGED_PROFILE}, - {"editPerson", IDS_SETTINGS_EDIT_PERSON}, - {"profileNameAndPicture", IDS_SETTINGS_PROFILE_NAME_AND_PICTURE}, - {"showShortcutLabel", IDS_SETTINGS_PROFILE_SHORTCUT_TOGGLE_LABEL}, - {"syncWillStart", IDS_SETTINGS_SYNC_WILL_START}, - {"syncSettingsSavedToast", IDS_SETTINGS_SYNC_SETTINGS_SAVED_TOAST_LABEL}, - {"cancelSync", IDS_SETTINGS_SYNC_SETTINGS_CANCEL_SYNC}, - {"syncSetupCancelDialogTitle", IDS_SETTINGS_SYNC_SETUP_CANCEL_DIALOG_TITLE}, - {"syncSetupCancelDialogBody", IDS_SETTINGS_SYNC_SETUP_CANCEL_DIALOG_BODY}, -#endif // defined(OS_CHROMEOS) -#if BUILDFLAG(ENABLE_DICE_SUPPORT) - {"peopleSignIn", IDS_PROFILES_DICE_SIGNIN_BUTTON}, - {"peopleSignOut", IDS_SETTINGS_PEOPLE_SIGN_OUT}, - {"peopleSignInPrompt", IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT}, - {"peopleSignInPromptSecondaryWithNoAccount", - IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT_SECONDARY_WITH_ACCOUNT}, - {"peopleSignInPromptSecondaryWithAccount", - IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT_SECONDARY_WITH_ACCOUNT}, - {"useAnotherAccount", IDS_SETTINGS_PEOPLE_SYNC_ANOTHER_ACCOUNT}, - {"syncingTo", IDS_SETTINGS_PEOPLE_SYNCING_TO_ACCOUNT}, - {"turnOffSync", IDS_SETTINGS_PEOPLE_SYNC_TURN_OFF}, - {"signInAgain", IDS_SYNC_ERROR_USER_MENU_SIGNIN_AGAIN_BUTTON}, - {"syncNotWorking", IDS_SETTINGS_PEOPLE_SYNC_NOT_WORKING}, - {"syncPasswordsNotWorking", IDS_SETTINGS_PEOPLE_SYNC_PASSWORDS_NOT_WORKING}, - {"syncPaused", IDS_SETTINGS_PEOPLE_SYNC_PAUSED}, - {"syncSignInPromptWithAccount", - IDS_SETTINGS_SYNC_SIGN_IN_PROMPT_WITH_ACCOUNT}, - {"syncSignInPromptWithNoAccount", - IDS_SETTINGS_SYNC_SIGN_IN_PROMPT_WITH_NO_ACCOUNT}, + bool is_dice_enabled = false; + bool is_split_sync_consent_enabled = + chromeos::features::IsSplitSyncConsentEnabled(); +#else + bool is_dice_enabled = + AccountConsistencyModeManager::IsDiceEnabledForProfile(profile); + bool is_split_sync_consent_enabled = false; #endif - {"syncOverview", IDS_SETTINGS_SYNC_OVERVIEW}, - {"syncDisabled", IDS_PROFILES_DICE_SYNC_DISABLED_TITLE}, - {"syncDisabledByAdministrator", IDS_SIGNED_IN_WITH_SYNC_DISABLED_BY_POLICY}, - {"syncSignin", IDS_SETTINGS_SYNC_SIGNIN}, - {"syncDisconnect", IDS_SETTINGS_PEOPLE_SIGN_OUT}, - {"syncDisconnectTitle", IDS_SETTINGS_SYNC_DISCONNECT_TITLE}, - {"syncDisconnectDeleteProfile", - IDS_SETTINGS_SYNC_DISCONNECT_DELETE_PROFILE}, - {"deleteProfileWarningExpandA11yLabel", - IDS_SETTINGS_SYNC_DISCONNECT_EXPAND_ACCESSIBILITY_LABEL}, - {"deleteProfileWarningWithCountsSingular", - IDS_SETTINGS_SYNC_DISCONNECT_DELETE_PROFILE_WARNING_WITH_COUNTS_SINGULAR}, - {"deleteProfileWarningWithCountsPlural", - IDS_SETTINGS_SYNC_DISCONNECT_DELETE_PROFILE_WARNING_WITH_COUNTS_PLURAL}, - {"deleteProfileWarningWithoutCounts", - IDS_SETTINGS_SYNC_DISCONNECT_DELETE_PROFILE_WARNING_WITHOUT_COUNTS}, - {"syncDisconnectConfirm", IDS_SETTINGS_SYNC_DISCONNECT_CONFIRM}, - {"sync", IDS_SETTINGS_SYNC}, - {"nonPersonalizedServicesSectionLabel", - IDS_SETTINGS_NON_PERSONALIZED_SERVICES_SECTION_LABEL}, - {"syncAndNonPersonalizedServices", - IDS_SETTINGS_SYNC_SYNC_AND_NON_PERSONALIZED_SERVICES}, - {"syncPageTitle", IDS_SETTINGS_SYNC_SYNC_AND_NON_PERSONALIZED_SERVICES}, - {"syncAdvancedPageTitle", IDS_SETTINGS_SYNC_ADVANCED_PAGE_TITLE}, - {"syncLoading", IDS_SETTINGS_SYNC_LOADING}, - {"syncTimeout", IDS_SETTINGS_SYNC_TIMEOUT}, - {"syncEverythingCheckboxLabel", - IDS_SETTINGS_SYNC_EVERYTHING_CHECKBOX_LABEL}, - {"manageGoogleAccount", IDS_SETTINGS_MANAGE_GOOGLE_ACCOUNT}, - {"appCheckboxLabel", IDS_SETTINGS_APPS_CHECKBOX_LABEL}, - {"extensionsCheckboxLabel", IDS_SETTINGS_EXTENSIONS_CHECKBOX_LABEL}, - {"settingsCheckboxLabel", IDS_SETTINGS_SETTINGS_CHECKBOX_LABEL}, - {"autofillCheckboxLabel", IDS_SETTINGS_AUTOFILL_CHECKBOX_LABEL}, - {"historyCheckboxLabel", IDS_SETTINGS_HISTORY_CHECKBOX_LABEL}, - {"themesAndWallpapersCheckboxLabel", - IDS_SETTINGS_THEMES_AND_WALLPAPERS_CHECKBOX_LABEL}, - {"bookmarksCheckboxLabel", IDS_SETTINGS_BOOKMARKS_CHECKBOX_LABEL}, - {"passwordsCheckboxLabel", IDS_SETTINGS_PASSWORDS_CHECKBOX_LABEL}, - {"openTabsCheckboxLabel", IDS_SETTINGS_OPEN_TABS_CHECKBOX_LABEL}, - {"driveSuggestPref", IDS_DRIVE_SUGGEST_PREF}, - {"driveSuggestPrefDesc", IDS_DRIVE_SUGGEST_PREF_DESC}, - {"manageSyncedDataTitle", - IDS_SETTINGS_MANAGE_SYNCED_DATA_TITLE_UNIFIED_CONSENT}, - {"encryptionOptionsTitle", IDS_SETTINGS_ENCRYPTION_OPTIONS}, - {"syncDataEncryptedText", IDS_SETTINGS_SYNC_DATA_ENCRYPTED_TEXT}, - {"encryptWithGoogleCredentialsLabel", - IDS_SETTINGS_ENCRYPT_WITH_GOOGLE_CREDENTIALS_LABEL}, - {"useDefaultSettingsButton", IDS_SETTINGS_USE_DEFAULT_SETTINGS}, - {"emptyPassphraseError", IDS_SETTINGS_EMPTY_PASSPHRASE_ERROR}, - {"mismatchedPassphraseError", IDS_SETTINGS_MISMATCHED_PASSPHRASE_ERROR}, - {"incorrectPassphraseError", IDS_SETTINGS_INCORRECT_PASSPHRASE_ERROR}, - {"passphrasePlaceholder", IDS_SETTINGS_PASSPHRASE_PLACEHOLDER}, - {"passphraseConfirmationPlaceholder", - IDS_SETTINGS_PASSPHRASE_CONFIRMATION_PLACEHOLDER}, - {"submitPassphraseButton", IDS_SETTINGS_SUBMIT_PASSPHRASE}, - {"personalizeGoogleServicesTitle", - IDS_SETTINGS_PERSONALIZE_GOOGLE_SERVICES_TITLE}, - {"existingPassphraseTitle", IDS_SETTINGS_EXISTING_PASSPHRASE_TITLE}, - {"enablePaymentsIntegrationCheckboxLabel", - IDS_AUTOFILL_ENABLE_PAYMENTS_INTEGRATION_CHECKBOX_LABEL}, - }; - AddLocalizedStringsBulk(html_source, kLocalizedStrings); -#if defined(OS_CHROMEOS) - // TODO(crbug.com/1013466): String for this row label. - html_source->AddString("peopleOsSyncRowLabel", "SYNC PLACEHOLDER LABEL"); - AddFingerprintStrings(html_source); -#endif // OS_CHROMEOS - html_source->AddString("managementPage", - ManagementUI::GetManagementPageSubtitle(profile)); - // Format numbers to be used on the pin keyboard. - for (int j = 0; j <= 9; j++) { - html_source->AddString("pinKeyboard" + base::NumberToString(j), - base::FormatNumber(int64_t{j})); + if (is_split_sync_consent_enabled || is_dice_enabled) { + static constexpr webui::LocalizedString kTurnOffStrings[] = { + {"syncDisconnect", IDS_SETTINGS_PEOPLE_SYNC_TURN_OFF}, + {"syncDisconnectTitle", + IDS_SETTINGS_TURN_OFF_SYNC_AND_SIGN_OUT_DIALOG_TITLE}, + }; + AddLocalizedStringsBulk(html_source, kTurnOffStrings); + } else { + static constexpr webui::LocalizedString kSignOutStrings[] = { + {"syncDisconnect", IDS_SETTINGS_PEOPLE_SIGN_OUT}, + {"syncDisconnectTitle", IDS_SETTINGS_SYNC_DISCONNECT_TITLE}, + }; + AddLocalizedStringsBulk(html_source, kSignOutStrings); } - html_source->AddString("syncLearnMoreUrl", chrome::kSyncLearnMoreURL); - html_source->AddString("supervisedUsersUrl", - chrome::kLegacySupervisedUserManagementURL); - - html_source->AddString( - "encryptWithSyncPassphraseLabel", - l10n_util::GetStringFUTF8( - IDS_SETTINGS_ENCRYPT_WITH_SYNC_PASSPHRASE_LABEL, -#if defined(OS_CHROMEOS) - GetHelpUrlWithBoard(chrome::kSyncEncryptionHelpURL))); -#else - base::ASCIIToUTF16(chrome::kSyncEncryptionHelpURL))); -#endif - std::string sync_dashboard_url = google_util::AppendGoogleLocaleParam( GURL(chrome::kSyncGoogleDashboardURL), g_browser_process->GetApplicationLocale()) .spec(); - html_source->AddString("syncDashboardUrl", sync_dashboard_url); - - html_source->AddString( - "passphraseExplanationText", - l10n_util::GetStringFUTF8(IDS_SETTINGS_PASSPHRASE_EXPLANATION_TEXT, - base::ASCIIToUTF16(sync_dashboard_url))); - html_source->AddString( - "passphraseResetHintEncryption", - l10n_util::GetStringFUTF8(IDS_SETTINGS_PASSPHRASE_RESET_HINT_ENCRYPTION, - base::ASCIIToUTF16(sync_dashboard_url))); - html_source->AddString( - "passphraseResetHintToggle", - l10n_util::GetStringFUTF8(IDS_SETTINGS_PASSPHRASE_RESET_HINT_TOGGLE, - base::ASCIIToUTF16(sync_dashboard_url))); - html_source->AddString( - "passphraseRecover", - l10n_util::GetStringFUTF8(IDS_SETTINGS_PASSPHRASE_RECOVER, - base::ASCIIToUTF16(sync_dashboard_url))); - html_source->AddString( - "syncDisconnectExplanation", - l10n_util::GetStringFUTF8(IDS_SETTINGS_SYNC_DISCONNECT_EXPLANATION, - base::ASCIIToUTF16(sync_dashboard_url))); -#if !defined(OS_CHROMEOS) - html_source->AddString( - "syncDisconnectManagedProfileExplanation", - l10n_util::GetStringFUTF8( - IDS_SETTINGS_SYNC_DISCONNECT_MANAGED_PROFILE_EXPLANATION, - base::ASCIIToUTF16("$1"), base::ASCIIToUTF16(sync_dashboard_url))); - // The syncDisconnect text differs depending on Dice-enabledness. - if (AccountConsistencyModeManager::IsDiceEnabledForProfile(profile)) { + if (is_dice_enabled) { static constexpr webui::LocalizedString kSyncDisconnectStrings[] = { - {"syncDisconnect", IDS_SETTINGS_PEOPLE_SYNC_TURN_OFF}, - {"syncDisconnectTitle", - IDS_SETTINGS_TURN_OFF_SYNC_AND_SIGN_OUT_DIALOG_TITLE}, {"syncDisconnectDeleteProfile", IDS_SETTINGS_TURN_OFF_SYNC_DIALOG_CHECKBOX}, {"syncDisconnectConfirm", IDS_SETTINGS_TURN_OFF_SYNC_DIALOG_MANAGED_CONFIRM}, + {"syncDisconnectExplanation", + IDS_SETTINGS_SYNC_DISCONNECT_AND_SIGN_OUT_EXPLANATION}, + }; + AddLocalizedStringsBulk(html_source, kSyncDisconnectStrings); + } else { + static constexpr webui::LocalizedString kSyncDisconnectStrings[] = { + {"syncDisconnectDeleteProfile", + IDS_SETTINGS_SYNC_DISCONNECT_DELETE_PROFILE}, + {"syncDisconnectConfirm", IDS_SETTINGS_SYNC_DISCONNECT_CONFIRM}, }; AddLocalizedStringsBulk(html_source, kSyncDisconnectStrings); - html_source->AddLocalizedString( + html_source->AddString( "syncDisconnectExplanation", - IDS_SETTINGS_SYNC_DISCONNECT_AND_SIGN_OUT_EXPLANATION); + l10n_util::GetStringFUTF8(IDS_SETTINGS_SYNC_DISCONNECT_EXPLANATION, + base::ASCIIToUTF16(sync_dashboard_url))); } + +#if !defined(OS_CHROMEOS) + html_source->AddString( + "syncDisconnectManagedProfileExplanation", + l10n_util::GetStringFUTF8( + IDS_SETTINGS_SYNC_DISCONNECT_MANAGED_PROFILE_EXPLANATION, + base::ASCIIToUTF16("$1"), base::ASCIIToUTF16(sync_dashboard_url))); #endif +} - html_source->AddString("activityControlsUrl", - chrome::kGoogleAccountActivityControlsURL); +void AddPeopleStrings(content::WebUIDataSource* html_source, Profile* profile) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + // Top level people strings: + {"peopleSignInPromptSecondaryWithAccount", + IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT_SECONDARY_WITH_ACCOUNT}, + {"peopleSignInPromptSecondaryWithNoAccount", + IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT_SECONDARY_WITH_ACCOUNT}, + {"peoplePageTitle", IDS_SETTINGS_PEOPLE}, + {"syncSettingsSavedToast", IDS_SETTINGS_SYNC_SETTINGS_SAVED_TOAST_LABEL}, + {"peopleSignInPrompt", IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT}, + {"manageGoogleAccount", IDS_SETTINGS_MANAGE_GOOGLE_ACCOUNT}, + {"syncAndNonPersonalizedServices", + IDS_SETTINGS_SYNC_SYNC_AND_NON_PERSONALIZED_SERVICES}, +#if defined(OS_CHROMEOS) + {"accountManagerSubMenuLabel", IDS_SETTINGS_ACCOUNT_MANAGER_SUBMENU_LABEL}, +#else + {"editPerson", IDS_SETTINGS_EDIT_PERSON}, + {"profileNameAndPicture", IDS_SETTINGS_PROFILE_NAME_AND_PICTURE}, +#endif + + // Manage profile strings: +#if !defined(OS_CHROMEOS) + {"showShortcutLabel", IDS_SETTINGS_PROFILE_SHORTCUT_TOGGLE_LABEL}, +#endif + {"deleteProfileWarningExpandA11yLabel", + IDS_SETTINGS_SYNC_DISCONNECT_EXPAND_ACCESSIBILITY_LABEL}, + {"deleteProfileWarningWithCountsSingular", + IDS_SETTINGS_SYNC_DISCONNECT_DELETE_PROFILE_WARNING_WITH_COUNTS_SINGULAR}, + {"deleteProfileWarningWithCountsPlural", + IDS_SETTINGS_SYNC_DISCONNECT_DELETE_PROFILE_WARNING_WITH_COUNTS_PLURAL}, + {"deleteProfileWarningWithoutCounts", + IDS_SETTINGS_SYNC_DISCONNECT_DELETE_PROFILE_WARNING_WITHOUT_COUNTS}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); // Add Google Account URL and include UTM parameter to signal the source of // the navigation. @@ -2336,52 +1061,21 @@ void AddPeopleStrings(content::WebUIDataSource* html_source, Profile* profile) { net::AppendQueryParameter(GURL(chrome::kGoogleAccountURL), "utm_source", "chrome-settings") .spec()); - html_source->AddBoolean("profileShortcutsEnabled", ProfileShortcutManager::IsFeatureEnabled()); - - html_source->AddBoolean( - "changePictureVideoModeEnabled", - base::FeatureList::IsEnabled(features::kChangePictureVideoMode)); - - html_source->AddBoolean( - "driveSuggestAvailable", - base::FeatureList::IsEnabled(omnibox::kDocumentProvider)); - #if defined(OS_CHROMEOS) // Toggles the Chrome OS Account Manager submenu in the People section. html_source->AddBoolean("isAccountManagerEnabled", chromeos::IsAccountManagerAvailable(profile)); +#endif - PrefService* local_state = g_browser_process->local_state(); - - // Toggles the Chrome OS Kerberos Accounts submenu in the People section. - // Note that the handler is also dependent on this pref. - html_source->AddBoolean("isKerberosEnabled", - local_state->GetBoolean(prefs::kKerberosEnabled)); - - // Whether the 'Remember password' checkbox is enabled. - html_source->AddBoolean( - "kerberosRememberPasswordEnabled", - local_state->GetBoolean(prefs::kKerberosRememberPasswordEnabled)); - - // Whether new Kerberos accounts may be added. - html_source->AddBoolean( - "kerberosAddAccountsAllowed", - local_state->GetBoolean(prefs::kKerberosAddAccountsAllowed)); - - // Kerberos default configuration. - html_source->AddString( - "defaultKerberosConfig", - chromeos::KerberosCredentialsManager::GetDefaultKerberosConfig()); - - // Kerberos accounts page with "Learn more" link. - html_source->AddString( - "kerberosAccountsDescription", - l10n_util::GetStringFUTF16( - IDS_SETTINGS_KERBEROS_ACCOUNTS_DESCRIPTION, - GetHelpUrlWithBoard(chrome::kKerberosAccountsLearnMoreURL))); + AddSignOutDialogStrings(html_source, profile); + AddSyncControlsStrings(html_source); + AddSyncAccountControlStrings(html_source); +#if defined(OS_CHROMEOS) + AddPasswordPromptDialogStrings(html_source); #endif + AddSyncPageStrings(html_source); } void AddPrintingStrings(content::WebUIDataSource* html_source) { @@ -2393,126 +1087,7 @@ void AddPrintingStrings(content::WebUIDataSource* html_source) { {"printingManageCloudPrintDevices", IDS_SETTINGS_PRINTING_MANAGE_CLOUD_PRINT_DEVICES}, {"cloudPrintersTitle", IDS_SETTINGS_PRINTING_CLOUD_PRINTERS}, -#if defined(OS_CHROMEOS) - {"cupsPrintersTitle", IDS_SETTINGS_PRINTING_CUPS_PRINTERS}, - {"cupsPrintersLearnMoreLabel", - IDS_SETTINGS_PRINTING_CUPS_PRINTERS_LEARN_MORE_LABEL}, - {"addCupsPrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_ADD_PRINTER}, - {"editPrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_EDIT}, - {"removePrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_REMOVE}, - {"setupPrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTER_SETUP_BUTTON}, - {"setupPrinterAria", IDS_SETTINGS_PRINTING_CUPS_PRINTER_SETUP_BUTTON_ARIA}, - {"savePrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTER_SAVE_BUTTON}, - {"savePrinterAria", IDS_SETTINGS_PRINTING_CUPS_PRINTER_SAVE_BUTTON_ARIA}, - {"searchLabel", IDS_SETTINGS_PRINTING_CUPS_SEARCH_LABEL}, - {"noSearchResults", IDS_SEARCH_NO_RESULTS}, - {"printerDetailsTitle", IDS_SETTINGS_PRINTING_CUPS_PRINTER_DETAILS_TITLE}, - {"printerName", IDS_SETTINGS_PRINTING_CUPS_PRINTER_DETAILS_NAME}, - {"printerModel", IDS_SETTINGS_PRINTING_CUPS_PRINTER_DETAILS_MODEL}, - {"printerQueue", IDS_SETTINGS_PRINTING_CUPS_PRINTER_DETAILS_QUEUE}, - {"savedPrintersTitle", IDS_SETTINGS_PRINTING_CUPS_SAVED_PRINTERS_TITLE}, - {"savedPrintersCountMany", - IDS_SETTINGS_PRINTING_CUPS_PRINTERS_SAVED_PRINTERS_COUNT_MANY}, - {"savedPrintersCountOne", - IDS_SETTINGS_PRINTING_CUPS_PRINTERS_SAVED_PRINTERS_COUNT_ONE}, - {"savedPrintersCountNone", - IDS_SETTINGS_PRINTING_CUPS_PRINTERS_SAVED_PRINTERS_COUNT_NONE}, - {"showMorePrinters", IDS_SETTINGS_PRINTING_CUPS_SHOW_MORE}, - {"addPrintersNearbyTitle", - IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTERS_NEARBY_TITLE}, - {"addPrintersManuallyTitle", - IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTERS_MANUALLY_TITLE}, - {"manufacturerAndModelDialogTitle", - IDS_SETTINGS_PRINTING_CUPS_SELECT_MANUFACTURER_AND_MODEL_TITLE}, - {"nearbyPrintersListTitle", - IDS_SETTINGS_PRINTING_CUPS_PRINTERS_AVAILABLE_PRINTERS}, - {"nearbyPrintersCountMany", - IDS_SETTINGS_PRINTING_CUPS_PRINTERS_AVAILABLE_PRINTERS_COUNT_MANY}, - {"nearbyPrintersCountOne", - IDS_SETTINGS_PRINTING_CUPS_PRINTERS_AVAILABLE_PRINTER_COUNT_ONE}, - {"nearbyPrintersCountNone", - IDS_SETTINGS_PRINTING_CUPS_PRINTERS_AVAILABLE_PRINTER_COUNT_NONE}, - {"nearbyPrintersListDescription", - IDS_SETTINGS_PRINTING_CUPS_PRINTERS_ADD_DETECTED_OR_NEW_PRINTER}, - {"manufacturerAndModelAdditionalInformation", - IDS_SETTINGS_PRINTING_CUPS_MANUFACTURER_MODEL_ADDITIONAL_INFORMATION}, - {"addPrinterButtonText", IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTER_BUTTON_ADD}, - {"printerDetailsAdvanced", IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADVANCED}, - {"printerDetailsA11yLabel", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADVANCED_ACCESSIBILITY_LABEL}, - {"printerAddress", IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADVANCED_ADDRESS}, - {"printerProtocol", IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADVANCED_PROTOCOL}, - {"printerURI", IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADVANCED_URI}, - {"manuallyAddPrinterButtonText", - IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTER_BUTTON_MANUAL_ADD}, - {"discoverPrintersButtonText", - IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTER_BUTTON_DISCOVER_PRINTERS}, - {"printerProtocolIpp", IDS_SETTINGS_PRINTING_CUPS_PRINTER_PROTOCOL_IPP}, - {"printerProtocolIpps", IDS_SETTINGS_PRINTING_CUPS_PRINTER_PROTOCOL_IPPS}, - {"printerProtocolHttp", IDS_SETTINGS_PRINTING_CUPS_PRINTER_PROTOCOL_HTTP}, - {"printerProtocolHttps", IDS_SETTINGS_PRINTING_CUPS_PRINTER_PROTOCOL_HTTPS}, - {"printerProtocolAppSocket", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_PROTOCOL_APP_SOCKET}, - {"printerProtocolLpd", IDS_SETTINGS_PRINTING_CUPS_PRINTER_PROTOCOL_LPD}, - {"printerProtocolUsb", IDS_SETTINGS_PRINTING_CUPS_PRINTER_PROTOCOL_USB}, - {"printerProtocolIppUsb", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_PROTOCOL_IPPUSB}, - {"printerConfiguringMessage", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_CONFIGURING_MESSAGE}, - {"printerManufacturer", IDS_SETTINGS_PRINTING_CUPS_PRINTER_MANUFACTURER}, - {"selectDriver", IDS_SETTINGS_PRINTING_CUPS_PRINTER_SELECT_DRIVER}, - {"selectDriverButtonText", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_BUTTON_SELECT_DRIVER}, - {"selectDriverButtonAriaLabel", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_BUTTON_SELECT_DRIVER_ARIA_LABEL}, - {"selectDriverErrorMessage", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_INVALID_DRIVER}, - {"printerAddedSuccessfulMessage", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_DONE_MESSAGE}, - {"printerEditedSuccessfulMessage", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_EDITED_PRINTER_DONE_MESSAGE}, - {"printerUnavailableMessage", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_UNAVAILABLE_MESSAGE}, - {"noPrinterNearbyMessage", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_NO_PRINTER_NEARBY}, - {"searchingNearbyPrinters", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_SEARCHING_NEARBY_PRINTER}, - {"printerAddedFailedMessage", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_ERROR_MESSAGE}, - {"printerAddedFatalErrorMessage", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_FATAL_ERROR_MESSAGE}, - {"printerAddedUnreachableMessage", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_PRINTER_UNREACHABLE_MESSAGE}, - {"printerAddedPpdTooLargeMessage", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_PPD_TOO_LARGE_MESSAGE}, - {"printerAddedInvalidPpdMessage", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_INVALID_PPD_MESSAGE}, - {"printerAddedPpdNotFoundMessage", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_PPD_NOT_FOUND}, - {"printerAddedPpdUnretrievableMessage", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_PPD_UNRETRIEVABLE}, - {"printerAddedNativePrintersNotAllowedMessage", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_NATIVE_PRINTERS_NOT_ALLOWED_MESSAGE}, - {"editPrinterInvalidPrinterUpdate", - IDS_SETTINGS_PRINTING_CUPS_EDIT_PRINTER_INVALID_PRINTER_UPDATE}, - {"requireNetworkMessage", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_REQUIRE_INTERNET_MESSAGE}, - {"checkNetworkMessage", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_CHECK_CONNECTION_MESSAGE}, - {"noInternetConnection", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_NO_INTERNET_CONNECTION}, - {"checkNetworkAndTryAgain", - IDS_SETTINGS_PRINTING_CUPS_PRINTER_CONNECT_TO_NETWORK_SUBTEXT}, - {"editPrinterDialogTitle", - IDS_SETTINGS_PRINTING_CUPS_EDIT_PRINTER_DIALOG_TITLE}, - {"editPrinterButtonText", IDS_SETTINGS_PRINTING_CUPS_EDIT_PRINTER_BUTTON}, - {"currentPpdMessage", - IDS_SETTINGS_PRINTING_CUPS_EDIT_PRINTER_CURRENT_PPD_MESSAGE}, - {"printerEulaNotice", IDS_SETTINGS_PRINTING_CUPS_EULA_NOTICE}, - {"ippPrinterUnreachable", IDS_SETTINGS_PRINTING_CUPS_IPP_URI_UNREACHABLE}, - {"generalPrinterDialogError", - IDS_SETTINGS_PRINTING_CUPS_DIALOG_GENERAL_ERROR}, -#else +#if !defined(OS_CHROMEOS) {"localPrintersTitle", IDS_SETTINGS_PRINTING_LOCAL_PRINTERS_TITLE}, #endif }; @@ -2521,18 +1096,6 @@ void AddPrintingStrings(content::WebUIDataSource* html_source) { html_source->AddString("devicesUrl", chrome::kChromeUIDevicesURL); html_source->AddString("printingCloudPrintLearnMoreUrl", chrome::kCloudPrintLearnMoreURL); - -#if defined(OS_CHROMEOS) - html_source->AddString("printingCUPSPrintLearnMoreUrl", - GetHelpUrlWithBoard(chrome::kCupsPrintLearnMoreURL)); - html_source->AddString( - "printingCUPSPrintPpdLearnMoreUrl", - GetHelpUrlWithBoard(chrome::kCupsPrintPPDLearnMoreURL)); - - html_source->AddBoolean( - "updatedCupsPrintersUiEnabled", - base::FeatureList::IsEnabled(features::kCupsPrintersUiOverhaul)); -#endif } void AddPrivacyStrings(content::WebUIDataSource* html_source, @@ -2540,16 +1103,46 @@ void AddPrivacyStrings(content::WebUIDataSource* html_source, static constexpr webui::LocalizedString kLocalizedStrings[] = { {"privacyPageTitle", IDS_SETTINGS_PRIVACY}, {"privacyPageMore", IDS_SETTINGS_PRIVACY_MORE}, - {"signinAllowedTitle", IDS_SETTINGS_SIGNIN_ALLOWED}, - {"signinAllowedDescription", IDS_SETTINGS_SIGNIN_ALLOWED_DESC}, {"doNotTrack", IDS_SETTINGS_ENABLE_DO_NOT_TRACK}, {"doNotTrackDialogTitle", IDS_SETTINGS_ENABLE_DO_NOT_TRACK_DIALOG_TITLE}, - {"enableContentProtectionAttestation", - IDS_SETTINGS_ENABLE_CONTENT_PROTECTION_ATTESTATION}, - {"wakeOnWifi", IDS_SETTINGS_WAKE_ON_WIFI_DESCRIPTION}, + // TODO(crbug.com/1062607): This string is no longer used. Remove. + {"permissionsPageTitle", IDS_SETTINGS_PERMISSIONS}, + {"permissionsPageDescription", IDS_SETTINGS_PERMISSIONS_DESCRIPTION}, + {"securityPageTitle", IDS_SETTINGS_SECURITY}, + {"securityPageDescription", IDS_SETTINGS_SECURITY_DESCRIPTION}, + {"securityPageAdvancedSectionLabel", + IDS_SETTINGS_SECURITY_ADVANCED_SECTION_LABEL}, + {"advancedProtectionProgramTitle", + IDS_SETTINGS_ADVANCED_PROTECTION_PROGRAM}, + {"advancedProtectionProgramDesc", + IDS_SETTINGS_ADVANCED_PROTECTION_PROGRAM_DESC}, {"manageCertificates", IDS_SETTINGS_MANAGE_CERTIFICATES}, {"manageCertificatesDescription", IDS_SETTINGS_MANAGE_CERTIFICATES_DESCRIPTION}, + {"secureDns", IDS_SETTINGS_SECURE_DNS}, + {"secureDnsDescription", IDS_SETTINGS_SECURE_DNS_DESCRIPTION}, + {"secureDnsDisabledForManagedEnvironment", + IDS_SETTINGS_SECURE_DNS_DISABLED_FOR_MANAGED_ENVIRONMENT}, + {"secureDnsDisabledForParentalControl", + IDS_SETTINGS_SECURE_DNS_DISABLED_FOR_PARENTAL_CONTROL}, + {"secureDnsAutomaticModeDescription", + IDS_SETTINGS_AUTOMATIC_MODE_DESCRIPTION}, + {"secureDnsAutomaticModeDescriptionSecondary", + IDS_SETTINGS_AUTOMATIC_MODE_DESCRIPTION_SECONDARY}, + {"secureDnsSecureModeA11yLabel", + IDS_SETTINGS_SECURE_MODE_DESCRIPTION_ACCESSIBILITY_LABEL}, + {"secureDnsDropdownA11yLabel", + IDS_SETTINGS_SECURE_DNS_DROPDOWN_ACCESSIBILITY_LABEL}, + {"secureDnsSecureDropdownModeDescription", + IDS_SETTINGS_SECURE_DROPDOWN_MODE_DESCRIPTION}, + {"secureDnsSecureDropdownModePrivacyPolicy", + IDS_SETTINGS_SECURE_DROPDOWN_MODE_PRIVACY_POLICY}, + {"secureDnsCustomPlaceholder", + IDS_SETTINGS_SECURE_DNS_CUSTOM_PLACEHOLDER}, + {"secureDnsCustomFormatError", + IDS_SETTINGS_SECURE_DNS_CUSTOM_FORMAT_ERROR}, + {"secureDnsCustomConnectionError", + IDS_SETTINGS_SECURE_DNS_CUSTOM_CONNECTION_ERROR}, {"contentSettings", IDS_SETTINGS_CONTENT_SETTINGS}, {"siteSettings", IDS_SETTINGS_SITE_SETTINGS}, {"siteSettingsDescription", IDS_SETTINGS_SITE_SETTINGS_DESCRIPTION}, @@ -2561,37 +1154,125 @@ void AddPrivacyStrings(content::WebUIDataSource* html_source, IDS_SETTINGS_SAFEBROWSING_ENABLE_REPORTING}, {"safeBrowsingEnableExtendedReportingDesc", IDS_SETTINGS_SAFEBROWSING_ENABLE_REPORTING_DESC}, + {"safeBrowsingEnhanced", IDS_SETTINGS_SAFEBROWSING_ENHANCED}, + {"safeBrowsingEnhancedDesc", IDS_SETTINGS_SAFEBROWSING_ENHANCED_DESC}, + {"safeBrowsingEnhancedBulOne", + IDS_SETTINGS_SAFEBROWSING_ENHANCED_BULLET_ONE}, + {"safeBrowsingEnhancedBulTwo", + IDS_SETTINGS_SAFEBROWSING_ENHANCED_BULLET_TWO}, + {"safeBrowsingEnhancedBulThree", + IDS_SETTINGS_SAFEBROWSING_ENHANCED_BULLET_THREE}, + {"safeBrowsingEnhancedBulFour", + IDS_SETTINGS_SAFEBROWSING_ENHANCED_BULLET_FOUR}, + {"safeBrowsingEnhancedBulFive", + IDS_SETTINGS_SAFEBROWSING_ENHANCED_BULLET_FIVE}, + {"safeBrowsingStandard", IDS_SETTINGS_SAFEBROWSING_STANDARD}, + {"safeBrowsingStandardDesc", IDS_SETTINGS_SAFEBROWSING_STANDARD_DESC}, + {"safeBrowsingStandardBulOne", + IDS_SETTINGS_SAFEBROWSING_STANDARD_BULLET_ONE}, + {"safeBrowsingStandardBulTwo", + IDS_SETTINGS_SAFEBROWSING_STANDARD_BULLET_TWO}, + {"safeBrowsingStandardReportingLabel", + IDS_SETTINGS_SAFEBROWSING_STANDARD_HELP_IMPROVE}, + {"safeBrowsingNone", IDS_SETTINGS_SAFEBROWSING_NONE}, + {"safeBrowsingNoneDesc", IDS_SETTINGS_SAFEBROWSING_NONE_DESC}, + {"safeBrowsingDisableDialog", + IDS_SETTINGS_SAFEBROWSING_DISABLE_DIALOG_TITLE}, + {"safeBrowsingDisableDialogDesc", + IDS_SETTINGS_SAFEBROWSING_DISABLE_DIALOG_DESC}, + {"safeBrowsingDisableDialogConfrim", + IDS_SETTINGS_SAFEBROWSING_DISABLE_DIALOG_CONFIRM}, {"safeBrowsingEnableProtection", IDS_SETTINGS_SAFEBROWSING_ENABLEPROTECTION}, {"safeBrowsingEnableProtectionDesc", IDS_SETTINGS_SAFEBROWSING_ENABLEPROTECTION_DESC}, + {"safeBrowsingSectionLabel", IDS_SETTINGS_SAFEBROWSING_SECTION_LABEL}, {"syncAndGoogleServicesPrivacyDescription", IDS_SETTINGS_SYNC_AND_GOOGLE_SERVICES_PRIVACY_DESC_UNIFIED_CONSENT}, {"urlKeyedAnonymizedDataCollection", IDS_SETTINGS_ENABLE_URL_KEYED_ANONYMIZED_DATA_COLLECTION}, {"urlKeyedAnonymizedDataCollectionDesc", IDS_SETTINGS_ENABLE_URL_KEYED_ANONYMIZED_DATA_COLLECTION_DESC}, - }; - AddLocalizedStringsBulk(html_source, kLocalizedStrings); - - static constexpr webui::LocalizedString kConditionalLocalizedStrings[] = { - {"searchSuggestPref", IDS_SETTINGS_SUGGEST_PREF}, - {"searchSuggestPrefDesc", IDS_SETTINGS_SUGGEST_PREF_DESC}, + {"noRecentPermissions", IDS_SETTINGS_RECENT_PERMISSIONS_NO_CHANGES}, + {"recentPermissionChangeAutoblockedSentenceStart", + IDS_SETTINGS_RECENT_PERMISSIONS_CHANGE_AUTOBLOCKED_SENTENCE_START}, + {"recentPermissionChangeBlockedSentenceStart", + IDS_SETTINGS_RECENT_PERMISSIONS_CHANGE_BLOCKED_SENTENCE_START}, + {"recentPermissionChangeAllowedSentenceStart", + IDS_SETTINGS_RECENT_PERMISSIONS_CHANGE_ALLOWED_SENTENCE_START}, + {"recentPermissionChangeAutoblocked", + IDS_SETTINGS_RECENT_PERMISSIONS_CHANGE_AUTOBLOCKED}, + {"recentPermissionChangeBlocked", + IDS_SETTINGS_RECENT_PERMISSIONS_CHANGE_BLOCKED}, + {"recentPermissionChangeAllowed", + IDS_SETTINGS_RECENT_PERMISSIONS_CHANGE_ALLOWED}, + {"recentPermissionsTwoItems", IDS_SETTINGS_RECENT_PERMISSIONS_TWO_ITEMS}, + {"recentPermissionsThreeItems", + IDS_SETTINGS_RECENT_PERMISSIONS_THREE_ITEMS}, + {"recentPermissionsOverThreeItems", + IDS_SETTINGS_RECENT_PERMISSIONS_OVER_THREE_ITEMS}, + {"recentPermissionsOneItemIncognito", + IDS_SETTINGS_RECENT_PERMISSIONS_ONE_ITEM_INCOGNITO}, + {"recentPermissionsTwoItemsIncognito", + IDS_SETTINGS_RECENT_PERMISSIONS_TWO_ITEMS_INCOGNITO}, + {"recentPermissionsThreeItemsIncognito", + IDS_SETTINGS_RECENT_PERMISSIONS_THREE_ITEMS_INCOGNITO}, + {"recentPermissionsOverThreeItemsIncognito", + IDS_SETTINGS_RECENT_PERMISSIONS_OVER_THREE_ITEMS_INCOGNITO}, {"networkPredictionEnabled", IDS_SETTINGS_NETWORK_PREDICTION_ENABLED_LABEL}, {"networkPredictionEnabledDesc", IDS_SETTINGS_NETWORK_PREDICTION_ENABLED_DESC}, - {"linkDoctorPref", IDS_SETTINGS_LINKDOCTOR_PREF}, - {"linkDoctorPrefDesc", IDS_SETTINGS_LINKDOCTOR_PREF_DESC}, - {"spellingPref", IDS_SETTINGS_SPELLING_PREF}, - {"spellingDescription", IDS_SETTINGS_SPELLING_PREF_DESC}, - {"enableLogging", IDS_SETTINGS_ENABLE_LOGGING_PREF}, - {"enableLoggingDesc", IDS_SETTINGS_ENABLE_LOGGING_PREF_DESC}, + {"networkPredictionEnabledDescCookiesPage", + IDS_SETTINGS_NETWORK_PREDICTION_ENABLED_DESC_COOKIES_PAGE}, + {"safetyCheckSectionTitle", IDS_SETTINGS_SAFETY_CHECK_SECTION_TITLE}, + {"safetyCheckParentPrimaryLabelBefore", + IDS_SETTINGS_SAFETY_CHECK_PARENT_PRIMARY_LABEL_BEFORE}, + {"safetyCheckRunning", IDS_SETTINGS_SAFETY_CHECK_RUNNING}, + {"safetyCheckParentPrimaryLabelAfter", + IDS_SETTINGS_SAFETY_CHECK_PARENT_PRIMARY_LABEL_AFTER}, + {"safetyCheckAriaLiveRunning", + IDS_SETTINGS_SAFETY_CHECK_ARIA_LIVE_RUNNING}, + {"safetyCheckAriaLiveAfter", IDS_SETTINGS_SAFETY_CHECK_ARIA_LIVE_AFTER}, + {"safetyCheckParentButton", IDS_SETTINGS_SAFETY_CHECK_PARENT_BUTTON}, + {"safetyCheckParentButtonAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_PARENT_BUTTON_ARIA_LABEL}, + {"safetyCheckIconRunningAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_ICON_RUNNING_ARIA_LABEL}, + {"safetyCheckIconSafeAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_ICON_SAFE_ARIA_LABEL}, + {"safetyCheckIconInfoAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_ICON_INFO_ARIA_LABEL}, + {"safetyCheckIconWarningAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_ICON_WARNING_ARIA_LABEL}, + {"safetyCheckUpdatesPrimaryLabel", + IDS_SETTINGS_SAFETY_CHECK_UPDATES_PRIMARY_LABEL}, + {"safetyCheckUpdatesButtonAriaLabel", + IDS_UPDATE_RECOMMENDED_DIALOG_TITLE}, + {"safetyCheckPasswordsButton", + IDS_SETTINGS_SAFETY_CHECK_PASSWORDS_BUTTON}, + {"safetyCheckSafeBrowsingButton", + IDS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_BUTTON}, + {"safetyCheckSafeBrowsingButtonAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_BUTTON_ARIA_LABEL}, + {"safetyCheckExtensionsPrimaryLabel", + IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_PRIMARY_LABEL}, + {"safetyCheckExtensionsButton", + IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_BUTTON}, + {"safetyCheckExtensionsButtonAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_BUTTON_ARIA_LABEL}, }; - AddLocalizedStringsBulk(html_source, kConditionalLocalizedStrings); + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + html_source->AddString("cookiesSettingsHelpCenterURL", + chrome::kCookiesSettingsHelpCenterURL); + + html_source->AddString("safeBrowsingHelpCenterURL", + chrome::kSafeBrowsingHelpCenterURL); html_source->AddString("syncAndGoogleServicesLearnMoreURL", chrome::kSyncAndGoogleServicesLearnMoreURL); + html_source->AddString( "doNotTrackDialogMessage", l10n_util::GetStringFUTF16( @@ -2604,6 +1285,29 @@ void AddPrivacyStrings(content::WebUIDataSource* html_source, html_source->AddString( "exceptionsLearnMoreURL", base::ASCIIToUTF16(chrome::kContentSettingsExceptionsLearnMoreURL)); + html_source->AddBoolean( + "installedAppsInCbd", + base::FeatureList::IsEnabled(features::kStoragePressureUI)); + html_source->AddBoolean( + "driveSuggestAvailable", + base::FeatureList::IsEnabled(omnibox::kDocumentProvider)); + html_source->AddBoolean("showSecureDnsSetting", + features::kDnsOverHttpsShowUiParam.Get()); + + // The link to the Advanced Protection Program landing page, with a referrer + // from Chrome settings. + GURL advanced_protection_url( + "https://landing.google.com/advancedprotection/"); + advanced_protection_url = net::AppendQueryParameter(advanced_protection_url, + "utm_source", "Chrome"); + advanced_protection_url = net::AppendQueryParameter( + advanced_protection_url, "utm_medium", "ChromeSecuritySettings"); + advanced_protection_url = net::AppendQueryParameter( + advanced_protection_url, "utm_campaign", "ChromeSettings"); + html_source->AddString("advancedProtectionURL", + advanced_protection_url.spec()); + + AddPersonalizationOptionsStrings(html_source); } void AddSearchInSettingsStrings(content::WebUIDataSource* html_source) { @@ -2623,52 +1327,18 @@ void AddSearchInSettingsStrings(content::WebUIDataSource* html_source) { html_source->AddString("searchNoResultsHelp", help_text); } -void AddSearchStrings(content::WebUIDataSource* html_source, Profile* profile) { -#if defined(OS_CHROMEOS) - // NOTE: This will be false when the flag is disabled. - const bool is_assistant_allowed = - assistant::IsAssistantAllowedForProfile(profile) == - ash::mojom::AssistantAllowedState::ALLOWED; - // SplitSettings moves Assistant to the OS settings window. - const bool assistant_in_browser_settings = - is_assistant_allowed && !chromeos::features::IsSplitSettingsEnabled(); -#endif - +void AddSearchStrings(content::WebUIDataSource* html_source) { static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"searchEnginesManage", IDS_SETTINGS_SEARCH_MANAGE_SEARCH_ENGINES}, -#if defined(OS_CHROMEOS) - {"osSearchEngineLabel", IDS_OS_SETTINGS_SEARCH_ENGINE_LABEL}, - {"searchGoogleAssistant", IDS_SETTINGS_SEARCH_GOOGLE_ASSISTANT}, - {"searchGoogleAssistantEnabled", - IDS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_ENABLED}, - {"searchGoogleAssistantDisabled", - IDS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_DISABLED}, -#endif + {"searchEnginesManage", IDS_SETTINGS_SEARCH_MANAGE_SEARCH_ENGINES}, + {"searchPageTitle", IDS_SETTINGS_SEARCH}, + }; AddLocalizedStringsBulk(html_source, kLocalizedStrings); -#if defined(OS_CHROMEOS) - html_source->AddLocalizedString("searchPageTitle", - assistant_in_browser_settings - ? IDS_SETTINGS_SEARCH_AND_ASSISTANT - : IDS_SETTINGS_SEARCH); - html_source->AddLocalizedString("osSearchPageTitle", - is_assistant_allowed - ? IDS_SETTINGS_SEARCH_AND_ASSISTANT - : IDS_SETTINGS_SEARCH); -#else - html_source->AddLocalizedString("searchPageTitle", IDS_SETTINGS_SEARCH); -#endif - base::string16 search_explanation_text = l10n_util::GetStringFUTF16( - IDS_SETTINGS_SEARCH_EXPLANATION, - base::ASCIIToUTF16(chrome::kOmniboxLearnMoreURL)); - html_source->AddString("searchExplanation", search_explanation_text); -#if defined(OS_CHROMEOS) - html_source->AddString( - "osSearchEngineTooltip", - ui::SubstituteChromeOSDeviceType(IDS_OS_SETTINGS_SEARCH_ENGINE_TOOLTIP)); - html_source->AddBoolean("isAssistantAllowed", is_assistant_allowed); -#endif + html_source->AddString("searchExplanation", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_SEARCH_EXPLANATION, + base::ASCIIToUTF16(chrome::kOmniboxLearnMoreURL))); } void AddSearchEnginesStrings(content::WebUIDataSource* html_source) { @@ -2699,52 +1369,6 @@ void AddSearchEnginesStrings(content::WebUIDataSource* html_source) { AddLocalizedStringsBulk(html_source, kLocalizedStrings); } -#if defined(OS_CHROMEOS) -void AddGoogleAssistantStrings(content::WebUIDataSource* html_source, - Profile* profile) { - static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"googleAssistantPageTitle", IDS_SETTINGS_GOOGLE_ASSISTANT}, - {"googleAssistantEnableContext", IDS_ASSISTANT_SCREEN_CONTEXT_TITLE}, - {"googleAssistantEnableContextDescription", - IDS_ASSISTANT_SCREEN_CONTEXT_DESC}, - {"googleAssistantEnableHotword", - IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD}, - {"googleAssistantEnableHotwordDescription", - IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_DESCRIPTION}, - {"googleAssistantVoiceSettings", - IDS_SETTINGS_GOOGLE_ASSISTANT_VOICE_SETTINGS}, - {"googleAssistantVoiceSettingsDescription", - IDS_ASSISTANT_VOICE_MATCH_RECORDING}, - {"googleAssistantVoiceSettingsRetrainButton", - IDS_SETTINGS_GOOGLE_ASSISTANT_VOICE_SETTINGS_RETRAIN}, - {"googleAssistantEnableHotwordWithoutDspDescription", - IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_WITHOUT_DSP_DESCRIPTION}, - {"googleAssistantEnableHotwordWithoutDspRecommended", - IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_WITHOUT_DSP_RECOMMENDED}, - {"googleAssistantEnableHotwordWithoutDspAlwaysOn", - IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_WITHOUT_DSP_ALWAYS_ON}, - {"googleAssistantEnableHotwordWithoutDspOff", - IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_WITHOUT_DSP_OFF}, - {"googleAssistantEnableNotification", - IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_NOTIFICATION}, - {"googleAssistantEnableNotificationDescription", - IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_NOTIFICATION_DESCRIPTION}, - {"googleAssistantLaunchWithMicOpen", - IDS_SETTINGS_GOOGLE_ASSISTANT_LAUNCH_WITH_MIC_OPEN}, - {"googleAssistantLaunchWithMicOpenDescription", - IDS_SETTINGS_GOOGLE_ASSISTANT_LAUNCH_WITH_MIC_OPEN_DESCRIPTION}, - {"googleAssistantSettings", IDS_SETTINGS_GOOGLE_ASSISTANT_SETTINGS}, - }; - AddLocalizedStringsBulk(html_source, kLocalizedStrings); - - html_source->AddBoolean("hotwordDspAvailable", - chromeos::IsHotwordDspAvailable()); - html_source->AddBoolean( - "voiceMatchDisabled", - chromeos::assistant::features::IsVoiceMatchDisabled()); -} -#endif - void AddSiteSettingsStrings(content::WebUIDataSource* html_source, Profile* profile) { static constexpr webui::LocalizedString kLocalizedStrings[] = { @@ -2800,6 +1424,8 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, {"mediaLicenseSize", IDS_SETTINGS_COOKIES_LOCAL_STORAGE_SIZE_ON_DISK_LABEL}, {"mediaLicenseLastModified", IDS_SETTINGS_COOKIES_LOCAL_STORAGE_LAST_MODIFIED_LABEL}, + {"noBluetoothDevicesFound", IDS_SETTINGS_NO_BLUETOOTH_DEVICES_FOUND}, + {"noHidDevicesFound", IDS_SETTINGS_NO_HID_DEVICES_FOUND}, {"noSerialPortsFound", IDS_SETTINGS_NO_SERIAL_PORTS_FOUND}, {"noUsbDevicesFound", IDS_SETTINGS_NO_USB_DEVICES_FOUND}, {"serviceWorkerOrigin", IDS_SETTINGS_COOKIES_LOCAL_STORAGE_ORIGIN_LABEL}, @@ -2808,8 +1434,37 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, {"sharedWorkerWorker", IDS_SETTINGS_COOKIES_SHARED_WORKER_WORKER_LABEL}, {"sharedWorkerName", IDS_SETTINGS_COOKIES_COOKIE_NAME_LABEL}, {"siteSettingsCategoryPageTitle", IDS_SETTINGS_SITE_SETTINGS_CATEGORY}, + {"siteSettingsRecentPermissionsSectionLabel", + IDS_SETTINGS_SITE_SETTINGS_RECENT_ACTIVITY}, {"siteSettingsCategoryCamera", IDS_SETTINGS_SITE_SETTINGS_CAMERA}, {"siteSettingsCameraLabel", IDS_SETTINGS_SITE_SETTINGS_CAMERA_LABEL}, + {"cookiePageTitle", IDS_SETTINGS_COOKIES_PAGE}, + {"cookiePageGeneralControls", IDS_SETTINGS_COOKIES_CONTROLS}, + {"cookiePageAllowAll", IDS_SETTINGS_COOKIES_ALLOW_ALL}, + {"cookiePageAllowAllBulOne", IDS_SETTINGS_COOKIES_ALLOW_ALL_BULLET_ONE}, + {"cookiePageAllowAllBulTwo", IDS_SETTINGS_COOKIES_ALLOW_ALL_BULLET_TWO}, + {"cookiePageBlockThirdIncognito", + IDS_SETTINGS_COOKIES_BLOCK_THIRD_PARTY_INCOGNITO}, + {"cookiePageBlockThirdIncognitoBulOne", + IDS_SETTINGS_COOKIES_BLOCK_THIRD_PARTY_INCOGNITO_BULLET_ONE}, + {"cookiePageBlockThirdIncognitoBulTwo", + IDS_SETTINGS_COOKIES_BLOCK_THIRD_PARTY_INCOGNITO_BULLET_TWO}, + {"cookiePageBlockThird", IDS_SETTINGS_COOKIES_BLOCK_THIRD_PARTY}, + {"cookiePageBlockThirdBulOne", + IDS_SETTINGS_COOKIES_BLOCK_THIRD_PARTY_BULLET_ONE}, + {"cookiePageBlockThirdBulTwo", + IDS_SETTINGS_COOKIES_BLOCK_THIRD_PARTY_BULLET_TWO}, + {"cookiePageBlockAll", IDS_SETTINGS_COOKIES_BLOCK_ALL}, + {"cookiePageBlockAllBulOne", IDS_SETTINGS_COOKIES_BLOCK_ALL_BULLET_ONE}, + {"cookiePageBlockAllBulTwo", IDS_SETTINGS_COOKIES_BLOCK_ALL_BULLET_TWO}, + {"cookiePageBlockAllBulThree", IDS_SETTINGS_COOKIES_BLOCK_ALL_BULLET_THREE}, + {"cookiePageClearOnExit", IDS_SETTINGS_COOKIES_CLEAR_ON_EXIT}, + {"cookiePageAllowExceptions", IDS_SETTINGS_COOKIES_ALLOW_EXCEPTIONS}, + {"cookiePageBlockExceptions", IDS_SETTINGS_COOKIES_BLOCK_EXCEPTIONS}, + {"cookiePageSessionOnlyExceptions", + IDS_SETTINGS_COOKIES_SESSION_ONLY_EXCEPTIONS}, + {"cookiesManageSiteSpecificExceptions", + IDS_SETTINGS_COOKIES_SITE_SPECIFIC_EXCEPTIONS}, {"siteSettingsCategoryCookies", IDS_SETTINGS_SITE_SETTINGS_COOKIES}, {"siteSettingsCategoryHandlers", IDS_SETTINGS_SITE_SETTINGS_HANDLERS}, {"siteSettingsCategoryImages", IDS_SETTINGS_SITE_SETTINGS_IMAGES}, @@ -2892,6 +1547,12 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, {"siteSettingsPopups", IDS_SETTINGS_SITE_SETTINGS_POPUPS}, {"siteSettingsUnsandboxedPlugins", IDS_SETTINGS_SITE_SETTINGS_UNSANDBOXED_PLUGINS}, + {"siteSettingsHidDevices", IDS_SETTINGS_SITE_SETTINGS_HID_DEVICES}, + {"siteSettingsHidDevicesAsk", IDS_SETTINGS_SITE_SETTINGS_HID_DEVICES_ASK}, + {"siteSettingsHidDevicesAskRecommended", + IDS_SETTINGS_SITE_SETTINGS_HID_DEVICES_ASK_RECOMMENDED}, + {"siteSettingsHidDevicesBlock", + IDS_SETTINGS_SITE_SETTINGS_HID_DEVICES_BLOCK}, {"siteSettingsMidiDevices", IDS_SETTINGS_SITE_SETTINGS_MIDI_DEVICES}, {"siteSettingsMidiDevicesAsk", IDS_SETTINGS_SITE_SETTINGS_MIDI_DEVICES_ASK}, {"siteSettingsMidiDevicesAskRecommended", @@ -2910,6 +1571,14 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, IDS_SETTINGS_SITE_SETTINGS_USB_DEVICES_ASK_RECOMMENDED}, {"siteSettingsUsbDevicesBlock", IDS_SETTINGS_SITE_SETTINGS_USB_DEVICES_BLOCK}, + {"siteSettingsBluetoothDevices", + IDS_SETTINGS_SITE_SETTINGS_BLUETOOTH_DEVICES}, + {"siteSettingsBluetoothDevicesAsk", + IDS_SETTINGS_SITE_SETTINGS_BLUETOOTH_DEVICES_ASK}, + {"siteSettingsBluetoothDevicesAskRecommended", + IDS_SETTINGS_SITE_SETTINGS_BLUETOOTH_DEVICES_ASK_RECOMMENDED}, + {"siteSettingsBluetoothDevicesBlock", + IDS_SETTINGS_SITE_SETTINGS_BLUETOOTH_DEVICES_BLOCK}, {"siteSettingsNativeFileSystemWrite", IDS_SETTINGS_SITE_SETTINGS_NATIVE_FILE_SYSTEM_WRITE}, {"siteSettingsNativeFileSystemWriteAsk", @@ -2996,6 +1665,10 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, {"siteSettingsUsage", IDS_SETTINGS_SITE_SETTINGS_USAGE}, {"siteSettingsUsageNone", IDS_SETTINGS_SITE_SETTINGS_USAGE_NONE}, {"siteSettingsPermissions", IDS_SETTINGS_SITE_SETTINGS_PERMISSIONS}, + {"siteSettingsPermissionsMore", + IDS_SETTINGS_SITE_SETTINGS_PERMISSIONS_MORE}, + {"siteSettingsContent", IDS_SETTINGS_SITE_SETTINGS_CONTENT}, + {"siteSettingsContentMore", IDS_SETTINGS_SITE_SETTINGS_CONTENT_MORE}, {"siteSettingsSourceExtensionAllow", IDS_PAGE_INFO_PERMISSION_ALLOWED_BY_EXTENSION}, {"siteSettingsSourceExtensionBlock", @@ -3048,6 +1721,24 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, {"siteSettingsCookieSearch", IDS_SETTINGS_SITE_SETTINGS_COOKIE_SEARCH}, {"siteSettingsCookieSubpage", IDS_SETTINGS_SITE_SETTINGS_COOKIE_SUBPAGE}, {"siteSettingsDelete", IDS_SETTINGS_SITE_SETTINGS_DELETE}, + {"siteSettingsClearAllStorageDialogTitle", + IDS_SETTINGS_SITE_SETTINGS_CLEAR_ALL_STORAGE_DIALOG_TITLE}, + {"siteSettingsClearAllStorageDescription", + IDS_SETTINGS_SITE_SETTINGS_CLEAR_ALL_STORAGE_DESCRIPTION}, + {"siteSettingsClearAllStorageLabel", + IDS_SETTINGS_SITE_SETTINGS_CLEAR_ALL_STORAGE_LABEL}, + {"siteSettingsClearAllStorageConfirmation", + IDS_SETTINGS_SITE_SETTINGS_CLEAR_ALL_STORAGE_CONFIRMATION}, + {"siteSettingsClearAllStorageConfirmationInstalled", + IDS_SETTINGS_SITE_SETTINGS_CLEAR_ALL_STORAGE_CONFIRMATION_INSTALLED}, + {"siteSettingsClearAllStorageSignOut", + IDS_SETTINGS_SITE_SETTINGS_CLEAR_ALL_STORAGE_SIGN_OUT}, + {"siteSettingsOriginDeleteConfirmation", + IDS_SETTINGS_SITE_SETTINGS_ORIGIN_DELETE_CONFIRMATION}, + {"siteSettingsOriginDeleteConfirmationInstalled", + IDS_SETTINGS_SITE_SETTINGS_ORIGIN_DELETE_CONFIRMATION_INSTALLED}, + {"siteSettingsSiteGroupDeleteConfirmationInstalledPlural", + IDS_SETTINGS_SITE_SETTINGS_SITE_GROUP_DELETE_CONFIRMATION_INSTALLED_PLURAL}, {"siteSettingsSiteClearStorage", IDS_SETTINGS_SITE_SETTINGS_SITE_CLEAR_STORAGE}, {"siteSettingsSiteClearStorageConfirmation", @@ -3069,6 +1760,8 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, IDS_SETTINGS_SITE_SETTINGS_SITE_GROUP_DELETE_CONFIRMATION}, {"siteSettingsSiteGroupDeleteConfirmationNew", IDS_SETTINGS_SITE_SETTINGS_SITE_GROUP_DELETE_CONFIRMATION_NEW}, + {"siteSettingsSiteGroupDeleteConfirmationInstalled", + IDS_SETTINGS_SITE_SETTINGS_SITE_GROUP_DELETE_CONFIRMATION_INSTALLED}, {"siteSettingsSiteGroupDeleteSignOut", IDS_SETTINGS_SITE_SETTINGS_SITE_GROUP_DELETE_SIGN_OUT}, {"siteSettingsSiteGroupDeleteOfflineData", @@ -3083,18 +1776,17 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, {"siteSettingsSiteResetAll", IDS_SETTINGS_SITE_SETTINGS_SITE_RESET_ALL}, {"siteSettingsSiteResetConfirmation", IDS_SETTINGS_SITE_SETTINGS_SITE_RESET_CONFIRMATION}, - {"thirdPartyCookie", IDS_SETTINGS_SITE_SETTINGS_THIRD_PARTY_COOKIE}, - {"thirdPartyCookieSublabel", - IDS_SETTINGS_SITE_SETTINGS_THIRD_PARTY_COOKIE_SUBLABEL}, + {"thirdPartyCookie", IDS_NEW_TAB_OTR_THIRD_PARTY_COOKIE}, + {"thirdPartyCookieSublabel", IDS_NEW_TAB_OTR_THIRD_PARTY_COOKIE_SUBLABEL}, {"deleteDataPostSession", IDS_SETTINGS_SITE_SETTINGS_DELETE_DATA_POST_SESSION}, {"handlerIsDefault", IDS_SETTINGS_SITE_SETTINGS_HANDLER_IS_DEFAULT}, {"handlerSetDefault", IDS_SETTINGS_SITE_SETTINGS_HANDLER_SET_DEFAULT}, {"handlerRemove", IDS_SETTINGS_SITE_SETTINGS_REMOVE}, {"adobeFlashStorage", IDS_SETTINGS_SITE_SETTINGS_ADOBE_FLASH_SETTINGS}, - {"incognitoSite", IDS_SETTINGS_SITE_SETTINGS_INCOGNITO}, {"incognitoSiteOnly", IDS_SETTINGS_SITE_SETTINGS_INCOGNITO_ONLY}, - {"embeddedIncognitoSite", IDS_SETTINGS_SITE_SETTINGS_INCOGNITO_EMBEDDED}, + {"incognitoSiteExceptionDesc", + IDS_SETTINGS_SITE_SETTINGS_INCOGNITO_SITE_EXCEPTION_DESC}, {"noSitesAdded", IDS_SETTINGS_SITE_NO_SITES_ADDED}, {"siteSettingsAds", IDS_SETTINGS_SITE_SETTINGS_ADS}, {"siteSettingsAdsBlock", IDS_SETTINGS_SITE_SETTINGS_ADS_BLOCK}, @@ -3119,6 +1811,16 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, IDS_SETTINGS_SITE_SETTINGS_BLUETOOTH_SCANNING_ASK_RECOMMENDED}, {"siteSettingsBluetoothScanningBlock", IDS_SETTINGS_SITE_SETTINGS_BLUETOOTH_SCANNING_BLOCK}, + {"siteSettingsAr", IDS_SETTINGS_SITE_SETTINGS_AR}, + {"siteSettingsArAsk", IDS_SETTINGS_SITE_SETTINGS_AR_ASK}, + {"siteSettingsArAskRecommended", + IDS_SETTINGS_SITE_SETTINGS_AR_ASK_RECOMMENDED}, + {"siteSettingsArBlock", IDS_SETTINGS_SITE_SETTINGS_AR_BLOCK}, + {"siteSettingsVr", IDS_SETTINGS_SITE_SETTINGS_VR}, + {"siteSettingsVrAsk", IDS_SETTINGS_SITE_SETTINGS_VR_ASK}, + {"siteSettingsVrAskRecommended", + IDS_SETTINGS_SITE_SETTINGS_VR_ASK_RECOMMENDED}, + {"siteSettingsVrBlock", IDS_SETTINGS_SITE_SETTINGS_VR_BLOCK}, }; AddLocalizedStringsBulk(html_source, kLocalizedStrings); @@ -3187,25 +1889,15 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, html_source->AddBoolean( "enableQuietNotificationPromptsSetting", base::FeatureList::IsEnabled(features::kQuietNotificationPrompts)); -} -#if defined(OS_CHROMEOS) -void AddUsersStrings(content::WebUIDataSource* html_source) { - static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"usersModifiedByOwnerLabel", IDS_SETTINGS_USERS_MODIFIED_BY_OWNER_LABEL}, - {"guestBrowsingLabel", IDS_SETTINGS_USERS_GUEST_BROWSING_LABEL}, - {"settingsManagedLabel", IDS_SETTINGS_USERS_MANAGED_LABEL}, - {"showOnSigninLabel", IDS_SETTINGS_USERS_SHOW_ON_SIGNIN_LABEL}, - {"restrictSigninLabel", IDS_SETTINGS_USERS_RESTRICT_SIGNIN_LABEL}, - {"deviceOwnerLabel", IDS_SETTINGS_USERS_DEVICE_OWNER_LABEL}, - {"removeUserTooltip", IDS_SETTINGS_USERS_REMOVE_USER_TOOLTIP}, - {"addUsers", IDS_SETTINGS_USERS_ADD_USERS}, - {"addUsersEmail", IDS_SETTINGS_USERS_ADD_USERS_EMAIL}, - {"userExistsError", IDS_SETTINGS_USER_EXISTS_ERROR}, - }; - AddLocalizedStringsBulk(html_source, kLocalizedStrings); + html_source->AddBoolean("enableWebBluetoothNewPermissionsBackend", + base::FeatureList::IsEnabled( + features::kWebBluetoothNewPermissionsBackend)); + + html_source->AddBoolean( + "enableWebXrContentSetting", + base::FeatureList::IsEnabled(features::kWebXrPermissionsApi)); } -#endif #if !defined(OS_CHROMEOS) void AddSystemStrings(content::WebUIDataSource* html_source) { @@ -3237,110 +1929,6 @@ void AddSystemStrings(content::WebUIDataSource* html_source) { } #endif -void AddWebContentStrings(content::WebUIDataSource* html_source) { - static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"webContent", IDS_SETTINGS_WEB_CONTENT}, - {"pageZoom", IDS_SETTINGS_PAGE_ZOOM_LABEL}, - {"fontSize", IDS_SETTINGS_FONT_SIZE_LABEL}, - {"verySmall", IDS_SETTINGS_VERY_SMALL_FONT}, - {"small", IDS_SETTINGS_SMALL_FONT}, - {"medium", IDS_SETTINGS_MEDIUM_FONT}, - {"large", IDS_SETTINGS_LARGE_FONT}, - {"veryLarge", IDS_SETTINGS_VERY_LARGE_FONT}, - {"custom", IDS_SETTINGS_CUSTOM}, - {"customizeFonts", IDS_SETTINGS_CUSTOMIZE_FONTS}, - {"fonts", IDS_SETTINGS_FONTS}, - {"standardFont", IDS_SETTINGS_STANDARD_FONT_LABEL}, - {"serifFont", IDS_SETTINGS_SERIF_FONT_LABEL}, - {"sansSerifFont", IDS_SETTINGS_SANS_SERIF_FONT_LABEL}, - {"fixedWidthFont", IDS_SETTINGS_FIXED_WIDTH_FONT_LABEL}, - {"minimumFont", IDS_SETTINGS_MINIMUM_FONT_SIZE_LABEL}, - {"tiny", IDS_SETTINGS_TINY_FONT_SIZE}, - {"huge", IDS_SETTINGS_HUGE_FONT_SIZE}, - {"loremIpsum", IDS_SETTINGS_LOREM_IPSUM}, - {"loading", IDS_SETTINGS_LOADING}, - {"advancedFontSettings", IDS_SETTINGS_ADVANCED_FONT_SETTINGS}, - {"openAdvancedFontSettings", IDS_SETTINGS_OPEN_ADVANCED_FONT_SETTINGS}, - {"requiresWebStoreExtension", IDS_SETTINGS_REQUIRES_WEB_STORE_EXTENSION}, - {"quickBrownFox", IDS_SETTINGS_QUICK_BROWN_FOX}, - }; - AddLocalizedStringsBulk(html_source, kLocalizedStrings); -} - -#if defined(OS_CHROMEOS) -void AddMultideviceStrings(content::WebUIDataSource* html_source) { - static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"multidevicePageTitle", IDS_SETTINGS_MULTIDEVICE}, - {"multideviceSetupButton", IDS_SETTINGS_MULTIDEVICE_SETUP_BUTTON}, - {"multideviceVerifyButton", IDS_SETTINGS_MULTIDEVICE_VERIFY_BUTTON}, - {"multideviceSetupItemHeading", - IDS_SETTINGS_MULTIDEVICE_SETUP_ITEM_HEADING}, - {"multideviceEnabled", IDS_SETTINGS_MULTIDEVICE_ENABLED}, - {"multideviceDisabled", IDS_SETTINGS_MULTIDEVICE_DISABLED}, - {"multideviceSmartLockItemTitle", IDS_SETTINGS_EASY_UNLOCK_SECTION_TITLE}, - {"multideviceInstantTetheringItemTitle", - IDS_SETTINGS_MULTIDEVICE_INSTANT_TETHERING}, - {"multideviceInstantTetheringItemSummary", - IDS_SETTINGS_MULTIDEVICE_INSTANT_TETHERING_SUMMARY}, - {"multideviceAndroidMessagesItemTitle", - IDS_SETTINGS_MULTIDEVICE_ANDROID_MESSAGES}, - {"multideviceForgetDevice", IDS_SETTINGS_MULTIDEVICE_FORGET_THIS_DEVICE}, - {"multideviceSmartLockOptions", - IDS_SETTINGS_PEOPLE_LOCK_SCREEN_OPTIONS_LOCK}, - {"multideviceForgetDeviceDisconnect", - IDS_SETTINGS_MULTIDEVICE_FORGET_THIS_DEVICE_DISCONNECT}, - }; - AddLocalizedStringsBulk(html_source, kLocalizedStrings); - - html_source->AddString( - "multideviceForgetDeviceSummary", - ui::SubstituteChromeOSDeviceType( - IDS_SETTINGS_MULTIDEVICE_FORGET_THIS_DEVICE_EXPLANATION)); - html_source->AddString( - "multideviceForgetDeviceDialogMessage", - ui::SubstituteChromeOSDeviceType( - IDS_SETTINGS_MULTIDEVICE_FORGET_DEVICE_DIALOG_MESSAGE)); - html_source->AddString( - "multideviceVerificationText", - l10n_util::GetStringFUTF16( - IDS_SETTINGS_MULTIDEVICE_VERIFICATION_TEXT, - base::UTF8ToUTF16( - chromeos::multidevice_setup:: - GetBoardSpecificBetterTogetherSuiteLearnMoreUrl() - .spec()))); - html_source->AddString( - "multideviceSetupSummary", - l10n_util::GetStringFUTF16( - IDS_SETTINGS_MULTIDEVICE_SETUP_SUMMARY, ui::GetChromeOSDeviceName(), - base::UTF8ToUTF16( - chromeos::multidevice_setup:: - GetBoardSpecificBetterTogetherSuiteLearnMoreUrl() - .spec()))); - html_source->AddString( - "multideviceNoHostText", - l10n_util::GetStringFUTF16( - IDS_SETTINGS_MULTIDEVICE_NO_ELIGIBLE_HOSTS, - base::UTF8ToUTF16( - chromeos::multidevice_setup:: - GetBoardSpecificBetterTogetherSuiteLearnMoreUrl() - .spec()))); - html_source->AddString( - "multideviceAndroidMessagesItemSummary", - l10n_util::GetStringFUTF16( - IDS_SETTINGS_MULTIDEVICE_ANDROID_MESSAGES_SUMMARY, - ui::GetChromeOSDeviceName(), - base::UTF8ToUTF16(chromeos::multidevice_setup:: - GetBoardSpecificMessagesLearnMoreUrl() - .spec()))); - html_source->AddString( - "multideviceSmartLockItemSummary", - l10n_util::GetStringFUTF16( - IDS_SETTINGS_MULTIDEVICE_SMART_LOCK_SUMMARY, - ui::GetChromeOSDeviceName(), - GetHelpUrlWithBoard(chrome::kEasyUnlockLearnMoreUrl))); -} -#endif - void AddExtensionsStrings(content::WebUIDataSource* html_source) { html_source->AddLocalizedString("extensionsPageTitle", IDS_SETTINGS_EXTENSIONS_CHECKBOX_LABEL); @@ -3358,6 +1946,10 @@ void AddSecurityKeysStrings(content::WebUIDataSource* html_source) { IDS_SETTINGS_SECURITY_KEYS_BIO_ENROLLMENT_ENROLLING_COMPLETE_LABEL}, {"securityKeysBioEnrollmentEnrollingLabel", IDS_SETTINGS_SECURITY_KEYS_BIO_ENROLLMENT_ENROLLING_LABEL}, + {"securityKeysBioEnrollmentEnrollingFailedLabel", + IDS_SETTINGS_SECURITY_KEYS_BIO_ENROLLMENT_FAILED_LABEL}, + {"securityKeysBioEnrollmentTryAgainLabel", + IDS_SETTINGS_SECURITY_KEYS_BIO_ENROLLMENT_TRY_AGAIN_LABEL}, {"securityKeysBioEnrollmentEnrollmentsLabel", IDS_SETTINGS_SECURITY_KEYS_BIO_ENROLLMENT_ENROLLMENTS_LABEL}, {"securityKeysBioEnrollmentNoEnrollmentsLabel", @@ -3453,11 +2045,11 @@ void AddSecurityKeysStrings(content::WebUIDataSource* html_source) { } // namespace -void AddLocalizedStrings(content::WebUIDataSource* html_source, - Profile* profile, - content::WebContents* web_contents) { +void AddBrowserLocalizedStrings(content::WebUIDataSource* html_source, + Profile* profile, + content::WebContents* web_contents) { AddA11yStrings(html_source); - AddAboutStrings(html_source); + AddAboutStrings(html_source, profile); AddAutofillStrings(html_source, profile, web_contents); AddAppearanceStrings(html_source, profile); @@ -3466,41 +2058,22 @@ void AddLocalizedStrings(content::WebUIDataSource* html_source, AddIncompatibleApplicationsStrings(html_source); #endif // defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - AddChangePasswordStrings(html_source); AddClearBrowsingDataStrings(html_source, profile); AddCommonStrings(html_source, profile); AddDownloadsStrings(html_source); - AddLanguagesStrings(html_source); + AddLanguagesStrings(html_source, profile); AddOnStartupStrings(html_source); AddPeopleStrings(html_source, profile); AddPrintingStrings(html_source); AddPrivacyStrings(html_source, profile); AddResetStrings(html_source); AddSearchEnginesStrings(html_source); -#if defined(OS_CHROMEOS) - AddGoogleAssistantStrings(html_source, profile); -#endif AddSearchInSettingsStrings(html_source); - AddSearchStrings(html_source, profile); + AddSearchStrings(html_source); AddSiteSettingsStrings(html_source, profile); - AddWebContentStrings(html_source); #if defined(OS_CHROMEOS) - AddAndroidAppStrings(html_source); - AddAppManagementStrings(html_source); - AddAppsStrings(html_source); - AddBluetoothStrings(html_source); AddChromeOSUserStrings(html_source, profile); - AddCrostiniStrings(html_source, profile); - AddDateTimeStrings(html_source); - AddDeviceStrings(html_source); - AddEasyUnlockStrings(html_source); - AddFilesStrings(html_source); - AddInternetStrings(html_source); - AddMultideviceStrings(html_source); - AddParentalControlStrings(html_source); - AddPluginVmStrings(html_source, profile); - AddUsersStrings(html_source); #else AddDefaultBrowserStrings(html_source); AddImportDataStrings(html_source); @@ -3512,13 +2085,6 @@ void AddLocalizedStrings(content::WebUIDataSource* html_source, certificate_manager::AddLocalizedStrings(html_source); #endif -#if defined(OS_CHROMEOS) - chromeos::network_element::AddLocalizedStrings(html_source); - chromeos::network_element::AddOncLocalizedStrings(html_source); - chromeos::network_element::AddDetailsLocalizedStrings(html_source); - chromeos::network_element::AddConfigLocalizedStrings(html_source); - chromeos::network_element::AddErrorLocalizedStrings(html_source); -#endif policy_indicator::AddLocalizedStrings(html_source); AddSecurityKeysStrings(html_source); diff --git a/chromium/chrome/browser/ui/webui/settings/settings_localized_strings_provider.h b/chromium/chrome/browser/ui/webui/settings/settings_localized_strings_provider.h index a72290f479f..0940dc5a24e 100644 --- a/chromium/chrome/browser/ui/webui/settings/settings_localized_strings_provider.h +++ b/chromium/chrome/browser/ui/webui/settings/settings_localized_strings_provider.h @@ -14,12 +14,14 @@ class WebContents; namespace settings { -// Adds the strings needed by the settings page to |html_source|. This function -// causes |html_source| to expose a strings.js file from its source which -// contains a mapping from string's name to its translated value. -void AddLocalizedStrings(content::WebUIDataSource* html_source, - Profile* profile, - content::WebContents* web_contents); +// Adds the strings needed by the browser settings page to |html_source| +// This function causes |html_source| to expose a strings.js file from its +// source which contains a mapping from string's name to its translated value. +// TODO(crbug/967888): This still contains OS Settings strings. Strings specific +// to OS settings should be moved to os_settings_localized_strings_provider.cc. +void AddBrowserLocalizedStrings(content::WebUIDataSource* html_source, + Profile* profile, + content::WebContents* web_contents); } // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/settings_secure_dns_handler.cc b/chromium/chrome/browser/ui/webui/settings/settings_secure_dns_handler.cc new file mode 100644 index 00000000000..0ba238f7959 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/settings_secure_dns_handler.cc @@ -0,0 +1,314 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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_secure_dns_handler.h" + +#include <memory> +#include <utility> + +#include "base/bind.h" +#include "base/metrics/histogram_macros.h" +#include "base/rand_util.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/net/dns_util.h" +#include "chrome/browser/net/stub_resolver_config_reader.h" +#include "chrome/browser/net/system_network_context_manager.h" +#include "chrome/common/chrome_features.h" +#include "chrome/common/pref_names.h" +#include "chrome/grit/generated_resources.h" +#include "components/country_codes/country_codes.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/storage_partition.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_ui.h" +#include "net/dns/public/dns_over_https_server_config.h" +#include "net/dns/public/doh_provider_list.h" +#include "net/dns/public/util.h" +#include "ui/base/l10n/l10n_util.h" + +namespace settings { + +namespace { + +const char kProbeHostname[] = "google.com"; + +std::unique_ptr<base::DictionaryValue> CreateSecureDnsSettingDict() { + // Fetch the current host resolver configuration. It is not sufficient to read + // the secure DNS prefs directly since the host resolver configuration takes + // other factors into account such as whether a managed environment or + // parental controls have been detected. + bool insecure_stub_resolver_enabled = false; + net::DnsConfig::SecureDnsMode secure_dns_mode; + std::vector<net::DnsOverHttpsServerConfig> dns_over_https_servers; + chrome_browser_net::SecureDnsUiManagementMode management_mode; + SystemNetworkContextManager::GetStubResolverConfigReader()->GetConfiguration( + true /* force_check_parental_controls_for_automatic_mode */, + &insecure_stub_resolver_enabled, &secure_dns_mode, + &dns_over_https_servers, &management_mode); + + std::string secure_dns_mode_str; + switch (secure_dns_mode) { + case net::DnsConfig::SecureDnsMode::SECURE: + secure_dns_mode_str = chrome_browser_net::kDnsOverHttpsModeSecure; + break; + case net::DnsConfig::SecureDnsMode::AUTOMATIC: + secure_dns_mode_str = chrome_browser_net::kDnsOverHttpsModeAutomatic; + break; + case net::DnsConfig::SecureDnsMode::OFF: + secure_dns_mode_str = chrome_browser_net::kDnsOverHttpsModeOff; + break; + default: + NOTREACHED(); + } + + auto secure_dns_templates = std::make_unique<base::ListValue>(); + for (const auto& doh_server : dns_over_https_servers) { + secure_dns_templates->Append(doh_server.server_template); + } + + auto dict = std::make_unique<base::DictionaryValue>(); + dict->SetString("mode", secure_dns_mode_str); + dict->SetList("templates", std::move(secure_dns_templates)); + dict->SetInteger("managementMode", static_cast<int>(management_mode)); + return dict; +} + +} // namespace + +SecureDnsHandler::SecureDnsHandler() = default; + +SecureDnsHandler::~SecureDnsHandler() = default; + +void SecureDnsHandler::RegisterMessages() { + web_ui()->RegisterMessageCallback( + "getSecureDnsResolverList", + base::BindRepeating(&SecureDnsHandler::HandleGetSecureDnsResolverList, + base::Unretained(this))); + + web_ui()->RegisterMessageCallback( + "getSecureDnsSetting", + base::BindRepeating(&SecureDnsHandler::HandleGetSecureDnsSetting, + base::Unretained(this))); + + web_ui()->RegisterMessageCallback( + "validateCustomDnsEntry", + base::BindRepeating(&SecureDnsHandler::HandleValidateCustomDnsEntry, + base::Unretained(this))); + + web_ui()->RegisterMessageCallback( + "probeCustomDnsTemplate", + base::BindRepeating(&SecureDnsHandler::HandleProbeCustomDnsTemplate, + base::Unretained(this))); + + web_ui()->RegisterMessageCallback( + "recordUserDropdownInteraction", + base::BindRepeating( + &SecureDnsHandler::HandleRecordUserDropdownInteraction, + base::Unretained(this))); +} + +void SecureDnsHandler::OnJavascriptAllowed() { + // Register for updates to the underlying secure DNS prefs so that the + // secure DNS setting can be updated to reflect the current host resolver + // configuration. + pref_registrar_.Init(g_browser_process->local_state()); + pref_registrar_.Add( + prefs::kDnsOverHttpsMode, + base::Bind(&SecureDnsHandler::SendSecureDnsSettingUpdatesToJavascript, + base::Unretained(this))); + pref_registrar_.Add( + prefs::kDnsOverHttpsTemplates, + base::Bind(&SecureDnsHandler::SendSecureDnsSettingUpdatesToJavascript, + base::Unretained(this))); +} + +void SecureDnsHandler::OnJavascriptDisallowed() { + pref_registrar_.RemoveAll(); +} + +base::Value SecureDnsHandler::GetSecureDnsResolverListForCountry( + int country_id, + const std::vector<net::DohProviderEntry>& providers) { + std::vector<std::string> disabled_providers = + SplitString(features::kDnsOverHttpsDisabledProvidersParam.Get(), ",", + base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + + base::Value resolvers(base::Value::Type::LIST); + resolver_histogram_map_.clear(); + // Add all non-disabled resolvers that should be displayed in |country_id|. + for (const auto& entry : providers) { + if (base::Contains(disabled_providers, entry.provider)) + continue; + + if (entry.display_globally || + std::find_if( + entry.display_countries.begin(), entry.display_countries.end(), + [&country_id](const std::string& country_code) { + return country_codes::CountryCharsToCountryID( + country_code[0], country_code[1]) == country_id; + }) != entry.display_countries.end()) { + DCHECK(!entry.ui_name.empty()); + DCHECK(!entry.privacy_policy.empty()); + base::Value dict(base::Value::Type::DICTIONARY); + dict.SetKey("name", base::Value(entry.ui_name)); + dict.SetKey("value", base::Value(entry.dns_over_https_template)); + dict.SetKey("policy", base::Value(entry.privacy_policy)); + resolvers.Append(std::move(dict)); + DCHECK(entry.provider_id_for_histogram.has_value()); + resolver_histogram_map_.insert({entry.dns_over_https_template, + entry.provider_id_for_histogram.value()}); + } + } + + // Randomize the order of the resolvers. + base::RandomShuffle(resolvers.GetList().begin(), resolvers.GetList().end()); + + // Add a custom option to the front of the list + base::Value custom(base::Value::Type::DICTIONARY); + custom.SetKey("name", + base::Value(l10n_util::GetStringUTF8(IDS_SETTINGS_CUSTOM))); + custom.SetKey("value", base::Value("custom")); + custom.SetKey("policy", base::Value(std::string())); + resolvers.Insert(resolvers.GetList().begin(), std::move(custom)); + resolver_histogram_map_.insert( + {"custom", net::DohProviderIdForHistogram::kCustom}); + + return resolvers; +} + +void SecureDnsHandler::SetNetworkContextForTesting( + network::mojom::NetworkContext* network_context) { + network_context_for_testing_ = network_context; +} + +void SecureDnsHandler::HandleGetSecureDnsResolverList( + const base::ListValue* args) { + AllowJavascript(); + std::string callback_id = args->GetList()[0].GetString(); + + ResolveJavascriptCallback( + base::Value(callback_id), + GetSecureDnsResolverListForCountry(country_codes::GetCurrentCountryID(), + net::GetDohProviderList())); +} + +void SecureDnsHandler::HandleGetSecureDnsSetting(const base::ListValue* args) { + AllowJavascript(); + CHECK_EQ(1u, args->GetList().size()); + const base::Value& callback_id = args->GetList()[0]; + ResolveJavascriptCallback(callback_id, *CreateSecureDnsSettingDict()); +} + +void SecureDnsHandler::HandleValidateCustomDnsEntry( + const base::ListValue* args) { + AllowJavascript(); + const base::Value* callback_id; + std::string custom_entry; + CHECK(args->Get(0, &callback_id)); + CHECK(args->GetString(1, &custom_entry)); + + // Return the first template, or none if the entry is invalid. + std::string first_template; + bool valid = !custom_entry.empty() && + chrome_browser_net::IsValidDohTemplateGroup(custom_entry); + if (valid) { + first_template = + std::string(chrome_browser_net::SplitDohTemplateGroup(custom_entry)[0]); + } + UMA_HISTOGRAM_BOOLEAN("Net.DNS.UI.ValidationAttemptSuccess", valid); + ResolveJavascriptCallback(*callback_id, base::Value(first_template)); +} + +void SecureDnsHandler::HandleProbeCustomDnsTemplate( + const base::ListValue* args) { + AllowJavascript(); + receiver_.reset(); + host_resolver_.reset(); + + std::string server_template; + CHECK(args->GetString(0, &probe_callback_id_)); + CHECK(args->GetString(1, &server_template)); + + net::DnsConfigOverrides overrides; + overrides.search = std::vector<std::string>(); + overrides.attempts = 1; + overrides.randomize_ports = false; + overrides.secure_dns_mode = net::DnsConfig::SecureDnsMode::SECURE; + std::string server_method; + // We only send probe queries to templates that have already passed a format + // validation check. + CHECK(net::dns_util::IsValidDohTemplate(server_template, &server_method)); + overrides.dns_over_https_servers.emplace({net::DnsOverHttpsServerConfig( + server_template, server_method == "POST")}); + auto* network_context = + network_context_for_testing_ + ? network_context_for_testing_ + : content::BrowserContext::GetDefaultStoragePartition( + web_ui()->GetWebContents()->GetBrowserContext()) + ->GetNetworkContext(); + network_context->CreateHostResolver( + overrides, host_resolver_.BindNewPipeAndPassReceiver()); + + network::mojom::ResolveHostParametersPtr parameters = + network::mojom::ResolveHostParameters::New(); + parameters->dns_query_type = net::DnsQueryType::A; + parameters->source = net::HostResolverSource::DNS; + parameters->cache_usage = + network::mojom::ResolveHostParameters::CacheUsage::DISALLOWED; + host_resolver_->ResolveHost(net::HostPortPair(kProbeHostname, 80), + net::NetworkIsolationKey::CreateTransient(), + std::move(parameters), + receiver_.BindNewPipeAndPassRemote()); + receiver_.set_disconnect_handler(base::BindOnce( + &SecureDnsHandler::OnMojoConnectionError, base::Unretained(this))); +} + +void SecureDnsHandler::HandleRecordUserDropdownInteraction( + const base::ListValue* args) { + CHECK_EQ(2U, args->GetSize()); + std::string old_provider; + std::string new_provider; + CHECK(args->GetString(0, &old_provider)); + CHECK(args->GetString(1, &new_provider)); + DCHECK(resolver_histogram_map_.find(old_provider) != + resolver_histogram_map_.end()); + DCHECK(resolver_histogram_map_.find(new_provider) != + resolver_histogram_map_.end()); + for (auto& pair : resolver_histogram_map_) { + if (pair.first == old_provider) { + UMA_HISTOGRAM_ENUMERATION("Net.DNS.UI.DropdownSelectionEvent.Unselected", + pair.second); + } else if (pair.first == new_provider) { + UMA_HISTOGRAM_ENUMERATION("Net.DNS.UI.DropdownSelectionEvent.Selected", + pair.second); + } else { + UMA_HISTOGRAM_ENUMERATION("Net.DNS.UI.DropdownSelectionEvent.Ignored", + pair.second); + } + } +} + +// network::ResolveHostClientBase impl: +void SecureDnsHandler::OnComplete( + int result, + const net::ResolveErrorInfo& resolve_error_info, + const base::Optional<net::AddressList>& resolved_addresses) { + receiver_.reset(); + host_resolver_.reset(); + UMA_HISTOGRAM_BOOLEAN("Net.DNS.UI.ProbeAttemptSuccess", (result == 0)); + ResolveJavascriptCallback(base::Value(probe_callback_id_), + base::Value(result == 0)); +} + +void SecureDnsHandler::OnMojoConnectionError() { + OnComplete(net::ERR_NAME_NOT_RESOLVED, net::ResolveErrorInfo(net::ERR_FAILED), + base::nullopt); +} + +void SecureDnsHandler::SendSecureDnsSettingUpdatesToJavascript() { + FireWebUIListener("secure-dns-setting-changed", + *CreateSecureDnsSettingDict()); +} + +} // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/settings_secure_dns_handler.h b/chromium/chrome/browser/ui/webui/settings/settings_secure_dns_handler.h new file mode 100644 index 00000000000..ed68ee5b664 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/settings_secure_dns_handler.h @@ -0,0 +1,89 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_SECURE_DNS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_SECURE_DNS_HANDLER_H_ + +#include <map> +#include <string> +#include <vector> + +#include "base/macros.h" +#include "base/values.h" +#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" +#include "components/prefs/pref_change_registrar.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "net/dns/public/doh_provider_list.h" +#include "services/network/public/cpp/resolve_host_client_base.h" +#include "services/network/public/mojom/host_resolver.mojom.h" +#include "services/network/public/mojom/network_context.mojom.h" + +namespace settings { + +// Handler for the Secure DNS setting. +class SecureDnsHandler : public SettingsPageUIHandler, + network::ResolveHostClientBase { + public: + SecureDnsHandler(); + ~SecureDnsHandler() override; + + // SettingsPageUIHandler: + void RegisterMessages() override; + void OnJavascriptAllowed() override; + void OnJavascriptDisallowed() override; + + // Get the list of dropdown resolver options. Each option is represented + // as a dictionary with the following keys: "name" (the text to display in the + // UI), "value" (the DoH template for this provider), and "policy" (the URL of + // the provider's privacy policy). + base::Value GetSecureDnsResolverListForCountry( + int country_id, + const std::vector<net::DohProviderEntry>& providers); + + void SetNetworkContextForTesting( + network::mojom::NetworkContext* network_context); + + protected: + // Retrieves all pre-approved secure resolvers and returns them to WebUI. + void HandleGetSecureDnsResolverList(const base::ListValue* args); + + // Intended to be called once upon creation of the secure DNS setting. + void HandleGetSecureDnsSetting(const base::ListValue* args); + + // Returns the first template if a custom entry is valid. + void HandleValidateCustomDnsEntry(const base::ListValue* args); + + // Returns whether or not a test query to the resolver succeeds. + void HandleProbeCustomDnsTemplate(const base::ListValue* args); + + // Records metrics on the user-initiated dropdown selection event. + void HandleRecordUserDropdownInteraction(const base::ListValue* args); + + // Retrieves the current host resolver configuration, computes the + // corresponding UI representation, and sends it to javascript. + void SendSecureDnsSettingUpdatesToJavascript(); + + private: + // network::ResolveHostClientBase impl: + void OnComplete( + int result, + const net::ResolveErrorInfo& resolve_error_info, + const base::Optional<net::AddressList>& resolved_addresses) override; + + void OnMojoConnectionError(); + + std::map<std::string, net::DohProviderIdForHistogram> resolver_histogram_map_; + network::mojom::NetworkContext* network_context_for_testing_ = nullptr; + mojo::Receiver<network::mojom::ResolveHostClient> receiver_{this}; + mojo::Remote<network::mojom::HostResolver> host_resolver_; + std::string probe_callback_id_; + PrefChangeRegistrar pref_registrar_; + + DISALLOW_COPY_AND_ASSIGN(SecureDnsHandler); +}; + +} // namespace settings + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_SECURE_DNS_HANDLER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc b/chromium/chrome/browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc new file mode 100644 index 00000000000..c57dde40d12 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc @@ -0,0 +1,609 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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_secure_dns_handler.h" + +#include "base/test/metrics/histogram_tester.h" +#include "build/build_config.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/net/dns_probe_test_util.h" +#include "chrome/browser/net/dns_util.h" +#include "chrome/common/chrome_features.h" +#include "chrome/common/pref_names.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "components/country_codes/country_codes.h" +#include "components/policy/core/browser/browser_policy_connector.h" +#include "components/policy/core/common/mock_configuration_policy_provider.h" +#include "components/policy/policy_constants.h" +#include "components/prefs/pref_service.h" +#include "content/public/test/test_web_ui.h" +#include "net/dns/public/resolve_error_info.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +#if defined(OS_WIN) +#include "base/win/win_util.h" +#endif + +using net::DohProviderEntry; +using testing::_; +using testing::Return; + +namespace settings { + +namespace { + +constexpr char kGetSecureDnsResolverList[] = "getSecureDnsResolverList"; +constexpr char kValidateCustomDnsEntry[] = "validateCustomDnsEntry"; +constexpr char kProbeCustomDnsTemplate[] = "probeCustomDnsTemplate"; +constexpr char kRecordUserDropdownInteraction[] = + "recordUserDropdownInteraction"; +constexpr char kWebUiFunctionName[] = "webUiCallbackName"; + +const std::vector<DohProviderEntry>& GetDohProviderListForTesting() { + static const base::NoDestructor<std::vector<DohProviderEntry>> test_providers{ + { + DohProviderEntry( + "Provider_Global1", net::DohProviderIdForHistogram(-1), + {} /*ip_strs */, {} /* dot_hostnames */, + "https://global1.provider/dns-query{?dns}", + "Global Provider 1" /* ui_name */, + "https://global1.provider/privacy_policy/" /* privacy_policy */, + true /* display_globally */, {} /* display_countries */), + DohProviderEntry( + "Provider_NoDisplay", net::DohProviderIdForHistogram(-2), + {} /*ip_strs */, {} /* dot_hostnames */, + "https://nodisplay.provider/dns-query{?dns}", + "No Display Provider" /* ui_name */, + "https://nodisplay.provider/privacy_policy/" /* privacy_policy */, + false /* display_globally */, {} /* display_countries */), + DohProviderEntry( + "Provider_EE_FR", net::DohProviderIdForHistogram(-3), + {} /*ip_strs */, {} /* dot_hostnames */, + "https://ee.fr.provider/dns-query{?dns}", + "EE/FR Provider" /* ui_name */, + "https://ee.fr.provider/privacy_policy/" /* privacy_policy */, + false /* display_globally */, + {"EE", "FR"} /* display_countries */), + DohProviderEntry( + "Provider_FR", net::DohProviderIdForHistogram(-4), + {} /*ip_strs */, {} /* dot_hostnames */, + "https://fr.provider/dns-query{?dns}", + "FR Provider" /* ui_name */, + "https://fr.provider/privacy_policy/" /* privacy_policy */, + false /* display_globally */, {"FR"} /* display_countries */), + DohProviderEntry( + "Provider_Global2", net::DohProviderIdForHistogram(-5), + {} /*ip_strs */, {} /* dot_hostnames */, + "https://global2.provider/dns-query{?dns}", + "Global Provider 2" /* ui_name */, + "https://global2.provider/privacy_policy/" /* privacy_policy */, + true /* display_globally */, {} /* display_countries */), + }}; + return *test_providers; +} + +bool FindDropdownItem(const base::Value& resolvers, + const std::string& name, + const std::string& value, + const std::string& policy) { + base::Value dict(base::Value::Type::DICTIONARY); + dict.SetKey("name", base::Value(name)); + dict.SetKey("value", base::Value(value)); + dict.SetKey("policy", base::Value(policy)); + + return std::find(resolvers.GetList().begin(), resolvers.GetList().end(), + dict) != resolvers.GetList().end(); +} + +} // namespace + +class TestSecureDnsHandler : public SecureDnsHandler { + public: + // Pull WebUIMessageHandler::set_web_ui() into public so tests can call it. + using SecureDnsHandler::set_web_ui; +}; + +class SecureDnsHandlerTest : public InProcessBrowserTest { + protected: +#if defined(OS_WIN) + SecureDnsHandlerTest() + // Mark as not enterprise managed to prevent the secure DNS mode from + // being downgraded to off. + : scoped_domain_(false) {} +#else + SecureDnsHandlerTest() = default; +#endif + ~SecureDnsHandlerTest() override = default; + + // InProcessBrowserTest: + void SetUpInProcessBrowserTestFixture() override { + // Initialize user policy. + ON_CALL(provider_, IsInitializationComplete(_)).WillByDefault(Return(true)); + policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_); + } + + void SetUpOnMainThread() override { + handler_ = std::make_unique<TestSecureDnsHandler>(); + handler_->set_web_ui(&web_ui_); + handler_->RegisterMessages(); + handler_->AllowJavascriptForTesting(); + base::RunLoop().RunUntilIdle(); + } + + void TearDownOnMainThread() override { handler_.reset(); } + + // Updates out-params from the last message sent to WebUI about a secure DNS + // change. Returns false if the message was invalid or not found. + bool GetLastSettingsChangedMessage( + std::string* secure_dns_mode, + std::vector<std::string>* secure_dns_templates, + int* management_mode) { + for (auto it = web_ui_.call_data().rbegin(); + it != web_ui_.call_data().rend(); ++it) { + const content::TestWebUI::CallData* data = it->get(); + if (data->function_name() != "cr.webUIListenerCallback" || + !data->arg1()->is_string() || + data->arg1()->GetString() != "secure-dns-setting-changed") { + continue; + } + + const base::DictionaryValue* dict = nullptr; + if (!data->arg2()->GetAsDictionary(&dict)) + return false; + + // Get the secure DNS mode. + if (!dict->FindStringPath("mode")) + return false; + *secure_dns_mode = *dict->FindStringPath("mode"); + + // Get the secure DNS templates. + if (!dict->FindListPath("templates")) + return false; + secure_dns_templates->clear(); + for (const auto& template_str : + dict->FindListPath("templates")->GetList()) { + if (!template_str.is_string()) + return false; + secure_dns_templates->push_back(template_str.GetString()); + } + + // Get the forced management description. + if (!dict->FindIntPath("managementMode")) + return false; + *management_mode = *dict->FindIntPath("managementMode"); + + return true; + } + return false; + } + + // Sets a policy update which will cause power pref managed change. + void SetPolicyForPolicyKey(policy::PolicyMap* policy_map, + const std::string& policy_key, + std::unique_ptr<base::Value> value) { + policy_map->Set(policy_key, policy::POLICY_LEVEL_MANDATORY, + policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD, + std::move(value), nullptr); + provider_.UpdateChromePolicy(*policy_map); + base::RunLoop().RunUntilIdle(); + } + + std::unique_ptr<TestSecureDnsHandler> handler_; + content::TestWebUI web_ui_; + policy::MockConfigurationPolicyProvider provider_; + + private: +#if defined(OS_WIN) + base::win::ScopedDomainStateForTesting scoped_domain_; +#endif + + DISALLOW_COPY_AND_ASSIGN(SecureDnsHandlerTest); +}; + +IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, SecureDnsModes) { + PrefService* local_state = g_browser_process->local_state(); + std::string secure_dns_mode; + std::vector<std::string> secure_dns_templates; + int management_mode; + + local_state->SetString(prefs::kDnsOverHttpsMode, + chrome_browser_net::kDnsOverHttpsModeOff); + EXPECT_TRUE(GetLastSettingsChangedMessage( + &secure_dns_mode, &secure_dns_templates, &management_mode)); + EXPECT_EQ(chrome_browser_net::kDnsOverHttpsModeOff, secure_dns_mode); + + local_state->SetString(prefs::kDnsOverHttpsMode, + chrome_browser_net::kDnsOverHttpsModeAutomatic); + EXPECT_TRUE(GetLastSettingsChangedMessage( + &secure_dns_mode, &secure_dns_templates, &management_mode)); + EXPECT_EQ(chrome_browser_net::kDnsOverHttpsModeAutomatic, secure_dns_mode); + + local_state->SetString(prefs::kDnsOverHttpsMode, + chrome_browser_net::kDnsOverHttpsModeSecure); + EXPECT_TRUE(GetLastSettingsChangedMessage( + &secure_dns_mode, &secure_dns_templates, &management_mode)); + EXPECT_EQ(chrome_browser_net::kDnsOverHttpsModeSecure, secure_dns_mode); + + local_state->SetString(prefs::kDnsOverHttpsMode, "unknown"); + EXPECT_TRUE(GetLastSettingsChangedMessage( + &secure_dns_mode, &secure_dns_templates, &management_mode)); + EXPECT_EQ(chrome_browser_net::kDnsOverHttpsModeOff, secure_dns_mode); +} + +IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, SecureDnsPolicy) { + policy::PolicyMap policy_map; + SetPolicyForPolicyKey(&policy_map, policy::key::kDnsOverHttpsMode, + std::make_unique<base::Value>( + chrome_browser_net::kDnsOverHttpsModeAutomatic)); + + PrefService* local_state = g_browser_process->local_state(); + local_state->SetString(prefs::kDnsOverHttpsMode, + chrome_browser_net::kDnsOverHttpsModeSecure); + + std::string secure_dns_mode; + std::vector<std::string> secure_dns_templates; + int management_mode; + EXPECT_TRUE(GetLastSettingsChangedMessage( + &secure_dns_mode, &secure_dns_templates, &management_mode)); + EXPECT_EQ(chrome_browser_net::kDnsOverHttpsModeAutomatic, secure_dns_mode); + EXPECT_EQ(static_cast<int>( + chrome_browser_net::SecureDnsUiManagementMode::kNoOverride), + management_mode); +} + +IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, SecureDnsPolicyChange) { + policy::PolicyMap policy_map; + SetPolicyForPolicyKey(&policy_map, policy::key::kDnsOverHttpsMode, + std::make_unique<base::Value>( + chrome_browser_net::kDnsOverHttpsModeAutomatic)); + + std::string secure_dns_mode; + std::vector<std::string> secure_dns_templates; + int management_mode; + EXPECT_TRUE(GetLastSettingsChangedMessage( + &secure_dns_mode, &secure_dns_templates, &management_mode)); + EXPECT_EQ(chrome_browser_net::kDnsOverHttpsModeAutomatic, secure_dns_mode); + EXPECT_EQ(static_cast<int>( + chrome_browser_net::SecureDnsUiManagementMode::kNoOverride), + management_mode); + + SetPolicyForPolicyKey( + &policy_map, policy::key::kDnsOverHttpsMode, + std::make_unique<base::Value>(chrome_browser_net::kDnsOverHttpsModeOff)); + EXPECT_TRUE(GetLastSettingsChangedMessage( + &secure_dns_mode, &secure_dns_templates, &management_mode)); + EXPECT_EQ(chrome_browser_net::kDnsOverHttpsModeOff, secure_dns_mode); + EXPECT_EQ(static_cast<int>( + chrome_browser_net::SecureDnsUiManagementMode::kNoOverride), + management_mode); +} + +// On platforms where enterprise policies do not have default values, test +// that DoH is disabled when non-DoH policies are set. +#if !defined(OS_CHROMEOS) +IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, OtherPoliciesSet) { + policy::PolicyMap policy_map; + SetPolicyForPolicyKey(&policy_map, policy::key::kIncognitoModeAvailability, + std::make_unique<base::Value>(1)); + + PrefService* local_state = g_browser_process->local_state(); + local_state->SetString(prefs::kDnsOverHttpsMode, + chrome_browser_net::kDnsOverHttpsModeSecure); + + std::string secure_dns_mode; + std::vector<std::string> secure_dns_templates; + int management_mode; + EXPECT_TRUE(GetLastSettingsChangedMessage( + &secure_dns_mode, &secure_dns_templates, &management_mode)); + EXPECT_EQ(chrome_browser_net::kDnsOverHttpsModeOff, secure_dns_mode); + EXPECT_EQ( + static_cast<int>( + chrome_browser_net::SecureDnsUiManagementMode::kDisabledManaged), + management_mode); +} +#endif + +// This test makes no assumptions about the country or underlying resolver list. +IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, DropdownList) { + base::ListValue args; + args.AppendString(kWebUiFunctionName); + + web_ui_.HandleReceivedMessage(kGetSecureDnsResolverList, &args); + const content::TestWebUI::CallData& call_data = *web_ui_.call_data().back(); + EXPECT_EQ("cr.webUIResponse", call_data.function_name()); + EXPECT_EQ(kWebUiFunctionName, call_data.arg1()->GetString()); + ASSERT_TRUE(call_data.arg2()->GetBool()); + + // Check results. + base::Value::ConstListView resolver_list = call_data.arg3()->GetList(); + ASSERT_GE(resolver_list.size(), 1U); + EXPECT_EQ("custom", resolver_list[0].FindKey("value")->GetString()); +} + +IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, DropdownListForCountry) { + // The 'EE' list should start with the custom entry, followed by the two + // global providers and the 'EE' provider in some random order. + base::Value resolver_list = handler_->GetSecureDnsResolverListForCountry( + country_codes::CountryCharsToCountryID('E', 'E'), + GetDohProviderListForTesting()); + EXPECT_EQ(4u, resolver_list.GetList().size()); + EXPECT_EQ("custom", resolver_list.GetList()[0].FindKey("value")->GetString()); + EXPECT_TRUE(FindDropdownItem(resolver_list, "Global Provider 1", + "https://global1.provider/dns-query{?dns}", + "https://global1.provider/privacy_policy/")); + EXPECT_TRUE(FindDropdownItem(resolver_list, "Global Provider 2", + "https://global2.provider/dns-query{?dns}", + "https://global2.provider/privacy_policy/")); + EXPECT_TRUE(FindDropdownItem(resolver_list, "EE/FR Provider", + "https://ee.fr.provider/dns-query{?dns}", + "https://ee.fr.provider/privacy_policy/")); + + // The 'FR' list should start with the custom entry, followed by the two + // global providers and the two 'FR' providers in some random order. + resolver_list = handler_->GetSecureDnsResolverListForCountry( + country_codes::CountryCharsToCountryID('F', 'R'), + GetDohProviderListForTesting()); + EXPECT_EQ(5u, resolver_list.GetList().size()); + EXPECT_EQ("custom", resolver_list.GetList()[0].FindKey("value")->GetString()); + EXPECT_TRUE(FindDropdownItem(resolver_list, "Global Provider 1", + "https://global1.provider/dns-query{?dns}", + "https://global1.provider/privacy_policy/")); + EXPECT_TRUE(FindDropdownItem(resolver_list, "Global Provider 2", + "https://global2.provider/dns-query{?dns}", + "https://global2.provider/privacy_policy/")); + EXPECT_TRUE(FindDropdownItem(resolver_list, "EE/FR Provider", + "https://ee.fr.provider/dns-query{?dns}", + "https://ee.fr.provider/privacy_policy/")); + EXPECT_TRUE(FindDropdownItem(resolver_list, "FR Provider", + "https://fr.provider/dns-query{?dns}", + "https://fr.provider/privacy_policy/")); + + // The 'CA' list should start with the custom entry, followed by the two + // global providers. + resolver_list = handler_->GetSecureDnsResolverListForCountry( + country_codes::CountryCharsToCountryID('C', 'A'), + GetDohProviderListForTesting()); + EXPECT_EQ(3u, resolver_list.GetList().size()); + EXPECT_EQ("custom", resolver_list.GetList()[0].FindKey("value")->GetString()); + EXPECT_TRUE(FindDropdownItem(resolver_list, "Global Provider 1", + "https://global1.provider/dns-query{?dns}", + "https://global1.provider/privacy_policy/")); + EXPECT_TRUE(FindDropdownItem(resolver_list, "Global Provider 2", + "https://global2.provider/dns-query{?dns}", + "https://global2.provider/privacy_policy/")); +} + +IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, DropdownListChange) { + // Populate the map for recording dropdown change metrics. + base::Value resolver_list = handler_->GetSecureDnsResolverListForCountry( + country_codes::CountryCharsToCountryID('E', 'E'), + GetDohProviderListForTesting()); + EXPECT_EQ(4u, resolver_list.GetList().size()); + + base::HistogramTester histograms; + base::ListValue args; + args.AppendString("custom" /* old_provider */); + args.AppendString( + "https://global1.provider/dns-query{?dns}" /* new_provider */); + web_ui_.HandleReceivedMessage(kRecordUserDropdownInteraction, &args); + + const std::string uma_base("Net.DNS.UI.DropdownSelectionEvent"); + histograms.ExpectTotalCount(uma_base + ".Ignored", 2u); + histograms.ExpectTotalCount(uma_base + ".Selected", 1u); + histograms.ExpectTotalCount(uma_base + ".Unselected", 1u); +} + +class SecureDnsHandlerTestWithDisabledProviders : public SecureDnsHandlerTest { + protected: + SecureDnsHandlerTestWithDisabledProviders() { + scoped_features_.InitAndEnableFeatureWithParameters( + features::kDnsOverHttps, + {{"DisabledProviders", + "Provider_Global2, , Provider_EE_FR,Unexpected"}}); + } + + private: + base::test::ScopedFeatureList scoped_features_; + + DISALLOW_COPY_AND_ASSIGN(SecureDnsHandlerTestWithDisabledProviders); +}; + +IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTestWithDisabledProviders, + DropdownListDisabledProviders) { + // The 'FR' list should start with the custom entry, followed by the two + // global providers and the two 'FR' providers in some random order. + base::Value resolver_list = handler_->GetSecureDnsResolverListForCountry( + country_codes::CountryCharsToCountryID('F', 'R'), + GetDohProviderListForTesting()); + EXPECT_EQ(3u, resolver_list.GetList().size()); + EXPECT_EQ("custom", resolver_list.GetList()[0].FindKey("value")->GetString()); + EXPECT_TRUE(FindDropdownItem(resolver_list, "Global Provider 1", + "https://global1.provider/dns-query{?dns}", + "https://global1.provider/privacy_policy/")); + EXPECT_TRUE(FindDropdownItem(resolver_list, "FR Provider", + "https://fr.provider/dns-query{?dns}", + "https://fr.provider/privacy_policy/")); +} + +IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTestWithDisabledProviders, + SecureDnsTemplates) { + std::string good_post_template = "https://foo.test/"; + std::string good_get_template = "https://bar.test/dns-query{?dns}"; + std::string bad_template = "dns-query{?dns}"; + + std::string secure_dns_mode; + std::vector<std::string> secure_dns_templates; + int management_mode; + PrefService* local_state = g_browser_process->local_state(); + local_state->SetString(prefs::kDnsOverHttpsTemplates, good_post_template); + EXPECT_TRUE(GetLastSettingsChangedMessage( + &secure_dns_mode, &secure_dns_templates, &management_mode)); + EXPECT_EQ(1u, secure_dns_templates.size()); + EXPECT_EQ(good_post_template, secure_dns_templates[0]); + + local_state->SetString(prefs::kDnsOverHttpsTemplates, + good_post_template + " " + good_get_template); + EXPECT_TRUE(GetLastSettingsChangedMessage( + &secure_dns_mode, &secure_dns_templates, &management_mode)); + EXPECT_EQ(2u, secure_dns_templates.size()); + EXPECT_EQ(good_post_template, secure_dns_templates[0]); + EXPECT_EQ(good_get_template, secure_dns_templates[1]); + + local_state->SetString(prefs::kDnsOverHttpsTemplates, bad_template); + EXPECT_TRUE(GetLastSettingsChangedMessage( + &secure_dns_mode, &secure_dns_templates, &management_mode)); + EXPECT_EQ(0u, secure_dns_templates.size()); + + local_state->SetString(prefs::kDnsOverHttpsTemplates, + bad_template + " " + good_post_template); + EXPECT_TRUE(GetLastSettingsChangedMessage( + &secure_dns_mode, &secure_dns_templates, &management_mode)); + EXPECT_EQ(1u, secure_dns_templates.size()); + EXPECT_EQ(good_post_template, secure_dns_templates[0]); + + // Should still return a provider that was disabled. + local_state->SetString(prefs::kDnsOverHttpsTemplates, + "https://global2.provider/dns-query{?dns}"); + EXPECT_TRUE(GetLastSettingsChangedMessage( + &secure_dns_mode, &secure_dns_templates, &management_mode)); + EXPECT_EQ(1u, secure_dns_templates.size()); + EXPECT_EQ("https://global2.provider/dns-query{?dns}", + secure_dns_templates[0]); +} + +IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, TemplateValid) { + base::ListValue args; + args.AppendString(kWebUiFunctionName); + args.AppendString("https://example.template/dns-query"); + + base::HistogramTester histograms; + web_ui_.HandleReceivedMessage(kValidateCustomDnsEntry, &args); + const content::TestWebUI::CallData& call_data = *web_ui_.call_data().back(); + EXPECT_EQ("cr.webUIResponse", call_data.function_name()); + EXPECT_EQ(kWebUiFunctionName, call_data.arg1()->GetString()); + // The request should be successful. + ASSERT_TRUE(call_data.arg2()->GetBool()); + // The template should be valid. + ASSERT_EQ("https://example.template/dns-query", + call_data.arg3()->GetString()); + histograms.ExpectBucketCount("Net.DNS.UI.ValidationAttemptSuccess", false, 0); + histograms.ExpectBucketCount("Net.DNS.UI.ValidationAttemptSuccess", true, 1); +} + +IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, TemplateInvalid) { + base::ListValue args; + args.AppendString(kWebUiFunctionName); + args.AppendString("invalid_template"); + + base::HistogramTester histograms; + web_ui_.HandleReceivedMessage(kValidateCustomDnsEntry, &args); + const content::TestWebUI::CallData& call_data = *web_ui_.call_data().back(); + EXPECT_EQ("cr.webUIResponse", call_data.function_name()); + EXPECT_EQ(kWebUiFunctionName, call_data.arg1()->GetString()); + // The request should be successful. + ASSERT_TRUE(call_data.arg2()->GetBool()); + // The template should be invalid. + ASSERT_EQ(std::string(), call_data.arg3()->GetString()); + histograms.ExpectBucketCount("Net.DNS.UI.ValidationAttemptSuccess", false, 1); + histograms.ExpectBucketCount("Net.DNS.UI.ValidationAttemptSuccess", true, 0); +} + +IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, MultipleTemplates) { + base::HistogramTester histograms; + base::ListValue args_valid; + args_valid.AppendString(kWebUiFunctionName); + args_valid.AppendString( + "https://example1.template/dns https://example2.template/dns-query"); + web_ui_.HandleReceivedMessage(kValidateCustomDnsEntry, &args_valid); + const content::TestWebUI::CallData& call_data_valid = + *web_ui_.call_data().back(); + EXPECT_EQ("cr.webUIResponse", call_data_valid.function_name()); + EXPECT_EQ(kWebUiFunctionName, call_data_valid.arg1()->GetString()); + // The request should be successful. + ASSERT_TRUE(call_data_valid.arg2()->GetBool()); + // Both templates are valid, so validate returns the first. + ASSERT_EQ("https://example1.template/dns", + call_data_valid.arg3()->GetString()); + histograms.ExpectBucketCount("Net.DNS.UI.ValidationAttemptSuccess", false, 0); + histograms.ExpectBucketCount("Net.DNS.UI.ValidationAttemptSuccess", true, 1); + + base::ListValue args_invalid; + args_invalid.AppendString(kWebUiFunctionName); + args_invalid.AppendString("invalid_template https://example.template/dns"); + web_ui_.HandleReceivedMessage(kValidateCustomDnsEntry, &args_invalid); + const content::TestWebUI::CallData& call_data_invalid = + *web_ui_.call_data().back(); + EXPECT_EQ("cr.webUIResponse", call_data_invalid.function_name()); + EXPECT_EQ(kWebUiFunctionName, call_data_invalid.arg1()->GetString()); + // The request should be successful. + ASSERT_TRUE(call_data_invalid.arg2()->GetBool()); + // The entry should be invalid. + ASSERT_EQ(std::string(), call_data_invalid.arg3()->GetString()); + histograms.ExpectBucketCount("Net.DNS.UI.ValidationAttemptSuccess", false, 1); + histograms.ExpectBucketCount("Net.DNS.UI.ValidationAttemptSuccess", true, 1); +} + +IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, TemplateProbeSuccess) { + auto network_context_ = + std::make_unique<chrome_browser_net::FakeHostResolverNetworkContext>( + std::vector<chrome_browser_net::FakeHostResolver::SingleResult>( + {chrome_browser_net::FakeHostResolver::SingleResult( + net::OK, net::ResolveErrorInfo(net::OK), + chrome_browser_net::FakeHostResolver:: + kOneAddressResponse)}) /* current_config_result_list */, + std::vector<chrome_browser_net::FakeHostResolver:: + SingleResult>() /* google_config_result_list */); + handler_->SetNetworkContextForTesting(network_context_.get()); + base::HistogramTester histograms; + base::ListValue args_valid; + args_valid.AppendString(kWebUiFunctionName); + args_valid.AppendString("https://example.template/dns-query"); + web_ui_.HandleReceivedMessage(kProbeCustomDnsTemplate, &args_valid); + base::RunLoop().RunUntilIdle(); + + const content::TestWebUI::CallData& call_data_valid = + *web_ui_.call_data().back(); + EXPECT_EQ("cr.webUIResponse", call_data_valid.function_name()); + EXPECT_EQ(kWebUiFunctionName, call_data_valid.arg1()->GetString()); + // The request should be successful. + ASSERT_TRUE(call_data_valid.arg2()->GetBool()); + // The probe query should have succeeded. + ASSERT_TRUE(call_data_valid.arg3()->GetBool()); + histograms.ExpectBucketCount("Net.DNS.UI.ProbeAttemptSuccess", false, 0); + histograms.ExpectBucketCount("Net.DNS.UI.ProbeAttemptSuccess", true, 1); +} + +IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, TemplateProbeFailure) { + auto network_context_ = + std::make_unique<chrome_browser_net::FakeHostResolverNetworkContext>( + std::vector<chrome_browser_net::FakeHostResolver::SingleResult>( + {chrome_browser_net::FakeHostResolver::SingleResult( + net::ERR_NAME_NOT_RESOLVED, + net::ResolveErrorInfo(net::ERR_DNS_MALFORMED_RESPONSE), + chrome_browser_net::FakeHostResolver:: + kNoResponse)}) /* current_config_result_list */, + std::vector<chrome_browser_net::FakeHostResolver:: + SingleResult>() /* google_config_result_list */); + handler_->SetNetworkContextForTesting(network_context_.get()); + base::HistogramTester histograms; + base::ListValue args_valid; + args_valid.AppendString(kWebUiFunctionName); + args_valid.AppendString("https://example.template/dns-query"); + web_ui_.HandleReceivedMessage(kProbeCustomDnsTemplate, &args_valid); + base::RunLoop().RunUntilIdle(); + + const content::TestWebUI::CallData& call_data_valid = + *web_ui_.call_data().back(); + EXPECT_EQ("cr.webUIResponse", call_data_valid.function_name()); + EXPECT_EQ(kWebUiFunctionName, call_data_valid.arg1()->GetString()); + // The request should be successful. + ASSERT_TRUE(call_data_valid.arg2()->GetBool()); + // The probe query should have failed. + ASSERT_FALSE(call_data_valid.arg3()->GetBool()); + histograms.ExpectBucketCount("Net.DNS.UI.ProbeAttemptSuccess", false, 1); + histograms.ExpectBucketCount("Net.DNS.UI.ProbeAttemptSuccess", true, 0); +} + +} // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/settings_security_key_handler.cc b/chromium/chrome/browser/ui/webui/settings/settings_security_key_handler.cc index b949500f09a..112a3e1dc4b 100644 --- a/chromium/chrome/browser/ui/webui/settings/settings_security_key_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/settings_security_key_handler.cc @@ -15,7 +15,6 @@ #include "chrome/browser/ui/webui/settings/settings_security_key_handler.h" #include "chrome/grit/generated_resources.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/system_connector.h" #include "content/public/browser/web_ui.h" #include "content/public/common/service_manager_connection.h" #include "device/fido/bio/enrollment_handler.h" @@ -103,7 +102,7 @@ void SecurityKeysPINHandler::HandleStartSetPIN(const base::ListValue* args) { callback_id_ = args->GetList()[0].GetString(); state_ = State::kStartSetPIN; set_pin_ = std::make_unique<device::SetPINRequestHandler>( - content::GetSystemConnector(), supported_transports(), + supported_transports(), base::BindOnce(&SecurityKeysPINHandler::OnGatherPIN, weak_factory_.GetWeakPtr()), base::BindRepeating(&SecurityKeysPINHandler::OnSetPINComplete, @@ -203,7 +202,7 @@ void SecurityKeysResetHandler::HandleReset(const base::ListValue* args) { state_ = State::kStartReset; reset_ = std::make_unique<device::ResetRequestHandler>( - content::GetSystemConnector(), supported_transports(), + supported_transports(), base::BindOnce(&SecurityKeysResetHandler::OnResetSent, weak_factory_.GetWeakPtr()), base::BindOnce(&SecurityKeysResetHandler::OnResetFinished, @@ -334,7 +333,6 @@ void SecurityKeysCredentialHandler::HandleStart(const base::ListValue* args) { discovery_factory_ = std::make_unique<device::FidoDiscoveryFactory>(); credential_management_ = std::make_unique<device::CredentialManagementHandler>( - content::ServiceManagerConnection::GetForProcess()->GetConnector(), discovery_factory_.get(), supported_transports(), base::BindOnce( &SecurityKeysCredentialHandler::OnCredentialManagementReady, @@ -589,7 +587,6 @@ void SecurityKeysBioEnrollmentHandler::HandleStart( callback_id_ = args->GetList()[0].GetString(); discovery_factory_ = std::make_unique<device::FidoDiscoveryFactory>(); bio_ = std::make_unique<device::BioEnrollmentHandler>( - content::ServiceManagerConnection::GetForProcess()->GetConnector(), supported_transports(), base::BindOnce(&SecurityKeysBioEnrollmentHandler::OnReady, weak_factory_.GetWeakPtr()), diff --git a/chromium/chrome/browser/ui/webui/settings/settings_ui.cc b/chromium/chrome/browser/ui/webui/settings/settings_ui.cc index 1f4acc97c4d..84d467e2229 100644 --- a/chromium/chrome/browser/ui/webui/settings/settings_ui.cc +++ b/chromium/chrome/browser/ui/webui/settings/settings_ui.cc @@ -19,10 +19,14 @@ #include "build/build_config.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/identity_manager_factory.h" +#include "chrome/browser/ui/hats/hats_service.h" +#include "chrome/browser/ui/hats/hats_service_factory.h" #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h" +#include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/webui/favicon_source.h" #include "chrome/browser/ui/webui/managed_ui_handler.h" #include "chrome/browser/ui/webui/metrics_handler.h" +#include "chrome/browser/ui/webui/plural_string_handler.h" #include "chrome/browser/ui/webui/settings/about_handler.h" #include "chrome/browser/ui/webui/settings/accessibility_main_handler.h" #include "chrome/browser/ui/webui/settings/appearance_handler.h" @@ -31,22 +35,28 @@ #include "chrome/browser/ui/webui/settings/downloads_handler.h" #include "chrome/browser/ui/webui/settings/extension_control_handler.h" #include "chrome/browser/ui/webui/settings/font_handler.h" +#include "chrome/browser/ui/webui/settings/hats_handler.h" +#include "chrome/browser/ui/webui/settings/import_data_handler.h" #include "chrome/browser/ui/webui/settings/metrics_reporting_handler.h" #include "chrome/browser/ui/webui/settings/on_startup_handler.h" #include "chrome/browser/ui/webui/settings/people_handler.h" #include "chrome/browser/ui/webui/settings/profile_info_handler.h" #include "chrome/browser/ui/webui/settings/protocol_handlers_handler.h" #include "chrome/browser/ui/webui/settings/reset_settings_handler.h" +#include "chrome/browser/ui/webui/settings/safe_browsing_handler.h" +#include "chrome/browser/ui/webui/settings/safety_check_handler.h" #include "chrome/browser/ui/webui/settings/search_engines_handler.h" #include "chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.h" #include "chrome/browser/ui/webui/settings/settings_cookies_view_handler.h" -#include "chrome/browser/ui/webui/settings/settings_import_data_handler.h" #include "chrome/browser/ui/webui/settings/settings_localized_strings_provider.h" #include "chrome/browser/ui/webui/settings/settings_media_devices_selection_handler.h" #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" +#include "chrome/browser/ui/webui/settings/settings_secure_dns_handler.h" #include "chrome/browser/ui/webui/settings/settings_security_key_handler.h" #include "chrome/browser/ui/webui/settings/settings_startup_pages_handler.h" +#include "chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.h" #include "chrome/browser/ui/webui/settings/site_settings_handler.h" +#include "chrome/browser/ui/webui/webui_util.h" #include "chrome/browser/web_applications/components/app_registrar.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/browser/web_applications/web_app_registrar.h" @@ -56,14 +66,19 @@ #include "chrome/grit/generated_resources.h" #include "chrome/grit/settings_resources.h" #include "chrome/grit/settings_resources_map.h" +#include "components/content_settings/core/common/features.h" #include "components/favicon_base/favicon_url_parser.h" #include "components/password_manager/core/common/password_manager_features.h" #include "components/pref_registry/pref_registry_syncable.h" +#include "components/prefs/pref_service.h" +#include "components/safe_browsing/core/features.h" +#include "components/signin/public/base/signin_pref_names.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 "printing/buildflags/buildflags.h" +#include "ui/resources/grit/webui_resources.h" #if defined(OS_WIN) #include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h" @@ -78,64 +93,28 @@ #if defined(OS_WIN) || defined(OS_CHROMEOS) #include "chrome/browser/ui/webui/settings/languages_handler.h" -#include "chrome/browser/ui/webui/settings/tts_handler.h" #endif // defined(OS_WIN) || defined(OS_CHROMEOS) #if defined(OS_CHROMEOS) -#include "ash/public/cpp/network_config_service.h" -#include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h" -#include "ash/public/cpp/stylus_utils.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/account_manager/account_manager_util.h" #include "chrome/browser/chromeos/android_sms/android_sms_app_manager.h" #include "chrome/browser/chromeos/android_sms/android_sms_service_factory.h" -#include "chrome/browser/chromeos/arc/arc_util.h" -#include "chrome/browser/chromeos/crostini/crostini_features.h" -#include "chrome/browser/chromeos/login/demo_mode/demo_session.h" -#include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h" #include "chrome/browser/chromeos/multidevice_setup/multidevice_setup_client_factory.h" -#include "chrome/browser/chromeos/plugin_vm/plugin_vm_util.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" -#include "chrome/browser/ui/web_applications/system_web_app_ui_utils.h" -#include "chrome/browser/ui/webui/chromeos/smb_shares/smb_handler.h" -#include "chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h" #include "chrome/browser/ui/webui/settings/chromeos/account_manager_handler.h" #include "chrome/browser/ui/webui/settings/chromeos/android_apps_handler.h" -#include "chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h" -#include "chrome/browser/ui/webui/settings/chromeos/crostini_handler.h" -#include "chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h" -#include "chrome/browser/ui/webui/settings/chromeos/date_time_handler.h" -#include "chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.h" -#include "chrome/browser/ui/webui/settings/chromeos/device_pointer_handler.h" -#include "chrome/browser/ui/webui/settings/chromeos/device_power_handler.h" -#include "chrome/browser/ui/webui/settings/chromeos/device_storage_handler.h" -#include "chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.h" -#include "chrome/browser/ui/webui/settings/chromeos/fingerprint_handler.h" -#include "chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.h" -#include "chrome/browser/ui/webui/settings/chromeos/internet_handler.h" -#include "chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.h" #include "chrome/browser/ui/webui/settings/chromeos/multidevice_handler.h" -#include "chrome/browser/ui/webui/settings/chromeos/parental_controls_handler.h" -#include "chrome/browser/ui/webui/settings/chromeos/plugin_vm_handler.h" -#include "chrome/browser/ui/webui/settings/chromeos/wallpaper_handler.h" -#include "chrome/browser/web_applications/system_web_app_manager.h" #include "chrome/common/chrome_switches.h" #include "chrome/grit/browser_resources.h" #include "chromeos/components/account_manager/account_manager.h" #include "chromeos/components/account_manager/account_manager_factory.h" #include "chromeos/constants/chromeos_features.h" -#include "chromeos/constants/chromeos_pref_names.h" #include "chromeos/login/auth/password_visibility_utils.h" -#include "chromeos/services/multidevice_setup/public/cpp/prefs.h" -#include "chromeos/services/network_config/public/mojom/constants.mojom.h" // nogncheck -#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h" // nogncheck #include "components/arc/arc_util.h" -#include "components/prefs/pref_service.h" #include "components/user_manager/user.h" #include "ui/base/ui_base_features.h" -#include "ui/chromeos/resources/grit/ui_chromeos_resources.h" -#include "ui/resources/grit/webui_resources.h" #else // !defined(OS_CHROMEOS) #include "chrome/browser/signin/account_consistency_mode_manager.h" #include "chrome/browser/ui/webui/settings/settings_default_browser_handler.h" @@ -154,6 +133,12 @@ #endif namespace settings { + +#if !BUILDFLAG(OPTIMIZE_WEBUI) +constexpr char kGeneratedPath[] = + "@out_folder@/gen/chrome/browser/resources/settings/"; +#endif + // static void SettingsUI::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { @@ -169,11 +154,7 @@ web_app::AppRegistrar& GetRegistrarForProfile(Profile* profile) { } SettingsUI::SettingsUI(content::WebUI* web_ui) -#if defined(OS_CHROMEOS) - : ui::MojoWebUIController(web_ui, /*enable_chrome_send =*/true), -#else : content::WebUIController(web_ui), -#endif webui_load_timer_(web_ui->GetWebContents(), "Settings.LoadDocumentTime.MD", "Settings.LoadCompletedTime.MD") { @@ -181,6 +162,18 @@ SettingsUI::SettingsUI(content::WebUI* web_ui) content::WebUIDataSource* html_source = content::WebUIDataSource::Create(chrome::kChromeUISettingsHost); + // TODO(dpapad): Replace the following calls with + // SetupBundledWebUIDataSource() when Settings is migrated to Polymer3. + // Currently only used for testing the Polymer 3 version of + // certificate-manager. +#if BUILDFLAG(OPTIMIZE_WEBUI) + html_source->EnableReplaceI18nInJS(); + html_source->OverrideContentSecurityPolicyScriptSrc( + "script-src chrome://resources chrome://test 'self';"); + html_source->AddResourcePath("test_loader.js", IDR_WEBUI_JS_TEST_LOADER); + html_source->AddResourcePath("test_loader.html", IDR_WEBUI_HTML_TEST_LOADER); +#endif + AddSettingsPageUIHandler(std::make_unique<AppearanceHandler>(web_ui)); #if defined(USE_NSS_CERTS) @@ -192,12 +185,15 @@ SettingsUI::SettingsUI(content::WebUI* web_ui) AddSettingsPageUIHandler(std::make_unique<AccessibilityMainHandler>()); AddSettingsPageUIHandler(std::make_unique<BrowserLifetimeHandler>()); - AddSettingsPageUIHandler(std::make_unique<ClearBrowsingDataHandler>(web_ui)); + AddSettingsPageUIHandler( + std::make_unique<ClearBrowsingDataHandler>(web_ui, profile)); + AddSettingsPageUIHandler(std::make_unique<SafetyCheckHandler>()); AddSettingsPageUIHandler(std::make_unique<CookiesViewHandler>()); AddSettingsPageUIHandler(std::make_unique<DownloadsHandler>(profile)); AddSettingsPageUIHandler(std::make_unique<ExtensionControlHandler>()); AddSettingsPageUIHandler(std::make_unique<FontHandler>(web_ui)); AddSettingsPageUIHandler(std::make_unique<ImportDataHandler>()); + AddSettingsPageUIHandler(std::make_unique<HatsHandler>()); #if defined(OS_WIN) || defined(OS_CHROMEOS) AddSettingsPageUIHandler(std::make_unique<LanguagesHandler>(web_ui)); @@ -212,7 +208,9 @@ SettingsUI::SettingsUI(content::WebUI* web_ui) AddSettingsPageUIHandler(std::make_unique<PeopleHandler>(profile)); AddSettingsPageUIHandler(std::make_unique<ProfileInfoHandler>(profile)); AddSettingsPageUIHandler(std::make_unique<ProtocolHandlersHandler>()); + AddSettingsPageUIHandler(std::make_unique<SafeBrowsingHandler>(profile)); AddSettingsPageUIHandler(std::make_unique<SearchEnginesHandler>(profile)); + AddSettingsPageUIHandler(std::make_unique<SecureDnsHandler>()); AddSettingsPageUIHandler(std::make_unique<SiteSettingsHandler>( profile, GetRegistrarForProfile(profile))); AddSettingsPageUIHandler(std::make_unique<StartupPagesHandler>(web_ui)); @@ -227,9 +225,7 @@ SettingsUI::SettingsUI(content::WebUI* web_ui) #endif #if defined(OS_CHROMEOS) - // TODO(950007): Remove this when SplitSettings is the default and there are - // no Chrome OS settings in the browser settings page. - InitOSWebUIHandlers(profile, web_ui, html_source); + InitBrowserSettingsWebUIHandlers(); #else AddSettingsPageUIHandler(std::make_unique<DefaultBrowserHandler>()); AddSettingsPageUIHandler(std::make_unique<ManageProfileHandler>(profile)); @@ -256,60 +252,77 @@ SettingsUI::SettingsUI(content::WebUI* web_ui) std::make_unique<IncompatibleApplicationsHandler>()); #endif // OS_WIN && BUILDFLAG(GOOGLE_CHROME_BRANDING) -#if !defined(OS_CHROMEOS) + html_source->AddBoolean("signinAllowed", !profile->IsGuestSession() && + profile->GetPrefs()->GetBoolean( + prefs::kSigninAllowed)); html_source->AddBoolean( - "diceEnabled", - AccountConsistencyModeManager::IsDiceEnabledForProfile(profile)); -#endif // !defined(OS_CHROMEOS) + "improvedCookieControlsEnabled", + base::FeatureList::IsEnabled(content_settings::kImprovedCookieControls)); html_source->AddBoolean( "privacySettingsRedesignEnabled", base::FeatureList::IsEnabled(features::kPrivacySettingsRedesign)); html_source->AddBoolean( + "safeBrowsingEnhancedEnabled", + base::FeatureList::IsEnabled(safe_browsing::kEnhancedProtection)); + + html_source->AddBoolean( "navigateToGooglePasswordManager", ShouldManagePasswordsinGooglePasswordManager(profile)); + html_source->AddBoolean( + "enablePasswordCheck", + base::FeatureList::IsEnabled(password_manager::features::kPasswordCheck)); + html_source->AddBoolean("showImportPasswords", base::FeatureList::IsEnabled( password_manager::features::kPasswordImport)); + html_source->AddBoolean( + "enableAccountStorage", + base::FeatureList::IsEnabled( + password_manager::features::kEnablePasswordsAccountStorage)); + + html_source->AddBoolean( + "syncSetupFriendlySettings", + base::FeatureList::IsEnabled(features::kSyncSetupFriendlySettings)); + #if defined(OS_CHROMEOS) + html_source->AddBoolean("splitSettingsSyncEnabled", + chromeos::features::IsSplitSettingsSyncEnabled()); + html_source->AddBoolean("splitSyncConsent", + chromeos::features::IsSplitSyncConsentEnabled()); + html_source->AddBoolean( - "showParentalControls", - chromeos::settings::ShouldShowParentalControls(profile)); + "userCannotManuallyEnterPassword", + !chromeos::password_visibility::AccountHasUserFacingPassword( + chromeos::ProfileHelper::Get() + ->GetUserByProfile(profile) + ->GetAccountId())); #endif #if defined(OS_CHROMEOS) // This is the browser settings page. html_source->AddBoolean("isOSSettings", false); - // If false, hides OS-specific settings (like networks) in browser settings. - html_source->AddBoolean( - "showOSSettings", - !base::FeatureList::IsEnabled(chromeos::features::kSplitSettings)); -#else - html_source->AddBoolean("showOSSettings", false); #endif + // TODO(crbug.com/1026455): Delete this as part of the SplitSettings cleanup. + html_source->AddBoolean("showOSSettings", false); AddSettingsPageUIHandler( base::WrapUnique(AboutHandler::Create(html_source, profile))); AddSettingsPageUIHandler( base::WrapUnique(ResetSettingsHandler::Create(html_source, profile))); + // Add a handler to provide pluralized strings. + auto plural_string_handler = std::make_unique<PluralStringHandler>(); + plural_string_handler->AddLocalizedString( + "compromisedPasswords", IDS_SETTINGS_COMPROMISED_PASSWORDS_COUNT); + web_ui->AddMessageHandler(std::move(plural_string_handler)); + // Add the metrics handler to write uma stats. web_ui->AddMessageHandler(std::make_unique<MetricsHandler>()); -#if defined(OS_CHROMEOS) - // Add the System Web App resources for Settings. - // TODO(jamescook|calamity): Migrate to chromeos::settings::OSSettingsUI. - if (web_app::SystemWebAppManager::IsEnabled()) { - html_source->AddResourcePath("icon-192.png", IDR_SETTINGS_LOGO_192); - html_source->AddResourcePath("pwa.html", IDR_PWA_HTML); - web_app::SetManifestRequestFilter(html_source, IDR_SETTINGS_MANIFEST, - IDS_SETTINGS_SETTINGS); - } -#endif // defined (OS_CHROMEOS) - #if BUILDFLAG(OPTIMIZE_WEBUI) html_source->AddResourcePath("crisper.js", IDR_SETTINGS_CRISPER_JS); html_source->AddResourcePath("lazy_load.crisper.js", @@ -317,16 +330,52 @@ SettingsUI::SettingsUI(content::WebUI* web_ui) html_source->AddResourcePath("lazy_load.html", IDR_SETTINGS_LAZY_LOAD_VULCANIZED_HTML); html_source->SetDefaultResource(IDR_SETTINGS_VULCANIZED_HTML); + + // Register SVG images that are purposefully not inlined in the HTML bundle + // above. + html_source->AddResourcePath("images/cookies_banner.svg", + IDR_SETTINGS_IMAGES_COOKIES_BANNER_SVG); + html_source->AddResourcePath("images/cookies_banner_dark.svg", + IDR_SETTINGS_IMAGES_COOKIES_BANNER_DARK_SVG); + html_source->AddResourcePath("images/permissions_banner.svg", + IDR_SETTINGS_IMAGES_PERMISSIONS_BANNER_SVG); + html_source->AddResourcePath("images/permissions_banner_dark.svg", + IDR_SETTINGS_IMAGES_PERMISSIONS_BANNER_DARK_SVG); + html_source->AddResourcePath("images/safe_browsing_banner.svg", + IDR_SETTINGS_IMAGES_SAFE_BROWSING_BANNER_SVG); + html_source->AddResourcePath( + "images/safe_browsing_banner_dark.svg", + IDR_SETTINGS_IMAGES_SAFE_BROWSING_BANNER_DARK_SVG); + html_source->AddResourcePath("images/sync_banner.svg", + IDR_SETTINGS_IMAGES_SYNC_BANNER_SVG); + html_source->AddResourcePath("images/sync_banner_dark.svg", + IDR_SETTINGS_IMAGES_SYNC_BANNER_DARK_SVG); + html_source->AddResourcePath("images/password_check_neutral.svg", + IDR_SETTINGS_IMAGES_PASSWORD_CHECK_NEUTRAL_SVG); + html_source->AddResourcePath( + "images/password_check_neutral_dark.svg", + IDR_SETTINGS_IMAGES_PASSWORD_CHECK_NEUTRAL_DARK_SVG); + html_source->AddResourcePath("images/password_check_positive.svg", + IDR_SETTINGS_IMAGES_PASSWORD_CHECK_POSITIVE_SVG); + html_source->AddResourcePath( + "images/password_check_positive_dark.svg", + IDR_SETTINGS_IMAGES_PASSWORD_CHECK_POSITIVE_DARK_SVG); + + // Only used in Polymer 3, see https://crbug.com/1026426. + html_source->AddResourcePath("settings.js", IDR_SETTINGS_SETTINGS_ROLLUP_JS); + html_source->AddResourcePath("shared.rollup.js", + IDR_SETTINGS_SHARED_ROLLUP_JS); + html_source->AddResourcePath("lazy_load.js", + IDR_SETTINGS_LAZY_LOAD_ROLLUP_JS); + html_source->AddResourcePath("settings_v3.html", + IDR_SETTINGS_SETTINGS_V3_HTML); #else - // Add all settings resources. - for (size_t i = 0; i < kSettingsResourcesSize; ++i) { - html_source->AddResourcePath(kSettingsResources[i].name, - kSettingsResources[i].value); - } - html_source->SetDefaultResource(IDR_SETTINGS_SETTINGS_HTML); + webui::SetupWebUIDataSource( + html_source, base::make_span(kSettingsResources, kSettingsResourcesSize), + kGeneratedPath, IDR_SETTINGS_SETTINGS_HTML); #endif - AddLocalizedStrings(html_source, profile, web_ui->GetWebContents()); + AddBrowserLocalizedStrings(html_source, profile, web_ui->GetWebContents()); ManagedUIHandler::Initialize(web_ui, html_source); @@ -337,19 +386,15 @@ SettingsUI::SettingsUI(content::WebUI* web_ui) profile, std::make_unique<FaviconSource>( profile, chrome::FaviconUrlFormat::kFavicon2)); -#if defined(OS_CHROMEOS) - AddHandlerToRegistry(base::BindRepeating(&SettingsUI::BindCrosNetworkConfig, - base::Unretained(this))); -#endif // defined (OS_CHROMEOS) + TryShowHatsSurveyWithTimeout(); } SettingsUI::~SettingsUI() = default; #if defined(OS_CHROMEOS) -// static -void SettingsUI::InitOSWebUIHandlers(Profile* profile, - content::WebUI* web_ui, - content::WebUIDataSource* html_source) { +void SettingsUI::InitBrowserSettingsWebUIHandlers() { + Profile* profile = Profile::FromWebUI(web_ui()); + // TODO(jamescook): Sort out how account management is split between Chrome OS // and browser settings. if (chromeos::IsAccountManagerAvailable(profile)) { @@ -359,75 +404,19 @@ void SettingsUI::InitOSWebUIHandlers(Profile* profile, factory->GetAccountManager(profile->GetPath().value()); DCHECK(account_manager); - web_ui->AddMessageHandler( + web_ui()->AddMessageHandler( std::make_unique<chromeos::settings::AccountManagerUIHandler>( account_manager, IdentityManagerFactory::GetForProfile(profile))); - html_source->AddBoolean( - "secondaryGoogleAccountSigninAllowed", - profile->GetPrefs()->GetBoolean( - chromeos::prefs::kSecondaryGoogleAccountSigninAllowed)); - } - - web_ui->AddMessageHandler( - std::make_unique<chromeos::settings::ChangePictureHandler>()); - - web_ui->AddMessageHandler( - std::make_unique<chromeos::settings::AccessibilityHandler>(web_ui)); - web_ui->AddMessageHandler( - std::make_unique<chromeos::settings::AndroidAppsHandler>(profile)); - if (crostini::CrostiniFeatures::Get()->IsUIAllowed(profile, - /*check_policy=*/false)) { - web_ui->AddMessageHandler( - std::make_unique<chromeos::settings::CrostiniHandler>(profile)); - } - web_ui->AddMessageHandler( - chromeos::settings::CupsPrintersHandler::Create(web_ui)); - web_ui->AddMessageHandler(base::WrapUnique( - chromeos::settings::DateTimeHandler::Create(html_source))); - web_ui->AddMessageHandler( - std::make_unique<chromeos::settings::FingerprintHandler>(profile)); - web_ui->AddMessageHandler( - std::make_unique<chromeos::settings::GoogleAssistantHandler>(profile)); - - std::unique_ptr<chromeos::settings::KerberosAccountsHandler> - kerberos_accounts_handler = - chromeos::settings::KerberosAccountsHandler::CreateIfKerberosEnabled( - profile); - if (kerberos_accounts_handler) { - // Note that the UI is enabled only if Kerberos is enabled. - web_ui->AddMessageHandler(std::move(kerberos_accounts_handler)); } - web_ui->AddMessageHandler( - std::make_unique<chromeos::settings::KeyboardHandler>()); - - // TODO(crbug/950007): Remove adding WallpaperHandler when - // SplitSettings complete. - web_ui->AddMessageHandler( - std::make_unique<chromeos::settings::WallpaperHandler>(web_ui)); - - if (plugin_vm::IsPluginVmEnabled(profile)) { - web_ui->AddMessageHandler( - std::make_unique<chromeos::settings::PluginVmHandler>(profile)); - } - web_ui->AddMessageHandler( - std::make_unique<chromeos::settings::PointerHandler>()); - web_ui->AddMessageHandler( - std::make_unique<chromeos::settings::StorageHandler>(profile, - html_source)); - web_ui->AddMessageHandler( - std::make_unique<chromeos::settings::StylusHandler>()); - web_ui->AddMessageHandler( - std::make_unique<chromeos::settings::InternetHandler>(profile)); - web_ui->AddMessageHandler(std::make_unique<TtsHandler>()); - web_ui->AddMessageHandler( - std::make_unique<chromeos::smb_dialog::SmbHandler>(profile)); - + // MultideviceHandler is required in browser settings to show a special note + // under the notification permission that is auto-granted for Android Messages + // integration in ChromeOS. if (!profile->IsGuestSession()) { chromeos::android_sms::AndroidSmsService* android_sms_service = chromeos::android_sms::AndroidSmsServiceFactory::GetForBrowserContext( profile); - web_ui->AddMessageHandler( + web_ui()->AddMessageHandler( std::make_unique<chromeos::settings::MultideviceHandler>( profile->GetPrefs(), chromeos::multidevice_setup::MultiDeviceSetupClientFactory:: @@ -437,93 +426,10 @@ void SettingsUI::InitOSWebUIHandlers(Profile* profile, : nullptr, android_sms_service ? android_sms_service->android_sms_app_manager() : nullptr)); - if (chromeos::settings::ShouldShowParentalControls(profile)) { - web_ui->AddMessageHandler( - std::make_unique<chromeos::settings::ParentalControlsHandler>( - profile)); - } - } - - html_source->AddBoolean( - "privacySettingsRedesignEnabled", - base::FeatureList::IsEnabled(::features::kPrivacySettingsRedesign)); - - html_source->AddBoolean( - "multideviceAllowedByPolicy", - chromeos::multidevice_setup::AreAnyMultiDeviceFeaturesAllowed( - profile->GetPrefs())); - html_source->AddBoolean( - "quickUnlockEnabled", - chromeos::quick_unlock::IsPinEnabled(profile->GetPrefs())); - html_source->AddBoolean( - "quickUnlockDisabledByPolicy", - chromeos::quick_unlock::IsPinDisabledByPolicy(profile->GetPrefs())); - html_source->AddBoolean( - "userCannotManuallyEnterPassword", - !chromeos::password_visibility::AccountHasUserFacingPassword( - chromeos::ProfileHelper::Get() - ->GetUserByProfile(profile) - ->GetAccountId())); - const bool fingerprint_unlock_enabled = - chromeos::quick_unlock::IsFingerprintEnabled(profile); - html_source->AddBoolean("fingerprintUnlockEnabled", - fingerprint_unlock_enabled); - if (fingerprint_unlock_enabled) { - html_source->AddInteger( - "fingerprintReaderLocation", - static_cast<int32_t>(chromeos::quick_unlock::GetFingerprintLocation())); - - // To use lottie, the worker-src CSP needs to be updated for the web ui that - // is using it. Since as of now there are only a couple of webuis using - // lottie animations, this update has to be performed manually. As the usage - // increases, set this as the default so manual override is no longer - // required. - html_source->OverrideContentSecurityPolicyWorkerSrc( - "worker-src blob: 'self';"); - html_source->AddResourcePath("finger_print.json", - IDR_LOGIN_FINGER_PRINT_TABLET_ANIMATION); } - html_source->AddBoolean("lockScreenNotificationsEnabled", - ash::features::IsLockScreenNotificationsEnabled()); - html_source->AddBoolean( - "lockScreenHideSensitiveNotificationsSupported", - ash::features::IsLockScreenHideSensitiveNotificationsSupported()); - html_source->AddBoolean("showTechnologyBadge", - !ash::features::IsSeparateNetworkIconsEnabled()); - html_source->AddBoolean("hasInternalStylus", - ash::stylus_utils::HasInternalStylus()); - - html_source->AddBoolean("showCrostini", - crostini::CrostiniFeatures::Get()->IsUIAllowed( - profile, /*check_policy=*/false)); - - html_source->AddBoolean( - "allowCrostini", crostini::CrostiniFeatures::Get()->IsUIAllowed(profile)); - html_source->AddBoolean("showPluginVm", - plugin_vm::IsPluginVmEnabled(profile)); - - html_source->AddBoolean("isDemoSession", - chromeos::DemoSession::IsDeviceInDemoMode()); - - // We have 2 variants of Android apps settings. Default case, when the Play - // Store app exists we show expandable section that allows as to - // enable/disable the Play Store and link to Android settings which is - // available once settings app is registered in the system. - // For AOSP images we don't have the Play Store app. In last case we Android - // apps settings consists only from root link to Android settings and only - // visible once settings app is registered. - html_source->AddBoolean("androidAppsVisible", - arc::IsArcAllowedForProfile(profile)); - html_source->AddBoolean("havePlayStoreApp", arc::IsPlayStoreAvailable()); - - html_source->AddBoolean("enablePowerSettings", true); - web_ui->AddMessageHandler( - std::make_unique<chromeos::settings::PowerHandler>(profile->GetPrefs())); - - html_source->AddBoolean( - "showParentalControlsSettings", - chromeos::settings::ShouldShowParentalControls(profile)); + web_ui()->AddMessageHandler( + std::make_unique<chromeos::settings::AndroidAppsHandler>(profile)); } #endif // defined(OS_CHROMEOS) @@ -533,12 +439,14 @@ void SettingsUI::AddSettingsPageUIHandler( web_ui()->AddMessageHandler(std::move(handler)); } -#if defined(OS_CHROMEOS) -void SettingsUI::BindCrosNetworkConfig( - mojo::PendingReceiver<chromeos::network_config::mojom::CrosNetworkConfig> - receiver) { - ash::GetNetworkConfigService(std::move(receiver)); +void SettingsUI::TryShowHatsSurveyWithTimeout() { + HatsService* hats_service = + HatsServiceFactory::GetForProfile(Profile::FromWebUI(web_ui()), + /* create_if_necessary = */ true); + if (hats_service) { + hats_service->LaunchDelayedSurveyForWebContents( + kHatsSurveyTriggerSettings, web_ui()->GetWebContents(), 20000); + } } -#endif // defined(OS_CHROMEOS) } // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/settings_ui.h b/chromium/chrome/browser/ui/webui/settings/settings_ui.h index 0353806fc15..ff4a05c608e 100644 --- a/chromium/chrome/browser/ui/webui/settings/settings_ui.h +++ b/chromium/chrome/browser/ui/webui/settings/settings_ui.h @@ -8,19 +8,9 @@ #include "base/macros.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/webui_load_timer.h" - -#if defined(OS_CHROMEOS) -#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom-forward.h" // nogncheck -#include "mojo/public/cpp/bindings/pending_receiver.h" -#include "ui/webui/mojo_web_ui_controller.h" -#else #include "content/public/browser/web_ui_controller.h" -#endif - -class Profile; namespace content { -class WebUIDataSource; class WebUIMessageHandler; } // namespace content @@ -31,13 +21,7 @@ class PrefRegistrySyncable; namespace settings { // The WebUI handler for chrome://settings. -class SettingsUI -#if defined(OS_CHROMEOS) - : public ui::MojoWebUIController -#else - : public content::WebUIController -#endif -{ +class SettingsUI : public content::WebUIController { public: static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); @@ -45,20 +29,17 @@ class SettingsUI ~SettingsUI() override; #if defined(OS_CHROMEOS) - // Initializes the WebUI message handlers for OS-specific settings. - static void InitOSWebUIHandlers(Profile* profile, - content::WebUI* web_ui, - content::WebUIDataSource* html_source); + // Initializes the WebUI message handlers for CrOS-specific settings that are + // still shown in the browser settings UI. + void InitBrowserSettingsWebUIHandlers(); #endif // defined(OS_CHROMEOS) private: void AddSettingsPageUIHandler( std::unique_ptr<content::WebUIMessageHandler> handler); -#if defined(OS_CHROMEOS) - void BindCrosNetworkConfig( - mojo::PendingReceiver<chromeos::network_config::mojom::CrosNetworkConfig> - receiver); -#endif + + // Makes a request to show a HaTS survey. + void TryShowHatsSurveyWithTimeout(); WebuiLoadTimer webui_load_timer_; diff --git a/chromium/chrome/browser/ui/webui/settings/settings_ui_browsertest.cc b/chromium/chrome/browser/ui/webui/settings/settings_ui_browsertest.cc index 459f2165900..c19638cf1bc 100644 --- a/chromium/chrome/browser/ui/webui/settings/settings_ui_browsertest.cc +++ b/chromium/chrome/browser/ui/webui/settings/settings_ui_browsertest.cc @@ -5,7 +5,10 @@ #include <string> #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/hats/hats_service_factory.h" +#include "chrome/browser/ui/hats/mock_hats_service.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/webui/settings/settings_ui.h" #include "chrome/common/url_constants.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" @@ -17,6 +20,7 @@ typedef InProcessBrowserTest SettingsUITest; +using ::testing::_; using ui_test_utils::NavigateToURL; IN_PROC_BROWSER_TEST_F(SettingsUITest, ViewSourceDoesntCrash) { @@ -43,3 +47,13 @@ IN_PROC_BROWSER_TEST_F(SettingsUITest, ToggleJavaScript) { handler->AllowJavascriptForTesting(); } } + +IN_PROC_BROWSER_TEST_F(SettingsUITest, TriggerHappinessTrackingSurveys) { + MockHatsService* mock_hats_service_ = static_cast<MockHatsService*>( + HatsServiceFactory::GetInstance()->SetTestingFactoryAndUse( + browser()->profile(), base::BindRepeating(&BuildMockHatsService))); + EXPECT_CALL(*mock_hats_service_, LaunchDelayedSurveyForWebContents( + kHatsSurveyTriggerSettings, _, _)); + NavigateToURL(browser(), GURL(chrome::kChromeUISettingsURL)); + base::RunLoop().RunUntilIdle(); +} diff --git a/chromium/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc b/chromium/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc new file mode 100644 index 00000000000..9a461686fd3 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc @@ -0,0 +1,243 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// 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/shared_settings_localized_strings_provider.h" + +#include "base/feature_list.h" +#include "base/strings/utf_string_conversions.h" +#include "base/system/sys_info.h" +#include "build/build_config.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/browser_process_platform_part.h" +#include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/ui/ui_features.h" +#include "chrome/browser/ui/webui/webui_util.h" +#include "chrome/common/chrome_features.h" +#include "chrome/common/url_constants.h" +#include "chrome/grit/chromium_strings.h" +#include "chrome/grit/generated_resources.h" +#include "chromeos/constants/chromeos_features.h" +#include "components/google/core/common/google_util.h" +#include "components/strings/grit/components_strings.h" +#include "components/user_manager/user_manager.h" +#include "content/public/browser/web_ui_data_source.h" +#include "content/public/common/content_features.h" +#include "media/base/media_switches.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/webui/web_ui_util.h" + +#if defined(OS_CHROMEOS) +#include "ui/base/l10n/l10n_util.h" +#endif + +namespace settings { +#if defined(OS_CHROMEOS) +namespace { + +// Generates a Google Help URL which includes a "board type" parameter. Some +// help pages need to be adjusted depending on the type of CrOS device that is +// accessing the page. +base::string16 GetHelpUrlWithBoard(const std::string& original_url) { + return base::ASCIIToUTF16(original_url + + "&b=" + base::SysInfo::GetLsbReleaseBoard()); +} + +} // namespace +#endif + +void AddCaptionSubpageStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"captionsTitle", IDS_SETTINGS_CAPTIONS}, + {"captionsSettings", IDS_SETTINGS_CAPTIONS_SETTINGS}, + {"captionsPreview", IDS_SETTINGS_CAPTIONS_PREVIEW}, + {"captionsTextSize", IDS_SETTINGS_CAPTIONS_TEXT_SIZE}, + {"captionsTextFont", IDS_SETTINGS_CAPTIONS_TEXT_FONT}, + {"captionsTextColor", IDS_SETTINGS_CAPTIONS_TEXT_COLOR}, + {"captionsTextOpacity", IDS_SETTINGS_CAPTIONS_TEXT_OPACITY}, + {"captionsBackgroundOpacity", IDS_SETTINGS_CAPTIONS_BACKGROUND_OPACITY}, + {"captionsOpacityOpaque", IDS_SETTINGS_CAPTIONS_OPACITY_OPAQUE}, + {"captionsOpacitySemiTransparent", + IDS_SETTINGS_CAPTIONS_OPACITY_SEMI_TRANSPARENT}, + {"captionsOpacityTransparent", IDS_SETTINGS_CAPTIONS_OPACITY_TRANSPARENT}, + {"captionsTextShadow", IDS_SETTINGS_CAPTIONS_TEXT_SHADOW}, + {"captionsTextShadowNone", IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_NONE}, + {"captionsTextShadowRaised", IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_RAISED}, + {"captionsTextShadowDepressed", + IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_DEPRESSED}, + {"captionsTextShadowUniform", IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_UNIFORM}, + {"captionsTextShadowDropShadow", + IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_DROP_SHADOW}, + {"captionsBackgroundColor", IDS_SETTINGS_CAPTIONS_BACKGROUND_COLOR}, + {"captionsColorBlack", IDS_SETTINGS_CAPTIONS_COLOR_BLACK}, + {"captionsColorWhite", IDS_SETTINGS_CAPTIONS_COLOR_WHITE}, + {"captionsColorRed", IDS_SETTINGS_CAPTIONS_COLOR_RED}, + {"captionsColorGreen", IDS_SETTINGS_CAPTIONS_COLOR_GREEN}, + {"captionsColorBlue", IDS_SETTINGS_CAPTIONS_COLOR_BLUE}, + {"captionsColorYellow", IDS_SETTINGS_CAPTIONS_COLOR_YELLOW}, + {"captionsColorCyan", IDS_SETTINGS_CAPTIONS_COLOR_CYAN}, + {"captionsColorMagenta", IDS_SETTINGS_CAPTIONS_COLOR_MAGENTA}, + {"captionsDefaultSetting", IDS_SETTINGS_CAPTIONS_DEFAULT_SETTING}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); +} + +void AddPersonalizationOptionsStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"urlKeyedAnonymizedDataCollection", + IDS_SETTINGS_ENABLE_URL_KEYED_ANONYMIZED_DATA_COLLECTION}, + {"urlKeyedAnonymizedDataCollectionDesc", + IDS_SETTINGS_ENABLE_URL_KEYED_ANONYMIZED_DATA_COLLECTION_DESC}, + {"spellingPref", IDS_SETTINGS_SPELLING_PREF}, +#if !defined(OS_CHROMEOS) + {"signinAllowedTitle", IDS_SETTINGS_SIGNIN_ALLOWED}, + {"signinAllowedDescription", IDS_SETTINGS_SIGNIN_ALLOWED_DESC}, +#endif + {"searchSuggestPref", IDS_SETTINGS_SUGGEST_PREF}, + {"enablePersonalizationLogging", IDS_SETTINGS_ENABLE_LOGGING_PREF}, + {"enablePersonalizationLoggingDesc", IDS_SETTINGS_ENABLE_LOGGING_PREF_DESC}, + {"spellingDescription", IDS_SETTINGS_SPELLING_PREF_DESC}, + {"searchSuggestPrefDesc", IDS_SETTINGS_SUGGEST_PREF_DESC}, + {"linkDoctorPref", IDS_SETTINGS_LINKDOCTOR_PREF}, + {"linkDoctorPrefDesc", IDS_SETTINGS_LINKDOCTOR_PREF_DESC}, + {"driveSuggestPref", IDS_DRIVE_SUGGEST_PREF}, + {"driveSuggestPrefDesc", IDS_DRIVE_SUGGEST_PREF_DESC}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); +} + +void AddSyncControlsStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"autofillCheckboxLabel", IDS_SETTINGS_AUTOFILL_CHECKBOX_LABEL}, + {"historyCheckboxLabel", IDS_SETTINGS_HISTORY_CHECKBOX_LABEL}, + {"extensionsCheckboxLabel", IDS_SETTINGS_EXTENSIONS_CHECKBOX_LABEL}, + {"openTabsCheckboxLabel", IDS_SETTINGS_OPEN_TABS_CHECKBOX_LABEL}, + {"syncEverythingCheckboxLabel", + IDS_SETTINGS_SYNC_EVERYTHING_CHECKBOX_LABEL}, + {"appCheckboxLabel", IDS_SETTINGS_APPS_CHECKBOX_LABEL}, + {"enablePaymentsIntegrationCheckboxLabel", + IDS_AUTOFILL_ENABLE_PAYMENTS_INTEGRATION_CHECKBOX_LABEL}, + {"nonPersonalizedServicesSectionLabel", + IDS_SETTINGS_NON_PERSONALIZED_SERVICES_SECTION_LABEL}, + {"customizeSyncLabel", IDS_SETTINGS_CUSTOMIZE_SYNC}, + {"syncData", IDS_SETTINGS_SYNC_DATA}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); +} + +void AddSyncAccountControlStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"syncingTo", IDS_SETTINGS_PEOPLE_SYNCING_TO_ACCOUNT}, + {"peopleSignIn", IDS_PROFILES_DICE_SIGNIN_BUTTON}, + {"syncPaused", IDS_SETTINGS_PEOPLE_SYNC_PAUSED}, + {"turnOffSync", IDS_SETTINGS_PEOPLE_SYNC_TURN_OFF}, + {"settingsCheckboxLabel", IDS_SETTINGS_SETTINGS_CHECKBOX_LABEL}, + {"syncNotWorking", IDS_SETTINGS_PEOPLE_SYNC_NOT_WORKING}, + {"syncDisabled", IDS_PROFILES_DICE_SYNC_DISABLED_TITLE}, + {"syncPasswordsNotWorking", + IDS_SETTINGS_PEOPLE_SYNC_PASSWORDS_NOT_WORKING}, + {"peopleSignOut", IDS_SETTINGS_PEOPLE_SIGN_OUT}, + {"useAnotherAccount", IDS_SETTINGS_PEOPLE_SYNC_ANOTHER_ACCOUNT}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + if (base::FeatureList::IsEnabled(features::kSyncSetupFriendlySettings)) { + html_source->AddLocalizedString("syncAdvancedPageTitle", + IDS_SETTINGS_NEW_SYNC_ADVANCED_PAGE_TITLE); + + } else { + html_source->AddLocalizedString("syncAdvancedPageTitle", + IDS_SETTINGS_SYNC_ADVANCED_PAGE_TITLE); + } +} + +#if defined(OS_CHROMEOS) +void AddPasswordPromptDialogStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"passwordPromptTitle", IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_TITLE}, + {"passwordPromptInvalidPassword", + IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_INVALID_PASSWORD}, + {"passwordPromptPasswordLabel", + IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_PASSWORD_LABEL}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); +} +#endif + +void AddSyncPageStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"syncDisabledByAdministrator", + IDS_SIGNED_IN_WITH_SYNC_DISABLED_BY_POLICY}, + {"passwordsCheckboxLabel", IDS_SETTINGS_PASSWORDS_CHECKBOX_LABEL}, + {"passphrasePlaceholder", IDS_SETTINGS_PASSPHRASE_PLACEHOLDER}, + {"peopleSignInSyncPagePromptSecondaryWithAccount", + IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT_SECONDARY_WITH_ACCOUNT}, + {"peopleSignInSyncPagePromptSecondaryWithNoAccount", + IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT_SECONDARY_WITH_ACCOUNT}, + {"existingPassphraseTitle", IDS_SETTINGS_EXISTING_PASSPHRASE_TITLE}, + {"submitPassphraseButton", IDS_SETTINGS_SUBMIT_PASSPHRASE}, + {"encryptWithGoogleCredentialsLabel", + IDS_SETTINGS_ENCRYPT_WITH_GOOGLE_CREDENTIALS_LABEL}, + {"bookmarksCheckboxLabel", IDS_SETTINGS_BOOKMARKS_CHECKBOX_LABEL}, + {"encryptionOptionsTitle", IDS_SETTINGS_ENCRYPTION_OPTIONS}, + {"mismatchedPassphraseError", IDS_SETTINGS_MISMATCHED_PASSPHRASE_ERROR}, + {"emptyPassphraseError", IDS_SETTINGS_EMPTY_PASSPHRASE_ERROR}, + {"incorrectPassphraseError", IDS_SETTINGS_INCORRECT_PASSPHRASE_ERROR}, + {"syncPageTitle", IDS_SETTINGS_SYNC_SYNC_AND_NON_PERSONALIZED_SERVICES}, + {"passphraseConfirmationPlaceholder", + IDS_SETTINGS_PASSPHRASE_CONFIRMATION_PLACEHOLDER}, + {"syncLoading", IDS_SETTINGS_SYNC_LOADING}, + {"themesAndWallpapersCheckboxLabel", + IDS_SETTINGS_THEMES_AND_WALLPAPERS_CHECKBOX_LABEL}, + {"syncDataEncryptedText", IDS_SETTINGS_SYNC_DATA_ENCRYPTED_TEXT}, + {"sync", IDS_SETTINGS_SYNC}, + {"cancelSync", IDS_SETTINGS_SYNC_SETTINGS_CANCEL_SYNC}, + {"syncSetupCancelDialogTitle", + IDS_SETTINGS_SYNC_SETUP_CANCEL_DIALOG_TITLE}, + {"syncSetupCancelDialogBody", IDS_SETTINGS_SYNC_SETUP_CANCEL_DIALOG_BODY}, + {"personalizeGoogleServicesTitle", + IDS_SETTINGS_PERSONALIZE_GOOGLE_SERVICES_TITLE}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings); + + std::string sync_dashboard_url = + google_util::AppendGoogleLocaleParam( + GURL(chrome::kSyncGoogleDashboardURL), + g_browser_process->GetApplicationLocale()) + .spec(); + + html_source->AddString( + "passphraseResetHintEncryption", + l10n_util::GetStringFUTF8(IDS_SETTINGS_PASSPHRASE_RESET_HINT_ENCRYPTION, + base::ASCIIToUTF16(sync_dashboard_url))); + html_source->AddString( + "passphraseRecover", + l10n_util::GetStringFUTF8(IDS_SETTINGS_PASSPHRASE_RECOVER, + base::ASCIIToUTF16(sync_dashboard_url))); + html_source->AddString("activityControlsUrl", + chrome::kGoogleAccountActivityControlsURL); + html_source->AddString("syncDashboardUrl", sync_dashboard_url); + html_source->AddString( + "passphraseExplanationText", + l10n_util::GetStringFUTF8(IDS_SETTINGS_PASSPHRASE_EXPLANATION_TEXT, + base::ASCIIToUTF16(sync_dashboard_url))); + html_source->AddString( + "encryptWithSyncPassphraseLabel", + l10n_util::GetStringFUTF8( + IDS_SETTINGS_ENCRYPT_WITH_SYNC_PASSPHRASE_LABEL, +#if defined(OS_CHROMEOS) + GetHelpUrlWithBoard(chrome::kSyncEncryptionHelpURL))); +#else + base::ASCIIToUTF16(chrome::kSyncEncryptionHelpURL))); +#endif + if (base::FeatureList::IsEnabled(features::kSyncSetupFriendlySettings)) { + html_source->AddLocalizedString( + "manageSyncedDataTitle", + IDS_SETTINGS_NEW_MANAGE_SYNCED_DATA_TITLE_UNIFIED_CONSENT); + } else { + html_source->AddLocalizedString( + "manageSyncedDataTitle", + IDS_SETTINGS_MANAGE_SYNCED_DATA_TITLE_UNIFIED_CONSENT); + } +} + +} // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.h b/chromium/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.h new file mode 100644 index 00000000000..33dc5c453d4 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.h @@ -0,0 +1,36 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_SHARED_SETTINGS_LOCALIZED_STRINGS_PROVIDER_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_SHARED_SETTINGS_LOCALIZED_STRINGS_PROVIDER_H_ + +namespace content { +class WebUIDataSource; +} // namespace content + +namespace settings { + +// Adds strings used by the <settings-captions> element. +void AddCaptionSubpageStrings(content::WebUIDataSource* html_source); + +// Adds strings used by the <settings-personalization-options> element. +void AddPersonalizationOptionsStrings(content::WebUIDataSource* html_source); + +// Adds strings used by the <settings-sync-controls> element. +void AddSyncControlsStrings(content::WebUIDataSource* html_source); + +// Adds strings used by the <settings-sync-account-control> element. +void AddSyncAccountControlStrings(content::WebUIDataSource* html_source); + +#if defined(OS_CHROMEOS) +// Adds strings used by the <settings-password-prompt-dialog> element. +void AddPasswordPromptDialogStrings(content::WebUIDataSource* html_source); +#endif + +// Adds strings used by the <settings-sync-page> element. +void AddSyncPageStrings(content::WebUIDataSource* html_source); + +} // namespace settings + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_SHARED_SETTINGS_LOCALIZED_STRINGS_PROVIDER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/site_settings_handler.cc b/chromium/chrome/browser/ui/webui/settings/site_settings_handler.cc index 95ccbe20024..b53e4f98315 100644 --- a/chromium/chrome/browser/ui/webui/settings/site_settings_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/site_settings_handler.cc @@ -5,11 +5,13 @@ #include "chrome/browser/ui/webui/settings/site_settings_handler.h" #include <algorithm> +#include <set> #include <utility> #include <vector> #include "base/barrier_closure.h" #include "base/bind.h" +#include "base/feature_list.h" #include "base/i18n/number_formatting.h" #include "base/macros.h" #include "base/metrics/histogram_macros.h" @@ -17,22 +19,22 @@ #include "base/stl_util.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" +#include "chrome/browser/bluetooth/bluetooth_chooser_context.h" +#include "chrome/browser/bluetooth/bluetooth_chooser_context_factory.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" -#include "chrome/browser/content_settings/web_site_settings_uma_util.h" #include "chrome/browser/engagement/site_engagement_service.h" +#include "chrome/browser/hid/hid_chooser_context.h" +#include "chrome/browser/hid/hid_chooser_context_factory.h" #include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/media/unified_autoplay_config.h" -#include "chrome/browser/permissions/chooser_context_base.h" -#include "chrome/browser/permissions/permission_decision_auto_blocker.h" -#include "chrome/browser/permissions/permission_manager.h" -#include "chrome/browser/permissions/permission_uma_util.h" -#include "chrome/browser/permissions/permission_util.h" +#include "chrome/browser/permissions/permission_decision_auto_blocker_factory.h" #include "chrome/browser/serial/serial_chooser_context.h" #include "chrome/browser/serial/serial_chooser_context_factory.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/page_info/page_info_infobar_delegate.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/webui/recent_site_settings_helper.h" #include "chrome/browser/ui/webui/site_settings_helper.h" #include "chrome/browser/usb/usb_chooser_context.h" #include "chrome/browser/usb/usb_chooser_context_factory.h" @@ -41,15 +43,24 @@ #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" +#include "components/content_settings/core/browser/cookie_settings.h" +#include "components/content_settings/core/browser/uma_util.h" #include "components/content_settings/core/browser/website_settings_registry.h" #include "components/content_settings/core/common/content_settings_types.h" #include "components/content_settings/core/common/content_settings_utils.h" +#include "components/content_settings/core/common/features.h" +#include "components/content_settings/core/common/pref_names.h" #include "components/crx_file/id_util.h" +#include "components/permissions/chooser_context_base.h" +#include "components/permissions/permission_decision_auto_blocker.h" +#include "components/permissions/permission_uma_util.h" +#include "components/permissions/permission_util.h" #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_service.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" +#include "content/public/common/content_features.h" #include "content/public/common/origin_util.h" #include "content/public/common/url_constants.h" #include "extensions/browser/extension_registry.h" @@ -92,6 +103,17 @@ enum class AllSitesAction { kMaxValue = kEnterSiteDetails, }; +enum class AllSitesAction2 { + kLoadPage = 0, + kResetSiteGroupPermissions = 1, + kResetOriginPermissions = 2, + kClearAllData = 3, + kClearSiteGroupData = 4, + kClearOriginData = 5, + kEnterSiteDetails = 6, + kMaxValue = kEnterSiteDetails, +}; + // Return an appropriate API Permission ID for the given string name. extensions::APIPermission::APIPermission::ID APIPermissionFromGroupName( std::string type) { @@ -142,32 +164,13 @@ void AddExceptionsGrantedByHostedApps( } } -base::flat_set<web_app::AppId> GetInstalledApps( +base::flat_set<std::string> GetInstalledAppOrigins( Profile* profile, - web_app::AppRegistrar& registrar) { - auto apps = registrar.GetAppIds(); - base::flat_set<std::string> installed; - for (auto app : apps) { - base::Optional<GURL> scope = registrar.GetAppScope(app); - if (scope.has_value()) - installed.insert(scope.value().GetOrigin().spec()); - } - return installed; -} - -// Whether |pattern| applies to a single origin. -bool PatternAppliesToSingleOrigin(const ContentSettingPatternSource& pattern) { - const GURL url(pattern.primary_pattern.ToString()); - // Default settings and other patterns apply to multiple origins. - if (url::Origin::Create(url).opaque()) - return false; - // Embedded content settings only when |url| is embedded in another origin, so - // ignore non-wildcard secondary patterns that are different to the primary. - if (pattern.primary_pattern != pattern.secondary_pattern && - pattern.secondary_pattern != ContentSettingsPattern::Wildcard()) { - return false; - } - return true; + const web_app::AppRegistrar& registrar) { + base::flat_set<std::string> origins; + for (const web_app::AppId& app : registrar.GetAppIds()) + origins.insert(registrar.GetAppScope(app).GetOrigin().spec()); + return origins; } // Groups |url| into sets of eTLD+1s in |site_group_map|, assuming |url| is an @@ -236,11 +239,11 @@ void ConvertSiteGroupMapToListValue( const std::set<std::string>& origin_permission_set, base::Value* list_value, Profile* profile, - web_app::AppRegistrar& registrar) { + const web_app::AppRegistrar& registrar) { DCHECK_EQ(base::Value::Type::LIST, list_value->type()); DCHECK(profile); - base::flat_set<web_app::AppId> installed_apps = - GetInstalledApps(profile, registrar); + base::flat_set<std::string> installed_origins = + GetInstalledAppOrigins(profile, registrar); SiteEngagementService* engagement_service = SiteEngagementService::Get(profile); for (const auto& entry : site_group_map) { @@ -267,7 +270,7 @@ void ConvertSiteGroupMapToListValue( origin_object.SetKey("usage", base::Value(0)); origin_object.SetKey(kNumCookies, base::Value(0)); - bool is_installed = installed_apps.contains(origin); + bool is_installed = installed_origins.contains(origin); if (is_installed) has_installed_pwa = true; origin_object.SetKey(kIsInstalled, base::Value(is_installed)); @@ -327,8 +330,58 @@ void UpdateDataFromCookiesTree( CreateOrAppendSiteGroupEntry(all_sites_map, origin); } -void LogAllSitesAction(AllSitesAction action) { - UMA_HISTOGRAM_ENUMERATION("WebsiteSettings.AllSitesAction", action); +void LogAllSitesAction(AllSitesAction2 action) { + UMA_HISTOGRAM_ENUMERATION("WebsiteSettings.AllSitesAction2", action); +} + +int GetNumCookieExceptionsOfTypes(HostContentSettingsMap* map, + const std::set<ContentSetting> types) { + ContentSettingsForOneType output; + map->GetSettingsForOneType(ContentSettingsType::COOKIES, std::string(), + &output); + return std::count_if( + output.begin(), output.end(), + [types](const ContentSettingPatternSource setting) { + return types.count( + content_settings::ValueToContentSetting(&setting.setting_value)); + }); +} + +std::string GetCookieSettingDescription(Profile* profile) { + HostContentSettingsMap* map = + HostContentSettingsMapFactory::GetForProfile(profile); + auto content_setting = + map->GetDefaultContentSetting(ContentSettingsType::COOKIES, nullptr); + + bool block_third_party = + profile->GetPrefs()->GetBoolean(prefs::kBlockThirdPartyCookies); + auto control_mode = static_cast<content_settings::CookieControlsMode>( + profile->GetPrefs()->GetInteger(prefs::kCookieControlsMode)); + + // Determine what the effective cookie setting is. These conditions are not + // mutually exclusive and rely on ordering. + if (content_setting == ContentSetting::CONTENT_SETTING_BLOCK) { + return l10n_util::GetPluralStringFUTF8( + IDS_SETTINGS_SITE_SETTINGS_COOKIES_BLOCK, + GetNumCookieExceptionsOfTypes( + map, {ContentSetting::CONTENT_SETTING_ALLOW, + ContentSetting::CONTENT_SETTING_SESSION_ONLY})); + } else if (block_third_party) { + return l10n_util::GetStringUTF8( + IDS_SETTINGS_SITE_SETTINGS_COOKIES_BLOCK_THIRD_PARTY); + } else if (base::FeatureList::IsEnabled( + content_settings::kImprovedCookieControls) && + control_mode == + content_settings::CookieControlsMode::kIncognitoOnly) { + return l10n_util::GetStringUTF8( + IDS_SETTINGS_SITE_SETTINGS_COOKIES_BLOCK_THIRD_PARTY_INCOGNITO); + } else { + // We do not make a distinction between allow and clear on exit. + return l10n_util::GetPluralStringFUTF8( + IDS_SETTINGS_SITE_SETTINGS_COOKIES_ALLOW, + GetNumCookieExceptionsOfTypes(map, + {ContentSetting::CONTENT_SETTING_BLOCK})); + } } } // namespace @@ -365,6 +418,20 @@ void SiteSettingsHandler::RegisterMessages() { base::BindRepeating(&SiteSettingsHandler::HandleGetAllSites, base::Unretained(this))); web_ui()->RegisterMessageCallback( + "getCookieControlsManagedState", + base::BindRepeating( + &SiteSettingsHandler::HandleGetCookieControlsManagedState, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "getCookieSettingDescription", + base::BindRepeating( + &SiteSettingsHandler::HandleGetCookieSettingDescription, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "getRecentSitePermissions", + base::BindRepeating(&SiteSettingsHandler::HandleGetRecentSitePermissions, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( "getFormattedBytes", base::BindRepeating(&SiteSettingsHandler::HandleGetFormattedBytes, base::Unretained(this))); @@ -454,8 +521,8 @@ void SiteSettingsHandler::OnJavascriptAllowed() { host_zoom_map_subscription_ = content::HostZoomMap::GetDefaultForBrowserContext(profile_) ->AddZoomLevelChangedCallback( - base::Bind(&SiteSettingsHandler::OnZoomLevelChanged, - base::Unretained(this))); + base::BindRepeating(&SiteSettingsHandler::OnZoomLevelChanged, + base::Unretained(this))); pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>(); pref_change_registrar_->Init(profile_->GetPrefs()); @@ -466,6 +533,16 @@ void SiteSettingsHandler::OnJavascriptAllowed() { base::Bind(&SiteSettingsHandler::SendBlockAutoplayStatus, base::Unretained(this))); + // Listen for prefs that impact the effective cookie setting + pref_change_registrar_->Add( + prefs::kBlockThirdPartyCookies, + base::Bind(&SiteSettingsHandler::SendCookieSettingDescription, + base::Unretained(this))); + pref_change_registrar_->Add( + prefs::kCookieControlsMode, + base::Bind(&SiteSettingsHandler::SendCookieSettingDescription, + base::Unretained(this))); + #if defined(OS_CHROMEOS) pref_change_registrar_->Add( prefs::kEnableDRM, @@ -479,6 +556,8 @@ void SiteSettingsHandler::OnJavascriptDisallowed() { chooser_observer_.RemoveAll(); host_zoom_map_subscription_.reset(); pref_change_registrar_->Remove(prefs::kBlockAutoplayEnabled); + pref_change_registrar_->Remove(prefs::kBlockThirdPartyCookies); + pref_change_registrar_->Remove(prefs::kCookieControlsMode); #if defined(OS_CHROMEOS) pref_change_registrar_->Remove(prefs::kEnableDRM); #endif @@ -505,9 +584,8 @@ void SiteSettingsHandler::OnGetUsageInfo() { } break; } - CallJavascriptFunction("settings.WebsiteUsagePrivateApi.returnUsageTotal", - base::Value(usage_host_), base::Value(usage_string), - base::Value(cookie_string)); + FireWebUIListener("usage-total-changed", base::Value(usage_host_), + base::Value(usage_string), base::Value(cookie_string)); } #if defined(OS_CHROMEOS) @@ -546,6 +624,12 @@ void SiteSettingsHandler::OnContentSettingChanged( content_type == ContentSettingsType::SOUND) { SendBlockAutoplayStatus(); } + + // If the default cookie setting changed we should update the effective + // setting description. + if (content_type == ContentSettingsType::COOKIES) { + SendCookieSettingDescription(); + } } void SiteSettingsHandler::OnOffTheRecordProfileCreated( @@ -671,22 +755,14 @@ void SiteSettingsHandler::HandleGetDefaultValueForContentType( void SiteSettingsHandler::HandleGetAllSites(const base::ListValue* args) { AllowJavascript(); - CHECK_EQ(2U, args->GetSize()); - const base::Value* callback_id; - CHECK(args->Get(0, &callback_id)); - const base::ListValue* types; - CHECK(args->GetList(1, &types)); + CHECK_EQ(2U, args->GetList().size()); + std::string callback_id = args->GetList()[0].GetString(); + auto types = args->GetList()[1].GetList(); all_sites_map_.clear(); origin_permission_set_.clear(); - // Convert |types| to a list of ContentSettingsTypes. - std::vector<ContentSettingsType> content_types; - for (size_t i = 0; i < types->GetSize(); ++i) { - std::string type; - types->GetString(i, &type); - content_types.push_back( - site_settings::ContentSettingsTypeFromGroupName(type)); - } + + auto content_types = site_settings::ContentSettingsTypesFromGroupNames(types); // Incognito contains incognito content settings plus non-incognito content // settings. Thus if it exists, just get exceptions for the incognito profile. @@ -701,38 +777,22 @@ void SiteSettingsHandler::HandleGetAllSites(const base::ListValue* args) { // Retrieve a list of embargoed settings to check separately. This ensures // that only settings included in |content_types| will be listed in all sites. - ContentSettingsForOneType embargo_settings; - map->GetSettingsForOneType(ContentSettingsType::PERMISSION_AUTOBLOCKER_DATA, - std::string(), &embargo_settings); - PermissionManager* permission_manager = PermissionManager::Get(profile); - for (const ContentSettingPatternSource& e : embargo_settings) { - for (ContentSettingsType content_type : content_types) { - if (PermissionUtil::IsPermission(content_type)) { - const GURL url(e.primary_pattern.ToString()); - // Add |url| to the set if there are any embargo settings. - PermissionResult result = - permission_manager->GetPermissionStatus(content_type, url, url); - if (result.source == PermissionStatusSource::MULTIPLE_DISMISSALS || - result.source == PermissionStatusSource::MULTIPLE_IGNORES) { - CreateOrAppendSiteGroupEntry(&all_sites_map_, url); - origin_permission_set_.insert(url.spec()); - break; - } - } - } + auto* autoblocker = + PermissionDecisionAutoBlockerFactory::GetForProfile(profile_); + for (auto& url : autoblocker->GetEmbargoedOrigins(content_types)) { + // Add |url| to the set if there are any embargo settings. + CreateOrAppendSiteGroupEntry(&all_sites_map_, url); + origin_permission_set_.insert(url.spec()); } - // Convert |types| to a list of ContentSettingsTypes. - for (ContentSettingsType content_type : content_types) { - ContentSettingsForOneType entries; - map->GetSettingsForOneType(content_type, std::string(), &entries); - for (const ContentSettingPatternSource& e : entries) { - if (PatternAppliesToSingleOrigin(e)) { - CreateOrAppendSiteGroupEntry(&all_sites_map_, - GURL(e.primary_pattern.ToString())); - origin_permission_set_.insert( - GURL(e.primary_pattern.ToString()).spec()); - } + // Get permission exceptions which apply to a single site + for (auto content_type : content_types) { + auto exceptions = + site_settings::GetSiteExceptionsForContentType(map, content_type); + for (const auto& e : exceptions) { + GURL url = GURL(e.primary_pattern.ToString()); + CreateOrAppendSiteGroupEntry(&all_sites_map_, url); + origin_permission_set_.insert(url.spec()); } } @@ -750,11 +810,95 @@ void SiteSettingsHandler::HandleGetAllSites(const base::ListValue* args) { ConvertSiteGroupMapToListValue(all_sites_map_, origin_permission_set_, &result, profile, app_registrar_); - LogAllSitesAction(AllSitesAction::kLoadPage); + LogAllSitesAction(AllSitesAction2::kLoadPage); send_sites_list_ = true; - ResolveJavascriptCallback(*callback_id, result); + ResolveJavascriptCallback(base::Value(callback_id), result); +} + +void SiteSettingsHandler::HandleGetCookieControlsManagedState( + const base::ListValue* args) { + AllowJavascript(); + CHECK_EQ(1U, args->GetList().size()); + std::string callback_id = args->GetList()[0].GetString(); + + auto managed_states = site_settings::GetCookieControlsManagedState(profile_); + + base::Value result(base::Value::Type::DICTIONARY); + result.SetKey( + site_settings::kAllowAll, + site_settings::GetValueForManagedState(managed_states.allow_all)); + result.SetKey(site_settings::kBlockThirdPartyIncognito, + site_settings::GetValueForManagedState( + managed_states.block_third_party_incognito)); + result.SetKey( + site_settings::kBlockThirdParty, + site_settings::GetValueForManagedState(managed_states.block_third_party)); + result.SetKey( + site_settings::kBlockAll, + site_settings::GetValueForManagedState(managed_states.block_all)); + result.SetKey( + site_settings::kSessionOnly, + site_settings::GetValueForManagedState(managed_states.session_only)); + + ResolveJavascriptCallback(base::Value(callback_id), result); +} + +void SiteSettingsHandler::HandleGetCookieSettingDescription( + const base::ListValue* args) { + AllowJavascript(); + CHECK_EQ(1U, args->GetList().size()); + std::string callback_id = args->GetList()[0].GetString(); + ResolveJavascriptCallback(base::Value(callback_id), + base::Value(GetCookieSettingDescription(profile_))); +} + +void SiteSettingsHandler::HandleGetRecentSitePermissions( + const base::ListValue* args) { + AllowJavascript(); + + CHECK_EQ(3U, args->GetList().size()); + std::string callback_id = args->GetList()[0].GetString(); + auto types = args->GetList()[1].GetList(); + size_t max_sources = base::checked_cast<size_t>(args->GetList()[2].GetInt()); + + auto content_types = site_settings::ContentSettingsTypesFromGroupNames(types); + auto recent_site_permissions = site_settings::GetRecentSitePermissions( + profile_, content_types, max_sources); + + // Convert groups of TimestampedPermissions for consumption by JS + base::Value result(base::Value::Type::LIST); + for (const auto& site_permissions : recent_site_permissions) { + DCHECK(!site_permissions.settings.empty()); + base::Value recent_site(base::Value::Type::DICTIONARY); + recent_site.SetKey(site_settings::kOrigin, + base::Value(site_permissions.origin.spec())); + recent_site.SetKey(site_settings::kIncognito, + base::Value(site_permissions.incognito)); + + base::Value permissions_list(base::Value::Type::LIST); + for (const auto& p : site_permissions.settings) { + base::Value recent_permission(base::Value::Type::DICTIONARY); + recent_permission.SetKey( + site_settings::kType, + base::Value( + site_settings::ContentSettingsTypeToGroupName(p.content_type))); + recent_permission.SetKey( + site_settings::kSetting, + base::Value( + content_settings::ContentSettingToString(p.content_setting))); + recent_permission.SetKey( + site_settings::kSource, + base::Value( + site_settings::SiteSettingSourceToString(p.setting_source))); + permissions_list.Append(std::move(recent_permission)); + } + recent_site.SetKey(site_settings::kRecentPermissions, + std::move(permissions_list)); + result.Append(std::move(recent_site)); + } + ResolveJavascriptCallback(base::Value(callback_id), result); } base::Value SiteSettingsHandler::PopulateCookiesAndUsageData(Profile* profile) { @@ -783,14 +927,16 @@ base::Value SiteSettingsHandler::PopulateCookiesAndUsageData(Profile* profile) { const std::string& origin = origin_info.FindKey("origin")->GetString(); const auto& size_info_it = origin_size_map.find(origin); if (size_info_it != origin_size_map.end()) - origin_info.SetKey("usage", base::Value(double(size_info_it->second))); + origin_info.SetKey( + "usage", base::Value(static_cast<double>(size_info_it->second))); + GURL origin_url(origin); const auto& origin_cookie_num_it = - origin_cookie_map.find(GURL(origin).host()); + origin_cookie_map.find(origin_url.host()); if (origin_cookie_num_it != origin_cookie_map.end()) { origin_info.SetKey(kNumCookies, base::Value(origin_cookie_num_it->second)); // Add cookies numbers for origins that isn't an eTLD+1. - if (GURL(origin).host() != etld_plus1) + if (origin_url.host() != etld_plus1) cookie_num += origin_cookie_num_it->second; } } @@ -946,13 +1092,14 @@ void SiteSettingsHandler::HandleSetOriginPermissions( HostContentSettingsMap* map = HostContentSettingsMapFactory::GetForProfile(profile_); - PermissionUtil::ScopedRevocationReporter scoped_revocation_reporter( - profile_, origin, origin, content_type, - PermissionSourceUI::SITE_SETTINGS); + permissions::PermissionUmaUtil::ScopedRevocationReporter + scoped_revocation_reporter( + profile_, origin, origin, content_type, + permissions::PermissionSourceUI::SITE_SETTINGS); // Clear any existing embargo status if the new setting isn't block. if (setting != CONTENT_SETTING_BLOCK) { - PermissionDecisionAutoBlocker::GetForProfile(profile_) + PermissionDecisionAutoBlockerFactory::GetForProfile(profile_) ->RemoveEmbargoByUrl(origin, content_type); } map->SetContentSettingDefaultScope(origin, origin, content_type, @@ -971,7 +1118,7 @@ void SiteSettingsHandler::HandleSetOriginPermissions( "SoundContentSetting.UnmuteBy.SiteSettings")); } } - WebSiteSettingsUmaUtil::LogPermissionChange(content_type, setting); + content_settings::LogWebSiteSettingsPermissionChange(content_type, setting); } // Show an infobar reminding the user to reload tabs where their site @@ -1036,9 +1183,10 @@ void SiteSettingsHandler::HandleResetCategoryPermissionForPattern( secondary_pattern_string.empty() ? ContentSettingsPattern::Wildcard() : ContentSettingsPattern::FromString(secondary_pattern_string); - PermissionUtil::ScopedRevocationReporter scoped_revocation_reporter( - profile, primary_pattern, secondary_pattern, content_type, - PermissionSourceUI::SITE_SETTINGS); + permissions::PermissionUmaUtil::ScopedRevocationReporter + scoped_revocation_reporter( + profile, primary_pattern, secondary_pattern, content_type, + permissions::PermissionSourceUI::SITE_SETTINGS); map->SetContentSettingCustomScope(primary_pattern, secondary_pattern, content_type, "", CONTENT_SETTING_DEFAULT); @@ -1054,7 +1202,7 @@ void SiteSettingsHandler::HandleResetCategoryPermissionForPattern( "SoundContentSetting.UnmuteBy.PatternException")); } } - WebSiteSettingsUmaUtil::LogPermissionChange( + content_settings::LogWebSiteSettingsPermissionChange( content_type, ContentSetting::CONTENT_SETTING_DEFAULT); } @@ -1096,9 +1244,10 @@ void SiteSettingsHandler::HandleSetCategoryPermissionForPattern( ? ContentSettingsPattern::Wildcard() : ContentSettingsPattern::FromString(secondary_pattern_string); - PermissionUtil::ScopedRevocationReporter scoped_revocation_reporter( - profile, primary_pattern, secondary_pattern, content_type, - PermissionSourceUI::SITE_SETTINGS); + permissions::PermissionUmaUtil::ScopedRevocationReporter + scoped_revocation_reporter( + profile, primary_pattern, secondary_pattern, content_type, + permissions::PermissionSourceUI::SITE_SETTINGS); map->SetContentSettingCustomScope(primary_pattern, secondary_pattern, content_type, "", setting); @@ -1117,7 +1266,7 @@ void SiteSettingsHandler::HandleSetCategoryPermissionForPattern( "SoundContentSetting.UnmuteBy.PatternException")); } } - WebSiteSettingsUmaUtil::LogPermissionChange(content_type, setting); + content_settings::LogWebSiteSettingsPermissionChange(content_type, setting); } void SiteSettingsHandler::HandleResetChooserExceptionForSite( @@ -1140,7 +1289,8 @@ void SiteSettingsHandler::HandleResetChooserExceptionForSite( GURL embedding_origin(embedding_origin_str); CHECK(embedding_origin.is_valid()); - ChooserContextBase* chooser_context = chooser_type->get_context(profile_); + permissions::ChooserContextBase* chooser_context = + chooser_type->get_context(profile_); chooser_context->RevokeObjectPermission( url::Origin::Create(requesting_origin), url::Origin::Create(embedding_origin), args->GetList()[3]); @@ -1352,6 +1502,18 @@ void SiteSettingsHandler::ObserveSourcesForProfile(Profile* profile) { if (!chooser_observer_.IsObserving(serial_context)) chooser_observer_.Add(serial_context); + auto* hid_context = HidChooserContextFactory::GetForProfile(profile); + if (!chooser_observer_.IsObserving(hid_context)) + chooser_observer_.Add(hid_context); + + if (base::FeatureList::IsEnabled( + features::kWebBluetoothNewPermissionsBackend)) { + auto* bluetooth_context = + BluetoothChooserContextFactory::GetForProfile(profile); + if (!chooser_observer_.IsObserving(bluetooth_context)) + chooser_observer_.Add(bluetooth_context); + } + observed_profiles_.Add(profile); } @@ -1368,6 +1530,18 @@ void SiteSettingsHandler::StopObservingSourcesForProfile(Profile* profile) { if (chooser_observer_.IsObserving(serial_context)) chooser_observer_.Remove(serial_context); + auto* hid_context = HidChooserContextFactory::GetForProfile(profile); + if (chooser_observer_.IsObserving(hid_context)) + chooser_observer_.Remove(hid_context); + + if (base::FeatureList::IsEnabled( + features::kWebBluetoothNewPermissionsBackend)) { + auto* bluetooth_context = + BluetoothChooserContextFactory::GetForProfile(profile); + if (chooser_observer_.IsObserving(bluetooth_context)) + chooser_observer_.Remove(bluetooth_context); + } + observed_profiles_.Remove(profile); } @@ -1444,18 +1618,16 @@ void SiteSettingsHandler::HandleClearEtldPlus1DataAndCookies( } for (auto* node : nodes_to_delete) cookies_tree_model_->DeleteCookieNode(node); - - LogAllSitesAction(AllSitesAction::kClearData); } void SiteSettingsHandler::HandleRecordAction(const base::ListValue* args) { CHECK_EQ(1U, args->GetSize()); int action; CHECK(args->GetInteger(0, &action)); - DCHECK_LE(action, static_cast<int>(AllSitesAction::kMaxValue)); - DCHECK_GE(action, static_cast<int>(AllSitesAction::kLoadPage)); + DCHECK_LE(action, static_cast<int>(AllSitesAction2::kMaxValue)); + DCHECK_GE(action, static_cast<int>(AllSitesAction2::kLoadPage)); - LogAllSitesAction(static_cast<AllSitesAction>(action)); + LogAllSitesAction(static_cast<AllSitesAction2>(action)); } void SiteSettingsHandler::SetCookiesTreeModelForTesting( @@ -1466,4 +1638,10 @@ void SiteSettingsHandler::SetCookiesTreeModelForTesting( void SiteSettingsHandler::ClearAllSitesMapForTesting() { all_sites_map_.clear(); } + +void SiteSettingsHandler::SendCookieSettingDescription() { + FireWebUIListener("cookieSettingDescriptionChanged", + base::Value(GetCookieSettingDescription(profile_))); +} + } // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/site_settings_handler.h b/chromium/chrome/browser/ui/webui/settings/site_settings_handler.h index b60de36fcc2..575661dc87e 100644 --- a/chromium/chrome/browser/ui/webui/settings/site_settings_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/site_settings_handler.h @@ -13,7 +13,6 @@ #include "base/containers/flat_set.h" #include "base/scoped_observer.h" #include "chrome/browser/browsing_data/cookies_tree_model.h" -#include "chrome/browser/permissions/chooser_context_base.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_observer.h" #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" @@ -21,6 +20,8 @@ #include "chrome/browser/web_applications/web_app_registrar.h" #include "components/content_settings/core/browser/content_settings_observer.h" #include "components/content_settings/core/browser/host_content_settings_map.h" +#include "components/permissions/chooser_context_base.h" +#include "components/prefs/pref_store.h" #include "content/public/browser/host_zoom_map.h" #include "ppapi/buildflags/buildflags.h" @@ -33,11 +34,12 @@ class ListValue; namespace settings { // Chrome "ContentSettings" settings page UI handler. -class SiteSettingsHandler : public SettingsPageUIHandler, - public content_settings::Observer, - public ProfileObserver, - public ChooserContextBase::PermissionObserver, - public CookiesTreeModel::Observer { +class SiteSettingsHandler + : public SettingsPageUIHandler, + public content_settings::Observer, + public ProfileObserver, + public permissions::ChooserContextBase::PermissionObserver, + public CookiesTreeModel::Observer { public: explicit SiteSettingsHandler(Profile* profile, web_app::AppRegistrar& web_app_registrar); @@ -110,6 +112,7 @@ class SiteSettingsHandler : public SettingsPageUIHandler, FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, ExceptionHelpers); FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, ExtensionDisplayName); FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, GetAllSites); + FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, GetRecentSitePermissions); FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, OnStorageFetched); FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, GetAndSetDefault); FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, GetAndSetForInvalidURLs); @@ -122,6 +125,8 @@ class SiteSettingsHandler : public SettingsPageUIHandler, FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, ZoomLevels); FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, HandleClearEtldPlus1DataAndCookies); + FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, CookieControlsManagedState); + FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, CookieSettingDescription); FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, HandleGetFormattedBytes); FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, NotificationPermissionRevokeUkm); @@ -163,6 +168,20 @@ class SiteSettingsHandler : public SettingsPageUIHandler, // the front end when fetching finished. void HandleGetAllSites(const base::ListValue* args); + // Returns whether each of the cookie controls is managed and if so what + // the source of that management is. + void HandleGetCookieControlsManagedState(const base::ListValue* args); + + // Returns a string for display describing the current cookie settings. + void HandleGetCookieSettingDescription(const base::ListValue* args); + + // Returns a list containing the most recent permission changes for the + // provided content types grouped by origin/profile (incognito, regular) + // combinations, limited to N origin/profile pairings. This includes + // permission changes made by embargo, but does not include permissions + // enforced via policy. + void HandleGetRecentSitePermissions(const base::ListValue* args); + // Called when the list of origins using storage has been fetched, and sends // this list back to the front end. void OnStorageFetched(); @@ -240,6 +259,10 @@ class SiteSettingsHandler : public SettingsPageUIHandler, void ClearAllSitesMapForTesting(); + // Notifies the JS side the effective cookies setting has changed and + // provides the updated description label for display. + void SendCookieSettingDescription(); + Profile* profile_; web_app::AppRegistrar& app_registrar_; @@ -260,7 +283,8 @@ class SiteSettingsHandler : public SettingsPageUIHandler, this}; // Change observer for chooser permissions. - ScopedObserver<ChooserContextBase, ChooserContextBase::PermissionObserver> + ScopedObserver<permissions::ChooserContextBase, + permissions::ChooserContextBase::PermissionObserver> chooser_observer_{this}; // Change observer for prefs. diff --git a/chromium/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc index 42c7a310795..0fd6541604d 100644 --- a/chromium/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc @@ -15,6 +15,7 @@ #include "base/logging.h" #include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "base/test/simple_test_clock.h" #include "base/values.h" #include "build/build_config.h" @@ -26,10 +27,7 @@ #include "chrome/browser/extensions/test_extension_system.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/infobars/infobar_service.h" -#include "chrome/browser/permissions/chooser_context_base.h" -#include "chrome/browser/permissions/chooser_context_base_mock_permission_observer.h" -#include "chrome/browser/permissions/permission_decision_auto_blocker.h" -#include "chrome/browser/permissions/permission_uma_util.h" +#include "chrome/browser/permissions/permission_decision_auto_blocker_factory.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/webui/site_settings_helper.h" @@ -38,14 +36,23 @@ #include "chrome/browser/web_applications/components/web_app_helpers.h" #include "chrome/browser/web_applications/test/test_app_registrar.h" #include "chrome/common/pref_names.h" +#include "chrome/grit/generated_resources.h" #include "chrome/test/base/browser_with_test_window_test.h" #include "chrome/test/base/testing_profile.h" +#include "components/content_settings/core/browser/cookie_settings.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/content_settings/core/common/content_settings.h" #include "components/content_settings/core/common/content_settings_types.h" +#include "components/content_settings/core/common/features.h" #include "components/content_settings/core/common/pref_names.h" +#include "components/content_settings/core/test/content_settings_mock_provider.h" +#include "components/content_settings/core/test/content_settings_test_utils.h" #include "components/history/core/browser/history_service.h" #include "components/infobars/core/infobar.h" +#include "components/permissions/chooser_context_base.h" +#include "components/permissions/permission_decision_auto_blocker.h" +#include "components/permissions/permission_uma_util.h" +#include "components/permissions/test/chooser_context_base_mock_permission_observer.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "components/ukm/test_ukm_recorder.h" #include "content/public/browser/navigation_controller.h" @@ -58,6 +65,7 @@ #include "ppapi/buildflags/buildflags.h" #include "services/device/public/cpp/test/fake_usb_device_manager.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/base/text/bytes_formatting.h" #if defined(OS_CHROMEOS) @@ -190,6 +198,8 @@ class SiteSettingsHandlerTest : public testing::Test { TestingProfile::Builder profile_builder; profile_builder.SetPath(profile_dir_.GetPath()); profile_ = profile_builder.Build(); + feature_list_.InitAndEnableFeature( + content_settings::kImprovedCookieControls); } void SetUp() override { @@ -399,6 +409,16 @@ class SiteSettingsHandlerTest : public testing::Test { } } + void ValidateCookieSettingUpdate(const std::string expected_string, + const int expected_call_index) { + const content::TestWebUI::CallData& data = + *web_ui()->call_data()[expected_call_index]; + + ASSERT_EQ("cr.webUIListenerCallback", data.function_name()); + ASSERT_EQ("cookieSettingDescriptionChanged", data.arg1()->GetString()); + ASSERT_EQ(expected_string, data.arg2()->GetString()); + } + void CreateIncognitoProfile() { incognito_profile_ = TestingProfile::Builder().BuildIncognito(profile()); } @@ -479,6 +499,10 @@ class SiteSettingsHandlerTest : public testing::Test { const std::string kCookies; const std::string kFlash; + // The number of listeners that are expected to fire when any content setting + // is changed. + const size_t kNumberContentSettingListeners = 2; + private: // A profile directory that outlives |task_environment_| is needed because // TestingProfile::CreateHistoryService uses the directory to host a @@ -490,6 +514,7 @@ class SiteSettingsHandlerTest : public testing::Test { web_app::TestAppRegistrar app_registrar_; content::TestWebUI web_ui_; std::unique_ptr<SiteSettingsHandler> handler_; + base::test::ScopedFeatureList feature_list_; #if defined(OS_CHROMEOS) std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_; #endif @@ -611,8 +636,8 @@ TEST_F(SiteSettingsHandlerTest, MAYBE_GetAllSites) { } // Test embargoed settings also appear. - PermissionDecisionAutoBlocker* auto_blocker = - PermissionDecisionAutoBlocker::GetForProfile(profile()); + permissions::PermissionDecisionAutoBlocker* auto_blocker = + PermissionDecisionAutoBlockerFactory::GetForProfile(profile()); base::SimpleTestClock clock; clock.SetNow(base::Time::Now()); auto_blocker->SetClockForTesting(&clock); @@ -712,12 +737,137 @@ TEST_F(SiteSettingsHandlerTest, MAYBE_GetAllSites) { } // Each call to HandleGetAllSites() above added a callback to the profile's - // BrowsingDataLocalStorageHelper, so make sure these aren't stuck waiting to - // run at the end of the test. + // browsing_data::LocalStorageHelper, so make sure these aren't stuck waiting + // to run at the end of the test. base::RunLoop run_loop; run_loop.RunUntilIdle(); } +TEST_F(SiteSettingsHandlerTest, GetRecentSitePermissions) { + // Constants used only in this test. + std::string kAllowed = content_settings::ContentSettingToString( + ContentSetting::CONTENT_SETTING_ALLOW); + std::string kBlocked = content_settings::ContentSettingToString( + ContentSetting::CONTENT_SETTING_BLOCK); + std::string kEmbargo = + SiteSettingSourceToString(site_settings::SiteSettingSource::kEmbargo); + std::string kPreference = + SiteSettingSourceToString(site_settings::SiteSettingSource::kPreference); + + base::ListValue get_recent_permissions_args; + get_recent_permissions_args.AppendString(kCallbackId); + base::Value category_list(base::Value::Type::LIST); + category_list.Append(kNotifications); + category_list.Append(kFlash); + get_recent_permissions_args.Append(std::move(category_list)); + get_recent_permissions_args.Append(3); + + // Configure prefs and auto blocker with a controllable clock. + base::SimpleTestClock clock; + clock.SetNow(base::Time::Now()); + HostContentSettingsMap* map = + HostContentSettingsMapFactory::GetForProfile(profile()); + map->SetClockForTesting(&clock); + permissions::PermissionDecisionAutoBlocker* auto_blocker = + PermissionDecisionAutoBlockerFactory::GetForProfile(profile()); + auto_blocker->SetClockForTesting(&clock); + clock.Advance(base::TimeDelta::FromHours(1)); + + // Test recent permissions is empty when there are no preferences. + handler()->HandleGetRecentSitePermissions(&get_recent_permissions_args); + EXPECT_EQ(1U, web_ui()->call_data().size()); + + { + const content::TestWebUI::CallData& data = *web_ui()->call_data().back(); + EXPECT_EQ("cr.webUIResponse", data.function_name()); + EXPECT_EQ(kCallbackId, data.arg1()->GetString()); + ASSERT_TRUE(data.arg2()->GetBool()); + + base::Value::ConstListView recent_permissions = data.arg3()->GetList(); + EXPECT_EQ(0UL, recent_permissions.size()); + } + + // Add numerous permissions from different sources and confirm that the recent + // permissions are correctly transformed for usage by JS. + const GURL url1("https://example.com"); + const GURL url2("http://example.com"); + for (int i = 0; i < 3; ++i) + auto_blocker->RecordDismissAndEmbargo( + url1, ContentSettingsType::NOTIFICATIONS, false); + + clock.Advance(base::TimeDelta::FromHours(2)); + map->SetContentSettingDefaultScope(url2, url2, ContentSettingsType::PLUGINS, + std::string(), CONTENT_SETTING_ALLOW); + clock.Advance(base::TimeDelta::FromHours(1)); + CreateIncognitoProfile(); + HostContentSettingsMap* incognito_map = + HostContentSettingsMapFactory::GetForProfile(incognito_profile()); + incognito_map->SetClockForTesting(&clock); + incognito_map->SetContentSettingDefaultScope( + url1, url1, ContentSettingsType::PLUGINS, std::string(), + CONTENT_SETTING_ALLOW); + + clock.Advance(base::TimeDelta::FromHours(1)); + permissions::PermissionDecisionAutoBlocker* incognito_auto_blocker = + PermissionDecisionAutoBlockerFactory::GetForProfile(incognito_profile()); + incognito_auto_blocker->SetClockForTesting(&clock); + for (int i = 0; i < 3; ++i) + incognito_auto_blocker->RecordDismissAndEmbargo( + url1, ContentSettingsType::NOTIFICATIONS, false); + + handler()->HandleGetRecentSitePermissions(&get_recent_permissions_args); + { + const content::TestWebUI::CallData& data = *web_ui()->call_data().back(); + EXPECT_EQ("cr.webUIResponse", data.function_name()); + EXPECT_EQ(kCallbackId, data.arg1()->GetString()); + ASSERT_TRUE(data.arg2()->GetBool()); + + base::Value::ConstListView recent_permissions = data.arg3()->GetList(); + EXPECT_EQ(3UL, recent_permissions.size()); + EXPECT_EQ(url1.spec(), + recent_permissions[2].FindKey("origin")->GetString()); + EXPECT_EQ(url2.spec(), + recent_permissions[1].FindKey("origin")->GetString()); + EXPECT_EQ(url1.spec(), + recent_permissions[0].FindKey("origin")->GetString()); + + EXPECT_TRUE(recent_permissions[0].FindKey("incognito")->GetBool()); + EXPECT_FALSE(recent_permissions[1].FindKey("incognito")->GetBool()); + EXPECT_FALSE(recent_permissions[2].FindKey("incognito")->GetBool()); + + base::Value::ConstListView incognito_url1_permissions = + recent_permissions[0].FindKey("recentPermissions")->GetList(); + base::Value::ConstListView url1_permissions = + recent_permissions[2].FindKey("recentPermissions")->GetList(); + base::Value::ConstListView url2_permissions = + recent_permissions[1].FindKey("recentPermissions")->GetList(); + + EXPECT_EQ(2UL, incognito_url1_permissions.size()); + + EXPECT_EQ(kNotifications, + incognito_url1_permissions[0].FindKey("type")->GetString()); + EXPECT_EQ(kBlocked, + incognito_url1_permissions[0].FindKey("setting")->GetString()); + EXPECT_EQ(kEmbargo, + incognito_url1_permissions[0].FindKey("source")->GetString()); + + EXPECT_EQ(kFlash, + incognito_url1_permissions[1].FindKey("type")->GetString()); + EXPECT_EQ(kAllowed, + incognito_url1_permissions[1].FindKey("setting")->GetString()); + EXPECT_EQ(kPreference, + incognito_url1_permissions[1].FindKey("source")->GetString()); + + EXPECT_EQ(kNotifications, url1_permissions[0].FindKey("type")->GetString()); + EXPECT_EQ(kBlocked, url1_permissions[0].FindKey("setting")->GetString()); + EXPECT_EQ(kEmbargo, url1_permissions[0].FindKey("source")->GetString()); + + EXPECT_EQ(kFlash, url2_permissions[0].FindKey("type")->GetString()); + EXPECT_EQ(kAllowed, url2_permissions[0].FindKey("setting")->GetString()); + EXPECT_EQ(kPreference, url2_permissions[0].FindKey("source")->GetString()); + } +} + TEST_F(SiteSettingsHandlerTest, OnStorageFetched) { SetUpCookiesTreeModel(); @@ -942,12 +1092,13 @@ TEST_F(SiteSettingsHandlerTest, NotificationPermissionRevokeUkm) { auto* entry = entries.front(); ukm_recorder.ExpectEntrySourceHasUrl(entry, GURL(google)); - EXPECT_EQ(*ukm_recorder.GetEntryMetric(entry, "Source"), - static_cast<int64_t>(PermissionSourceUI::SITE_SETTINGS)); + EXPECT_EQ( + *ukm_recorder.GetEntryMetric(entry, "Source"), + static_cast<int64_t>(permissions::PermissionSourceUI::SITE_SETTINGS)); EXPECT_EQ(*ukm_recorder.GetEntryMetric(entry, "PermissionType"), static_cast<int64_t>(ContentSettingsType::NOTIFICATIONS)); EXPECT_EQ(*ukm_recorder.GetEntryMetric(entry, "Action"), - static_cast<int64_t>(PermissionAction::REVOKED)); + static_cast<int64_t>(permissions::PermissionAction::REVOKED)); } TEST_F(SiteSettingsHandlerTest, DefaultSettingSource) { @@ -956,6 +1107,8 @@ TEST_F(SiteSettingsHandlerTest, DefaultSettingSource) { // Use a non-default port to verify the display name does not strip this off. const std::string google("https://www.google.com:183"); + const std::string expected_display_name("www.google.com:183"); + ContentSettingSourceSetter source_setter(profile(), ContentSettingsType::NOTIFICATIONS); @@ -968,7 +1121,7 @@ TEST_F(SiteSettingsHandlerTest, DefaultSettingSource) { // Test Chrome built-in defaults are marked as default. handler()->HandleGetOriginPermissions(&get_origin_permissions_args); - ValidateOrigin(google, google, google, CONTENT_SETTING_ASK, + ValidateOrigin(google, google, expected_display_name, CONTENT_SETTING_ASK, site_settings::SiteSettingSource::kDefault, 1U); base::ListValue default_value_args; @@ -978,7 +1131,7 @@ TEST_F(SiteSettingsHandlerTest, DefaultSettingSource) { handler()->HandleSetDefaultValueForContentType(&default_value_args); // A user-set global default should also show up as default. handler()->HandleGetOriginPermissions(&get_origin_permissions_args); - ValidateOrigin(google, google, google, CONTENT_SETTING_BLOCK, + ValidateOrigin(google, google, expected_display_name, CONTENT_SETTING_BLOCK, site_settings::SiteSettingSource::kDefault, 3U); base::ListValue set_notification_pattern_args; @@ -992,7 +1145,7 @@ TEST_F(SiteSettingsHandlerTest, DefaultSettingSource) { &set_notification_pattern_args); // A user-set pattern should not show up as default. handler()->HandleGetOriginPermissions(&get_origin_permissions_args); - ValidateOrigin(google, google, google, CONTENT_SETTING_ALLOW, + ValidateOrigin(google, google, expected_display_name, CONTENT_SETTING_ALLOW, site_settings::SiteSettingSource::kPreference, 5U); base::ListValue set_notification_origin_args; @@ -1006,20 +1159,20 @@ TEST_F(SiteSettingsHandlerTest, DefaultSettingSource) { &set_notification_origin_args); // A user-set per-origin permission should not show up as default. handler()->HandleGetOriginPermissions(&get_origin_permissions_args); - ValidateOrigin(google, google, google, CONTENT_SETTING_BLOCK, + ValidateOrigin(google, google, expected_display_name, CONTENT_SETTING_BLOCK, site_settings::SiteSettingSource::kPreference, 7U); // Enterprise-policy set defaults should not show up as default. source_setter.SetPolicyDefault(CONTENT_SETTING_ALLOW); handler()->HandleGetOriginPermissions(&get_origin_permissions_args); - ValidateOrigin(google, google, google, CONTENT_SETTING_ALLOW, + ValidateOrigin(google, google, expected_display_name, CONTENT_SETTING_ALLOW, site_settings::SiteSettingSource::kPolicy, 8U); } TEST_F(SiteSettingsHandlerTest, GetAndSetOriginPermissions) { const std::string origin_with_port("https://www.example.com:443"); // The display name won't show the port if it's default for that scheme. - const std::string origin("https://www.example.com"); + const std::string origin("www.example.com"); base::ListValue get_args; get_args.AppendString(kCallbackId); get_args.AppendString(origin_with_port); @@ -1511,7 +1664,8 @@ TEST_F(SiteSettingsHandlerTest, SessionOnlyException) { set_args.AppendBoolean(false); // Incognito. base::HistogramTester histograms; handler()->HandleSetCategoryPermissionForPattern(&set_args); - EXPECT_EQ(1U, web_ui()->call_data().size()); + + EXPECT_EQ(kNumberContentSettingListeners, web_ui()->call_data().size()); histograms.ExpectTotalCount(uma_base, 1); histograms.ExpectTotalCount(uma_base + ".SessionOnly", 1); } @@ -1564,10 +1718,6 @@ TEST_F(SiteSettingsHandlerTest, BlockAutoplay_Update) { namespace { -const GURL kAndroidUrl("https://android.com"); -const GURL kChromiumUrl("https://chromium.org"); -const GURL kGoogleUrl("https://google.com"); - constexpr char kUsbPolicySetting[] = R"( [ { @@ -1585,6 +1735,18 @@ constexpr char kUsbPolicySetting[] = R"( } ])"; +// TODO(https://crbug.com/1042727): Fix test GURL scoping and remove this getter +// function. +GURL AndroidUrl() { + return GURL("https://android.com"); +} +GURL ChromiumUrl() { + return GURL("https://chromium.org"); +} +GURL GoogleUrl() { + return GURL("https://google.com"); +} + } // namespace class SiteSettingsHandlerChooserExceptionTest : public SiteSettingsHandlerTest { @@ -1601,7 +1763,8 @@ class SiteSettingsHandlerChooserExceptionTest : public SiteSettingsHandlerTest { void TearDown() override { auto* chooser_context = UsbChooserContextFactory::GetForProfile(profile()); - chooser_context->ChooserContextBase::RemoveObserver(&observer_); + chooser_context->permissions::ChooserContextBase::RemoveObserver( + &observer_); } // Sets up the UsbChooserContext with two devices and permissions for these @@ -1627,9 +1790,9 @@ class SiteSettingsHandlerChooserExceptionTest : public SiteSettingsHandlerTest { base::DoNothing::Once<std::vector<device::mojom::UsbDeviceInfoPtr>>()); base::RunLoop().RunUntilIdle(); - const auto kAndroidOrigin = url::Origin::Create(kAndroidUrl); - const auto kChromiumOrigin = url::Origin::Create(kChromiumUrl); - const auto kGoogleOrigin = url::Origin::Create(kGoogleUrl); + const auto kAndroidOrigin = url::Origin::Create(AndroidUrl()); + const auto kChromiumOrigin = url::Origin::Create(ChromiumUrl()); + const auto kGoogleOrigin = url::Origin::Create(GoogleUrl()); // Add the user granted permissions for testing. // These two persistent device permissions should be lumped together with @@ -1652,7 +1815,7 @@ class SiteSettingsHandlerChooserExceptionTest : public SiteSettingsHandlerTest { *policy_value); // Add the observer for permission changes. - chooser_context->ChooserContextBase::AddObserver(&observer_); + chooser_context->permissions::ChooserContextBase::AddObserver(&observer_); } void SetUpOffTheRecordUsbChooserContext() { @@ -1670,19 +1833,20 @@ class SiteSettingsHandlerChooserExceptionTest : public SiteSettingsHandlerTest { base::DoNothing::Once<std::vector<device::mojom::UsbDeviceInfoPtr>>()); base::RunLoop().RunUntilIdle(); - const auto kAndroidOrigin = url::Origin::Create(kAndroidUrl); - const auto kChromiumOrigin = url::Origin::Create(kChromiumUrl); + const auto kAndroidOrigin = url::Origin::Create(AndroidUrl()); + const auto kChromiumOrigin = url::Origin::Create(ChromiumUrl()); chooser_context->GrantDevicePermission(kChromiumOrigin, kAndroidOrigin, *off_the_record_device_); // Add the observer for permission changes. - chooser_context->ChooserContextBase::AddObserver(&observer_); + chooser_context->permissions::ChooserContextBase::AddObserver(&observer_); } void DestroyIncognitoProfile() override { auto* chooser_context = UsbChooserContextFactory::GetForProfile(incognito_profile()); - chooser_context->ChooserContextBase::RemoveObserver(&observer_); + chooser_context->permissions::ChooserContextBase::RemoveObserver( + &observer_); SiteSettingsHandlerTest::DestroyIncognitoProfile(); } @@ -1778,7 +1942,7 @@ class SiteSettingsHandlerChooserExceptionTest : public SiteSettingsHandlerTest { device::mojom::UsbDeviceInfoPtr persistent_device_info_; device::mojom::UsbDeviceInfoPtr user_granted_device_info_; - MockPermissionObserver observer_; + permissions::MockPermissionObserver observer_; private: device::FakeUsbDeviceManager device_manager_; @@ -1836,10 +2000,10 @@ TEST_F(SiteSettingsHandlerChooserExceptionTest, const std::string kUsbChooserGroupName = site_settings::ContentSettingsTypeToGroupName( ContentSettingsType::USB_CHOOSER_DATA); - const auto kAndroidOrigin = url::Origin::Create(kAndroidUrl); - const auto kChromiumOrigin = url::Origin::Create(kChromiumUrl); - const std::string kAndroidOriginStr = kAndroidUrl.GetOrigin().spec(); - const std::string kChromiumOriginStr = kChromiumUrl.GetOrigin().spec(); + const auto kAndroidOrigin = url::Origin::Create(AndroidUrl()); + const auto kChromiumOrigin = url::Origin::Create(ChromiumUrl()); + const std::string kAndroidOriginStr = AndroidUrl().GetOrigin().spec(); + const std::string kChromiumOriginStr = ChromiumUrl().GetOrigin().spec(); { const base::Value& exceptions = GetChooserExceptionListFromWebUiCallData( @@ -2013,6 +2177,158 @@ TEST_F(SiteSettingsHandlerTest, HandleClearEtldPlus1DataAndCookies) { EXPECT_EQ(0U, storage_and_cookie_list->GetSize()); } +TEST_F(SiteSettingsHandlerTest, CookieControlsManagedState) { + // Test that the handler correctly wraps the helper result. Helper with + // extensive logic is tested in site_settings_helper_unittest.cc. + const std::string kNone = "none"; + const std::string kDevicePolicy = "devicePolicy"; + const std::vector<std::string> kControlNames = { + "allowAll", "blockAll", "blockThirdParty", "blockThirdPartyIncognito", + "sessionOnly"}; + + // Check that the default cookie control state is handled correctly. + base::ListValue get_args; + get_args.AppendString(kCallbackId); + handler()->HandleGetCookieControlsManagedState(&get_args); + { + const content::TestWebUI::CallData& data = *web_ui()->call_data().back(); + EXPECT_EQ("cr.webUIResponse", data.function_name()); + EXPECT_EQ(kCallbackId, data.arg1()->GetString()); + ASSERT_TRUE(data.arg2()->GetBool()); + for (const auto& control_name : kControlNames) { + auto* control_state = data.arg3()->FindPath(control_name); + ASSERT_FALSE(control_state->FindKey("disabled")->GetBool()); + ASSERT_EQ(kNone, control_state->FindKey("indicator")->GetString()); + } + } + + // Check that a fully managed cookie state is handled correctly. + HostContentSettingsMap* map = + HostContentSettingsMapFactory::GetForProfile(profile()); + auto provider = std::make_unique<content_settings::MockProvider>(); + provider->SetWebsiteSetting( + ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(), + ContentSettingsType::COOKIES, std::string(), + std::make_unique<base::Value>(CONTENT_SETTING_ALLOW)); + content_settings::TestUtils::OverrideProvider( + map, std::move(provider), HostContentSettingsMap::POLICY_PROVIDER); + sync_preferences::TestingPrefServiceSyncable* pref_service = + profile()->GetTestingPrefService(); + pref_service->SetManagedPref(prefs::kBlockThirdPartyCookies, + std::make_unique<base::Value>(true)); + + handler()->HandleGetCookieControlsManagedState(&get_args); + { + const content::TestWebUI::CallData& data = *web_ui()->call_data().back(); + EXPECT_EQ("cr.webUIResponse", data.function_name()); + EXPECT_EQ(kCallbackId, data.arg1()->GetString()); + ASSERT_TRUE(data.arg2()->GetBool()); + for (const auto& control_name : kControlNames) { + auto* control_state = data.arg3()->FindPath(control_name); + ASSERT_TRUE(control_state->FindKey("disabled")->GetBool()); + ASSERT_EQ(kDevicePolicy, + control_state->FindKey("indicator")->GetString()); + } + } +} + +TEST_F(SiteSettingsHandlerTest, CookieSettingDescription) { + const auto kBlocked = [](int num) { + return l10n_util::GetPluralStringFUTF8( + IDS_SETTINGS_SITE_SETTINGS_COOKIES_BLOCK, num); + }; + const auto kAllowed = [](int num) { + return l10n_util::GetPluralStringFUTF8( + IDS_SETTINGS_SITE_SETTINGS_COOKIES_ALLOW, num); + }; + const std::string kBlockThirdParty = l10n_util::GetStringUTF8( + IDS_SETTINGS_SITE_SETTINGS_COOKIES_BLOCK_THIRD_PARTY); + const std::string kBlockThirdPartyIncognito = l10n_util::GetStringUTF8( + IDS_SETTINGS_SITE_SETTINGS_COOKIES_BLOCK_THIRD_PARTY_INCOGNITO); + + // Enforce expected default profile setting. + profile()->GetPrefs()->SetBoolean(prefs::kBlockThirdPartyCookies, false); + profile()->GetPrefs()->SetInteger( + prefs::kCookieControlsMode, + static_cast<int>(content_settings::CookieControlsMode::kIncognitoOnly)); + auto* content_settings = + HostContentSettingsMapFactory::GetForProfile(profile()); + content_settings->SetDefaultContentSetting( + ContentSettingsType::COOKIES, ContentSetting::CONTENT_SETTING_ALLOW); + web_ui()->ClearTrackedCalls(); + + // Validate get method works. + base::ListValue get_args; + get_args.AppendString(kCallbackId); + handler()->HandleGetCookieSettingDescription(&get_args); + const content::TestWebUI::CallData& data = *web_ui()->call_data().back(); + + EXPECT_EQ("cr.webUIResponse", data.function_name()); + EXPECT_EQ(kCallbackId, data.arg1()->GetString()); + ASSERT_TRUE(data.arg2()->GetBool()); + EXPECT_EQ(kBlockThirdPartyIncognito, data.arg3()->GetString()); + + // Multiple listeners will be called when prefs and content settings are + // changed in this test. Increment our expected call_data index accordingly. + int expected_call_index = 0; + const int kPrefListenerIndex = 1; + const int kContentSettingListenerIndex = 2; + + // Check updates are working, + profile()->GetPrefs()->SetBoolean(prefs::kBlockThirdPartyCookies, true); + expected_call_index += kPrefListenerIndex; + ValidateCookieSettingUpdate(kBlockThirdParty, expected_call_index); + + content_settings->SetDefaultContentSetting( + ContentSettingsType::COOKIES, ContentSetting::CONTENT_SETTING_BLOCK); + expected_call_index += kContentSettingListenerIndex; + ValidateCookieSettingUpdate(kBlocked(0), expected_call_index); + + // Check changes which do not affect the effective cookie setting. + profile()->GetPrefs()->SetBoolean(prefs::kBlockThirdPartyCookies, false); + expected_call_index += kPrefListenerIndex; + ValidateCookieSettingUpdate(kBlocked(0), expected_call_index); + + profile()->GetPrefs()->SetInteger( + prefs::kCookieControlsMode, + static_cast<int>(content_settings::CookieControlsMode::kOff)); + expected_call_index += kPrefListenerIndex; + ValidateCookieSettingUpdate(kBlocked(0), expected_call_index); + + // Set to allow and check previous changes are respected. + content_settings->SetDefaultContentSetting( + ContentSettingsType::COOKIES, ContentSetting::CONTENT_SETTING_ALLOW); + expected_call_index += kContentSettingListenerIndex; + ValidateCookieSettingUpdate(kAllowed(0), expected_call_index); + + // Confirm exceptions are counted correctly. + GURL url1("https://example.com"); + GURL url2("http://example.com"); + GURL url3("http://another.example.com"); + content_settings->SetContentSettingDefaultScope( + url1, url1, ContentSettingsType::COOKIES, std::string(), + ContentSetting::CONTENT_SETTING_BLOCK); + expected_call_index += kContentSettingListenerIndex; + ValidateCookieSettingUpdate(kAllowed(1), expected_call_index); + + content_settings->SetContentSettingDefaultScope( + url2, url2, ContentSettingsType::COOKIES, std::string(), + ContentSetting::CONTENT_SETTING_ALLOW); + expected_call_index += kContentSettingListenerIndex; + ValidateCookieSettingUpdate(kAllowed(1), expected_call_index); + + content_settings->SetContentSettingDefaultScope( + url3, url3, ContentSettingsType::COOKIES, std::string(), + ContentSetting::CONTENT_SETTING_SESSION_ONLY); + expected_call_index += kContentSettingListenerIndex; + ValidateCookieSettingUpdate(kAllowed(1), expected_call_index); + + content_settings->SetDefaultContentSetting( + ContentSettingsType::COOKIES, ContentSetting::CONTENT_SETTING_BLOCK); + expected_call_index += kContentSettingListenerIndex; + ValidateCookieSettingUpdate(kBlocked(2), expected_call_index); +} + TEST_F(SiteSettingsHandlerTest, HandleGetFormattedBytes) { const double size = 120000000000; base::ListValue get_args; |