diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2023-09-05 12:37:36 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2023-10-17 13:53:46 +0000 |
commit | 5a424f4a7b188b75da63eb697f63558af0b17f6f (patch) | |
tree | 54c427fcbc567dac8181ab5fd22d20e72cc51609 /chromium/chrome/browser/ui/webui/settings | |
parent | acbcf08a6dffdfe90a6eaf661fcd6923f0de2447 (diff) |
BASELINE: Update Chromium to 116.0.5845.183
Change-Id: Iaaf57e02c218c93993a5044c659b63674e2c8a12
Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/512320
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/chrome/browser/ui/webui/settings')
135 files changed, 5313 insertions, 3151 deletions
diff --git a/chromium/chrome/browser/ui/webui/settings/OWNERS b/chromium/chrome/browser/ui/webui/settings/OWNERS index d9e345949fd..8c3434dc1a1 100644 --- a/chromium/chrome/browser/ui/webui/settings/OWNERS +++ b/chromium/chrome/browser/ui/webui/settings/OWNERS @@ -3,15 +3,15 @@ file://chrome/browser/resources/settings/OWNERS per-file people_handler*=msalama@chromium.org per-file people_handler*=treib@chromium.org -per-file extensions_safety_check_handler*=psarouthakis@google.com +per-file safety_check_extensions_handler*=psarouthakis@google.com per-file hats_handler*=sauski@google.com per-file privacy_sandbox_handler*=file://components/privacy_sandbox/OWNERS per-file *site_settings*=msramek@chromium.org per-file *site_settings*=sauski@google.com -per-file site_settings_permissions_handler*=rainhard@chromium.org +per-file safety_hub_handler*=sideyilmaz@chromium.org,rainhard@chromium.org per-file safe_browsing_handler*=msramek@chromium.org per-file safe_browsing_handler*=sauski@google.com -per-file safety_check_handler*=andzaytsev@google.com,rainhard@chromium.org +per-file safety_check_handler*=andzaytsev@google.com,rainhard@chromium.org,sideyilmaz@chromium.org per-file settings_clear_browsing_data_handler*=sauski@google.com per-file settings_localized_strings_provider*=sauski@google.com per-file settings_security_key_handler*=file://device/fido/OWNERS diff --git a/chromium/chrome/browser/ui/webui/settings/about_handler.cc b/chromium/chrome/browser/ui/webui/settings/about_handler.cc index ab6b211b5b2..76ca56df5bc 100644 --- a/chromium/chrome/browser/ui/webui/settings/about_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/about_handler.cc @@ -242,6 +242,9 @@ std::string UpdateStatusToString(VersionUpdater::Status status) { case VersionUpdater::DISABLED_BY_ADMIN: status_str = "disabled_by_admin"; break; + case VersionUpdater::UPDATE_TO_ROLLBACK_VERSION_DISALLOWED: + status_str = "update_to_rollback_version_disallowed"; + break; case VersionUpdater::NEED_PERMISSION_TO_UPDATE: status_str = "need_permission_to_update"; break; diff --git a/chromium/chrome/browser/ui/webui/settings/ash/OWNERS b/chromium/chrome/browser/ui/webui/settings/ash/OWNERS index 527ce0485c9..f7c4d143805 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/OWNERS +++ b/chromium/chrome/browser/ui/webui/settings/ash/OWNERS @@ -1,4 +1,4 @@ -file://chrome/browser/resources/settings/chromeos/OWNERS +file://chrome/browser/resources/ash/settings/OWNERS per-file account_manager_*=file://chromeos/ash/components/account_manager/OWNERS per-file apps_section*=file://chrome/browser/ui/webui/app_management/OWNERS diff --git a/chromium/chrome/browser/ui/webui/settings/ash/about_section.cc b/chromium/chrome/browser/ui/webui/settings/ash/about_section.cc index 761256b25a9..c4afddbbda0 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/about_section.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/about_section.cc @@ -360,6 +360,8 @@ void AboutSection::AddLoadTimeData(content::WebUIDataSource* html_source) { {"aboutUpgradeTryAgain", IDS_SETTINGS_UPGRADE_TRY_AGAIN}, {"aboutUpgradeDownloadError", IDS_SETTINGS_UPGRADE_DOWNLOAD_ERROR}, {"aboutUpgradeAdministrator", IDS_SETTINGS_UPGRADE_ADMINISTRATOR_ERROR}, + {"aboutUpdateToRollbackVersionDisallowed", + IDS_SETTINGS_UPDATE_TO_ROLLBACK_VERSION_DISALLOWED}, // About page auto update toggle. {"aboutConsumerAutoUpdateToggleTitle", diff --git a/chromium/chrome/browser/ui/webui/settings/ash/accessibility_handler.cc b/chromium/chrome/browser/ui/webui/settings/ash/accessibility_handler.cc index df10109b28e..5bd9a22184f 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/accessibility_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/accessibility_handler.cc @@ -24,6 +24,7 @@ #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/webui_url_constants.h" #include "chrome/grit/generated_resources.h" +#include "chromeos/components/kiosk/kiosk_utils.h" #include "components/language/core/browser/pref_names.h" #include "components/language/core/common/locale_util.h" #include "components/prefs/pref_service.h" @@ -96,6 +97,10 @@ void AccessibilityHandler::RegisterMessages() { base::BindRepeating( &AccessibilityHandler::HandleUpdateBluetoothBrailleDisplayAddress, base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "getStartupSoundEnabled", + base::BindRepeating(&AccessibilityHandler::HandleGetStartupSoundEnabled, + base::Unretained(this))); } void AccessibilityHandler::HandleShowBrowserAppearanceSettings( @@ -167,6 +172,14 @@ void AccessibilityHandler::HandleUpdateBluetoothBrailleDisplayAddress( AccessibilityManager::Get()->UpdateBluetoothBrailleDisplayAddress(address); } +void AccessibilityHandler::HandleGetStartupSoundEnabled( + const base::Value::List& args) { + AllowJavascript(); + FireWebUIListener( + "startup-sound-setting-retrieved", + base::Value(AccessibilityManager::Get()->GetStartupSoundEnabled())); +} + void AccessibilityHandler::OpenExtensionOptionsPage(const char extension_id[]) { const extensions::Extension* extension = extensions::ExtensionRegistry::Get(profile_)->GetExtensionById( @@ -180,7 +193,7 @@ void AccessibilityHandler::OpenExtensionOptionsPage(const char extension_id[]) { // doesn't support SWA but already hide the navigation bar. bool open_with_os_url_handler = !crosapi::browser_util::IsAshWebBrowserEnabled() && - !profiles::IsKioskSession(); + !chromeos::IsKioskSession(); if (open_with_os_url_handler) { DCHECK(extensions::OptionsPageInfo::ShouldOpenInTab(extension)); GURL url = extensions::OptionsPageInfo::GetOptionsPage(extension); diff --git a/chromium/chrome/browser/ui/webui/settings/ash/accessibility_handler.h b/chromium/chrome/browser/ui/webui/settings/ash/accessibility_handler.h index 62c349b9b02..15c03bb5844 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/accessibility_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/accessibility_handler.h @@ -45,6 +45,7 @@ class AccessibilityHandler : public ::settings::SettingsPageUIHandler, void HandleSetStartupSoundEnabled(const base::Value::List& args); void HandleUpdateBluetoothBrailleDisplayAddress( const base::Value::List& args); + void HandleGetStartupSoundEnabled(const base::Value::List& args); void OpenExtensionOptionsPage(const char extension_id[]); diff --git a/chromium/chrome/browser/ui/webui/settings/ash/accessibility_handler_browsertest.cc b/chromium/chrome/browser/ui/webui/settings/ash/accessibility_handler_browsertest.cc index 7b32564c780..efe002668b2 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/accessibility_handler_browsertest.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/accessibility_handler_browsertest.cc @@ -10,12 +10,15 @@ #include "ash/constants/ash_features.h" #include "ash/constants/ash_pref_names.h" #include "base/containers/adapters.h" +#include "chrome/browser/ash/accessibility/accessibility_manager.h" #include "chrome/browser/ash/input_method/mock_input_method_engine.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/profiles/profile_test_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/testing_profile.h" +#include "chromeos/ash/components/browser_context_helper/browser_context_helper.h" #include "components/language/core/browser/pref_names.h" #include "components/language/core/common/locale_util.h" #include "components/prefs/pref_service.h" @@ -32,6 +35,14 @@ using ::testing::Not; namespace ash::settings { +namespace { + +// Use a real domain to avoid policy loading problems. +constexpr char kTestUserName[] = "owner@gmail.com"; +constexpr char kTestUserGaiaId[] = "9876543210"; + +} // namespace + class TestAccessibilityHandler : public AccessibilityHandler { public: explicit TestAccessibilityHandler(Profile* profile) @@ -124,15 +135,38 @@ class AccessibilityHandlerTest : public InProcessBrowserTest { prefs::kAccessibilityDictationLocale, locale); } + void CreateSession(const AccountId& account_id) { + auto* session_manager = session_manager::SessionManager::Get(); + session_manager->CreateSession(account_id, account_id.GetUserEmail(), + false); + } + + void StartUserSession(const AccountId& account_id) { + profiles::testing::CreateProfileSync( + g_browser_process->profile_manager(), + BrowserContextHelper::Get()->GetBrowserContextPathByUserIdHash( + user_manager::UserManager::Get() + ->FindUser(account_id) + ->username_hash())); + + auto* session_manager = session_manager::SessionManager::Get(); + session_manager->NotifyUserProfileLoaded(account_id); + session_manager->SessionStarted(); + } + speech::SodaInstaller* soda_installer() { return speech::SodaInstaller::GetInstance(); } speech::LanguageCode en_us() { return speech::LanguageCode::kEnUs; } speech::LanguageCode fr_fr() { return speech::LanguageCode::kFrFr; } + content::TestWebUI* web_ui() { return &web_ui_; } std::unique_ptr<input_method::MockInputMethodEngine> mock_ime_engine_handler_; + const AccountId test_account_id_ = + AccountId::FromUserEmailGaiaId(kTestUserName, kTestUserGaiaId); + private: std::unique_ptr<TestingProfile> profile_; std::unique_ptr<TestAccessibilityHandler> handler_; @@ -303,4 +337,23 @@ IN_PROC_BROWSER_TEST_F(AccessibilityHandlerTest, } } +IN_PROC_BROWSER_TEST_F(AccessibilityHandlerTest, GetStartupSoundEnabled) { + CreateSession(test_account_id_); + StartUserSession(test_account_id_); + AccessibilityManager::Get()->SetStartupSoundEnabled(true); + + size_t call_data_count_before_call = web_ui()->call_data().size(); + + base::Value::List empty_args; + web_ui()->HandleReceivedMessage("getStartupSoundEnabled", empty_args); + + ASSERT_EQ(call_data_count_before_call + 1u, web_ui()->call_data().size()); + + const content::TestWebUI::CallData& call_data = + *(web_ui()->call_data()[call_data_count_before_call]); + EXPECT_EQ("cr.webUIListenerCallback", call_data.function_name()); + EXPECT_EQ("startup-sound-setting-retrieved", call_data.arg1()->GetString()); + EXPECT_TRUE(call_data.arg2()->GetBool()); +} + } // namespace ash::settings diff --git a/chromium/chrome/browser/ui/webui/settings/ash/accessibility_section.cc b/chromium/chrome/browser/ui/webui/settings/ash/accessibility_section.cc index 5ab81754a76..766eff0c09c 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/accessibility_section.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/accessibility_section.cc @@ -643,6 +643,12 @@ void AccessibilitySection::AddLoadTimeData( IDS_SETTINGS_CHROMEVOX_BRAILLE_TABLE_DESCRIPTION}, {"chromeVoxBrailleTable6Dot", IDS_SETTINGS_CHROMEVOX_BRAILLE_TABLE_6_DOT}, {"chromeVoxBrailleTable8Dot", IDS_SETTINGS_CHROMEVOX_BRAILLE_TABLE_8_DOT}, + {"chromeVoxBrailleTableNameWithGrade", + IDS_SETTINGS_CHROMEVOX_BRAILLE_TABLE_NAME_WITH_GRADE}, + {"chromeVoxBrailleTableNameWithVariant", + IDS_SETTINGS_CHROMEVOX_BRAILLE_TABLE_NAME_WITH_VARIANT}, + {"chromeVoxBrailleTableNameWithVariantAndGrade", + IDS_SETTINGS_CHROMEVOX_BRAILLE_TABLE_NAME_WITH_VARIANT_AND_GRADE}, {"chromeVoxTutorialLabel", IDS_SETTINGS_CHROMEVOX_TUTORIAL_LABEL}, {"clickOnStopDescription", IDS_SETTINGS_CLICK_ON_STOP_DESCRIPTION}, {"clickOnStopLabel", IDS_SETTINGS_CLICK_ON_STOP_LABEL}, @@ -727,15 +733,34 @@ void AccessibilitySection::AddLoadTimeData( IDS_SETTINGS_ACCESSIBILITY_FOCUS_HIGHLIGHT_DESCRIPTION}, {"focusHighlightLabelSubtext", IDS_SETTINGS_ACCESSIBILITY_FOCUS_HIGHLIGHT_DESCRIPTION_SUBTEXT}, + {"focusHighlightDisabledByChromevoxTooltip", + IDS_SETTINGS_FOCUS_HIGHLIGHT_DISABLED_BY_CHROMEVOX_TOOLTIP}, {"greyscaleLabel", IDS_SETTINGS_GREYSCALE_LABEL}, {"highContrastDescription", IDS_SETTINGS_HIGH_CONTRAST_DESCRIPTION}, {"highContrastLabel", IDS_SETTINGS_HIGH_CONTRAST_LABEL}, - {"hueRotationLabel", IDS_SETTINGS_HUE_ROTATION_LABEL}, {"protanomalyFilter", IDS_SETTINGS_PROTANOMALY_FILTER}, {"tritanomalyFilter", IDS_SETTINGS_TRITANOMALY_FILTER}, {"deuteranomalyFilter", IDS_SETTINGS_DEUTERANOMALY_FILTER}, {"colorFilteringLabel", IDS_SETTINGS_COLOR_FILTERING_LABEL}, {"colorFilteringDescription", IDS_SETTINGS_COLOR_FILTERING_DESCRIPTION}, + {"colorFilteringPreviewInstructions", + IDS_SETTINGS_COLOR_FILTERING_PREVIEW_INSTRUCTIONS}, + {"colorFilteringPreviewColorRed", + IDS_SETTINGS_COLOR_FILTERING_PREVIEW_COLOR_RED}, + {"colorFilteringPreviewColorOrange", + IDS_SETTINGS_COLOR_FILTERING_PREVIEW_COLOR_ORANGE}, + {"colorFilteringPreviewColorYellow", + IDS_SETTINGS_COLOR_FILTERING_PREVIEW_COLOR_YELLOW}, + {"colorFilteringPreviewColorGreen", + IDS_SETTINGS_COLOR_FILTERING_PREVIEW_COLOR_GREEN}, + {"colorFilteringPreviewColorCyan", + IDS_SETTINGS_COLOR_FILTERING_PREVIEW_COLOR_CYAN}, + {"colorFilteringPreviewColorBlue", + IDS_SETTINGS_COLOR_FILTERING_PREVIEW_COLOR_BLUE}, + {"colorFilteringPreviewColorPurple", + IDS_SETTINGS_COLOR_FILTERING_PREVIEW_COLOR_PURPLE}, + {"colorFilteringPreviewColorGray", + IDS_SETTINGS_COLOR_FILTERING_PREVIEW_COLOR_GRAY}, {"colorVisionDeficiencyTypeLabel", IDS_SETTINGS_COLOR_VISION_DEFICIENCY_TYPE_LABEL}, {"colorVisionFilterIntensityLabel", @@ -783,7 +808,6 @@ void AccessibilitySection::AddLoadTimeData( {"pdfOcrSubtitle", IDS_SETTINGS_PDF_OCR_SUBTITLE}, {"pdfOcrTitle", IDS_SETTINGS_PDF_OCR_TITLE}, {"percentage", IDS_SETTINGS_PERCENTAGE}, - {"saturationLabel", IDS_SETTINGS_SATURATION_LABEL}, {"screenMagnifierDescriptionOff", IDS_SETTINGS_SCREEN_MAGNIFIER_DESCRIPTION_OFF}, {"screenMagnifierDescriptionOn", @@ -877,12 +901,13 @@ void AccessibilitySection::AddLoadTimeData( {"selectToSpeakOptionsLabel", IDS_SETTINGS_ACCESSIBILITY_SELECT_TO_SPEAK_OPTIONS_LABEL}, {"selectToSpeakTitle", IDS_SETTINGS_ACCESSIBILITY_SELECT_TO_SPEAK_TITLE}, - {"sepiaLabel", IDS_SETTINGS_SEPIA_LABEL}, {"settingsSliderRoleDescription", IDS_SETTINGS_SLIDER_MIN_MAX_ARIA_ROLE_DESCRIPTION}, {"startupSoundLabel", IDS_SETTINGS_STARTUP_SOUND_LABEL}, {"stickyKeysDescription", IDS_SETTINGS_STICKY_KEYS_DESCRIPTION}, {"stickyKeysLabel", IDS_SETTINGS_STICKY_KEYS_LABEL}, + {"stickyKeysDisabledByChromevoxTooltip", + IDS_SETTINGS_STICKY_KEYS_DISABLED_BY_CHROMEVOX_TOOLTIP}, {"switchAccessActionAssignmentAddAssignmentIconLabel", IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_ADD_ASSIGNMENT_ICON_LABEL}, {"switchAccessActionAssignmentAssignedIconLabel", diff --git a/chromium/chrome/browser/ui/webui/settings/ash/account_manager_ui_handler.cc b/chromium/chrome/browser/ui/webui/settings/ash/account_manager_ui_handler.cc index d7c94924258..c27d4ade670 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/account_manager_ui_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/account_manager_ui_handler.cc @@ -417,7 +417,7 @@ void AccountManagerUIHandler::HandleReauthenticateAccount( ->ShowReauthAccountDialog( account_manager::AccountManagerFacade::AccountAdditionSource:: kSettingsReauthAccountButton, - account_email, base::OnceClosure()); + account_email, base::DoNothing()); } void AccountManagerUIHandler::HandleMigrateAccount( diff --git a/chromium/chrome/browser/ui/webui/settings/ash/app_management/app_management_uma.h b/chromium/chrome/browser/ui/webui/settings/ash/app_management/app_management_uma.h index bfe59801fcc..ef9f8c1ed03 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/app_management/app_management_uma.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/app_management/app_management_uma.h @@ -28,7 +28,8 @@ enum class AppManagementEntryPoint { kNotificationPluginVm = 12, kAppManagementMainViewBorealis = 13, kPageInfoView = 14, - kMaxValue = kPageInfoView, + kPrivacyIndicatorsNotificationSettings = 15, + kMaxValue = kPrivacyIndicatorsNotificationSettings, }; } // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/ash/apps_section.cc b/chromium/chrome/browser/ui/webui/settings/ash/apps_section.cc index 50b16dbcb84..439a160a1fb 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/apps_section.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/apps_section.cc @@ -197,6 +197,8 @@ const std::vector<SearchConcept>& GetOnStartupSearchConcepts() { void AddAppManagementStrings(content::WebUIDataSource* html_source) { static constexpr webui::LocalizedString kLocalizedStrings[] = { {"appManagementAppDetailsTitle", IDS_APP_MANAGEMENT_APP_DETAILS_TITLE}, + {"appManagementAppDetailsTooltipSystem", + IDS_APP_MANAGEMENT_APP_DETAILS_TOOLTIP_SYSTEM}, {"appManagementAppDetailsTypeAndroid", IDS_APP_MANAGEMENT_APP_DETAILS_TYPE_ANDROID}, {"appManagementAppDetailsTypeChrome", @@ -272,6 +274,11 @@ void AddAppManagementStrings(content::WebUIDataSource* html_source) { {"appManagementNoPermissions", IDS_APPLICATION_INFO_APP_NO_PERMISSIONS_TEXT}, {"appManagementNotificationsLabel", IDS_APP_MANAGEMENT_NOTIFICATIONS}, + {"appManagementPermissionAllowed", IDS_APP_MANAGEMENT_PERMISSION_ALLOWED}, + {"appManagementPermissionAllowedWithDetails", + IDS_APP_MANAGEMENT_PERMISSION_ALLOWED_WITH_DETAILS}, + {"appManagementPermissionAsk", IDS_APP_MANAGEMENT_PERMISSION_ASK}, + {"appManagementPermissionDenied", IDS_APP_MANAGEMENT_PERMISSION_DENIED}, {"appManagementPermissionsLabel", IDS_APP_MANAGEMENT_PERMISSIONS}, {"appManagementPinToShelfLabel", IDS_APP_MANAGEMENT_PIN_TO_SHELF}, {"appManagementPresetWindowSizesLabel", @@ -281,6 +288,8 @@ void AddAppManagementStrings(content::WebUIDataSource* html_source) { {"appManagementPrintingPermissionLabel", IDS_APP_MANAGEMENT_PRINTING}, {"appManagementSearchPrompt", IDS_APP_MANAGEMENT_SEARCH_PROMPT}, {"appManagementStoragePermissionLabel", IDS_APP_MANAGEMENT_STORAGE}, + {"appManagementSubAppsListHeading", + IDS_APP_MANAGEMENT_SUB_APPS_LIST_HEADING}, {"appManagementUninstallLabel", IDS_APP_MANAGEMENT_UNINSTALL_APP}, {"close", IDS_CLOSE}, {"fileHandlingOverflowDialogTitle", @@ -440,7 +449,7 @@ void AppsSection::AddLoadTimeData(content::WebUIDataSource* html_source) { // visible once settings app is registered. html_source->AddBoolean("androidAppsVisible", arc::IsArcAllowedForProfile(profile())); - html_source->AddBoolean("havePlayStoreApp", arc::IsPlayStoreAvailable()); + html_source->AddBoolean("isPlayStoreAvailable", arc::IsPlayStoreAvailable()); html_source->AddBoolean( "showOsSettingsAppNotificationsRow", @@ -448,7 +457,7 @@ void AppsSection::AddLoadTimeData(content::WebUIDataSource* html_source) { html_source->AddBoolean( "showOsSettingsAppBadgingToggle", base::FeatureList::IsEnabled(features::kOsSettingsAppBadgingToggle)); - html_source->AddBoolean("showArcvmManageUsb", arc::IsArcVmEnabled()); + html_source->AddBoolean("isArcVmEnabled", arc::IsArcVmEnabled()); AddAppManagementStrings(html_source); AddGuestOsStrings(html_source); @@ -612,7 +621,7 @@ void AppsSection::AddPluginVmLoadTimeData( }; html_source->AddLocalizedStrings(kLocalizedStrings); - html_source->AddBoolean("showPluginVm", + html_source->AddBoolean("isPluginVmAvailable", ShowPluginVm(profile(), *pref_service_)); html_source->AddString( "pluginVmSharedPathsInstructionsLocate", diff --git a/chromium/chrome/browser/ui/webui/settings/ash/calculator/size_calculator.cc b/chromium/chrome/browser/ui/webui/settings/ash/calculator/size_calculator.cc index b9e6412eec8..e6e69e8d676 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/calculator/size_calculator.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/calculator/size_calculator.cc @@ -22,6 +22,7 @@ #include "chrome/browser/ash/crostini/crostini_features.h" #include "chrome/browser/ash/crostini/crostini_pref_names.h" #include "chrome/browser/ash/drive/drive_integration_service.h" +#include "chrome/browser/ash/drive/file_system_util.h" #include "chrome/browser/ash/file_manager/path_util.h" #include "chrome/browser/ash/profiles/profile_helper.h" #include "chrome/browser/browsing_data/browsing_data_file_system_util.h" @@ -233,7 +234,7 @@ DriveOfflineSizeCalculator::DriveOfflineSizeCalculator(Profile* profile) DriveOfflineSizeCalculator::~DriveOfflineSizeCalculator() = default; void DriveOfflineSizeCalculator::PerformCalculation() { - if (!base::FeatureList::IsEnabled(ash::features::kDriveFsBulkPinning)) { + if (!drive::util::IsDriveFsBulkPinningEnabled(profile_)) { NotifySizeCalculated(0); return; } diff --git a/chromium/chrome/browser/ui/webui/settings/ash/crostini_section.cc b/chromium/chrome/browser/ui/webui/settings/ash/crostini_section.cc index 64178734b84..b155552a5dc 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/crostini_section.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/crostini_section.cc @@ -447,14 +447,15 @@ void CrostiniSection::AddLoadTimeData(content::WebUIDataSource* html_source) { html_source->AddString("crostiniContainerUpgradeSubtext", ""); } - // Should the crostini section in settings be displayed? + // Crostini section in settings is always displayed. + // Should we show that Crostini is supported? html_source->AddBoolean( - "showCrostini", + "isCrostiniSupported", crostini::CrostiniFeatures::Get()->CouldBeAllowed(profile_)); // Should we actually enable the button to install it? html_source->AddBoolean( - "allowCrostini", + "isCrostiniAllowed", crostini::CrostiniFeatures::Get()->IsAllowedNow(profile_)); // Should Bruschetta be displayed in the settings at all? diff --git a/chromium/chrome/browser/ui/webui/settings/ash/crostini_section_unittest.cc b/chromium/chrome/browser/ui/webui/settings/ash/crostini_section_unittest.cc index 0739cdbf817..cf024db68fe 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/crostini_section_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/crostini_section_unittest.cc @@ -70,7 +70,7 @@ class CrostiniSectionTest : public testing::Test { private: content::BrowserTaskEnvironment task_environment_; std::unique_ptr<TestingProfileManager> profile_manager_; - base::raw_ptr<TestingProfile> profile_; + raw_ptr<TestingProfile, DanglingUntriaged> profile_; }; // Test that Bruschetta doesn't show up when it's disabled by flags. diff --git a/chromium/chrome/browser/ui/webui/settings/ash/cups_printers_handler.cc b/chromium/chrome/browser/ui/webui/settings/ash/cups_printers_handler.cc index eac6cf5dfbb..5342d50f8d5 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/cups_printers_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/cups_printers_handler.cc @@ -7,6 +7,7 @@ #include <set> #include <utility> +#include "ash/constants/ash_features.h" #include "ash/public/cpp/new_window_delegate.h" #include "base/containers/flat_map.h" #include "base/files/file_path.h" @@ -26,7 +27,6 @@ #include "base/values.h" #include "chrome/browser/ash/printing/cups_printers_manager.h" #include "chrome/browser/ash/printing/ppd_provider_factory.h" -#include "chrome/browser/ash/printing/printer_configurer.h" #include "chrome/browser/ash/printing/printer_event_tracker.h" #include "chrome/browser/ash/printing/printer_event_tracker_factory.h" #include "chrome/browser/ash/printing/printer_info.h" @@ -81,17 +81,8 @@ constexpr char kNearbyAutomaticPrintersHistogramName[] = "Printing.CUPS.NearbyNetworkAutomaticPrintersCount"; constexpr char kNearbyDiscoveredPrintersHistogramName[] = "Printing.CUPS.NearbyNetworkDiscoveredPrintersCount"; - -void OnRemovedPrinter(const Printer::PrinterProtocol& protocol, bool success) { - if (success) { - PRINTER_LOG(DEBUG) << "Printer removal succeeded."; - } else { - PRINTER_LOG(DEBUG) << "Printer removal failed."; - } - - UMA_HISTOGRAM_ENUMERATION("Printing.CUPS.PrinterRemoved", protocol, - Printer::PrinterProtocol::kProtocolMax); -} +constexpr char kSavedPrintersCountHistogramName[] = + "Printing.CUPS.SavedPrintersCount"; // Log if the IPP attributes request was succesful. void RecordIppQueryResult(const PrinterQueryResult& result) { @@ -260,17 +251,14 @@ CupsPrintersHandler::CupsPrintersHandler(Profile* profile, CupsPrintersManager* printers_manager) : CupsPrintersHandler(profile, CreatePpdProvider(profile), - PrinterConfigurer::Create(profile), printers_manager) {} CupsPrintersHandler::CupsPrintersHandler( Profile* profile, scoped_refptr<PpdProvider> ppd_provider, - std::unique_ptr<PrinterConfigurer> printer_configurer, CupsPrintersManager* printers_manager) : profile_(profile), ppd_provider_(ppd_provider), - printer_configurer_(std::move(printer_configurer)), printers_manager_(printers_manager), endpoint_resolver_( std::make_unique<local_discovery::EndpointResolver>()) {} @@ -279,11 +267,10 @@ CupsPrintersHandler::CupsPrintersHandler( std::unique_ptr<CupsPrintersHandler> CupsPrintersHandler::CreateForTesting( Profile* profile, scoped_refptr<PpdProvider> ppd_provider, - std::unique_ptr<PrinterConfigurer> printer_configurer, CupsPrintersManager* printers_manager) { // Using 'new' to access non-public constructor. - return base::WrapUnique(new CupsPrintersHandler( - profile, ppd_provider, std::move(printer_configurer), printers_manager)); + return base::WrapUnique( + new CupsPrintersHandler(profile, ppd_provider, printers_manager)); } CupsPrintersHandler::~CupsPrintersHandler() { @@ -374,6 +361,10 @@ void CupsPrintersHandler::RegisterMessages() { "openScanningApp", base::BindRepeating(&CupsPrintersHandler::HandleOpenScanningApp, base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "requestPrinterStatus", + base::BindRepeating(&CupsPrintersHandler::HandleRequestPrinterStatus, + base::Unretained(this))); } void CupsPrintersHandler::OnJavascriptAllowed() { @@ -398,6 +389,8 @@ void CupsPrintersHandler::HandleGetCupsSavedPrintersList( std::vector<Printer> printers = printers_manager_->GetPrinters(PrinterClass::kSaved); + base::UmaHistogramCounts100(kSavedPrintersCountHistogramName, + printers.size()); ResolveJavascriptCallback(base::Value(callback_id), BuildCupsPrintersList(printers)); @@ -467,7 +460,7 @@ void CupsPrintersHandler::HandleRetrieveCupsPrinterPpd( } ash::printing::SetUpPrinter( - printers_manager_, printer_configurer_.get(), *printer, + printers_manager_, *printer, base::BindOnce(&CupsPrintersHandler::OnSetUpPrinter, weak_factory_.GetWeakPtr(), printer_id, printer_name, eula)); @@ -599,13 +592,8 @@ void CupsPrintersHandler::HandleRemoveCupsPrinter( PrinterEventTrackerFactory::GetForBrowserContext(profile_) ->RecordPrinterRemoved(*printer); - Printer::PrinterProtocol protocol = printer->GetProtocol(); // Printer is deleted here. Do not access after this line. printers_manager_->RemoveSavedPrinter(printer_id); - - DebugDaemonClient::Get()->CupsRemovePrinter( - printer_id, base::BindOnce(&OnRemovedPrinter, protocol), - base::DoNothing()); } void CupsPrintersHandler::HandleGetPrinterInfo(const base::Value::List& args) { @@ -698,7 +686,7 @@ void CupsPrintersHandler::OnAutoconfQueriedDiscovered( if (ipp_everywhere) { PRINTER_LOG(DEBUG) << "Performing autoconf setup"; printer.mutable_ppd_reference()->autoconf = true; - printer_configurer_->SetUpPrinter( + printers_manager_->SetUpPrinter( printer, base::BindOnce(&CupsPrintersHandler::OnAddedDiscoveredPrinter, weak_factory_.GetWeakPtr(), callback_id, printer)); @@ -730,7 +718,7 @@ void CupsPrintersHandler::OnAutoconfQueried( PRINTER_LOG(DEBUG) << "Could not reach printer"; RejectJavascriptCallback( base::Value(callback_id), - base::Value(PrinterSetupResult::kPrinterUnreachable)); + base::Value(static_cast<int>(PrinterSetupResult::kPrinterUnreachable))); return; } @@ -738,8 +726,9 @@ void CupsPrintersHandler::OnAutoconfQueried( PRINTER_LOG(DEBUG) << "Could not query printer"; base::Value::Dict reject; reject.Set("message", "Querying printer failed"); - RejectJavascriptCallback(base::Value(callback_id), - base::Value(PrinterSetupResult::kFatalError)); + RejectJavascriptCallback( + base::Value(callback_id), + base::Value(static_cast<int>(PrinterSetupResult::kFatalError))); return; } @@ -895,7 +884,7 @@ void CupsPrintersHandler::AddOrReconfigurePrinter(const base::Value::List& args, << "A configuration option must have been selected to add a printer"; } - printer_configurer_->SetUpPrinter( + printers_manager_->SetUpPrinter( *printer, base::BindOnce(&CupsPrintersHandler::OnAddedOrEditedSpecifiedPrinter, weak_factory_.GetWeakPtr(), callback_id, *printer, @@ -948,10 +937,10 @@ void CupsPrintersHandler::OnAddedOrEditedPrinterCommon( case PrinterSetupResult::kMemoryAllocationError: case PrinterSetupResult::kFatalError: case PrinterSetupResult::kManualSetupRequired: + case PrinterSetupResult::kPrinterRemoved: PRINTER_LOG(ERROR) << ResultCodeToMessage(result_code); break; case PrinterSetupResult::kComponentUnavailable: - case PrinterSetupResult::kMaxValue: NOTREACHED() << ResultCodeToMessage(result_code); break; } @@ -967,7 +956,7 @@ void CupsPrintersHandler::OnAddedDiscoveredPrinter( OnAddedOrEditedPrinterCommon(printer, result_code, /*is_automatic=*/true); if (result_code == PrinterSetupResult::kSuccess) { ResolveJavascriptCallback(base::Value(callback_id), - base::Value(result_code)); + base::Value(static_cast<int>(result_code))); } else { PRINTER_LOG(EVENT) << "Automatic setup failed for discovered printer. " "Fall back to manual."; @@ -985,24 +974,28 @@ void CupsPrintersHandler::OnAddedOrEditedSpecifiedPrinter( if (is_printer_edit && result_code == PrinterSetupResult::kSuccess) { result_code = PrinterSetupResult::kEditSuccess; } - PRINTER_LOG(EVENT) << "Add/Update manual printer: " << result_code; + const int result_code_int = static_cast<int>(result_code); + PRINTER_LOG(EVENT) << "Add/Update manual printer: " << result_code_int; OnAddedOrEditedPrinterCommon(printer, result_code, /*is_automatic=*/false); if (result_code != PrinterSetupResult::kSuccess && result_code != PrinterSetupResult::kEditSuccess) { RejectJavascriptCallback(base::Value(callback_id), - base::Value(result_code)); + base::Value(result_code_int)); return; } - ResolveJavascriptCallback(base::Value(callback_id), base::Value(result_code)); + ResolveJavascriptCallback(base::Value(callback_id), + base::Value(result_code_int)); } void CupsPrintersHandler::OnAddOrEditPrinterError( const std::string& callback_id, PrinterSetupResult result_code) { - PRINTER_LOG(EVENT) << "Add printer error: " << result_code; - RejectJavascriptCallback(base::Value(callback_id), base::Value(result_code)); + const int result_code_int = static_cast<int>(result_code); + PRINTER_LOG(EVENT) << "Add printer error: " << result_code_int; + RejectJavascriptCallback(base::Value(callback_id), + base::Value(result_code_int)); } void CupsPrintersHandler::HandleGetCupsPrinterManufacturers( @@ -1058,7 +1051,7 @@ void CupsPrintersHandler::HandleSelectPPDFile(const base::Value::List& args) { web_contents ? chrome::FindBrowserWithWebContents(web_contents) ->window() ->GetNativeWindow() - : gfx::kNullNativeWindow; + : gfx::NativeWindow(); ui::SelectFileDialog::FileTypeInfo file_type_info; file_type_info.extensions.push_back({"ppd"}); @@ -1238,7 +1231,7 @@ void CupsPrintersHandler::HandleAddDiscoveredPrinter( // can't really do much. Fail the add. ResolveJavascriptCallback( base::Value(callback_id), - base::Value(PrinterSetupResult::kPrinterUnreachable)); + base::Value(static_cast<int>(PrinterSetupResult::kPrinterUnreachable))); return; } @@ -1247,7 +1240,7 @@ void CupsPrintersHandler::HandleAddDiscoveredPrinter( // The printer uri was not parsed successfully. Fail the add. ResolveJavascriptCallback( base::Value(callback_id), - base::Value(PrinterSetupResult::kPrinterUnreachable)); + base::Value(static_cast<int>(PrinterSetupResult::kPrinterUnreachable))); return; } @@ -1257,7 +1250,7 @@ void CupsPrintersHandler::HandleAddDiscoveredPrinter( PRINTER_LOG(EVENT) << "Start setup of discovered printer"; // If we have something that looks like a ppd reference for this printer, // try to configure it. - printer_configurer_->SetUpPrinter( + printers_manager_->SetUpPrinter( *printer, base::BindOnce(&CupsPrintersHandler::OnAddedDiscoveredPrinter, weak_factory_.GetWeakPtr(), callback_id, *printer)); @@ -1492,4 +1485,28 @@ void CupsPrintersHandler::HandleOpenScanningApp(const base::Value::List& args) { chrome::ShowScanningApp(profile_); } +void CupsPrintersHandler::HandleRequestPrinterStatus( + const base::Value::List& args) { + CHECK(features::IsPrinterSettingsPrinterStatusEnabled()); + AllowJavascript(); + CHECK_EQ(2U, args.size()); + const std::string& callback_id = args[0].GetString(); + const std::string& printer_id = args[1].GetString(); + + printers_manager_->FetchPrinterStatus( + printer_id, base::BindOnce(&CupsPrintersHandler::OnPrinterStatusReceived, + weak_factory_.GetWeakPtr(), callback_id)); +} + +void CupsPrintersHandler::OnPrinterStatusReceived( + const std::string& callback_id, + const chromeos::CupsPrinterStatus& printer_status) { + if (!IsJavascriptAllowed()) { + return; + } + + ResolveJavascriptCallback(base::Value(callback_id), + printer_status.ConvertToValue()); +} + } // namespace ash::settings diff --git a/chromium/chrome/browser/ui/webui/settings/ash/cups_printers_handler.h b/chromium/chrome/browser/ui/webui/settings/ash/cups_printers_handler.h index e993fccf8b1..fd69553f488 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/cups_printers_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/cups_printers_handler.h @@ -14,9 +14,9 @@ #include "base/memory/weak_ptr.h" #include "base/scoped_observation.h" #include "chrome/browser/ash/printing/cups_printers_manager.h" -#include "chrome/browser/ash/printing/printer_configurer.h" #include "chrome/browser/ash/printing/printer_event_tracker.h" #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" +#include "chromeos/printing/cups_printer_status.h" #include "chromeos/printing/ppd_provider.h" #include "chromeos/printing/printer_configuration.h" #include "printing/printer_query_result.h" @@ -55,7 +55,6 @@ class CupsPrintersHandler : public ::settings::SettingsPageUIHandler, static std::unique_ptr<CupsPrintersHandler> CreateForTesting( Profile* profile, scoped_refptr<chromeos::PpdProvider> ppd_provider, - std::unique_ptr<PrinterConfigurer> printer_configurer, CupsPrintersManager* printers_manager); CupsPrintersHandler(Profile* profile, CupsPrintersManager* printers_manager); @@ -75,7 +74,6 @@ class CupsPrintersHandler : public ::settings::SettingsPageUIHandler, private: CupsPrintersHandler(Profile* profile, scoped_refptr<chromeos::PpdProvider> ppd_provider, - std::unique_ptr<PrinterConfigurer> printer_configurer, CupsPrintersManager* printers_manager); // Gets all CUPS printers and return it to WebUI. @@ -264,6 +262,12 @@ class CupsPrintersHandler : public ::settings::SettingsPageUIHandler, void HandleOpenScanningApp(const base::Value::List& args); + void HandleRequestPrinterStatus(const base::Value::List& args); + + void OnPrinterStatusReceived( + const std::string& callback_id, + const chromeos::CupsPrinterStatus& printer_status); + raw_ptr<Profile, ExperimentalAsh> profile_; // Discovery support. discovery_active_ tracks whether or not the UI @@ -278,7 +282,6 @@ class CupsPrintersHandler : public ::settings::SettingsPageUIHandler, // // TODO(crbug/757887) - Remove this subtle initialization constraint. scoped_refptr<chromeos::PpdProvider> ppd_provider_; - std::unique_ptr<PrinterConfigurer> printer_configurer_; // Cached list of {printer name, PpdReference} pairs for each manufacturer // that has been resolved in the lifetime of this object. diff --git a/chromium/chrome/browser/ui/webui/settings/ash/cups_printers_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/ash/cups_printers_handler_unittest.cc index 358b75f118b..a61d9b1d887 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/cups_printers_handler_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/cups_printers_handler_unittest.cc @@ -7,6 +7,7 @@ #include <memory> #include "ash/public/cpp/test/test_new_window_delegate.h" +#include "base/containers/flat_set.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" @@ -14,10 +15,10 @@ #include "base/functional/callback_helpers.h" #include "base/json/json_string_value_serializer.h" #include "base/memory/raw_ptr.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/values_test_util.h" #include "base/values.h" -#include "chrome/browser/ash/printing/printing_stubs.h" -#include "chrome/browser/ash/printing/test_printer_configurer.h" +#include "chrome/browser/ash/printing/fake_cups_printers_manager.h" #include "chrome/browser/download/chrome_download_manager_delegate.h" #include "chrome/browser/download/download_core_service_factory.h" #include "chrome/browser/download/download_core_service_impl.h" @@ -38,6 +39,15 @@ namespace ash::settings { +namespace { + +constexpr char kSavedPrintersCountHistogramName[] = + "Printing.CUPS.SavedPrintersCount"; + +constexpr char kHandlerFunctionName[] = "handlerFunctionName"; + +} // namespace + using ::chromeos::Printer; class CupsPrintersHandlerTest; @@ -55,24 +65,6 @@ void RemovedPrinter(base::OnceClosure quit_closure, std::move(quit_closure).Run(); } -class TestCupsPrintersManager : public StubCupsPrintersManager { - public: - absl::optional<Printer> GetPrinter(const std::string& id) const override { - return printer_; - } - bool IsPrinterInstalled(const chromeos::Printer& printer) const override { - return printer_installed_; - } - - // Used to configured our test manager for specific tests. - void SetPrinter(absl::optional<Printer> printer) { printer_ = printer; } - void SetPrinterInstalled(bool installed) { printer_installed_ = installed; } - - private: - absl::optional<Printer> printer_ = Printer(); - bool printer_installed_ = true; -}; - class FakePpdProvider : public chromeos::PpdProvider { public: FakePpdProvider() = default; @@ -214,7 +206,7 @@ class CupsPrintersHandlerTest : public testing::Test { void SetUp() override { printers_handler_ = CupsPrintersHandler::CreateForTesting( profile_.get(), base::MakeRefCounted<FakePpdProvider>(), - std::make_unique<TestPrinterConfigurer>(), &printers_manager_); + &printers_manager_); printers_handler_->SetWebUIForTest(&web_ui_); printers_handler_->RegisterMessages(); printers_handler_->AllowJavascriptForTesting(); @@ -244,9 +236,10 @@ class CupsPrintersHandlerTest : public testing::Test { printing::PrintBackend::SetPrintBackendForTesting(nullptr); } - void CallRetrieveCupsPpd(std::string license_url = "") { + void CallRetrieveCupsPpd(const std::string& printer_id, + const std::string& license_url = "") { base::Value::List args; - args.Append("printer_id"); + args.Append(printer_id); args.Append(kPpdPrinterName); args.Append(license_url); @@ -254,6 +247,12 @@ class CupsPrintersHandlerTest : public testing::Test { run_loop_.Run(); } + void CallGetCupsSavedPrintersList() { + base::Value::List args; + args.Append(kHandlerFunctionName); + web_ui_.HandleReceivedMessage("getCupsSavedPrintersList", args); + } + // Get the contents of the file that was downloaded. Return true on success, // false on error. bool GetDownloadedPpdContents(std::string& contents) const { @@ -271,13 +270,14 @@ class CupsPrintersHandlerTest : public testing::Test { std::unique_ptr<TestingProfile> profile_; content::TestWebUI web_ui_; std::unique_ptr<CupsPrintersHandler> printers_handler_; - TestCupsPrintersManager printers_manager_; + FakeCupsPrintersManager printers_manager_; base::RunLoop run_loop_; scoped_refptr<printing::TestPrintBackend> print_backend_ = base::MakeRefCounted<printing::TestPrintBackend>(); raw_ptr<MockNewWindowDelegate, ExperimentalAsh> new_window_delegate_primary_; std::unique_ptr<TestNewWindowDelegateProvider> new_window_provider_; base::ScopedTempDir download_dir_; + base::HistogramTester histogram_tester_; const std::string kPpdPrinterName = "printer_name"; const std::string kDefaultPpdData = "PPD data used for testing"; @@ -295,29 +295,21 @@ TEST_F(CupsPrintersHandlerTest, RemoveCorrectPrinter) { ConciergeClient::InitializeFake( /*fake_cicerone_client=*/nullptr); - DebugDaemonClient* client = DebugDaemonClient::Get(); - client->CupsAddAutoConfiguredPrinter("testprinter1", "fakeuri", - base::BindOnce(&AddedPrinter)); + Printer printer("id"); + printers_manager_.SavePrinter(printer); + printers_manager_.SetUpPrinter(printer, base::DoNothing()); + printers_manager_.PrinterInstalled(printer, /*is_automatic=*/true); const std::string remove_list = R"( - ["testprinter1", "Test Printer 1"] + [")" + printer.id() + R"(", "Test Printer 1"] )"; std::string error; base::Value remove_printers = base::test::ParseJson(remove_list); ASSERT_TRUE(remove_printers.is_list()); + EXPECT_TRUE(printers_manager_.IsPrinterInstalled(printer)); web_ui_.HandleReceivedMessage("removeCupsPrinter", remove_printers.GetList()); - - // We expect this printer removal to fail since the printer should have - // already been removed by the previous call to 'removeCupsPrinter'. - base::RunLoop run_loop; - bool expected = true; - client->CupsRemovePrinter( - "testprinter1", - base::BindOnce(&RemovedPrinter, run_loop.QuitClosure(), &expected), - base::DoNothing()); - run_loop.Run(); - EXPECT_FALSE(expected); + EXPECT_FALSE(printers_manager_.IsPrinterInstalled(printer)); profile_.reset(); ConciergeClient::Shutdown(); @@ -329,7 +321,7 @@ TEST_F(CupsPrintersHandlerTest, VerifyOnlyPpdFilesAllowed) { expected_file_type_info.extensions.push_back({"ppd"}); expected_file_type_info.extensions.push_back({"ppd.gz"}); ui::SelectFileDialog::SetFactory( - new TestSelectFileDialogFactory(&expected_file_type_info)); + std::make_unique<TestSelectFileDialogFactory>(&expected_file_type_info)); base::Value::List args; args.Append("handleFunctionName"); @@ -342,10 +334,11 @@ TEST_F(CupsPrintersHandlerTest, ViewPPD) { static_cast<FakeDebugDaemonClient*>(DebugDaemonClient::Get()) ->SetPpdDataForTesting(kPpdData); - absl::optional<Printer> printer = printers_manager_.GetPrinter(""); - ASSERT_TRUE(printer); + Printer printer("id"); + printers_manager_.SavePrinter(printer); + print_backend_->AddValidPrinter( - printer->id(), + printer.id(), std::make_unique<printing::PrinterSemanticCapsAndDefaults>(), nullptr); EXPECT_CALL(*new_window_delegate_primary_, @@ -355,7 +348,7 @@ TEST_F(CupsPrintersHandlerTest, ViewPPD) { ash::NewWindowDelegate::Disposition::kSwitchToTab)) .WillOnce(testing::InvokeWithoutArgs(&run_loop_, &base::RunLoop::Quit)); - CallRetrieveCupsPpd(); + CallRetrieveCupsPpd(printer.id()); // Check for the downloaded PPD file. std::string contents; @@ -370,10 +363,11 @@ TEST_F(CupsPrintersHandlerTest, ViewPPDWithLicense) { static_cast<FakeDebugDaemonClient*>(DebugDaemonClient::Get()) ->SetPpdDataForTesting(kPpdDataWithHeader); - absl::optional<Printer> printer = printers_manager_.GetPrinter(""); - ASSERT_TRUE(printer); + Printer printer("id"); + printers_manager_.SavePrinter(printer); + print_backend_->AddValidPrinter( - printer->id(), + printer.id(), std::make_unique<printing::PrinterSemanticCapsAndDefaults>(), nullptr); EXPECT_CALL(*new_window_delegate_primary_, @@ -384,7 +378,7 @@ TEST_F(CupsPrintersHandlerTest, ViewPPDWithLicense) { .WillOnce(testing::InvokeWithoutArgs(&run_loop_, &base::RunLoop::Quit)); const std::string license_url("chrome://os-credits/xerox-printing-license"); - CallRetrieveCupsPpd(license_url); + CallRetrieveCupsPpd(printer.id(), license_url); // Check that the downloaded PPD file contains the license URL. std::string contents; @@ -401,10 +395,11 @@ TEST_F(CupsPrintersHandlerTest, ViewPPDWithLicenseBadPpd) { static_cast<FakeDebugDaemonClient*>(DebugDaemonClient::Get()) ->SetPpdDataForTesting(kPpdData); - absl::optional<Printer> printer = printers_manager_.GetPrinter(""); - ASSERT_TRUE(printer); + Printer printer("id"); + printers_manager_.SavePrinter(printer); + print_backend_->AddValidPrinter( - printer->id(), + printer.id(), std::make_unique<printing::PrinterSemanticCapsAndDefaults>(), nullptr); EXPECT_CALL(*new_window_delegate_primary_, @@ -415,7 +410,7 @@ TEST_F(CupsPrintersHandlerTest, ViewPPDWithLicenseBadPpd) { .WillOnce(testing::InvokeWithoutArgs(&run_loop_, &base::RunLoop::Quit)); const std::string license_url("chrome://os-credits/xerox-printing-license"); - CallRetrieveCupsPpd(license_url); + CallRetrieveCupsPpd(printer.id(), license_url); // Check that the downloaded PPD file contains the error message. std::string contents; @@ -425,9 +420,7 @@ TEST_F(CupsPrintersHandlerTest, ViewPPDWithLicenseBadPpd) { TEST_F(CupsPrintersHandlerTest, ViewPPDPrinterNotFound) { // Test the case where the printer is not known to the printer manager. - - // Set an empty printer to simluate not being able to find the printer. - printers_manager_.SetPrinter(absl::optional<Printer>()); + // No printers were added to CupsPrintersManager. EXPECT_CALL(*new_window_delegate_primary_, OpenUrl(testing::Property(&GURL::ExtractFileName, @@ -436,7 +429,7 @@ TEST_F(CupsPrintersHandlerTest, ViewPPDPrinterNotFound) { ash::NewWindowDelegate::Disposition::kSwitchToTab)) .WillOnce(testing::InvokeWithoutArgs(&run_loop_, &base::RunLoop::Quit)); - CallRetrieveCupsPpd(); + CallRetrieveCupsPpd("printer_id"); // Check that the downloaded PPD file contains the error message. std::string contents; @@ -450,15 +443,13 @@ TEST_F(CupsPrintersHandlerTest, ViewPPDPrinterNotSetup) { static_cast<FakeDebugDaemonClient*>(DebugDaemonClient::Get()) ->SetPpdDataForTesting(kPpdData); - absl::optional<Printer> printer = printers_manager_.GetPrinter(""); - ASSERT_TRUE(printer); + Printer printer("id"); + printers_manager_.SavePrinter(printer); + print_backend_->AddValidPrinter( - printer->id(), + printer.id(), std::make_unique<printing::PrinterSemanticCapsAndDefaults>(), nullptr); - // This will cause our printer to get set up. - printers_manager_.SetPrinterInstalled(false); - EXPECT_CALL(*new_window_delegate_primary_, OpenUrl(testing::Property(&GURL::ExtractFileName, testing::StartsWith(kPpdPrinterName)), @@ -466,7 +457,7 @@ TEST_F(CupsPrintersHandlerTest, ViewPPDPrinterNotSetup) { ash::NewWindowDelegate::Disposition::kSwitchToTab)) .WillOnce(testing::InvokeWithoutArgs(&run_loop_, &base::RunLoop::Quit)); - CallRetrieveCupsPpd(); + CallRetrieveCupsPpd(printer.id()); // Check for the downloaded PPD file. std::string contents; @@ -480,10 +471,11 @@ TEST_F(CupsPrintersHandlerTest, ViewPPDEmptyPPD) { static_cast<FakeDebugDaemonClient*>(DebugDaemonClient::Get()) ->SetPpdDataForTesting({}); - absl::optional<Printer> printer = printers_manager_.GetPrinter(""); - ASSERT_TRUE(printer); + Printer printer("id"); + printers_manager_.SavePrinter(printer); + print_backend_->AddValidPrinter( - printer->id(), + printer.id(), std::make_unique<printing::PrinterSemanticCapsAndDefaults>(), nullptr); EXPECT_CALL(*new_window_delegate_primary_, @@ -493,7 +485,7 @@ TEST_F(CupsPrintersHandlerTest, ViewPPDEmptyPPD) { ash::NewWindowDelegate::Disposition::kSwitchToTab)) .WillOnce(testing::InvokeWithoutArgs(&run_loop_, &base::RunLoop::Quit)); - CallRetrieveCupsPpd(); + CallRetrieveCupsPpd(printer.id()); // Check that the downloaded PPD file contains the error message. std::string contents; @@ -501,4 +493,21 @@ TEST_F(CupsPrintersHandlerTest, ViewPPDEmptyPPD) { EXPECT_THAT(contents, testing::HasSubstr(kPpdErrorString)); } +TEST_F(CupsPrintersHandlerTest, GetSavedPrinters) { + Printer printer("id"); + printer.SetUri("http://printer/uri"); + printers_manager_.SavePrinter(printer); + Printer printer2("id2"); + printer2.SetUri("http://printer/uri2"); + printers_manager_.SavePrinter(printer2); + + CallGetCupsSavedPrintersList(); + + // Expect 2 printers are recorded to the histogram from the `GetPrinters()` + // result. + histogram_tester_.ExpectBucketCount(kSavedPrintersCountHistogramName, + /*sample=*/2, + /*expected_count=*/1); +} + } // namespace ash::settings diff --git a/chromium/chrome/browser/ui/webui/settings/ash/device_keyboard_handler.cc b/chromium/chrome/browser/ui/webui/settings/ash/device_keyboard_handler.cc index 95d81ed142d..f688a4469b3 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/device_keyboard_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/device_keyboard_handler.cc @@ -17,6 +17,7 @@ #include "content/public/browser/web_ui.h" #include "ui/events/ash/keyboard_capability.h" #include "ui/events/ash/keyboard_layout_util.h" +#include "ui/events/devices/keyboard_device.h" namespace { @@ -29,10 +30,11 @@ struct KeyboardsStateResult { KeyboardsStateResult GetKeyboardsState() { KeyboardsStateResult result; - for (const ui::InputDevice& keyboard : + for (const ui::KeyboardDevice& keyboard : ui::DeviceDataManager::GetInstance()->GetKeyboardDevices()) { switch (ash::Shell::Get()->keyboard_capability()->GetDeviceType(keyboard)) { case ui::KeyboardCapability::DeviceType::kDeviceInternalKeyboard: + case ui::KeyboardCapability::DeviceType::kDeviceInternalRevenKeyboard: result.has_launcher_key = true; break; case ui::KeyboardCapability::DeviceType::kDeviceExternalAppleKeyboard: diff --git a/chromium/chrome/browser/ui/webui/settings/ash/device_keyboard_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/ash/device_keyboard_handler_unittest.cc index 0b646c941da..4846d198187 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/device_keyboard_handler_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/device_keyboard_handler_unittest.cc @@ -192,7 +192,7 @@ TEST_F(KeyboardHandlerTest, ExternalKeyboard) { auto fake_udev = std::make_unique<testing::FakeUdevLoader>(); // Standard internal keyboard on x86 device. - const ui::InputDevice internal_kbd( + const ui::KeyboardDevice internal_kbd( 1, ui::INPUT_DEVICE_INTERNAL, "AT Translated Set 2 keyboard", "", base::FilePath("/devices/platform/i8042/serio0/input/input1"), 1, 1, 0xab41); @@ -201,7 +201,7 @@ TEST_F(KeyboardHandlerTest, ExternalKeyboard) { /*devtype=*/absl::nullopt, /*sysattrs=*/{}, /*properties=*/{}); // Generic external USB keyboard. - const ui::InputDevice external_generic_kbd( + const ui::KeyboardDevice 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/" @@ -213,7 +213,7 @@ TEST_F(KeyboardHandlerTest, ExternalKeyboard) { /*devtype=*/absl::nullopt, /*sysattrs=*/{}, /*properties=*/{}); // Apple keyboard. - const ui::InputDevice external_apple_kbd( + const ui::KeyboardDevice 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"), @@ -224,7 +224,7 @@ TEST_F(KeyboardHandlerTest, ExternalKeyboard) { /*devtype=*/absl::nullopt, /*sysattrs=*/{}, /*properties=*/{}); // Chrome OS external USB keyboard. - const ui::InputDevice external_chromeos_kbd( + const ui::KeyboardDevice 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"), @@ -236,7 +236,7 @@ TEST_F(KeyboardHandlerTest, ExternalKeyboard) { /*properties=*/{{"CROS_KEYBOARD_TOP_ROW_LAYOUT", "1"}}); // Chrome OS external Bluetooth keyboard. - const ui::InputDevice external_bt_chromeos_kbd( + const ui::KeyboardDevice external_bt_chromeos_kbd( 4, ui::INPUT_DEVICE_BLUETOOTH, "LG BT Keyboard", "", base::FilePath("/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/" "0003:04CA:0082.000B/input/input5"), @@ -261,7 +261,7 @@ 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>{internal_kbd, external_generic_kbd}); + std::vector<ui::KeyboardDevice>{internal_kbd, external_generic_kbd}); EXPECT_TRUE(HasLauncherKey()); EXPECT_TRUE(HasCapsLock()); EXPECT_TRUE(HasExternalMetaKey()); @@ -271,7 +271,7 @@ TEST_F(KeyboardHandlerTest, ExternalKeyboard) { // 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}); + std::vector<ui::KeyboardDevice>{internal_kbd, external_chromeos_kbd}); EXPECT_TRUE(HasLauncherKey()); EXPECT_FALSE(HasCapsLock()); EXPECT_FALSE(HasExternalMetaKey()); @@ -281,7 +281,7 @@ TEST_F(KeyboardHandlerTest, ExternalKeyboard) { // Connecting external Bluetooth ChromeOS-branded keyboard, we should not // see neither CapsLock not meta keys. device_data_manager_test_api_.SetKeyboardDevices( - std::vector<ui::InputDevice>{external_bt_chromeos_kbd}); + std::vector<ui::KeyboardDevice>{external_bt_chromeos_kbd}); EXPECT_TRUE(HasLauncherKey()); EXPECT_FALSE(HasCapsLock()); EXPECT_FALSE(HasExternalMetaKey()); @@ -291,7 +291,7 @@ TEST_F(KeyboardHandlerTest, ExternalKeyboard) { // Simulate an external Apple keyboard being connected. Now users can remap // the command key. device_data_manager_test_api_.SetKeyboardDevices( - std::vector<ui::InputDevice>{internal_kbd, external_apple_kbd}); + std::vector<ui::KeyboardDevice>{internal_kbd, external_apple_kbd}); EXPECT_TRUE(HasLauncherKey()); EXPECT_TRUE(HasCapsLock()); EXPECT_FALSE(HasExternalMetaKey()); @@ -301,7 +301,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>{external_generic_kbd, external_apple_kbd}); + std::vector<ui::KeyboardDevice>{external_generic_kbd, + external_apple_kbd}); EXPECT_FALSE(HasLauncherKey()); EXPECT_TRUE(HasCapsLock()); EXPECT_TRUE(HasExternalMetaKey()); @@ -312,9 +313,10 @@ TEST_F(KeyboardHandlerTest, ExternalKeyboard) { // device names. Those should also be detected as external keyboards, and // should show the capslock and external meta remapping. // https://crbug.com/834594. - device_data_manager_test_api_.SetKeyboardDevices(std::vector<ui::InputDevice>{ - {6, ui::INPUT_DEVICE_USB, "Topre Corporation Realforce 87", "", - external_generic_kbd.sys_path, 0x046d, 0xc31c, 0x0111}}); + device_data_manager_test_api_.SetKeyboardDevices( + std::vector<ui::KeyboardDevice>{ + {6, ui::INPUT_DEVICE_USB, "Topre Corporation Realforce 87", "", + external_generic_kbd.sys_path, 0x046d, 0xc31c, 0x0111}}); EXPECT_FALSE(HasLauncherKey()); EXPECT_TRUE(HasCapsLock()); EXPECT_TRUE(HasExternalMetaKey()); diff --git a/chromium/chrome/browser/ui/webui/settings/ash/device_power_handler.cc b/chromium/chrome/browser/ui/webui/settings/ash/device_power_handler.cc index 77624974e9a..ea31884acae 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/device_power_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/device_power_handler.cc @@ -7,6 +7,7 @@ #include <memory> #include <utility> +#include "ash/constants/ash_features.h" #include "ash/constants/ash_pref_names.h" #include "ash/public/cpp/power_utils.h" #include "base/functional/bind.h" @@ -115,6 +116,8 @@ const char PowerHandler::kHasLidKey[] = "hasLid"; const char PowerHandler::kAdaptiveChargingKey[] = "adaptiveCharging"; const char PowerHandler::kAdaptiveChargingManagedKey[] = "adaptiveChargingManaged"; +const char PowerHandler::kBatterySaverFeatureEnabledKey[] = + "batterySaverFeatureEnabled"; PowerHandler::TestAPI::TestAPI(PowerHandler* handler) : handler_(handler) {} @@ -401,7 +404,8 @@ void PowerHandler::SendPowerManagementSettings(bool force) { prefs_->GetBoolean(ash::prefs::kPowerAdaptiveChargingEnabled); const bool adaptive_charging_managed = prefs_->IsManagedPreference(ash::prefs::kPowerAdaptiveChargingEnabled); - + const bool battery_saver_feature_enabled = + ash::features::IsBatterySaverAvailable(); // Don't notify the UI if nothing changed. if (!force && ac_idle_info == last_ac_idle_info_ && battery_idle_info == last_battery_idle_info_ && @@ -409,7 +413,8 @@ void PowerHandler::SendPowerManagementSettings(bool force) { lid_closed_controlled == last_lid_closed_controlled_ && has_lid == last_has_lid_ && adaptive_charging == last_adaptive_charging_ && - adaptive_charging_managed == last_adaptive_charging_managed_) { + adaptive_charging_managed == last_adaptive_charging_managed_ && + battery_saver_feature_enabled == last_battery_saver_feature_enabled_) { return; } @@ -432,6 +437,7 @@ void PowerHandler::SendPowerManagementSettings(bool force) { dict.Set(kHasLidKey, has_lid); dict.Set(kAdaptiveChargingKey, adaptive_charging); dict.Set(kAdaptiveChargingManagedKey, adaptive_charging_managed); + dict.Set(kBatterySaverFeatureEnabledKey, battery_saver_feature_enabled); FireWebUIListener(kPowerManagementSettingsChangedName, dict); last_ac_idle_info_ = ac_idle_info; @@ -441,6 +447,7 @@ void PowerHandler::SendPowerManagementSettings(bool force) { last_has_lid_ = has_lid; last_adaptive_charging_ = adaptive_charging; last_adaptive_charging_managed_ = adaptive_charging_managed; + last_battery_saver_feature_enabled_ = battery_saver_feature_enabled; } void PowerHandler::OnGotSwitchStates( diff --git a/chromium/chrome/browser/ui/webui/settings/ash/device_power_handler.h b/chromium/chrome/browser/ui/webui/settings/ash/device_power_handler.h index 7a271c24898..4088dc9f74a 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/device_power_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/device_power_handler.h @@ -53,6 +53,7 @@ class PowerHandler : public ::settings::SettingsPageUIHandler, static const char kHasLidKey[]; static const char kAdaptiveChargingKey[]; static const char kAdaptiveChargingManagedKey[]; + static const char kBatterySaverFeatureEnabledKey[]; // Class used by tests to interact with PowerHandler internals. class TestAPI { @@ -186,6 +187,7 @@ class PowerHandler : public ::settings::SettingsPageUIHandler, bool last_has_lid_ = true; bool last_adaptive_charging_ = false; bool last_adaptive_charging_managed_ = false; + bool last_battery_saver_feature_enabled_ = false; base::WeakPtrFactory<PowerHandler> weak_ptr_factory_{this}; }; diff --git a/chromium/chrome/browser/ui/webui/settings/ash/device_power_handler_browsertest.cc b/chromium/chrome/browser/ui/webui/settings/ash/device_power_handler_browsertest.cc index 6c4c386b96b..2da9e6b7d58 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/device_power_handler_browsertest.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/device_power_handler_browsertest.cc @@ -78,6 +78,7 @@ class PowerHandlerTest : public InProcessBrowserTest { bool has_lid = true; bool adaptive_charging = true; bool adaptive_charging_managed = false; + bool battery_saver_feature_enabled = false; }; PowerHandlerTest() = default; @@ -161,6 +162,8 @@ class PowerHandlerTest : public InProcessBrowserTest { dict.Set(PowerHandler::kAdaptiveChargingKey, settings.adaptive_charging); dict.Set(PowerHandler::kAdaptiveChargingManagedKey, settings.adaptive_charging_managed); + dict.Set(PowerHandler::kBatterySaverFeatureEnabledKey, + settings.battery_saver_feature_enabled); std::string out; EXPECT_TRUE(base::JSONWriter::Write(dict, &out)); return out; diff --git a/chromium/chrome/browser/ui/webui/settings/ash/device_section.cc b/chromium/chrome/browser/ui/webui/settings/ash/device_section.cc index 4f46daa07ff..fc0fb553b24 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/device_section.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/device_section.cc @@ -17,6 +17,7 @@ #include "base/no_destructor.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/browser/ash/drive/file_system_util.h" #include "chrome/browser/ash/login/demo_mode/demo_session.h" #include "chrome/browser/ui/webui/settings/ash/device_display_handler.h" #include "chrome/browser/ui/webui/settings/ash/device_keyboard_handler.h" @@ -33,6 +34,7 @@ #include "components/user_manager/user_manager.h" #include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui_data_source.h" +#include "media/base/media_switches.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/webui/web_ui_util.h" #include "ui/display/display_features.h" @@ -49,6 +51,7 @@ using ::chromeos::settings::mojom::kAudioSubpagePath; using ::chromeos::settings::mojom::kDeviceSectionPath; using ::chromeos::settings::mojom::kDisplaySubpagePath; using ::chromeos::settings::mojom::kExternalStorageSubpagePath; +using ::chromeos::settings::mojom::kGraphicsTabletSubpagePath; using ::chromeos::settings::mojom::kKeyboardSubpagePath; using ::chromeos::settings::mojom::kPerDeviceKeyboardRemapKeysSubpagePath; using ::chromeos::settings::mojom::kPerDeviceKeyboardSubpagePath; @@ -134,48 +137,57 @@ const std::vector<SearchConcept>& GetDeviceSearchConcepts() { {.setting = mojom::Setting::kPowerIdleBehaviorWhileOnBattery}, {IDS_OS_SETTINGS_TAG_POWER_IDLE_WHILE_ON_BATTERY_ALT1, SearchConcept::kAltTagEnd}}, + {IDS_OS_SETTINGS_TAG_AUDIO_SETTINGS, + mojom::kAudioSubpagePath, + mojom::SearchResultIcon::kAudio, + mojom::SearchResultDefaultRank::kMedium, + mojom::SearchResultType::kSubpage, + {.subpage = mojom::Subpage::kAudio}, + {IDS_OS_SETTINGS_TAG_AUDIO_SETTINGS_ALT1, + IDS_OS_SETTINGS_TAG_AUDIO_SETTINGS_ALT2, + IDS_OS_SETTINGS_TAG_AUDIO_SETTINGS_ALT3, + IDS_OS_SETTINGS_TAG_AUDIO_SETTINGS_ALT4, SearchConcept::kAltTagEnd}}, }); return *tags; } const std::vector<SearchConcept>& GetKeyboardSearchConcepts() { - static const base::NoDestructor<std::vector<SearchConcept>> tags({ - {IDS_OS_SETTINGS_TAG_KEYBOARD, - mojom::kKeyboardSubpagePath, - mojom::SearchResultIcon::kKeyboard, - mojom::SearchResultDefaultRank::kMedium, - mojom::SearchResultType::kSubpage, - {.subpage = mojom::Subpage::kKeyboard}}, - {IDS_OS_SETTINGS_TAG_KEYBOARD_AUTO_REPEAT, - mojom::kKeyboardSubpagePath, - mojom::SearchResultIcon::kKeyboard, - mojom::SearchResultDefaultRank::kMedium, - mojom::SearchResultType::kSetting, - {.setting = mojom::Setting::kKeyboardAutoRepeat}, - {IDS_OS_SETTINGS_TAG_KEYBOARD_AUTO_REPEAT_ALT1, - SearchConcept::kAltTagEnd}}, - {IDS_OS_SETTINGS_TAG_KEYBOARD_SHORTCUTS, - mojom::kKeyboardSubpagePath, - mojom::SearchResultIcon::kKeyboard, - mojom::SearchResultDefaultRank::kMedium, - mojom::SearchResultType::kSetting, - {.setting = mojom::Setting::kKeyboardShortcuts}}, - {IDS_OS_SETTINGS_TAG_KEYBOARD_FUNCTION_KEYS, - mojom::kKeyboardSubpagePath, - mojom::SearchResultIcon::kKeyboard, - mojom::SearchResultDefaultRank::kMedium, - mojom::SearchResultType::kSetting, - {.setting = mojom::Setting::kKeyboardFunctionKeys}}, - {IDS_OS_SETTINGS_TAG_KEYBOARD_DIACRITIC, - mojom::kKeyboardSubpagePath, - mojom::SearchResultIcon::kKeyboard, - mojom::SearchResultDefaultRank::kMedium, - mojom::SearchResultType::kSetting, - {.setting = mojom::Setting::kShowDiacritic}, - {IDS_OS_SETTINGS_TAG_KEYBOARD_DIACRITIC1, - IDS_OS_SETTINGS_TAG_KEYBOARD_DIACRITIC2, - IDS_OS_SETTINGS_TAG_KEYBOARD_DIACRITIC3, SearchConcept::kAltTagEnd}} - }); + static const base::NoDestructor<std::vector<SearchConcept>> tags( + {{IDS_OS_SETTINGS_TAG_KEYBOARD, + mojom::kKeyboardSubpagePath, + mojom::SearchResultIcon::kKeyboard, + mojom::SearchResultDefaultRank::kMedium, + mojom::SearchResultType::kSubpage, + {.subpage = mojom::Subpage::kKeyboard}}, + {IDS_OS_SETTINGS_TAG_KEYBOARD_AUTO_REPEAT, + mojom::kKeyboardSubpagePath, + mojom::SearchResultIcon::kKeyboard, + mojom::SearchResultDefaultRank::kMedium, + mojom::SearchResultType::kSetting, + {.setting = mojom::Setting::kKeyboardAutoRepeat}, + {IDS_OS_SETTINGS_TAG_KEYBOARD_AUTO_REPEAT_ALT1, + SearchConcept::kAltTagEnd}}, + {IDS_OS_SETTINGS_TAG_KEYBOARD_SHORTCUTS, + mojom::kKeyboardSubpagePath, + mojom::SearchResultIcon::kKeyboard, + mojom::SearchResultDefaultRank::kMedium, + mojom::SearchResultType::kSetting, + {.setting = mojom::Setting::kKeyboardShortcuts}}, + {IDS_OS_SETTINGS_TAG_KEYBOARD_FUNCTION_KEYS, + mojom::kKeyboardSubpagePath, + mojom::SearchResultIcon::kKeyboard, + mojom::SearchResultDefaultRank::kMedium, + mojom::SearchResultType::kSetting, + {.setting = mojom::Setting::kKeyboardFunctionKeys}}, + {IDS_OS_SETTINGS_TAG_KEYBOARD_DIACRITIC, + mojom::kKeyboardSubpagePath, + mojom::SearchResultIcon::kKeyboard, + mojom::SearchResultDefaultRank::kMedium, + mojom::SearchResultType::kSetting, + {.setting = mojom::Setting::kShowDiacritic}, + {IDS_OS_SETTINGS_TAG_KEYBOARD_DIACRITIC1, + IDS_OS_SETTINGS_TAG_KEYBOARD_DIACRITIC2, + IDS_OS_SETTINGS_TAG_KEYBOARD_DIACRITIC3, SearchConcept::kAltTagEnd}}}); return *tags; } @@ -557,18 +569,24 @@ const std::vector<SearchConcept>& GetStylusSearchConcepts() { return *tags; } -const std::vector<SearchConcept>& GetAudioSearchConcepts() { +const std::vector<SearchConcept>& GetAudioPowerSoundsSearchConcepts() { static const base::NoDestructor<std::vector<SearchConcept>> tags({ - {IDS_OS_SETTINGS_TAG_AUDIO_SETTINGS, - mojom::kAudioSubpagePath, - mojom::SearchResultIcon::kAudio, - mojom::SearchResultDefaultRank::kMedium, - mojom::SearchResultType::kSubpage, - {.subpage = mojom::Subpage::kAudio}, - {IDS_OS_SETTINGS_TAG_AUDIO_SETTINGS_ALT1, - IDS_OS_SETTINGS_TAG_AUDIO_SETTINGS_ALT2, - IDS_OS_SETTINGS_TAG_AUDIO_SETTINGS_ALT3, - IDS_OS_SETTINGS_TAG_AUDIO_SETTINGS_ALT4, SearchConcept::kAltTagEnd}}, + { + IDS_OS_SETTINGS_TAG_CHARGING_SOUNDS, + mojom::kAudioSubpagePath, + mojom::SearchResultIcon::kAudio, + mojom::SearchResultDefaultRank::kMedium, + mojom::SearchResultType::kSetting, + {.setting = mojom::Setting::kChargingSounds}, + }, + { + IDS_OS_SETTINGS_TAG_LOW_BATTERY_SOUND, + mojom::kAudioSubpagePath, + mojom::SearchResultIcon::kAudio, + mojom::SearchResultDefaultRank::kMedium, + mojom::SearchResultType::kSetting, + {.setting = mojom::Setting::kLowBatterySound}, + }, }); return *tags; } @@ -772,21 +790,21 @@ bool IsTouchCalibrationAvailable() { display::HasExternalTouchscreenDevice(); } -bool IsDriveFsBulkPinningEnabled() { - return ash::features::IsDriveFsBulkPinningEnabled(); -} - bool IsListAllDisplayModesEnabled() { return display::features::IsListAllDisplayModesEnabled(); } +bool IsShowForceRespectUiGainsToggleEnabled() { + // No need to show the toggle if UI gains is not going to be ignored. + if (!base::FeatureList::IsEnabled(media::kIgnoreUiGains)) { + return false; + } + return base::FeatureList::IsEnabled(media::kShowForceRespectUiGainsToggle); +} + void AddDeviceKeyboardStrings(content::WebUIDataSource* html_source) { static constexpr webui::LocalizedString keyboard_strings[] = { {"builtInKeyboardName", IDS_SETTINGS_BUILT_IN_KEYBOARD_NAME}, - {"keyboardBlockMetaFunctionKeyRewrites", - IDS_SETTINGS_KEYBOARD_BLOCK_META_FUNCTION_KEY_REWRITES}, - {"keyboardBlockMetaFunctionKeyRewritesDescription", - IDS_SETTINGS_KEYBOARD_BLOCK_META_FUNCTION_KEY_REWRITES_DESCRIPTION}, {"keyboardEnableAutoRepeat", IDS_SETTINGS_KEYBOARD_AUTO_REPEAT_ENABLE}, {"keyboardEnableAutoRepeatSubLabel", IDS_SETTINGS_KEYBOARD_AUTO_REPEAT_ENABLE_SUB_LABEL}, @@ -824,6 +842,8 @@ void AddDeviceKeyboardStrings(content::WebUIDataSource* html_source) { IDS_SETTINGS_KEYBOARD_REMAP_KEYS_DESCRIPTION}, {"showKeyboardShortcutViewer", IDS_SETTINGS_KEYBOARD_SHOW_SHORTCUT_VIEWER}, + {"viewAndCustomizeKeyboardShortcut", + IDS_SETTINGS_KEYBOARD_VIEW_AND_CUSTOMIZE_SHORTCUTS}, {"keyboardKeyLauncher", IDS_SETTINGS_KEYBOARD_KEY_LAUNCHER}, {"keyboardKeySearch", IDS_SETTINGS_KEYBOARD_KEY_SEARCH}, {"keyboardRemapRestoreDefaultsLabel", @@ -849,24 +869,41 @@ void AddDeviceKeyboardStrings(content::WebUIDataSource* html_source) { IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_DISABLED}, {"perDeviceKeyboardKeyEscape", IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_ESCAPE}, - {"perDeviceKeyboardKeyExternalMeta", - IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_EXTERNAL_META}, - {"perDeviceKeyboardKeySearch", - IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_SEARCH}, - + {"perDeviceKeyboardKeyMeta", IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_META}, }; html_source->AddLocalizedStrings(keyboard_strings); - html_source->AddLocalizedString( - "keyboardKeySearch", - Shell::Get()->keyboard_capability()->HasLauncherButton() - ? IDS_SETTINGS_KEYBOARD_KEY_LAUNCHER - : IDS_SETTINGS_KEYBOARD_KEY_SEARCH); - html_source->AddLocalizedString( - "keyboardSendFunctionKeysDescription", - Shell::Get()->keyboard_capability()->HasLauncherButton() - ? IDS_SETTINGS_KEYBOARD_SEND_FUNCTION_KEYS_LAYOUT2_DESCRIPTION - : IDS_SETTINGS_KEYBOARD_SEND_FUNCTION_KEYS_DESCRIPTION); + if (Shell::Get()->keyboard_capability()->HasLauncherButtonOnAnyKeyboard()) { + html_source->AddLocalizedString( + "keyboardBlockMetaFunctionKeyRewrites", + IDS_SETTINGS_KEYBOARD_BLOCK_META_FUNCTION_KEY_REWRITES_LAUNCHER); + html_source->AddLocalizedString( + "keyboardBlockMetaFunctionKeyRewritesDescription", + IDS_SETTINGS_KEYBOARD_BLOCK_META_FUNCTION_KEY_REWRITES_DESCRIPTION_LAUNCHER); + html_source->AddLocalizedString( + "perDeviceKeyboardKeySearch", + IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_LAUNCHER); + html_source->AddLocalizedString("keyboardKeySearch", + IDS_SETTINGS_KEYBOARD_KEY_LAUNCHER); + html_source->AddLocalizedString( + "keyboardSendFunctionKeysDescription", + IDS_SETTINGS_KEYBOARD_SEND_FUNCTION_KEYS_LAYOUT2_DESCRIPTION); + } else { + html_source->AddLocalizedString( + "keyboardBlockMetaFunctionKeyRewrites", + IDS_SETTINGS_KEYBOARD_BLOCK_META_FUNCTION_KEY_REWRITES_SEARCH); + html_source->AddLocalizedString( + "keyboardBlockMetaFunctionKeyRewritesDescription", + IDS_SETTINGS_KEYBOARD_BLOCK_META_FUNCTION_KEY_REWRITES_DESCRIPTION_SEARCH); + html_source->AddLocalizedString( + "perDeviceKeyboardKeySearch", + IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_SEARCH); + html_source->AddLocalizedString("keyboardKeySearch", + IDS_SETTINGS_KEYBOARD_KEY_SEARCH); + html_source->AddLocalizedString( + "keyboardSendFunctionKeysDescription", + IDS_SETTINGS_KEYBOARD_SEND_FUNCTION_KEYS_DESCRIPTION); + } } void AddDeviceStylusStrings(content::WebUIDataSource* html_source) { @@ -894,120 +931,6 @@ void AddDeviceStylusStrings(content::WebUIDataSource* html_source) { stylus_utils::HasInternalStylus()); } -void AddDeviceDisplayStrings(content::WebUIDataSource* html_source) { - static constexpr webui::LocalizedString kDisplayStrings[] = { - {"displayAmbientColorTitle", IDS_SETTINGS_DISPLAY_AMBIENT_COLOR_TITLE}, - {"displayAmbientColorSubtitle", - IDS_SETTINGS_DISPLAY_AMBIENT_COLOR_SUBTITLE}, - {"displayArrangementTitle", IDS_SETTINGS_DISPLAY_ARRANGEMENT_TITLE}, - {"displayMirror", IDS_SETTINGS_DISPLAY_MIRROR}, - {"displayMirrorDisplayName", IDS_SETTINGS_DISPLAY_MIRROR_DISPLAY_NAME}, - {"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}, - {"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}, - {"displayNightLightText", IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_TEXT}, - {"displayOrientation", IDS_SETTINGS_DISPLAY_ORIENTATION}, - {"displayOrientationAutoRotate", - IDS_SETTINGS_DISPLAY_ORIENTATION_AUTO_ROTATE}, - {"displayOrientationStandard", IDS_SETTINGS_DISPLAY_ORIENTATION_STANDARD}, - {"displayOverscanInstructions", - IDS_SETTINGS_DISPLAY_OVERSCAN_INSTRUCTIONS}, - {"displayOverscanPageText", IDS_SETTINGS_DISPLAY_OVERSCAN_TEXT}, - {"displayOverscanPageTitle", IDS_SETTINGS_DISPLAY_OVERSCAN_TITLE}, - {"displayOverscanPosition", IDS_SETTINGS_DISPLAY_OVERSCAN_POSITION}, - {"displayOverscanResize", IDS_SETTINGS_DISPLAY_OVERSCAN_RESIZE}, - {"displayOverscanReset", IDS_SETTINGS_DISPLAY_OVERSCAN_RESET}, - {"displayOverscanSubtitle", IDS_SETTINGS_DISPLAY_OVERSCAN_SUBTITLE}, - {"displayRefreshRateInterlacedMenuItem", - IDS_SETTINGS_DISPLAY_REFRESH_RATE_INTERLACED_MENU_ITEM}, - {"displayRefreshRateMenuItem", - IDS_SETTINGS_DISPLAY_REFRESH_RATE_MENU_ITEM}, - {"displayRefreshRateSublabel", - IDS_SETTINGS_DISPLAY_REFRESH_RATE_SUBLABEL}, - {"displayRefreshRateTitle", IDS_SETTINGS_DISPLAY_REFRESH_RATE_TITLE}, - {"displayResolutionInterlacedMenuItem", - IDS_SETTINGS_DISPLAY_RESOLUTION_INTERLACED_MENU_ITEM}, - {"displayResolutionMenuItem", IDS_SETTINGS_DISPLAY_RESOLUTION_MENU_ITEM}, - {"displayResolutionOnlyMenuItem", - IDS_SETTINGS_DISPLAY_RESOLUTION_ONLY_MENU_ITEM}, - {"displayResolutionSublabel", IDS_SETTINGS_DISPLAY_RESOLUTION_SUBLABEL}, - {"displayResolutionText", IDS_SETTINGS_DISPLAY_RESOLUTION_TEXT}, - {"displayResolutionTextBest", IDS_SETTINGS_DISPLAY_RESOLUTION_TEXT_BEST}, - {"displayResolutionTextNative", - IDS_SETTINGS_DISPLAY_RESOLUTION_TEXT_NATIVE}, - {"displayResolutionTitle", IDS_SETTINGS_DISPLAY_RESOLUTION_TITLE}, - {"displayScreenExtended", IDS_SETTINGS_DISPLAY_SCREEN_EXTENDED}, - {"displayScreenPrimary", IDS_SETTINGS_DISPLAY_SCREEN_PRIMARY}, - {"displayScreenTitle", IDS_SETTINGS_DISPLAY_SCREEN}, - {"displaySizeSliderMaxLabel", IDS_SETTINGS_DISPLAY_ZOOM_SLIDER_MAXIMUM}, - {"displaySizeSliderMinLabel", IDS_SETTINGS_DISPLAY_ZOOM_SLIDER_MINIMUM}, - {"displayTitle", IDS_SETTINGS_DISPLAY_TITLE}, - {"displayTouchCalibrationText", - IDS_SETTINGS_DISPLAY_TOUCH_CALIBRATION_TEXT}, - {"displayTouchCalibrationTitle", - IDS_SETTINGS_DISPLAY_TOUCH_CALIBRATION_TITLE}, - {"displayUnifiedDesktop", IDS_SETTINGS_DISPLAY_UNIFIED_DESKTOP}, - {"displayUnifiedDesktopOff", IDS_SETTINGS_DISPLAY_UNIFIED_DESKTOP_OFF}, - {"displayUnifiedDesktopOn", IDS_SETTINGS_DISPLAY_UNIFIED_DESKTOP_ON}, - {"displayZoomLogicalResolutionDefaultText", - IDS_SETTINGS_DISPLAY_ZOOM_LOGICAL_RESOLUTION_DEFAULT_TEXT}, - {"displayZoomLogicalResolutionText", - IDS_SETTINGS_DISPLAY_ZOOM_LOGICAL_RESOLUTION_TEXT}, - {"displayZoomNativeLogicalResolutionNativeText", - IDS_SETTINGS_DISPLAY_ZOOM_LOGICAL_RESOLUTION_NATIVE_TEXT}, - {"displayZoomSublabel", IDS_SETTINGS_DISPLAY_ZOOM_SUBLABEL}, - {"displayZoomTitle", IDS_SETTINGS_DISPLAY_ZOOM_TITLE}, - {"displayZoomValue", IDS_SETTINGS_DISPLAY_ZOOM_VALUE}, - }; - html_source->AddLocalizedStrings(kDisplayStrings); - - html_source->AddLocalizedString( - "displayArrangementText", - IDS_SETTINGS_DISPLAY_ARRANGEMENT_WITH_KEYBOARD_TEXT); - - html_source->AddBoolean( - "isCryptohomeDataEphemeral", - user_manager::UserManager::Get()->IsCurrentUserCryptohomeDataEphemeral()); - - html_source->AddBoolean("unifiedDesktopAvailable", - IsUnifiedDesktopAvailable()); - - html_source->AddBoolean("listAllDisplayModes", - IsListAllDisplayModesEnabled()); - - html_source->AddBoolean("deviceSupportsAmbientColor", - DoesDeviceSupportAmbientColor()); - - html_source->AddBoolean("enableTouchCalibrationSetting", - IsTouchCalibrationAvailable()); - - html_source->AddBoolean("enableDriveFsBulkPinning", - IsDriveFsBulkPinningEnabled()); - - html_source->AddString("invalidDisplayId", - base::NumberToString(display::kInvalidDisplayId)); - - html_source->AddBoolean( - "allowDisplayAlignmentApi", - base::FeatureList::IsEnabled(ash::features::kDisplayAlignAssist)); -} - void AddDeviceStorageStrings(content::WebUIDataSource* html_source, bool is_external_storage_page_available) { static constexpr webui::LocalizedString kStorageStrings[] = { @@ -1067,6 +990,7 @@ void AddDeviceAudioStrings(content::WebUIDataSource* html_source) { {"audioDeviceRearMicLabel", IDS_SETTINGS_AUDIO_DEVICE_REAR_MIC_LABEL}, {"audioDeviceUsbLabel", IDS_SETTINGS_AUDIO_DEVICE_USB_LABEL}, {"audioInputDeviceTitle", IDS_SETTINGS_AUDIO_INPUT_DEVICE_TITLE}, + {"audioInputAllowAGCTitle", IDS_SETTINGS_AUDIO_INPUT_ALLOW_AGC_TITLE}, {"audioInputGainTitle", IDS_SETTINGS_AUDIO_INPUT_GAIN_TITLE}, {"audioInputMuteButtonAriaLabelMuted", IDS_SETTINGS_AUDIO_INPUT_MUTE_BUTTON_ARIA_LABEL_MUTED}, @@ -1091,9 +1015,19 @@ void AddDeviceAudioStrings(content::WebUIDataSource* html_source) { {"audioToggleToUnmuteTooltip", IDS_SETTINGS_AUDIO_TOGGLE_TO_UNMUTE_TOOLTIP}, {"audioVolumeTitle", IDS_SETTINGS_AUDIO_VOLUME_TITLE}, + {"chargingSoundsLabel", + IDS_SETTINGS_AUDIO_DEVICE_SOUNDS_CHARGING_SOUNDS_LABEL}, + {"deviceStartupSoundLabel", + IDS_SETTINGS_AUDIO_DEVICE_SOUNDS_STARTUP_SOUND_LABEL}, + {"deviceSoundsTitle", IDS_SETTINGS_AUDIO_DEVICE_SOUNDS_TITLE}, + {"lowBatterySoundLabel", + IDS_SETTINGS_AUDIO_DEVICE_SOUNDS_LOW_BATTERY_SOUND_LABEL}, }; html_source->AddLocalizedStrings(kAudioStrings); + + html_source->AddBoolean("areSystemSoundsEnabled", + ash::features::AreSystemSoundsEnabled()); } void AddDevicePowerStrings(content::WebUIDataSource* html_source) { @@ -1126,11 +1060,17 @@ void AddDevicePowerStrings(content::WebUIDataSource* html_source) { {"powerSourceLowPowerCharger", IDS_SETTINGS_POWER_SOURCE_LOW_POWER_CHARGER}, {"powerTitle", IDS_SETTINGS_POWER_TITLE}, + {"powerBatterySaverLabel", IDS_SETTINGS_POWER_BATTERY_SAVER_LABEL}, + {"powerBatterySaverSubtext", IDS_SETTINGS_POWER_BATTERY_SAVER_SUBTEXT}, }; html_source->AddLocalizedStrings(kPowerStrings); - // TODO(b:216035280): create and link to real "learn more" webpage. - html_source->AddString("powerAdaptiveChargingLearnMoreUrl", u"about://blank"); + html_source->AddString( + "powerAdaptiveChargingLearnMoreUrl", + u"https://support.google.com/chromebook/?p=settings_adaptive_charging"); + + // TODO(b:278957245): create and link to real "learn more" webpage. + html_source->AddString("powerBatterySaverLearnMoreUrl", "about://blank"); } // Mirrors enum of the same name in enums.xml. @@ -1159,11 +1099,14 @@ DeviceSection::DeviceSection(Profile* profile, } else { updater.AddSearchTags(GetKeyboardSearchConcepts()); } - if (ShouldShowExternalStorageSettings(profile)) + if (ShouldShowExternalStorageSettings(profile)) { updater.AddSearchTags(GetExternalStorageSearchConcepts()); + } - if (ash::features::IsAudioSettingsPageEnabled()) { - updater.AddSearchTags(GetAudioSearchConcepts()); + // Only when the feature is enabled, the toggle buttons for charging sounds + // and the low battery sound will be shown up. + if (ash::features::AreSystemSoundsEnabled()) { + updater.AddSearchTags(GetAudioPowerSoundsSearchConcepts()); } chromeos::PowerManagerClient* power_manager_client = @@ -1173,8 +1116,9 @@ DeviceSection::DeviceSection(Profile* profile, const absl::optional<power_manager::PowerSupplyProperties>& last_status = power_manager_client->GetLastStatus(); - if (last_status) + if (last_status) { PowerChanged(*last_status); + } // Determine whether to show laptop lid power settings. power_manager_client->GetSwitchStates(base::BindOnce( @@ -1224,13 +1168,15 @@ DeviceSection::~DeviceSection() { chromeos::PowerManagerClient* power_manager_client = chromeos::PowerManagerClient::Get(); - if (power_manager_client) + if (power_manager_client) { power_manager_client->RemoveObserver(this); + } NightLightController* night_light_controller = NightLightController::GetInstance(); - if (night_light_controller) + if (night_light_controller) { night_light_controller->RemoveObserver(this); + } } void DeviceSection::AddLoadTimeData(content::WebUIDataSource* html_source) { @@ -1242,7 +1188,20 @@ void DeviceSection::AddLoadTimeData(content::WebUIDataSource* html_source) { html_source->AddBoolean("isDemoSession", DemoSession::IsDeviceInDemoMode()); + html_source->AddBoolean( + "enableInputDeviceSettingsSplit", + base::FeatureList::IsEnabled(ash::features::kInputDeviceSettingsSplit)); + + html_source->AddBoolean( + "enablePeripheralCustomization", + base::FeatureList::IsEnabled(ash::features::kPeripheralCustomization)); + + html_source->AddBoolean("enableAltClickAndSixPackCustomization", + base::FeatureList::IsEnabled( + ash::features::kAltClickAndSixPackCustomization)); + AddDevicePointersStrings(html_source); + AddDeviceGraphicsTabletStrings(html_source); AddDeviceKeyboardStrings(html_source); AddDeviceStylusStrings(html_source); AddDeviceDisplayStrings(html_source); @@ -1373,6 +1332,16 @@ void DeviceSection::RegisterHierarchy(HierarchyGenerator* generator) const { mojom::kPerDevicePointingStickSubpagePath); } + if (base::FeatureList::IsEnabled(ash::features::kPeripheralCustomization)) { + // TODO(yyhyyh@): Add icon for graphics tablet to replace the temporary + // stylus icon. + generator->RegisterTopLevelSubpage(IDS_SETTINGS_GRAPHICS_TABLET_TITLE, + mojom::Subpage::kGraphicsTablet, + mojom::SearchResultIcon::kStylus, + mojom::SearchResultDefaultRank::kMedium, + mojom::kGraphicsTabletSubpagePath); + } + // Keyboard. generator->RegisterTopLevelSubpage( IDS_SETTINGS_KEYBOARD_TITLE, mojom::Subpage::kKeyboard, @@ -1439,6 +1408,10 @@ void DeviceSection::RegisterHierarchy(HierarchyGenerator* generator) const { IDS_SETTINGS_AUDIO_TITLE, mojom::Subpage::kAudio, mojom::SearchResultIcon::kAudio, mojom::SearchResultDefaultRank::kMedium, mojom::kAudioSubpagePath); + generator->RegisterNestedSetting(mojom::Setting::kChargingSounds, + mojom::Subpage::kAudio); + generator->RegisterNestedSetting(mojom::Setting::kLowBatterySound, + mojom::Subpage::kAudio); // Power. generator->RegisterTopLevelSubpage( @@ -1451,6 +1424,7 @@ void DeviceSection::RegisterHierarchy(HierarchyGenerator* generator) const { mojom::Setting::kPowerSource, mojom::Setting::kSleepWhenLaptopLidClosed, mojom::Setting::kAdaptiveCharging, + mojom::Setting::kBatterySaver, }; RegisterNestedSettingBulk(mojom::Subpage::kPower, kPowerSettings, generator); } @@ -1607,16 +1581,18 @@ void DeviceSection::OnGetDisplayLayoutInfo( SearchTagRegistry::ScopedTagUpdater updater = registry()->StartUpdate(); // Arrangement UI. - if (has_multiple_displays || is_mirrored) + if (has_multiple_displays || is_mirrored) { updater.AddSearchTags(GetDisplayArrangementSearchConcepts()); - else + } else { updater.RemoveSearchTags(GetDisplayArrangementSearchConcepts()); + } // Mirror toggle. - if (is_mirrored || (!unified_desktop_mode && has_multiple_displays)) + if (is_mirrored || (!unified_desktop_mode && has_multiple_displays)) { updater.AddSearchTags(GetDisplayMirrorSearchConcepts()); - else + } else { updater.RemoveSearchTags(GetDisplayMirrorSearchConcepts()); + } // Unified Desktop toggle. if (unified_desktop_mode || @@ -1627,65 +1603,74 @@ void DeviceSection::OnGetDisplayLayoutInfo( } // External display settings. - if (has_external_display) + if (has_external_display) { updater.AddSearchTags(GetDisplayExternalSearchConcepts()); - else + } else { updater.RemoveSearchTags(GetDisplayExternalSearchConcepts()); + } // Refresh Rate dropdown. - if (has_external_display && IsListAllDisplayModesEnabled()) + if (has_external_display && IsListAllDisplayModesEnabled()) { updater.AddSearchTags(GetDisplayExternalWithRefreshSearchConcepts()); - else + } else { updater.RemoveSearchTags(GetDisplayExternalWithRefreshSearchConcepts()); + } // Orientation settings. - if (!unified_desktop_mode) + if (!unified_desktop_mode) { updater.AddSearchTags(GetDisplayOrientationSearchConcepts()); - else + } else { updater.RemoveSearchTags(GetDisplayOrientationSearchConcepts()); + } // Ambient color settings. - if (DoesDeviceSupportAmbientColor() && has_internal_display) + if (DoesDeviceSupportAmbientColor() && has_internal_display) { updater.AddSearchTags(GetDisplayAmbientSearchConcepts()); - else + } else { updater.RemoveSearchTags(GetDisplayAmbientSearchConcepts()); + } // Touch calibration settings. - if (IsTouchCalibrationAvailable()) + if (IsTouchCalibrationAvailable()) { updater.AddSearchTags(GetDisplayTouchCalibrationSearchConcepts()); - else + } else { updater.RemoveSearchTags(GetDisplayTouchCalibrationSearchConcepts()); + } // Night Light on settings. - if (NightLightController::GetInstance()->GetEnabled()) + if (NightLightController::GetInstance()->GetEnabled()) { updater.AddSearchTags(GetDisplayNightLightOnSearchConcepts()); - else + } else { updater.RemoveSearchTags(GetDisplayNightLightOnSearchConcepts()); + } } void DeviceSection::OnGotSwitchStates( absl::optional<chromeos::PowerManagerClient::SwitchStates> result) { SearchTagRegistry::ScopedTagUpdater updater = registry()->StartUpdate(); - if (result && - result->lid_state != chromeos::PowerManagerClient::LidState::NOT_PRESENT) + if (result && result->lid_state != + chromeos::PowerManagerClient::LidState::NOT_PRESENT) { updater.AddSearchTags(GetPowerWithLaptopLidSearchConcepts()); + } } void DeviceSection::UpdateStylusSearchTags() { // If not yet complete, wait for OnDeviceListsComplete() callback. - if (!ui::DeviceDataManager::GetInstance()->AreDeviceListsComplete()) + if (!ui::DeviceDataManager::GetInstance()->AreDeviceListsComplete()) { return; + } SearchTagRegistry::ScopedTagUpdater updater = registry()->StartUpdate(); // TODO(https://crbug.com/1071905): Only show stylus settings if a stylus has // been set up. HasStylusInput() will return true for any stylus-compatible // device, even if it doesn't have a stylus. - if (stylus_utils::HasStylusInput()) + if (stylus_utils::HasStylusInput()) { updater.AddSearchTags(GetStylusSearchConcepts()); - else + } else { updater.RemoveSearchTags(GetStylusSearchConcepts()); + } } void DeviceSection::AddDevicePointersStrings( @@ -1731,7 +1716,17 @@ void DeviceSection::AddDevicePointersStrings( {"touchpadScrollAccelerationLabel", IDS_SETTINGS_TOUCHPAD_SCROLL_ACCELERATION_LABEL}, {"touchpadScrollSpeed", IDS_SETTINGS_TOUCHPAD_SCROLL_SPEED_LABEL}, + {"touchpadSimulateRightClickLabel", + IDS_SETTINGS_TOUCHPAD_SIMULATE_RIGHT_CLICK_LABEL}, + {"touchpadSimulateRightClickOptionAlt", + IDS_SETTINGS_TOUCHPAD_SIMULATE_RIGHT_CLICK_OPTION_ALT}, + {"touchpadSimulateRightClickOptionOff", + IDS_SETTINGS_TOUCHPAD_SIMULATE_RIGHT_CLICK_OPTION_OFF}, + {"touchpadSimulateRightClickOptionSearch", + IDS_SETTINGS_TOUCHPAD_SIMULATE_RIGHT_CLICK_OPTION_SEARCH}, {"learnMoreLabel", IDS_SETTINGS_LEARN_MORE_LABEL}, + {"modifierKeysLabel", IDS_SETTINGS_MODIFIER_KEYS_LABEL}, + {"otherKeysLabel", IDS_SETTINGS_OTHER_KEYS_LABEL}, }; html_source->AddLocalizedStrings(kPointersStrings); @@ -1741,14 +1736,132 @@ void DeviceSection::AddDevicePointersStrings( GetHelpUrlWithBoard(chrome::kHapticFeedbackHelpURL)); html_source->AddBoolean("allowScrollSettings", AreScrollSettingsAllowed()); +} + +void DeviceSection::AddDeviceGraphicsTabletStrings( + content::WebUIDataSource* html_source) const { + static constexpr webui::LocalizedString kGraphicsTabletStrings[] = { + {"tabletTitle", IDS_SETTINGS_GRAPHICS_TABLET_TITLE}, + }; + html_source->AddLocalizedStrings(kGraphicsTabletStrings); +} + +void DeviceSection::AddDeviceDisplayStrings( + content::WebUIDataSource* html_source) const { + static constexpr webui::LocalizedString kDisplayStrings[] = { + {"displayAmbientColorTitle", IDS_SETTINGS_DISPLAY_AMBIENT_COLOR_TITLE}, + {"displayAmbientColorSubtitle", + IDS_SETTINGS_DISPLAY_AMBIENT_COLOR_SUBTITLE}, + {"displayArrangementTitle", IDS_SETTINGS_DISPLAY_ARRANGEMENT_TITLE}, + {"displayMirror", IDS_SETTINGS_DISPLAY_MIRROR}, + {"displayMirrorDisplayName", IDS_SETTINGS_DISPLAY_MIRROR_DISPLAY_NAME}, + {"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}, + {"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}, + {"displayNightLightText", IDS_SETTINGS_DISPLAY_NIGHT_LIGHT_TEXT}, + {"displayOrientation", IDS_SETTINGS_DISPLAY_ORIENTATION}, + {"displayOrientationAutoRotate", + IDS_SETTINGS_DISPLAY_ORIENTATION_AUTO_ROTATE}, + {"displayOrientationStandard", IDS_SETTINGS_DISPLAY_ORIENTATION_STANDARD}, + {"displayOverscanInstructions", + IDS_SETTINGS_DISPLAY_OVERSCAN_INSTRUCTIONS}, + {"displayOverscanPageText", IDS_SETTINGS_DISPLAY_OVERSCAN_TEXT}, + {"displayOverscanPageTitle", IDS_SETTINGS_DISPLAY_OVERSCAN_TITLE}, + {"displayOverscanPosition", IDS_SETTINGS_DISPLAY_OVERSCAN_POSITION}, + {"displayOverscanResize", IDS_SETTINGS_DISPLAY_OVERSCAN_RESIZE}, + {"displayOverscanReset", IDS_SETTINGS_DISPLAY_OVERSCAN_RESET}, + {"displayOverscanSubtitle", IDS_SETTINGS_DISPLAY_OVERSCAN_SUBTITLE}, + {"displayRefreshRateInterlacedMenuItem", + IDS_SETTINGS_DISPLAY_REFRESH_RATE_INTERLACED_MENU_ITEM}, + {"displayRefreshRateMenuItem", + IDS_SETTINGS_DISPLAY_REFRESH_RATE_MENU_ITEM}, + {"displayRefreshRateSublabel", + IDS_SETTINGS_DISPLAY_REFRESH_RATE_SUBLABEL}, + {"displayRefreshRateTitle", IDS_SETTINGS_DISPLAY_REFRESH_RATE_TITLE}, + {"displayResolutionInterlacedMenuItem", + IDS_SETTINGS_DISPLAY_RESOLUTION_INTERLACED_MENU_ITEM}, + {"displayResolutionMenuItem", IDS_SETTINGS_DISPLAY_RESOLUTION_MENU_ITEM}, + {"displayResolutionOnlyMenuItem", + IDS_SETTINGS_DISPLAY_RESOLUTION_ONLY_MENU_ITEM}, + {"displayResolutionSublabel", IDS_SETTINGS_DISPLAY_RESOLUTION_SUBLABEL}, + {"displayResolutionText", IDS_SETTINGS_DISPLAY_RESOLUTION_TEXT}, + {"displayResolutionTextBest", IDS_SETTINGS_DISPLAY_RESOLUTION_TEXT_BEST}, + {"displayResolutionTextNative", + IDS_SETTINGS_DISPLAY_RESOLUTION_TEXT_NATIVE}, + {"displayResolutionTitle", IDS_SETTINGS_DISPLAY_RESOLUTION_TITLE}, + {"displayScreenExtended", IDS_SETTINGS_DISPLAY_SCREEN_EXTENDED}, + {"displayScreenPrimary", IDS_SETTINGS_DISPLAY_SCREEN_PRIMARY}, + {"displayScreenTitle", IDS_SETTINGS_DISPLAY_SCREEN}, + {"displaySizeSliderMaxLabel", IDS_SETTINGS_DISPLAY_ZOOM_SLIDER_MAXIMUM}, + {"displaySizeSliderMinLabel", IDS_SETTINGS_DISPLAY_ZOOM_SLIDER_MINIMUM}, + {"displayTitle", IDS_SETTINGS_DISPLAY_TITLE}, + {"displayTouchCalibrationText", + IDS_SETTINGS_DISPLAY_TOUCH_CALIBRATION_TEXT}, + {"displayTouchCalibrationTitle", + IDS_SETTINGS_DISPLAY_TOUCH_CALIBRATION_TITLE}, + {"displayUnifiedDesktop", IDS_SETTINGS_DISPLAY_UNIFIED_DESKTOP}, + {"displayUnifiedDesktopOff", IDS_SETTINGS_DISPLAY_UNIFIED_DESKTOP_OFF}, + {"displayUnifiedDesktopOn", IDS_SETTINGS_DISPLAY_UNIFIED_DESKTOP_ON}, + {"displayZoomLogicalResolutionDefaultText", + IDS_SETTINGS_DISPLAY_ZOOM_LOGICAL_RESOLUTION_DEFAULT_TEXT}, + {"displayZoomLogicalResolutionText", + IDS_SETTINGS_DISPLAY_ZOOM_LOGICAL_RESOLUTION_TEXT}, + {"displayZoomNativeLogicalResolutionNativeText", + IDS_SETTINGS_DISPLAY_ZOOM_LOGICAL_RESOLUTION_NATIVE_TEXT}, + {"displayZoomSublabel", IDS_SETTINGS_DISPLAY_ZOOM_SUBLABEL}, + {"displayZoomTitle", IDS_SETTINGS_DISPLAY_ZOOM_TITLE}, + {"displayZoomValue", IDS_SETTINGS_DISPLAY_ZOOM_VALUE}, + }; + html_source->AddLocalizedStrings(kDisplayStrings); + + html_source->AddLocalizedString( + "displayArrangementText", + IDS_SETTINGS_DISPLAY_ARRANGEMENT_WITH_KEYBOARD_TEXT); html_source->AddBoolean( - "enableAudioSettingsPage", - base::FeatureList::IsEnabled(ash::features::kAudioSettingsPage)); + "isCryptohomeDataEphemeral", + user_manager::UserManager::Get()->IsCurrentUserCryptohomeDataEphemeral()); + + html_source->AddBoolean("unifiedDesktopAvailable", + IsUnifiedDesktopAvailable()); + + html_source->AddBoolean("listAllDisplayModes", + IsListAllDisplayModesEnabled()); + + html_source->AddBoolean("deviceSupportsAmbientColor", + DoesDeviceSupportAmbientColor()); + + html_source->AddBoolean("enableForceRespectUiGainsToggle", + IsShowForceRespectUiGainsToggleEnabled()); + + html_source->AddBoolean("enableTouchCalibrationSetting", + IsTouchCalibrationAvailable()); + + html_source->AddString("invalidDisplayId", + base::NumberToString(display::kInvalidDisplayId)); + + html_source->AddBoolean("enableDriveFsBulkPinning", + drive::util::IsDriveFsBulkPinningEnabled(profile())); html_source->AddBoolean( - "enableInputDeviceSettingsSplit", - base::FeatureList::IsEnabled(ash::features::kInputDeviceSettingsSplit)); + "allowDisplayAlignmentApi", + base::FeatureList::IsEnabled(ash::features::kDisplayAlignAssist)); } } // namespace ash::settings diff --git a/chromium/chrome/browser/ui/webui/settings/ash/device_section.h b/chromium/chrome/browser/ui/webui/settings/ash/device_section.h index 161fa7b443b..ac36287fddb 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/device_section.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/device_section.h @@ -85,6 +85,9 @@ class DeviceSection : public OsSettingsSection, crosapi::mojom::DisplayLayoutInfoPtr display_layout_info); void AddDevicePointersStrings(content::WebUIDataSource* html_source); + void AddDeviceGraphicsTabletStrings( + content::WebUIDataSource* html_source) const; + void AddDeviceDisplayStrings(content::WebUIDataSource* html_source) const; raw_ptr<PrefService, ExperimentalAsh> pref_service_; system::PointerDeviceObserver pointer_device_observer_; diff --git a/chromium/chrome/browser/ui/webui/settings/ash/device_section_unittest.cc b/chromium/chrome/browser/ui/webui/settings/ash/device_section_unittest.cc index 2ab0fb3ec14..b0738305488 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/device_section_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/device_section_unittest.cc @@ -128,7 +128,7 @@ TEST_F(DeviceSectionTest, SearchResultChangeToSettingsSplitWithFlag) { // Verify registry updated with regular settings search tags when flag is // disabled. TEST_F(DeviceSectionTest, SearchResultChangeBackWithoutFlag) { - feature_list_.Reset(); + feature_list_.InitAndDisableFeature(features::kInputDeviceSettingsSplit); device_section_ = std::make_unique<DeviceSection>( profile(), search_tag_registry(), pref_service()); diff --git a/chromium/chrome/browser/ui/webui/settings/ash/files_page/google_drive_handler_browsertest.cc b/chromium/chrome/browser/ui/webui/settings/ash/files_page/google_drive_handler_browsertest.cc index fec2174b837..c9ed2bf30cc 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/files_page/google_drive_handler_browsertest.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/files_page/google_drive_handler_browsertest.cc @@ -182,6 +182,34 @@ IN_PROC_BROWSER_TEST_F(GoogleDriveHandlerTest, } IN_PROC_BROWSER_TEST_F(GoogleDriveHandlerTest, + NegativeRemainingSpaceReturnsEmptyStrings) { + SetUpSearchResultExpectations(); + + auto* fake_drivefs = GetFakeDriveFsForProfile(browser()->profile()); + EXPECT_CALL(*fake_drivefs, GetOfflineFilesSpaceUsage(_)) + .WillOnce(RunOnceCallback<0>(drive::FILE_ERROR_OK, 1)); + + // Each item is 250 MB in size, total required space should be 1 GB. + int64_t file_size = 250 << 20; + fake_search_query_.SetSearchResults( + {{.size = file_size}, {.size = file_size}}); + fake_search_query_.SetSearchResults( + {{.size = file_size}, {.size = file_size}}); + fake_search_query_.SetSearchResults({}); + + // Mock negative remaining space, the required space is 1 GB and the free + // space is 500 MB, so the remaining space ends up being -500MB. This is + // indicated by a -1 on the UI layer. + int64_t free_space = 500 << 20; + ash::FakeSpacedClient::Get()->set_free_disk_space(free_space); + + auto google_drive_settings = OpenGoogleDriveSettings(); + google_drive_settings.AssertBulkPinningSpace( + FormatBytesToString(file_size * 4), + /*remaining_space=*/"-1"); +} + +IN_PROC_BROWSER_TEST_F(GoogleDriveHandlerTest, TotalPinnedSizeUpdatesValueOnElement) { SetUpSearchResultExpectations(); diff --git a/chromium/chrome/browser/ui/webui/settings/ash/files_page/google_drive_page_handler.cc b/chromium/chrome/browser/ui/webui/settings/ash/files_page/google_drive_page_handler.cc index 011bf80aba2..a1b42eb4526 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/files_page/google_drive_page_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/files_page/google_drive_page_handler.cc @@ -20,9 +20,15 @@ namespace { google_drive::mojom::StatusPtr CreateStatusPtr(const Progress& progress) { auto status = google_drive::mojom::Status::New(); status->required_space = - base::UTF16ToUTF8(ui::FormatBytes(progress.required_space)); - status->remaining_space = base::UTF16ToUTF8( - ui::FormatBytes(progress.free_space - progress.required_space)); + (progress.required_space >= 0) + ? base::UTF16ToUTF8(ui::FormatBytes(progress.required_space)) + : ""; + int64_t remaining_space = progress.free_space - progress.required_space; + status->remaining_space = + (remaining_space >= 0) + ? base::UTF16ToUTF8( + ui::FormatBytes(progress.free_space - progress.required_space)) + : ""; status->stage = progress.stage; status->is_error = progress.IsError(); return status; @@ -36,27 +42,25 @@ GoogleDrivePageHandler::GoogleDrivePageHandler( Profile* profile) : profile_(profile), page_(std::move(page)), - receiver_(this, std::move(receiver)) {} + receiver_(this, std::move(receiver)) { + if (drive::DriveIntegrationService* const drive_service = GetDriveService()) { + drive_service->AddObserver(this); + } +} GoogleDrivePageHandler::~GoogleDrivePageHandler() { - auto* const pin_manager = GetPinManager(); - if (!pin_manager || !pin_manager->HasObserver(this)) { - return; + if (drive::DriveIntegrationService* const drive_service = GetDriveService()) { + drive_service->RemoveObserver(this); } - pin_manager->RemoveObserver(this); } void GoogleDrivePageHandler::CalculateRequiredSpace() { - auto* pin_manager = GetPinManager(); + auto* const pin_manager = GetPinManager(); if (!pin_manager) { page_->OnServiceUnavailable(); return; } - NotifyProgress(pin_manager->GetProgress()); - if (!pin_manager->HasObserver(this)) { - pin_manager->AddObserver(this); - } pin_manager->CalculateRequiredSpace(); } @@ -81,8 +85,8 @@ drivefs::pinning::PinManager* GoogleDrivePageHandler::GetPinManager() { return service->GetPinManager(); } -void GoogleDrivePageHandler::OnProgress(const Progress& progress) { - auto* pin_manager = GetPinManager(); +void GoogleDrivePageHandler::OnBulkPinProgress(const Progress& progress) { + auto* const pin_manager = GetPinManager(); if (!pin_manager) { page_->OnServiceUnavailable(); return; @@ -91,10 +95,6 @@ void GoogleDrivePageHandler::OnProgress(const Progress& progress) { NotifyProgress(progress); } -void GoogleDrivePageHandler::OnDrop() { - page_->OnServiceUnavailable(); -} - void GoogleDrivePageHandler::GetTotalPinnedSize( GetTotalPinnedSizeCallback callback) { if (!GetDriveService()) { diff --git a/chromium/chrome/browser/ui/webui/settings/ash/files_page/google_drive_page_handler.h b/chromium/chrome/browser/ui/webui/settings/ash/files_page/google_drive_page_handler.h index f3dfae9bd7b..41d8903873e 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/files_page/google_drive_page_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/files_page/google_drive_page_handler.h @@ -9,7 +9,6 @@ #include "base/memory/weak_ptr.h" #include "chrome/browser/ash/drive/drive_integration_service.h" #include "chrome/browser/ui/webui/settings/ash/files_page/mojom/google_drive_handler.mojom.h" -#include "chromeos/ash/components/drivefs/drivefs_pin_manager.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/receiver.h" @@ -21,7 +20,7 @@ namespace ash::settings { // ChromeOS "Google Drive" settings page UI handler. class GoogleDrivePageHandler : public google_drive::mojom::PageHandler, - drivefs::pinning::PinManager::Observer { + public drive::DriveIntegrationServiceObserver { public: GoogleDrivePageHandler( mojo::PendingReceiver<google_drive::mojom::PageHandler> receiver, @@ -39,9 +38,8 @@ class GoogleDrivePageHandler : public google_drive::mojom::PageHandler, void GetTotalPinnedSize(GetTotalPinnedSizeCallback callback) override; void ClearPinnedFiles(ClearPinnedFilesCallback callback) override; - // drivefs::pinning::PinManager::Observer - void OnProgress(const drivefs::pinning::Progress& progress) override; - void OnDrop() override; + // drive::DriveIntegrationServiceObserver + void OnBulkPinProgress(const drivefs::pinning::Progress& progress) override; void NotifyServiceUnavailable(); void NotifyProgress(const drivefs::pinning::Progress& progress); diff --git a/chromium/chrome/browser/ui/webui/settings/ash/files_page/mojom/BUILD.gn b/chromium/chrome/browser/ui/webui/settings/ash/files_page/mojom/BUILD.gn index 4e77d3d6c8b..e140c15e5ea 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/files_page/mojom/BUILD.gn +++ b/chromium/chrome/browser/ui/webui/settings/ash/files_page/mojom/BUILD.gn @@ -8,7 +8,10 @@ import("//mojo/public/tools/bindings/mojom.gni") assert(is_chromeos_ash) mojom("mojom") { - sources = [ "google_drive_handler.mojom" ] + sources = [ + "google_drive_handler.mojom", + "one_drive_handler.mojom", + ] webui_module_path = "/" use_typescript_sources = true diff --git a/chromium/chrome/browser/ui/webui/settings/ash/files_page/mojom/one_drive_handler.mojom b/chromium/chrome/browser/ui/webui/settings/ash/files_page/mojom/one_drive_handler.mojom new file mode 100644 index 00000000000..1f0fb68d1d5 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/ash/files_page/mojom/one_drive_handler.mojom @@ -0,0 +1,38 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module ash.settings.one_drive.mojom; + +// Lives in the browser process. A renderer uses this to create a page handler +// that enables communication between a renderer and the browser process. +interface PageHandlerFactory { + // Creates a PageHandler and connects it up to the Page. + CreatePageHandler(pending_remote<Page> page, + pending_receiver<PageHandler> handler); +}; + +// Lives in the browser process. A renderer uses this to invoke methods that +// are implemented in the browser process. +interface PageHandler { + // Returns the email address associated with the currently connected OneDrive + // account. + GetUserEmailAddress() => (string? email); + + // Emits a OneDrive mount request and returns whether the request succeeded. + ConnectToOneDrive() => (bool success); + + // Emits a OneDrive unmount request and returns whether the request succeeded. + DisconnectFromOneDrive() => (bool success); + + // Opens Files app on OneDrive folder location. + OpenOneDriveFolder() => (bool success); +}; + +// Interface for the OneDrive settings. Implemented in Javascript and +// used by the page handler to send asynchronous updates. +interface Page { + // Invoked on ODFS mount or unmount, indicating that the user has signed in + // or out of OneDrive. + OnODFSMountOrUnmount(); +}; diff --git a/chromium/chrome/browser/ui/webui/settings/ash/files_page/one_drive_page_handler.cc b/chromium/chrome/browser/ui/webui/settings/ash/files_page/one_drive_page_handler.cc new file mode 100644 index 00000000000..ca6121c228f --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/ash/files_page/one_drive_page_handler.cc @@ -0,0 +1,198 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/settings/ash/files_page/one_drive_page_handler.h" + +#include "ash/webui/system_apps/public/system_web_app_type.h" +#include "chrome/browser/ash/file_manager/open_util.h" +#include "chrome/browser/ash/file_system_provider/mount_path_util.h" +#include "chrome/browser/ash/file_system_provider/provided_file_system_info.h" +#include "chrome/browser/ash/file_system_provider/provided_file_system_interface.h" +#include "chrome/browser/ash/file_system_provider/service.h" +#include "chrome/browser/platform_util.h" +#include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h" +#include "chrome/browser/ui/webui/settings/ash/files_page/mojom/one_drive_handler.mojom.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace ash::settings { + +namespace { +void OnGetEmailAddress( + OneDrivePageHandler::GetUserEmailAddressCallback callback, + const ash::file_system_provider::Actions& actions, + base::File::Error result) { + if (result != base::File::Error::FILE_OK) { + LOG(ERROR) << "Failed to get actions: " << result; + std::move(callback).Run(absl::nullopt); + return; + } + for (const file_system_provider::Action& action : actions) { + if (action.id == cloud_upload::kUserEmailActionId) { + std::move(callback).Run(action.title); + return; + } + } + std::move(callback).Run(absl::nullopt); +} + +void OnShowItemInFolder( + OneDrivePageHandler::OpenOneDriveFolderCallback callback, + platform_util::OpenOperationResult result) { + std::move(callback).Run(result == + platform_util::OpenOperationResult::OPEN_SUCCEEDED); +} +} // namespace + +OneDrivePageHandler::OneDrivePageHandler( + mojo::PendingReceiver<one_drive::mojom::PageHandler> receiver, + mojo::PendingRemote<one_drive::mojom::Page> page, + Profile* profile) + : profile_(profile), + page_(std::move(page)), + receiver_(this, std::move(receiver)) { + file_system_provider::Service* service = + file_system_provider::Service::Get(profile_); + if (service) { + service->AddObserver(this); + } +} + +OneDrivePageHandler::~OneDrivePageHandler() { + file_system_provider::Service* service = + file_system_provider::Service::Get(profile_); + if (service) { + service->RemoveObserver(this); + } +} + +void OneDrivePageHandler::GetUserEmailAddress( + GetUserEmailAddressCallback callback) { + file_system_provider::Service* service = + file_system_provider::Service::Get(profile_); + file_system_provider::ProviderId provider_id = + file_system_provider::ProviderId::CreateFromExtensionId( + file_manager::file_tasks::GetODFSExtensionId(profile_)); + std::vector<file_system_provider::ProvidedFileSystemInfo> + odfs_file_system_infos = + service->GetProvidedFileSystemInfoList(provider_id); + if (odfs_file_system_infos.size() == 0) { + // ODFS is not mounted. + std::move(callback).Run(absl::nullopt); + return; + } + if (odfs_file_system_infos.size() != 1u) { + LOG(ERROR) << "One and only one filesystem should be mounted for the ODFS " + "extension"; + std::move(callback).Run(absl::nullopt); + return; + } + auto* file_system = service->GetProvidedFileSystem( + provider_id, odfs_file_system_infos[0].file_system_id()); + file_system->GetActions( + {base::FilePath("/")}, + base::BindOnce(&OnGetEmailAddress, std::move(callback))); +} + +void OneDrivePageHandler::ConnectToOneDrive( + ConnectToOneDriveCallback callback) { + file_system_provider::Service* service = + file_system_provider::Service::Get(profile_); + // First check if OneDrive is already mounted. + CHECK(service); + file_system_provider::ProviderId provider_id = + file_system_provider::ProviderId::CreateFromExtensionId( + file_manager::file_tasks::GetODFSExtensionId(profile_)); + std::vector<file_system_provider::ProvidedFileSystemInfo> + odfs_file_system_infos = + service->GetProvidedFileSystemInfoList(provider_id); + if (odfs_file_system_infos.size() > 0) { + // ODFS is already mounted. + std::move(callback).Run(false); + return; + } + // Show connect OneDrive dialog. This method's callback is called before the + // user tries to sign in. The connection status is detected separately by + // listening to provided file system mount events. + Browser* browser = + FindSystemWebAppBrowser(profile_, ash::SystemWebAppType::FILE_MANAGER); + gfx::NativeWindow modal_parent = + browser ? browser->window()->GetNativeWindow() : nullptr; + std::move(callback).Run( + ash::cloud_upload::ShowConnectOneDriveDialog(modal_parent)); +} + +void OneDrivePageHandler::DisconnectFromOneDrive( + DisconnectFromOneDriveCallback callback) { + file_system_provider::Service* service = + file_system_provider::Service::Get(profile_); + CHECK(service); + file_system_provider::ProviderId provider_id = + file_system_provider::ProviderId::CreateFromExtensionId( + file_manager::file_tasks::GetODFSExtensionId(profile_)); + std::vector<file_system_provider::ProvidedFileSystemInfo> + odfs_file_system_infos = + service->GetProvidedFileSystemInfoList(provider_id); + if (odfs_file_system_infos.size() == 0) { + // ODFS is not mounted. + std::move(callback).Run(false); + return; + } + std::move(callback).Run( + service->RequestUnmount(odfs_file_system_infos[0].provider_id(), + odfs_file_system_infos[0].file_system_id())); +} + +void OneDrivePageHandler::OpenOneDriveFolder( + OpenOneDriveFolderCallback callback) { + file_system_provider::Service* service = + file_system_provider::Service::Get(profile_); + CHECK(service); + file_system_provider::ProviderId provider_id = + file_system_provider::ProviderId::CreateFromExtensionId( + file_manager::file_tasks::GetODFSExtensionId(profile_)); + std::vector<file_system_provider::ProvidedFileSystemInfo> + odfs_file_system_infos = + service->GetProvidedFileSystemInfoList(provider_id); + if (odfs_file_system_infos.size() == 0) { + // ODFS is not mounted. + std::move(callback).Run(false); + return; + } + file_manager::util::ShowItemInFolder( + profile_, odfs_file_system_infos[0].mount_path(), + base::BindOnce(&OnShowItemInFolder, std::move(callback))); +} + +void OneDrivePageHandler::OnProvidedFileSystemMount( + const ash::file_system_provider::ProvidedFileSystemInfo& file_system_info, + ash::file_system_provider::MountContext context, + base::File::Error error) { + file_system_provider::ProviderId odfs_provider_id = + file_system_provider::ProviderId::CreateFromExtensionId( + file_manager::file_tasks::GetODFSExtensionId(profile_)); + // Only observe successful mount events for ODFS. + if (file_system_info.provider_id() != odfs_provider_id || + error != base::File::FILE_OK) { + return; + } + page_->OnODFSMountOrUnmount(); +} + +void OneDrivePageHandler::OnProvidedFileSystemUnmount( + const ash::file_system_provider::ProvidedFileSystemInfo& file_system_info, + base::File::Error error) { + file_system_provider::ProviderId odfs_provider_id = + file_system_provider::ProviderId::CreateFromExtensionId( + file_manager::file_tasks::GetODFSExtensionId(profile_)); + // Only observe successful unmount events for ODFS. + if (file_system_info.provider_id() != odfs_provider_id || + error != base::File::FILE_OK) { + return; + } + page_->OnODFSMountOrUnmount(); +} + +} // namespace ash::settings diff --git a/chromium/chrome/browser/ui/webui/settings/ash/files_page/one_drive_page_handler.h b/chromium/chrome/browser/ui/webui/settings/ash/files_page/one_drive_page_handler.h new file mode 100644 index 00000000000..371a39e5c1d --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/ash/files_page/one_drive_page_handler.h @@ -0,0 +1,59 @@ +// Copyright 2023 The Chromium Authors +// 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_ASH_FILES_PAGE_ONE_DRIVE_PAGE_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_FILES_PAGE_ONE_DRIVE_PAGE_HANDLER_H_ + +#include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/ash/file_system_provider/observer.h" +#include "chrome/browser/ui/webui/settings/ash/files_page/mojom/one_drive_handler.mojom.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" + +class Profile; + +namespace ash::settings { + +// Page handler for settings related to OneDrive. +class OneDrivePageHandler : public one_drive::mojom::PageHandler, + public ash::file_system_provider::Observer { + public: + OneDrivePageHandler( + mojo::PendingReceiver<one_drive::mojom::PageHandler> receiver, + mojo::PendingRemote<one_drive::mojom::Page> page, + Profile* profile); + + OneDrivePageHandler(const OneDrivePageHandler&) = delete; + OneDrivePageHandler& operator=(const OneDrivePageHandler&) = delete; + + ~OneDrivePageHandler() override; + + private: + // one_drive::mojom::PageHandler: + void GetUserEmailAddress(GetUserEmailAddressCallback callback) override; + void ConnectToOneDrive(ConnectToOneDriveCallback callback) override; + void DisconnectFromOneDrive(DisconnectFromOneDriveCallback callback) override; + void OpenOneDriveFolder(OpenOneDriveFolderCallback callback) override; + + // ash::file_system_provider::Observer overrides. + void OnProvidedFileSystemMount( + const ash::file_system_provider::ProvidedFileSystemInfo& file_system_info, + ash::file_system_provider::MountContext context, + base::File::Error error) override; + void OnProvidedFileSystemUnmount( + const ash::file_system_provider::ProvidedFileSystemInfo& file_system_info, + base::File::Error error) override; + + raw_ptr<Profile> profile_; + mojo::Remote<one_drive::mojom::Page> page_; + mojo::Receiver<one_drive::mojom::PageHandler> receiver_{this}; + base::WeakPtrFactory<OneDrivePageHandler> weak_ptr_factory_{this}; +}; + +} // namespace ash::settings + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_FILES_PAGE_ONE_DRIVE_PAGE_HANDLER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/ash/files_page/one_drive_page_handler_factory.cc b/chromium/chrome/browser/ui/webui/settings/ash/files_page/one_drive_page_handler_factory.cc new file mode 100644 index 00000000000..381da58d31b --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/ash/files_page/one_drive_page_handler_factory.cc @@ -0,0 +1,33 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/settings/ash/files_page/one_drive_page_handler_factory.h" + +#include <memory> +#include <utility> + +#include "chrome/browser/ui/webui/settings/ash/files_page/mojom/one_drive_handler.mojom.h" + +namespace ash::settings { + +OneDrivePageHandlerFactory::OneDrivePageHandlerFactory( + Profile* profile, + mojo::PendingReceiver<one_drive::mojom::PageHandlerFactory> receiver) + : profile_(profile) { + page_factory_receiver_.Bind(std::move(receiver)); +} + +OneDrivePageHandlerFactory::~OneDrivePageHandlerFactory() = default; + +void OneDrivePageHandlerFactory::CreatePageHandler( + mojo::PendingRemote<one_drive::mojom::Page> page, + mojo::PendingReceiver<one_drive::mojom::PageHandler> receiver) { + DCHECK(page); + DCHECK(!page_handler_); + + page_handler_ = std::make_unique<OneDrivePageHandler>( + std::move(receiver), std::move(page), profile_); +} + +} // namespace ash::settings diff --git a/chromium/chrome/browser/ui/webui/settings/ash/files_page/one_drive_page_handler_factory.h b/chromium/chrome/browser/ui/webui/settings/ash/files_page/one_drive_page_handler_factory.h new file mode 100644 index 00000000000..36e8d57310e --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/ash/files_page/one_drive_page_handler_factory.h @@ -0,0 +1,47 @@ +// Copyright 2023 The Chromium Authors +// 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_ASH_FILES_PAGE_ONE_DRIVE_PAGE_HANDLER_FACTORY_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_FILES_PAGE_ONE_DRIVE_PAGE_HANDLER_FACTORY_H_ + +#include <memory> + +#include "chrome/browser/ui/webui/settings/ash/files_page/mojom/one_drive_handler.mojom.h" +#include "chrome/browser/ui/webui/settings/ash/files_page/one_drive_page_handler.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver.h" + +class Profile; + +namespace ash::settings { + +class OneDrivePageHandlerFactory : public one_drive::mojom::PageHandlerFactory { + public: + OneDrivePageHandlerFactory( + Profile* profile, + mojo::PendingReceiver<one_drive::mojom::PageHandlerFactory> receiver); + + OneDrivePageHandlerFactory(const OneDrivePageHandlerFactory&) = delete; + OneDrivePageHandlerFactory& operator=(const OneDrivePageHandlerFactory&) = + delete; + + ~OneDrivePageHandlerFactory() override; + + private: + // one_drive::mojom::PageHandlerFactory: + void CreatePageHandler( + mojo::PendingRemote<one_drive::mojom::Page> page, + mojo::PendingReceiver<one_drive::mojom::PageHandler> receiver) override; + + raw_ptr<Profile> profile_; + + std::unique_ptr<OneDrivePageHandler> page_handler_; + mojo::Receiver<one_drive::mojom::PageHandlerFactory> page_factory_receiver_{ + this}; +}; + +} // namespace ash::settings + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_FILES_PAGE_ONE_DRIVE_PAGE_HANDLER_FACTORY_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/ash/files_section.cc b/chromium/chrome/browser/ui/webui/settings/ash/files_section.cc index 77df4c5e74f..e24667a82d9 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/files_section.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/files_section.cc @@ -8,6 +8,7 @@ #include "base/functional/callback_helpers.h" #include "base/no_destructor.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/browser/ash/drive/file_system_util.h" #include "chrome/browser/ash/profiles/profile_helper.h" #include "chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h" #include "chrome/browser/ui/webui/ash/smb_shares/smb_handler.h" @@ -28,6 +29,7 @@ using ::chromeos::settings::mojom::kFilesSectionPath; using ::chromeos::settings::mojom::kGoogleDriveSubpagePath; using ::chromeos::settings::mojom::kNetworkFileSharesSubpagePath; using ::chromeos::settings::mojom::kOfficeFilesSubpagePath; +using ::chromeos::settings::mojom::kOneDriveSubpagePath; using ::chromeos::settings::mojom::Section; using ::chromeos::settings::mojom::Setting; using ::chromeos::settings::mojom::Subpage; @@ -76,7 +78,7 @@ const std::vector<SearchConcept>& GetFilesGoogleDriveSearchConcepts() { static const base::NoDestructor<std::vector<SearchConcept>> tags( {{IDS_OS_SETTINGS_TAG_FILES_GOOGLE_DRIVE, mojom::kGoogleDriveSubpagePath, - mojom::SearchResultIcon::kFolder, + mojom::SearchResultIcon::kDrive, mojom::SearchResultDefaultRank::kMedium, mojom::SearchResultType::kSubpage, {.subpage = mojom::Subpage::kGoogleDrive}}}); @@ -90,10 +92,10 @@ FilesSection::FilesSection(Profile* profile, : OsSettingsSection(profile, search_tag_registry) { SearchTagRegistry::ScopedTagUpdater updater = registry()->StartUpdate(); updater.AddSearchTags(GetFilesSearchConcepts()); - if (cloud_upload::IsEligibleAndEnabledUploadOfficeToCloud()) { + if (cloud_upload::IsEligibleAndEnabledUploadOfficeToCloud(profile)) { updater.AddSearchTags(GetFilesOfficeSearchConcepts()); } - if (ash::features::IsDriveFsBulkPinningEnabled()) { + if (drive::util::IsDriveFsBulkPinningEnabled(profile)) { updater.AddSearchTags(GetFilesGoogleDriveSearchConcepts()); } } @@ -104,7 +106,6 @@ void FilesSection::AddLoadTimeData(content::WebUIDataSource* html_source) { static constexpr webui::LocalizedString kLocalizedStrings[] = { {"disconnectGoogleDriveAccount", IDS_SETTINGS_DISCONNECT_GOOGLE_DRIVE}, {"googleDriveLabel", IDS_SETTINGS_GOOGLE_DRIVE}, - {"googleDriveEnabledLabel", IDS_SETTINGS_GOOGLE_DRIVE_ENABLED}, {"googleDriveDisabledLabel", IDS_SETTINGS_GOOGLE_DRIVE_DISABLED}, {"googleDriveDisconnectLabel", IDS_SETTINGS_GOOGLE_DRIVE_DISCONNECT}, {"googleDriveConnectLabel", IDS_SETTINGS_GOOGLE_DRIVE_CONNECT}, @@ -125,6 +126,8 @@ void FilesSection::AddLoadTimeData(content::WebUIDataSource* html_source) { IDS_SETTINGS_GOOGLE_DRIVE_OFFLINE_CLEAR_DIALOG_TITLE}, {"googleDriveOfflineClearDialogBody", IDS_SETTINGS_GOOGLE_DRIVE_OFFLINE_CLEAR_DIALOG_BODY}, + {"googleDriveClearStorageDisabledTooltip", + IDS_SETTINGS_GOOGLE_DRIVE_OFFLINE_CLEAR_DISABLED_TOOLTIP}, {"googleDriveTurnOffLabel", IDS_SETTINGS_GOOGLE_DRIVE_TURN_OFF_BUTTON_LABEL}, {"googleDriveTurnOffTitle", @@ -161,7 +164,14 @@ void FilesSection::AddLoadTimeData(content::WebUIDataSource* html_source) { IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_MOUNT_INVALID_URL_MESSAGE}, {"smbShareAddedInvalidSSOURLMessage", IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_MOUNT_INVALID_SSO_URL_MESSAGE}, + {"oneDriveLabel", IDS_SETTINGS_ONE_DRIVE_LABEL}, + {"oneDriveSignedInAs", IDS_SETTINGS_ONE_DRIVE_SIGNED_IN_AS}, + {"oneDriveDisconnected", IDS_SETTINGS_ONE_DRIVE_DISCONNECTED}, + {"oneDriveConnect", IDS_SETTINGS_ONE_DRIVE_CONNECT}, + {"oneDriveDisconnect", IDS_SETTINGS_ONE_DRIVE_DISCONNECT}, + {"openOneDriveFolder", IDS_SETTINGS_OPEN_ONE_DRIVE_FOLDER}, {"officeLabel", IDS_SETTINGS_OFFICE_LABEL}, + {"officeSublabel", IDS_SETTINGS_OFFICE_SUBLABEL}, {"officeSubpageTitle", IDS_SETTINGS_OFFICE_SUBPAGE_TITLE}, {"alwaysMoveToDrivePreferenceLabel", IDS_SETTINGS_ALWAYS_MOVE_OFFICE_TO_DRIVE_PREFERENCE_LABEL}, @@ -177,7 +187,7 @@ void FilesSection::AddLoadTimeData(content::WebUIDataSource* html_source) { html_source->AddBoolean( "showOfficeSettings", - cloud_upload::IsEligibleAndEnabledUploadOfficeToCloud()); + cloud_upload::IsEligibleAndEnabledUploadOfficeToCloud(profile())); const user_manager::User* user = ProfileHelper::Get()->GetUserByProfile(profile()); @@ -198,7 +208,7 @@ void FilesSection::AddLoadTimeData(content::WebUIDataSource* html_source) { } html_source->AddBoolean("enableDriveFsBulkPinning", - features::IsDriveFsBulkPinningEnabled()); + drive::util::IsDriveFsBulkPinningEnabled(profile())); } void FilesSection::AddHandlers(content::WebUI* web_ui) { @@ -237,9 +247,8 @@ void FilesSection::RegisterHierarchy(HierarchyGenerator* generator) const { mojom::kNetworkFileSharesSubpagePath); // Office. - // TODO(b:264314789): Correct string (not smb). generator->RegisterTopLevelSubpage( - IDS_SETTINGS_DOWNLOADS_SMB_SHARES, mojom::Subpage::kOfficeFiles, + IDS_SETTINGS_OFFICE_LABEL, mojom::Subpage::kOfficeFiles, mojom::SearchResultIcon::kFolder, mojom::SearchResultDefaultRank::kMedium, mojom::kNetworkFileSharesSubpagePath); @@ -247,6 +256,11 @@ void FilesSection::RegisterHierarchy(HierarchyGenerator* generator) const { IDS_SETTINGS_GOOGLE_DRIVE, mojom::Subpage::kGoogleDrive, mojom::SearchResultIcon::kFolder, mojom::SearchResultDefaultRank::kMedium, mojom::kGoogleDriveSubpagePath); + + generator->RegisterTopLevelSubpage( + IDS_SETTINGS_ONE_DRIVE_LABEL, mojom::Subpage::kOneDrive, + mojom::SearchResultIcon::kFolder, mojom::SearchResultDefaultRank::kMedium, + mojom::kOneDriveSubpagePath); } } // namespace ash::settings diff --git a/chromium/chrome/browser/ui/webui/settings/ash/input_device_settings/input_device_settings_provider.cc b/chromium/chrome/browser/ui/webui/settings/ash/input_device_settings/input_device_settings_provider.cc index 9f0706645fe..070f4c98e5a 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/input_device_settings/input_device_settings_provider.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/input_device_settings/input_device_settings_provider.cc @@ -69,6 +69,14 @@ void InputDeviceSettingsProvider::BindInterface( receiver_.Bind(std::move(receiver)); } +void InputDeviceSettingsProvider::RestoreDefaultKeyboardRemappings( + uint32_t device_id) { + DCHECK(features::IsInputDeviceSettingsSplitEnabled()); + DCHECK(InputDeviceSettingsController::Get()); + InputDeviceSettingsController::Get()->RestoreDefaultKeyboardRemappings( + device_id); +} + void InputDeviceSettingsProvider::SetKeyboardSettings( uint32_t device_id, ::ash::mojom::KeyboardSettingsPtr settings) { diff --git a/chromium/chrome/browser/ui/webui/settings/ash/input_device_settings/input_device_settings_provider.h b/chromium/chrome/browser/ui/webui/settings/ash/input_device_settings/input_device_settings_provider.h index 8e97fe3aed0..c2b1bb47c7e 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/input_device_settings/input_device_settings_provider.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/input_device_settings/input_device_settings_provider.h @@ -38,6 +38,7 @@ class InputDeviceSettingsProvider override; void ObserveMouseSettings( mojo::PendingRemote<mojom::MouseSettingsObserver> observer) override; + void RestoreDefaultKeyboardRemappings(uint32_t device_id) override; void SetKeyboardSettings(uint32_t device_id, ::ash::mojom::KeyboardSettingsPtr settings) override; void SetPointingStickSettings( diff --git a/chromium/chrome/browser/ui/webui/settings/ash/input_device_settings/input_device_settings_provider.mojom b/chromium/chrome/browser/ui/webui/settings/ash/input_device_settings/input_device_settings_provider.mojom index f75ae9fdbe1..fd904a3e513 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/input_device_settings/input_device_settings_provider.mojom +++ b/chromium/chrome/browser/ui/webui/settings/ash/input_device_settings/input_device_settings_provider.mojom @@ -63,6 +63,8 @@ interface InputDeviceSettingsProvider { // The observer which is registered is immediately informed // of the current state via its ObserveMouseSettings function. ObserveMouseSettings(pending_remote<MouseSettingsObserver> observer); + // Restore the keyboard remappings to default base on its id. + RestoreDefaultKeyboardRemappings(uint32 device_id); // Sets the keyboard settings based on its id. SetKeyboardSettings(uint32 device_id, ash.mojom.KeyboardSettings settings); // Sets the point stick settings based on its id. diff --git a/chromium/chrome/browser/ui/webui/settings/ash/input_device_settings/input_device_settings_provider_unittest.cc b/chromium/chrome/browser/ui/webui/settings/ash/input_device_settings/input_device_settings_provider_unittest.cc index 5db798999c5..d0a9fe7b83c 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/input_device_settings/input_device_settings_provider_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/input_device_settings/input_device_settings_provider_unittest.cc @@ -54,12 +54,14 @@ const ::ash::mojom::Touchpad kTouchpad1 = /*is_external=*/false, /*id=*/3, /*device_key=*/"fake-device-key3", + /*is_haptic=*/true, ::ash::mojom::TouchpadSettings::New()); const ::ash::mojom::Touchpad kTouchpad2 = ::ash::mojom::Touchpad(/*name=*/"Logitech T650", /*is_external=*/true, /*id=*/4, /*device_key=*/"fake-device-key4", + /*is_haptic=*/false, ::ash::mojom::TouchpadSettings::New()); const ::ash::mojom::PointingStick kPointingStick1 = ::ash::mojom::PointingStick(/*name=*/"test pointing stick", @@ -242,6 +244,9 @@ class FakeInputDeviceSettingsController : public InputDeviceSettingsController { const ::ash::mojom::MousePolicies& GetMousePolicies() override { return *mouse_policies_; } + void RestoreDefaultKeyboardRemappings(DeviceId id) override { + ++num_times_restore_default_keyboard_remappings_called_; + } void SetKeyboardSettings( DeviceId id, ::ash::mojom::KeyboardSettingsPtr settings) override { @@ -337,6 +342,9 @@ class FakeInputDeviceSettingsController : public InputDeviceSettingsController { pointing_sticks_.erase(iter); observer_->OnPointingStickDisconnected(*temp_pointing_stick); } + int num_times_restore_default_keyboard_remappings_called() { + return num_times_restore_default_keyboard_remappings_called_; + } int num_times_set_keyboard_settings_called() { return num_times_set_keyboard_settings_called_; } @@ -361,6 +369,7 @@ class FakeInputDeviceSettingsController : public InputDeviceSettingsController { ::ash::mojom::MousePolicies::New(); raw_ptr<InputDeviceSettingsController::Observer> observer_ = nullptr; + int num_times_restore_default_keyboard_remappings_called_ = 0; int num_times_set_keyboard_settings_called_ = 0; int num_times_set_pointing_stick_settings_called_ = 0; int num_times_set_mouse_settings_called_ = 0; @@ -409,6 +418,22 @@ TEST_F(InputDeviceSettingsProviderTest, TestSetKeyboardSettings) { EXPECT_EQ(2, controller_->num_times_set_keyboard_settings_called()); } +TEST_F(InputDeviceSettingsProviderTest, TestRestoreDefaultKeyboardRemappings) { + controller_->AddKeyboard(kKeyboard1.Clone()); + provider_->RestoreDefaultKeyboardRemappings(kKeyboard1.id); + + base::RunLoop().RunUntilIdle(); + EXPECT_EQ( + 1, controller_->num_times_restore_default_keyboard_remappings_called()); + + controller_->AddKeyboard(kKeyboard2.Clone()); + provider_->RestoreDefaultKeyboardRemappings(kKeyboard2.id); + + base::RunLoop().RunUntilIdle(); + EXPECT_EQ( + 2, controller_->num_times_restore_default_keyboard_remappings_called()); +} + TEST_F(InputDeviceSettingsProviderTest, TestSetPointingStickSettings) { controller_->AddPointingStick(kPointingStick1.Clone()); provider_->SetPointingStickSettings(kPointingStick1.id, diff --git a/chromium/chrome/browser/ui/webui/settings/ash/internet_handler.cc b/chromium/chrome/browser/ui/webui/settings/ash/internet_handler.cc index 2025ce61f86..2c995206993 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/internet_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/internet_handler.cc @@ -249,7 +249,7 @@ void InternetHandler::SetGmsCoreNotificationsDisabledDeviceNames() { gms_core_notifications_state_tracker_ ->GetGmsCoreNotificationsDisabledDeviceNames(); for (const auto& device_name : device_names) { - device_names_without_notifications_.emplace_back(base::Value(device_name)); + device_names_without_notifications_.Append(base::Value(device_name)); } SendGmsCoreNotificationsDisabledDeviceNames(); } diff --git a/chromium/chrome/browser/ui/webui/settings/ash/internet_handler.h b/chromium/chrome/browser/ui/webui/settings/ash/internet_handler.h index f622405636b..f638cadc99d 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/internet_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/internet_handler.h @@ -61,7 +61,7 @@ class InternetHandler tether::GmsCoreNotificationsStateTracker* gms_core_notifications_state_tracker); - std::vector<base::Value> device_names_without_notifications_; + base::Value::List device_names_without_notifications_; const raw_ptr<Profile, ExperimentalAsh> profile_; diff --git a/chromium/chrome/browser/ui/webui/settings/ash/internet_section.cc b/chromium/chrome/browser/ui/webui/settings/ash/internet_section.cc index 5ecaa33e55e..f9b48cd10ab 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/internet_section.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/internet_section.cc @@ -15,6 +15,7 @@ #include "base/no_destructor.h" #include "base/strings/stringprintf.h" #include "chrome/browser/ui/webui/ash/cellular_setup/cellular_setup_localized_strings_provider.h" +#include "chrome/browser/ui/webui/extension_control_handler.h" #include "chrome/browser/ui/webui/settings/ash/internet_handler.h" #include "chrome/browser/ui/webui/settings/ash/search/search_tag_registry.h" #include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h" @@ -49,6 +50,7 @@ using ::chromeos::settings::mojom::kHotspotSubpagePath; using ::chromeos::settings::mojom::kKnownNetworksSubpagePath; using ::chromeos::settings::mojom::kMobileDataNetworksSubpagePath; using ::chromeos::settings::mojom::kNetworkSectionPath; +using ::chromeos::settings::mojom::kPasspointDetailSubpagePath; using ::chromeos::settings::mojom::kTetherDetailsSubpagePath; using ::chromeos::settings::mojom::kVpnDetailsSubpagePath; using ::chromeos::settings::mojom::kWifiDetailsSubpagePath; @@ -823,6 +825,16 @@ void InternetSection::AddLoadTimeData(content::WebUIDataSource* html_source) { IDS_SETTINGS_INTERNET_NETWORK_SECTION_PASSPOINT_REMOVAL_TITLE}, {"networkSectionPasspointRemovalDescription", IDS_SETTINGS_INTERNET_NETWORK_SECTION_PASSPOINT_REMOVAL_DESCRIPTION}, + {"networkSectionPasspointRemovalInformation", + IDS_SETTINGS_INTERNET_NETWORK_SECTION_PASSPOINT_REMOVAL_INFORMATION}, + {"networkSectionPasspointGoToSubscriptionTitle", + IDS_SETTINGS_INTERNET_NETWORK_SECTION_PASSPOINT_GO_TO_SUBSCRIPTION_TITLE}, + {"networkSectionPasspointGoToSubscriptionInformation", + IDS_SETTINGS_INTERNET_NETWORK_SECTION_PASSPOINT_GO_TO_SUBSCRIPTION_INFORMATION}, + {"networkSectionPasspointGoToSubscriptionButtonLabel", + IDS_SETTINGS_INTERNET_NETWORK_SECTION_PASSPOINT_GO_TO_SUBSCRIPTION_BUTTON}, + {"passpointRemoveGoToSubscriptionButtonA11yLabel", + IDS_SETTINGS_INTERNET_NETWORK_SECTION_PASSPOINT_GO_TO_SUBSCRIPTION_BUTTON_A11Y_LABEL}, {"networkSectionProxy", IDS_SETTINGS_INTERNET_NETWORK_SECTION_PROXY}, {"networkSectionProxyExpandA11yLabel", IDS_SETTINGS_INTERNET_NETWORK_SECTION_PROXY_ACCESSIBILITY_LABEL}, @@ -994,6 +1006,31 @@ void InternetSection::AddLoadTimeData(content::WebUIDataSource* html_source) { IDS_SETTINGS_INTERNET_HOTSPOT_CONFIG_INVALID_CONFIGURATION_ERROR_MESSAGE}, {"hotspotConfigNotLoginErrorMessage", IDS_SETTINGS_INTERNET_HOTSPOT_CONFIG_NOT_LOGIN_ERROR_MESSAGE}, + {"passpointProviderLabel", + IDS_SETTINGS_INTERNET_PASSPOINT_PROVIDER_LABEL}, + {"passpointRemoveButton", + IDS_SETTINGS_INTERNET_PASSPOINT_REMOVE_SUBSCRIPTION}, + {"passpointSectionLabel", IDS_SETTINGS_INTERNET_PASSPOINT_SECTION_LABEL}, + {"passpointHeadlineText", IDS_SETTINGS_INTERNET_PASSPOINT_HEADLINE}, + {"passpointSubscriptionExpirationLabel", + IDS_SETTINGS_INTERNET_PASSPOINT_SUBSCRIPTION_EXPIRATION}, + {"passpointSourceLabel", IDS_SETTINGS_INTERNET_PASSPOINT_SOURCE}, + {"passpointTrustedCALabel", IDS_SETTINGS_INTERNET_PASSPOINT_TRUSTED_CA}, + {"passpointSystemCALabel", IDS_SETTINGS_INTERNET_PASSPOINT_SYSTEM_CA}, + {"passpointAssociatedWifiNetworks", + IDS_SETTINGS_INTERNET_PASSPOINT_ASSOCIATED_WIFI_NETWORKS}, + {"passpointDomainsLabel", IDS_SETTINGS_INTERNET_PASSPOINT_DOMAINS}, + {"passpointDomainsA11yLabel", + IDS_SETTINGS_INTERNET_PASSPOINT_DOMAINS_A11Y_LABEL}, + {"passpointRemovalTitle", IDS_SETTINGS_INTERNET_PASSPOINT_REMOVAL_TITLE}, + {"passpointRemovalDescription", + IDS_SETTINGS_INTERNET_PASSPOINT_REMOVAL_DESCRIPTION}, + {"passpointLearnMoreA11yLabel", + IDS_SETTINGS_INTERNET_PASSPOINT_LEARN_MORE_A11Y}, + {"passpointRemoveCancelA11yLabel", + IDS_SETTINGS_INTERNET_PASSPOINT_REMOVE_CANCEL_A11Y}, + {"passpointRemoveConfirmA11yLabel", + IDS_SETTINGS_INTERNET_PASSPOINT_REMOVE_CONFIRM_A11Y}, }; html_source->AddLocalizedStrings(kLocalizedStrings); @@ -1019,6 +1056,8 @@ void InternetSection::AddLoadTimeData(content::WebUIDataSource* html_source) { html_source->AddBoolean( "showHiddenToggle", base::FeatureList::IsEnabled(::features::kShowHiddenNetworkToggle)); + html_source->AddBoolean("isSmdsSupportEnabled", + ash::features::IsSmdsSupportEnabled()); html_source->AddBoolean("isHotspotEnabled", ash::features::IsHotspotEnabled()); html_source->AddBoolean("isPasspointEnabled", @@ -1088,6 +1127,7 @@ void InternetSection::AddLoadTimeData(content::WebUIDataSource* html_source) { void InternetSection::AddHandlers(content::WebUI* web_ui) { web_ui->AddMessageHandler(std::make_unique<InternetHandler>(profile())); + web_ui->AddMessageHandler(std::make_unique<ExtensionControlHandler>()); } int InternetSection::GetSectionNameMessageId() const { @@ -1180,6 +1220,13 @@ void InternetSection::RegisterHierarchy(HierarchyGenerator* generator) const { kMobileDataNetworksSettings, generator); generator->RegisterTopLevelAltSetting(mojom::Setting::kMobileOnOff); + // Passpoint details. + generator->RegisterNestedSubpage( + IDS_SETTINGS_INTERNET_PASSPOINT_DETAILS, + mojom::Subpage::kPasspointDetails, mojom::Subpage::kKnownNetworks, + mojom::SearchResultIcon::kWifi, mojom::SearchResultDefaultRank::kMedium, + mojom::kPasspointDetailSubpagePath); + // Cellular details. Cellular details are considered a child of the mobile // data subpage. However, note that if Instant Tethering is not available, // clicking on "Mobile data" at the Network section navigates users directly diff --git a/chromium/chrome/browser/ui/webui/settings/ash/kerberos_accounts_handler.cc b/chromium/chrome/browser/ui/webui/settings/ash/kerberos_accounts_handler.cc index 8741f77b0e5..36617c957ad 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/kerberos_accounts_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/kerberos_accounts_handler.cc @@ -7,6 +7,7 @@ #include <string> #include <utility> +#include "ash/constants/ash_features.h" #include "base/functional/bind.h" #include "base/memory/ptr_util.h" #include "base/strings/string_util.h" @@ -107,6 +108,8 @@ void AddKerberosAddAccountDialogStrings(content::WebUIDataSource* html_source) { IDS_SETTINGS_KERBEROS_CONFIG_ERROR_KRB5_FAILED_TO_PARSE}, {"kerberosConfigErrorTooManyNestedGroups", IDS_SETTINGS_KERBEROS_CONFIG_ERROR_TOO_MANY_NESTED_GROUPS}, + {"kerberosConfigErrorLineTooLong", + IDS_SETTINGS_KERBEROS_CONFIG_ERROR_LINE_TOO_LONG}, {"addKerberosAccountRefreshButtonLabel", IDS_SETTINGS_ADD_KERBEROS_ACCOUNT_REFRESH_BUTTON_LABEL}, {"addKerberosAccount", IDS_SETTINGS_ADD_KERBEROS_ACCOUNT}, @@ -121,6 +124,11 @@ void AddKerberosAddAccountDialogStrings(content::WebUIDataSource* html_source) { "kerberosRememberPasswordEnabled", local_state->GetBoolean(::prefs::kKerberosRememberPasswordEnabled)); + // Whether the 'Remember password' checkbox should be checked by default. + html_source->AddBoolean( + "kerberosRememberPasswordByDefault", + features::IsKerberosRememberPasswordByDefaultEnabled()); + // Prefilled domain if policy is enabled. Note that Kerberos // domains should be in all uppercase. html_source->AddString("kerberosDomainAutocomplete", diff --git a/chromium/chrome/browser/ui/webui/settings/ash/languages_section.cc b/chromium/chrome/browser/ui/webui/settings/ash/languages_section.cc index cec3161ac19..268503a4b93 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/languages_section.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/languages_section.cc @@ -157,10 +157,6 @@ const std::vector<SearchConcept>& GetEmojiSuggestionSearchConcepts() { return *tags; } -bool IsPredictiveWritingAllowed() { - return features::IsAssistiveMultiWordEnabled(); -} - // TODO(crbug/1113611): As Smart Inputs page is renamed to Suggestions. // All related strings, function names and filenames should be renamed as well. void AddSmartInputsStrings(content::WebUIDataSource* html_source, @@ -176,7 +172,10 @@ void AddSmartInputsStrings(content::WebUIDataSource* html_source, html_source->AddBoolean("allowEmojiSuggestion", is_emoji_suggestion_allowed); } -void AddInputMethodOptionsStrings(content::WebUIDataSource* html_source) { +void AddInputMethodOptionsStrings( + content::WebUIDataSource* html_source, + bool is_physical_keyboard_autocorrect_allowed, + bool is_physical_keyboard_predictive_writing_allowed) { static constexpr webui::LocalizedString kLocalizedStrings[] = { {"inputMethodOptionsBasicSectionTitle", IDS_SETTINGS_INPUT_METHOD_OPTIONS_BASIC}, @@ -342,8 +341,12 @@ void AddInputMethodOptionsStrings(content::WebUIDataSource* html_source) { IDS_SETTINGS_INPUT_METHOD_OPTIONS_KEYBOARD_COLEMAK}, }; html_source->AddLocalizedStrings(kLocalizedStrings); - html_source->AddBoolean("allowPredictiveWriting", - IsPredictiveWritingAllowed()); + html_source->AddBoolean("isPhysicalKeyboardAutocorrectAllowed", + is_physical_keyboard_autocorrect_allowed); + html_source->AddBoolean( + "isPhysicalKeyboardPredictiveWritingAllowed", + base::FeatureList::IsEnabled(features::kAssistMultiWord) && + is_physical_keyboard_predictive_writing_allowed); html_source->AddBoolean( "allowDiacriticsOnPhysicalKeyboardLongpress", base::FeatureList::IsEnabled( @@ -547,7 +550,10 @@ void LanguagesSection::AddLoadTimeData(content::WebUIDataSource* html_source) { IDS_SETTINGS_LANGUAGES_LANGUAGE_PACKS_NOTICE, base::ASCIIToUTF16(chrome::kLanguagePacksLearnMoreURL))); AddSmartInputsStrings(html_source, IsEmojiSuggestionAllowed()); - AddInputMethodOptionsStrings(html_source); + AddInputMethodOptionsStrings( + html_source, + input_method::IsPhysicalKeyboardAutocorrectAllowed(*pref_service_), + input_method::IsPhysicalKeyboardPredictiveWritingAllowed(*pref_service_)); AddLanguagesPageStringsV2(html_source); AddInputPageStringsV2(html_source); diff --git a/chromium/chrome/browser/ui/webui/settings/ash/main_section.cc b/chromium/chrome/browser/ui/webui/settings/ash/main_section.cc index 35887bca2c1..16eb1028c62 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/main_section.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/main_section.cc @@ -176,8 +176,10 @@ void MainSection::AddLoadTimeData(content::WebUIDataSource* html_source) { // This handler is for chrome://os-settings. html_source->AddBoolean("isOSSettings", true); - html_source->AddBoolean("searchFeedbackEnabled", - ash::features::IsOsSettingsSearchFeedbackEnabled()); + + // Add app-wide feature flags + html_source->AddBoolean("isRevampWayfindingEnabled", + ash::features::IsOsSettingsRevampWayfindingEnabled()); html_source->AddBoolean("isGuest", IsGuestModeActive()); html_source->AddBoolean( diff --git a/chromium/chrome/browser/ui/webui/settings/ash/metrics_consent_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/ash/metrics_consent_handler_unittest.cc index 113263d0859..01c08a5d5c6 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/metrics_consent_handler_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/metrics_consent_handler_unittest.cc @@ -130,7 +130,7 @@ class MetricsConsentHandlerTest : public testing::Test { test_user_manager_->SetOwnerId(account_id); EXPECT_THAT(DeviceSettingsService::Get()->GetOwnershipStatus(), - Eq(DeviceSettingsService::OWNERSHIP_TAKEN)); + Eq(DeviceSettingsService::OwnershipStatus::kOwnershipTaken)); return owner; } diff --git a/chromium/chrome/browser/ui/webui/settings/ash/multidevice_handler.cc b/chromium/chrome/browser/ui/webui/settings/ash/multidevice_handler.cc index b2288b4862b..9aecc0ef152 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/multidevice_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/multidevice_handler.cc @@ -147,10 +147,6 @@ void MultideviceHandler::RegisterMessages() { base::BindRepeating(&MultideviceHandler::HandleSetUpAndroidSms, base::Unretained(this))); web_ui()->RegisterMessageCallback( - "getSmartLockSignInAllowed", - base::BindRepeating(&MultideviceHandler::HandleGetSmartLockSignInAllowed, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( "getAndroidSmsInfo", base::BindRepeating(&MultideviceHandler::HandleGetAndroidSmsInfo, base::Unretained(this))); @@ -250,11 +246,6 @@ void MultideviceHandler::OnJavascriptAllowed() { browser_tabs_model_provider_.get()); } - pref_change_registrar_.Add( - multidevice_setup::kSmartLockSigninAllowedPrefName, - base::BindRepeating( - &MultideviceHandler::NotifySmartLockSignInAllowedChanged, - base::Unretained(this))); if (NearbySharingServiceFactory::IsNearbyShareSupportedForBrowserContext( Profile::FromWebUI(web_ui()))) { pref_change_registrar_.Add( @@ -473,16 +464,6 @@ void MultideviceHandler::HandleSetUpAndroidSms(const base::Value::List& args) { android_sms_app_manager_->SetUpAndLaunchAndroidSmsApp(); } -void MultideviceHandler::HandleGetSmartLockSignInAllowed( - const base::Value::List& args) { - const base::Value& callback_id = args[0]; - CHECK(callback_id.is_string()); - - bool sign_in_allowed = - prefs_->GetBoolean(multidevice_setup::kSmartLockSigninAllowedPrefName); - ResolveJavascriptCallback(callback_id, base::Value(sign_in_allowed)); -} - base::Value::Dict MultideviceHandler::GenerateAndroidSmsInfo() { absl::optional<GURL> app_url; if (android_sms_app_manager_) { @@ -885,13 +866,6 @@ base::Value::Dict MultideviceHandler::GeneratePageContentDataDictionary() { return page_content_dictionary; } -void MultideviceHandler::NotifySmartLockSignInAllowedChanged() { - bool sign_in_allowed = - prefs_->GetBoolean(multidevice_setup::kSmartLockSigninAllowedPrefName); - FireWebUIListener("smart-lock-signin-allowed-changed", - base::Value(sign_in_allowed)); -} - bool MultideviceHandler::IsAuthTokenValid(const std::string& auth_token) { Profile* profile = Profile::FromWebUI(web_ui()); quick_unlock::QuickUnlockStorage* quick_unlock_storage = diff --git a/chromium/chrome/browser/ui/webui/settings/ash/multidevice_handler.h b/chromium/chrome/browser/ui/webui/settings/ash/multidevice_handler.h index 017b8f39ea9..cfca0a88525 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/multidevice_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/multidevice_handler.h @@ -142,9 +142,6 @@ class MultideviceHandler void HandleRemoveHostDevice(const base::Value::List& args); void HandleRetryPendingHostSetup(const base::Value::List& args); void HandleSetUpAndroidSms(const base::Value::List& args); - // TODO(b/227674947):Now that Sign in with Smart Lock is deprecated, delete - // this method. - void HandleGetSmartLockSignInAllowed(const base::Value::List& args); void HandleGetAndroidSmsInfo(const base::Value::List& args); void HandleAttemptNotificationSetup(const base::Value::List& args); void HandleCancelNotificationSetup(const base::Value::List& args); @@ -160,10 +157,6 @@ class MultideviceHandler void OnSetFeatureStateEnabledResult(const std::string& js_callback_id, bool success); - // TODO(b/227674947):Now that Sign in with Smart Lock is deprecated, delete - // this methods. - void NotifySmartLockSignInAllowedChanged(); - // Generate android sms info dictionary containing the messages for web // content settings origin url and messages feature state. base::Value::Dict GenerateAndroidSmsInfo(); diff --git a/chromium/chrome/browser/ui/webui/settings/ash/multidevice_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/ash/multidevice_handler_unittest.cc index 5b6a973e040..cf3a042aa9e 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/multidevice_handler_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/multidevice_handler_unittest.cc @@ -981,7 +981,7 @@ class MultideviceHandlerTest : public testing::Test { std::unique_ptr<eche_app::FakeAppsAccessManager> fake_apps_access_manager_; std::unique_ptr<phonehub::FakeCameraRollManager> fake_camera_roll_manager_; phonehub::FakeBrowserTabsModelProvider fake_browser_tabs_model_provider_; - MockNewWindowDelegate* new_window_delegate_primary_; + raw_ptr<MockNewWindowDelegate, ExperimentalAsh> new_window_delegate_primary_; std::unique_ptr<TestNewWindowDelegateProvider> new_window_provider_; multidevice_setup::MultiDeviceSetupClient::HostStatusWithDevice diff --git a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_hats_manager_factory.cc b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_hats_manager_factory.cc index 02bb0dd328e..cc219c9bb75 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_hats_manager_factory.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_hats_manager_factory.cc @@ -26,7 +26,12 @@ OsSettingsHatsManagerFactory* OsSettingsHatsManagerFactory::GetInstance() { OsSettingsHatsManagerFactory::OsSettingsHatsManagerFactory() : ProfileKeyedServiceFactory( "OsSettingsHatsManager", - ProfileSelections::BuildForRegularAndIncognito()) {} + ProfileSelections::Builder() + .WithRegular(ProfileSelection::kOwnInstance) + // TODO(crbug.com/1418376): Check if this service is needed in + // Guest mode. + .WithGuest(ProfileSelection::kOwnInstance) + .Build()) {} OsSettingsHatsManagerFactory::~OsSettingsHatsManagerFactory() = default; diff --git a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_hats_manager_factory.h b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_hats_manager_factory.h index 19e75695057..e1ac38055e7 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_hats_manager_factory.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_hats_manager_factory.h @@ -5,7 +5,6 @@ #ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_OS_SETTINGS_HATS_MANAGER_FACTORY_H_ #define CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_OS_SETTINGS_HATS_MANAGER_FACTORY_H_ -#include "base/memory/singleton.h" #include "base/no_destructor.h" #include "chrome/browser/profiles/profile_keyed_service_factory.h" diff --git a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager.cc b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager.cc index 2df826727fd..7853a323154 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager.cc @@ -5,6 +5,7 @@ #include "chrome/browser/ui/webui/settings/ash/os_settings_manager.h" #include "ash/public/cpp/input_device_settings_controller.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/settings/ash/hierarchy.h" #include "chrome/browser/ui/webui/settings/ash/input_device_settings/input_device_settings_provider.h" #include "chrome/browser/ui/webui/settings/ash/os_apps_page/app_notification_handler.h" @@ -23,7 +24,6 @@ OsSettingsManager::OsSettingsManager( local_search_service::LocalSearchServiceProxy* local_search_service_proxy, multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client, phonehub::PhoneHubManager* phone_hub_manager, - syncer::SyncService* sync_service, KerberosCredentialsManager* kerberos_credentials_manager, ArcAppListPrefs* arc_app_list_prefs, signin::IdentityManager* identity_manager, @@ -38,7 +38,6 @@ OsSettingsManager::OsSettingsManager( search_tag_registry_.get(), multidevice_setup_client, phone_hub_manager, - sync_service, kerberos_credentials_manager, arc_app_list_prefs, identity_manager, @@ -49,7 +48,8 @@ OsSettingsManager::OsSettingsManager( hierarchy_(std::make_unique<Hierarchy>(sections_.get())), settings_user_action_tracker_( std::make_unique<SettingsUserActionTracker>(hierarchy_.get(), - sections_.get())), + sections_.get(), + profile->GetPrefs())), search_handler_( std::make_unique<SearchHandler>(search_tag_registry_.get(), sections_.get(), diff --git a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager.h b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager.h index bc28ac11f0f..7940dbe486f 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager.h @@ -25,10 +25,6 @@ namespace signin { class IdentityManager; } // namespace signin -namespace syncer { -class SyncService; -} // namespace syncer - namespace ash { class CupsPrintersManager; @@ -92,7 +88,6 @@ class OsSettingsManager : public KeyedService { local_search_service::LocalSearchServiceProxy* local_search_service_proxy, multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client, phonehub::PhoneHubManager* phone_hub_manager, - syncer::SyncService* sync_service, KerberosCredentialsManager* kerberos_credentials_manager, ArcAppListPrefs* arc_app_list_prefs, signin::IdentityManager* identity_manager, diff --git a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager_factory.cc b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager_factory.cc index cf9a4dbd22a..a9af04e0260 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager_factory.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager_factory.cc @@ -15,7 +15,6 @@ #include "chrome/browser/ash/printing/cups_printers_manager_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/identity_manager_factory.h" -#include "chrome/browser/sync/sync_service_factory.h" #include "chrome/browser/ui/webui/settings/ash/os_settings_manager.h" #include "chromeos/ash/components/local_search_service/public/cpp/local_search_service_proxy_factory.h" @@ -30,18 +29,23 @@ OsSettingsManager* OsSettingsManagerFactory::GetForProfile(Profile* profile) { // static OsSettingsManagerFactory* OsSettingsManagerFactory::GetInstance() { - return base::Singleton<OsSettingsManagerFactory>::get(); + static base::NoDestructor<OsSettingsManagerFactory> instance; + return instance.get(); } OsSettingsManagerFactory::OsSettingsManagerFactory() : ProfileKeyedServiceFactory( "OsSettingsManager", - ProfileSelections::BuildForRegularAndIncognito()) { + ProfileSelections::Builder() + .WithRegular(ProfileSelection::kOwnInstance) + // TODO(crbug.com/1418376): Check if this service is needed in + // Guest mode. + .WithGuest(ProfileSelection::kOwnInstance) + .Build()) { DependsOn( local_search_service::LocalSearchServiceProxyFactory::GetInstance()); DependsOn(multidevice_setup::MultiDeviceSetupClientFactory::GetInstance()); DependsOn(phonehub::PhoneHubManagerFactory::GetInstance()); - DependsOn(SyncServiceFactory::GetInstance()); DependsOn(KerberosCredentialsManagerFactory::GetInstance()); DependsOn(ArcAppListPrefsFactory::GetInstance()); DependsOn(IdentityManagerFactory::GetInstance()); @@ -63,7 +67,6 @@ KeyedService* OsSettingsManagerFactory::BuildServiceInstanceFor( GetForBrowserContext(context), multidevice_setup::MultiDeviceSetupClientFactory::GetForProfile(profile), phonehub::PhoneHubManagerFactory::GetForProfile(profile), - SyncServiceFactory::GetForProfile(profile), KerberosCredentialsManagerFactory::Get(profile), ArcAppListPrefsFactory::GetForBrowserContext(profile), IdentityManagerFactory::GetForProfile(profile), diff --git a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager_factory.h b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager_factory.h index 15279a05214..dad2c9ce335 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager_factory.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager_factory.h @@ -5,7 +5,7 @@ #ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_OS_SETTINGS_MANAGER_FACTORY_H_ #define CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_OS_SETTINGS_MANAGER_FACTORY_H_ -#include "base/memory/singleton.h" +#include "base/no_destructor.h" #include "chrome/browser/profiles/profile_keyed_service_factory.h" class Profile; @@ -20,7 +20,7 @@ class OsSettingsManagerFactory : public ProfileKeyedServiceFactory { static OsSettingsManagerFactory* GetInstance(); private: - friend struct base::DefaultSingletonTraits<OsSettingsManagerFactory>; + friend base::NoDestructor<OsSettingsManagerFactory>; OsSettingsManagerFactory(); ~OsSettingsManagerFactory() override; diff --git a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager_unittest.cc b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager_unittest.cc index e209dc6c14c..69057eb21eb 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_manager_unittest.cc @@ -17,7 +17,6 @@ #include "chrome/browser/ash/phonehub/phone_hub_manager_factory.h" #include "chrome/browser/ash/printing/cups_printers_manager_factory.h" #include "chrome/browser/signin/identity_manager_factory.h" -#include "chrome/browser/sync/sync_service_factory.h" #include "chrome/browser/ui/webui/settings/ash/constants/constants_util.h" #include "chrome/browser/ui/webui/settings/ash/hierarchy.h" #include "chrome/browser/ui/webui/settings/ash/os_settings_manager_factory.h" @@ -55,7 +54,8 @@ class OsSettingsManagerTest : public testing::Test { scoped_feature_list_.InitWithFeatures( {::features::kAccessibilityChromeVoxPageMigration, ::features::kAccessibilitySelectToSpeakPageMigration, - ash::features::kInputDeviceSettingsSplit}, + ash::features::kInputDeviceSettingsSplit, + ash::features::kPeripheralCustomization}, {}); ASSERT_TRUE(profile_manager_.SetUp()); TestingProfile* profile = @@ -75,7 +75,6 @@ class OsSettingsManagerTest : public testing::Test { multidevice_setup::MultiDeviceSetupClientFactory::GetForProfile( profile), phonehub::PhoneHubManagerFactory::GetForProfile(profile), - SyncServiceFactory::GetForProfile(profile), KerberosCredentialsManagerFactory::Get(profile), ArcAppListPrefsFactory::GetForBrowserContext(profile), IdentityManagerFactory::GetForProfile(profile), diff --git a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_metrics_provider.cc b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_metrics_provider.cc new file mode 100644 index 00000000000..8fd0adfde07 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_metrics_provider.cc @@ -0,0 +1,30 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/settings/ash/os_settings_metrics_provider.h" + +#include "base/metrics/histogram_functions.h" +#include "chrome/browser/ash/settings/cros_settings.h" +#include "chromeos/ash/components/settings/cros_settings_names.h" + +namespace ash::settings { + +namespace { + +constexpr char kOsSettingsVerifiedAccessEnabledHistogramName[] = + "ChromeOS.Settings.Privacy.VerifiedAccessEnabled"; + +} // namespace + +void OsSettingsMetricsProvider::ProvideCurrentSessionData( + metrics::ChromeUserMetricsExtension* uma_proto_unused) { + // Log verified access enabled/disabled value for this session + bool verified_access_enabled; + ash::CrosSettings::Get()->GetBoolean( + ash::kAttestationForContentProtectionEnabled, &verified_access_enabled); + base::UmaHistogramBoolean(kOsSettingsVerifiedAccessEnabledHistogramName, + verified_access_enabled); +} + +} // namespace ash::settings diff --git a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_metrics_provider.h b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_metrics_provider.h new file mode 100644 index 00000000000..544b0015e5c --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_metrics_provider.h @@ -0,0 +1,29 @@ +// Copyright 2023 The Chromium Authors +// 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_ASH_OS_SETTINGS_METRICS_PROVIDER_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_OS_SETTINGS_METRICS_PROVIDER_H_ + +#include "components/metrics/metrics_provider.h" + +namespace ash::settings { + +class OsSettingsMetricsProvider : public metrics::MetricsProvider { + public: + OsSettingsMetricsProvider() = default; + + OsSettingsMetricsProvider(const OsSettingsMetricsProvider&) = delete; + OsSettingsMetricsProvider& operator=(const OsSettingsMetricsProvider&) = + delete; + + ~OsSettingsMetricsProvider() override = default; + + // metrics::MetricsProvider: + void ProvideCurrentSessionData( + metrics::ChromeUserMetricsExtension* uma_proto) override; +}; + +} // namespace ash::settings + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_OS_SETTINGS_METRICS_PROVIDER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_notification_settings_browsertest.cc b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_notification_settings_browsertest.cc new file mode 100644 index 00000000000..9aa1cf9e989 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_notification_settings_browsertest.cc @@ -0,0 +1,42 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/constants/ash_features.h" +#include "ash/constants/ash_pref_names.h" +#include "base/strings/string_number_conversions.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/ash/profiles/profile_helper.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/settings/ash/os_settings_lock_screen_browser_test_base.h" +#include "chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom-shared.h" +#include "chrome/test/data/webui/settings/chromeos/test_api.test-mojom-test-utils.h" +#include "components/prefs/pref_service.h" +#include "content/public/test/browser_test.h" + +namespace ash::settings { + +// Tests the toggle that controls notifications on the lock screen in the +// lock-screen section of the chrome://os-settings webui. +class OSSettingsNotificationSettingsTest + : public OSSettingsLockScreenBrowserTestBase { + public: + OSSettingsNotificationSettingsTest() { + feature_list_.InitAndEnableFeature(ash::features::kLockScreenNotifications); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +// Checks that the deep link to the notification toggle works. +IN_PROC_BROWSER_TEST_F(OSSettingsNotificationSettingsTest, + NotificationSettings) { + mojom::LockScreenSettingsAsyncWaiter lock_screen_settings = + OpenLockScreenSettingsDeepLinkAndAuthenticate( + base::NumberToString(static_cast<int>( + chromeos::settings::mojom::Setting::kLockScreenNotification))); + lock_screen_settings.AssertLockScreenNotificationFocused(); +} + +} // namespace ash::settings diff --git a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_section.h b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_section.h index 50fcb4b9189..2a537abeaee 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_section.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_section.h @@ -180,8 +180,9 @@ class OsSettingsSection { OsSettingsIdentifier id, const std::string& url_to_modify); - raw_ptr<Profile, ExperimentalAsh> profile_; - raw_ptr<SearchTagRegistry, ExperimentalAsh> search_tag_registry_; + const raw_ptr<Profile, ExperimentalAsh> profile_ = nullptr; + const raw_ptr<SearchTagRegistry, ExperimentalAsh> search_tag_registry_ = + nullptr; }; } // namespace ash::settings diff --git a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_sections.cc b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_sections.cc index 55f427446ad..3e4db6d579c 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_sections.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_sections.cc @@ -39,7 +39,6 @@ OsSettingsSections::OsSettingsSections( SearchTagRegistry* search_tag_registry, multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client, phonehub::PhoneHubManager* phone_hub_manager, - syncer::SyncService* sync_service, KerberosCredentialsManager* kerberos_credentials_manager, ArcAppListPrefs* arc_app_list_prefs, signin::IdentityManager* identity_manager, @@ -66,10 +65,9 @@ OsSettingsSections::OsSettingsSections( profile, search_tag_registry, multidevice_setup_client, phone_hub_manager, android_sms_service, prefs, eche_app_manager)); - AddSection( - mojom::Section::kPeople, - std::make_unique<PeopleSection>(profile, search_tag_registry, - sync_service, identity_manager, prefs)); + AddSection(mojom::Section::kPeople, + std::make_unique<PeopleSection>(profile, search_tag_registry, + identity_manager, prefs)); AddSection(mojom::Section::kDevice, std::make_unique<DeviceSection>( profile, search_tag_registry, prefs)); diff --git a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_sections.h b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_sections.h index 6ebf5847195..6e574081ef5 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_sections.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_sections.h @@ -20,10 +20,6 @@ namespace signin { class IdentityManager; } // namespace signin -namespace syncer { -class SyncService; -} // namespace syncer - namespace ash { class CupsPrintersManager; @@ -51,7 +47,6 @@ class OsSettingsSections { SearchTagRegistry* search_tag_registry, multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client, phonehub::PhoneHubManager* phone_hub_manager, - syncer::SyncService* sync_service, KerberosCredentialsManager* kerberos_credentials_manager, ArcAppListPrefs* arc_app_list_prefs, signin::IdentityManager* identity_manager, diff --git a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_ui.cc b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_ui.cc index 7a7ec31b490..6cab9488424 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_ui.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_ui.cc @@ -16,6 +16,7 @@ #include "ash/webui/personalization_app/search/search.mojom.h" #include "ash/webui/personalization_app/search/search_handler.h" #include "base/metrics/histogram_functions.h" +#include "chrome/browser/ash/drive/file_system_util.h" #include "chrome/browser/ash/login/quick_unlock/pin_backend.h" #include "chrome/browser/ash/login/quick_unlock/quick_unlock_factory.h" #include "chrome/browser/ash/web_applications/personalization_app/personalization_app_manager.h" @@ -103,7 +104,7 @@ OSSettingsUI::OSSettingsUI(content::WebUI* web_ui) webui::SetupWebUIDataSource( html_source, base::make_span(kOsSettingsResources, kOsSettingsResourcesSize), - IDR_OS_SETTINGS_OS_SETTINGS_V3_HTML); + IDR_OS_SETTINGS_OS_SETTINGS_HTML); #if !BUILDFLAG(OPTIMIZE_WEBUI) html_source->AddResourcePaths( @@ -255,7 +256,6 @@ void OSSettingsUI::BindInterface( void OSSettingsUI::BindInterface( mojo::PendingReceiver<audio_config::mojom::CrosAudioConfig> receiver) { - DCHECK(features::IsAudioSettingsPageEnabled()); GetAudioConfigService(std::move(receiver)); } @@ -301,7 +301,6 @@ void OSSettingsUI::BindInterface( void OSSettingsUI::BindInterface( mojo::PendingReceiver<google_drive::mojom::PageHandlerFactory> receiver) { - CHECK(ash::features::IsDriveFsBulkPinningEnabled()); // The PageHandlerFactory is reused across same-origin navigations, so ensure // any existing factories are reset. google_drive_page_handler_factory_.reset(); @@ -311,6 +310,13 @@ void OSSettingsUI::BindInterface( } void OSSettingsUI::BindInterface( + mojo::PendingReceiver<one_drive::mojom::PageHandlerFactory> receiver) { + one_drive_page_handler_factory_ = + std::make_unique<OneDrivePageHandlerFactory>(Profile::FromWebUI(web_ui()), + std::move(receiver)); +} + +void OSSettingsUI::BindInterface( mojo::PendingReceiver<chromeos::connectivity::mojom::PasspointService> receiver) { ash::GetPasspointService(std::move(receiver)); diff --git a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_ui.h b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_ui.h index a27bfdef7f5..016571b0a95 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/os_settings_ui.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/os_settings_ui.h @@ -14,6 +14,8 @@ #include "chrome/browser/ui/webui/nearby_share/nearby_share.mojom.h" #include "chrome/browser/ui/webui/settings/ash/files_page/google_drive_page_handler_factory.h" #include "chrome/browser/ui/webui/settings/ash/files_page/mojom/google_drive_handler.mojom-forward.h" +#include "chrome/browser/ui/webui/settings/ash/files_page/mojom/one_drive_handler.mojom-forward.h" +#include "chrome/browser/ui/webui/settings/ash/files_page/one_drive_page_handler_factory.h" #include "chrome/browser/ui/webui/settings/ash/input_device_settings/input_device_settings_provider.mojom.h" #include "chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_notification_handler.mojom-forward.h" #include "chrome/browser/ui/webui/settings/ash/search/user_action_recorder.mojom-forward.h" @@ -170,6 +172,10 @@ class OSSettingsUI : public ui::MojoWebUIController { void BindInterface( mojo::PendingReceiver<google_drive::mojom::PageHandlerFactory> receiver); + // Binds to the OneDrive page handler mojo. + void BindInterface( + mojo::PendingReceiver<one_drive::mojom::PageHandlerFactory> receiver); + // Binds to the cros Passpoint service. void BindInterface( mojo::PendingReceiver<chromeos::connectivity::mojom::PasspointService> @@ -185,6 +191,7 @@ class OSSettingsUI : public ui::MojoWebUIController { app_management_page_handler_factory_; std::unique_ptr<GoogleDrivePageHandlerFactory> google_drive_page_handler_factory_; + std::unique_ptr<OneDrivePageHandlerFactory> one_drive_page_handler_factory_; // This handler notifies the WebUI when the color provider changes. std::unique_ptr<ui::ColorChangeHandler> color_provider_handler_; diff --git a/chromium/chrome/browser/ui/webui/settings/ash/parental_controls_handler.cc b/chromium/chrome/browser/ui/webui/settings/ash/parental_controls_handler.cc index e752fb2f759..7ab482cdda3 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/parental_controls_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/parental_controls_handler.cc @@ -4,6 +4,7 @@ #include "chrome/browser/ui/webui/settings/ash/parental_controls_handler.h" +#include "ash/public/cpp/new_window_delegate.h" #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" #include "base/values.h" @@ -12,15 +13,11 @@ #include "chrome/browser/apps/app_service/launch_utils.h" #include "chrome/browser/ash/app_list/arc/arc_app_utils.h" #include "chrome/browser/ash/child_accounts/child_user_service.h" -#include "chrome/browser/ui/browser_navigator.h" -#include "chrome/browser/ui/browser_navigator_params.h" #include "chrome/browser/ui/webui/ash/add_supervision/add_supervision_ui.h" #include "components/services/app_service/public/cpp/app_launch_util.h" #include "components/services/app_service/public/cpp/app_registry_cache.h" #include "components/services/app_service/public/cpp/app_types.h" #include "components/services/app_service/public/cpp/app_update.h" -#include "ui/base/page_transition_types.h" -#include "ui/base/window_open_disposition.h" #include "ui/display/types/display_constants.h" #include "ui/events/event_constants.h" #include "url/gurl.h" @@ -85,11 +82,10 @@ void ParentalControlsHandler::HandleLaunchFamilyLinkSettings( } // As a last resort, launch browser to the family link site. - NavigateParams params(profile_, GURL(kFamilyLinkSiteURL), - ui::PAGE_TRANSITION_FROM_API); - params.disposition = WindowOpenDisposition::NEW_WINDOW; - params.window_action = NavigateParams::SHOW_WINDOW; - Navigate(¶ms); + NewWindowDelegate::GetPrimary()->OpenUrl( + GURL(kFamilyLinkSiteURL), + NewWindowDelegate::OpenUrlFrom::kUserInteraction, + NewWindowDelegate::Disposition::kNewWindow); } } // namespace ash::settings diff --git a/chromium/chrome/browser/ui/webui/settings/ash/pdf_ocr_handler.cc b/chromium/chrome/browser/ui/webui/settings/ash/pdf_ocr_handler.cc index 7920260c6f9..ed56b8486f4 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/pdf_ocr_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/pdf_ocr_handler.cc @@ -5,9 +5,9 @@ #include <string> #include "base/feature_list.h" +#include "chrome/browser/screen_ai/screen_ai_install_state.h" #include "chrome/browser/ui/webui/settings/ash/pdf_ocr_handler.h" #include "chrome/grit/generated_resources.h" -#include "components/services/screen_ai/public/cpp/screen_ai_install_state.h" #include "ui/accessibility/accessibility_features.h" #include "ui/base/l10n/l10n_util.h" diff --git a/chromium/chrome/browser/ui/webui/settings/ash/pdf_ocr_handler.h b/chromium/chrome/browser/ui/webui/settings/ash/pdf_ocr_handler.h index ceb50090a31..f40a3925dcf 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/pdf_ocr_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/pdf_ocr_handler.h @@ -7,8 +7,8 @@ #include "base/memory/weak_ptr.h" #include "base/scoped_observation.h" +#include "chrome/browser/screen_ai/screen_ai_install_state.h" #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" -#include "components/services/screen_ai/public/cpp/screen_ai_install_state.h" namespace settings { diff --git a/chromium/chrome/browser/ui/webui/settings/ash/pdf_ocr_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/ash/pdf_ocr_handler_unittest.cc index cc7ba384ca7..b589855edbf 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/pdf_ocr_handler_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/pdf_ocr_handler_unittest.cc @@ -7,8 +7,8 @@ #include "base/memory/raw_ptr.h" #include "base/test/scoped_feature_list.h" +#include "chrome/browser/screen_ai/screen_ai_install_state.h" #include "chrome/test/base/testing_profile.h" -#include "components/services/screen_ai/public/cpp/screen_ai_install_state.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_task_environment.h" #include "content/public/test/test_web_ui.h" @@ -32,7 +32,11 @@ class TestScreenAIInstallState : public screen_ai::ScreenAIInstallState { TestScreenAIInstallState(const TestScreenAIInstallState&) = delete; TestScreenAIInstallState& operator=(const TestScreenAIInstallState&) = delete; - ~TestScreenAIInstallState() = default; + ~TestScreenAIInstallState() override {} + + void SetLastUsageTime() override {} + + void DownloadComponent() override {} }; class TestPdfOcrHandler : public PdfOcrHandler { diff --git a/chromium/chrome/browser/ui/webui/settings/ash/people_section.cc b/chromium/chrome/browser/ui/webui/settings/ash/people_section.cc index 3318a24fda5..78b10eac276 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/people_section.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/people_section.cc @@ -50,8 +50,6 @@ #include "components/prefs/pref_service.h" #include "components/strings/grit/components_strings.h" #include "components/sync/base/features.h" -#include "components/sync/driver/sync_service.h" -#include "components/sync/driver/sync_user_settings.h" #include "components/user_manager/user.h" #include "components/user_manager/user_manager.h" #include "content/public/browser/web_ui.h" @@ -427,6 +425,10 @@ void AddSyncControlsStrings(content::WebUIDataSource* html_source) { base::FeatureList::IsEnabled(syncer::kSyncChromeOSAppsToggleSharing) && crosapi::browser_util::IsLacrosEnabled()); + html_source->AddBoolean( + "osDeprecateSyncMetricsToggle", + ash::features::IsOsSettingsDeprecateSyncMetricsToggleEnabled()); + // This handler is for chrome://os-settings. html_source->AddBoolean("isOSSettings", true); } @@ -487,10 +489,8 @@ bool IsSameAccount(const ::account_manager::AccountKey& account_key, } // namespace -// TODO(https://crbug.com/1274802): Remove sync_service param. PeopleSection::PeopleSection(Profile* profile, SearchTagRegistry* search_tag_registry, - syncer::SyncService* sync_service, signin::IdentityManager* identity_manager, PrefService* pref_service) : OsSettingsSection(profile, search_tag_registry), diff --git a/chromium/chrome/browser/ui/webui/settings/ash/people_section.h b/chromium/chrome/browser/ui/webui/settings/ash/people_section.h index 1c4bcfe22fd..5d378dd6570 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/people_section.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/people_section.h @@ -16,7 +16,6 @@ #include "components/account_manager_core/account_manager_facade.h" #include "components/account_manager_core/chromeos/account_manager.h" #include "components/prefs/pref_change_registrar.h" -#include "components/sync/driver/sync_service_observer.h" class PrefService; class Profile; @@ -29,10 +28,6 @@ namespace signin { class IdentityManager; } // namespace signin -namespace syncer { -class SyncService; -} // namespace syncer - namespace ash { class AccountAppsAvailability; @@ -52,7 +47,6 @@ class PeopleSection : public OsSettingsSection, public: PeopleSection(Profile* profile, SearchTagRegistry* search_tag_registry, - syncer::SyncService* sync_service, signin::IdentityManager* identity_manager, PrefService* pref_service); ~PeopleSection() override; diff --git a/chromium/chrome/browser/ui/webui/settings/ash/printing_section.cc b/chromium/chrome/browser/ui/webui/settings/ash/printing_section.cc index f70821634c5..ec99d9f3a35 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/printing_section.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/printing_section.cc @@ -120,6 +120,8 @@ void PrintingSection::AddLoadTimeData(content::WebUIDataSource* html_source) { {"cupsPrintersLearnMoreLabel", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_LEARN_MORE_LABEL}, {"addCupsPrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_ADD_PRINTER}, + {"addCupsPrinterManually", + IDS_SETTINGS_PRINTING_CUPS_PRINTERS_ADD_PRINTER_MANUALLY}, {"editPrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_EDIT}, {"viewPrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_VIEW}, {"removePrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_REMOVE}, @@ -150,6 +152,10 @@ void PrintingSection::AddLoadTimeData(content::WebUIDataSource* html_source) { IDS_SETTINGS_PRINTING_CUPS_PRINTERS_SAVED_PRINTERS_COUNT_ONE}, {"savedPrintersCountNone", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_SAVED_PRINTERS_COUNT_NONE}, + {"noSavedPrinters", IDS_SETTINGS_PRINTING_CUPS_NO_SAVED_PRINTERS}, + {"helpSectionTitle", IDS_SETTINGS_PRINTING_CUPS_HELP_SECTION_TITLE}, + {"helpSectionDescription", + IDS_SETTINGS_PRINTING_CUPS_HELP_SECTION_DESCRIPTION}, {"showMorePrinters", IDS_SETTINGS_PRINTING_CUPS_SHOW_MORE}, {"addPrintersNearbyTitle", IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTERS_NEARBY_TITLE}, @@ -279,6 +285,30 @@ void PrintingSection::AddLoadTimeData(content::WebUIDataSource* html_source) { IDS_SETTINGS_PRINTING_CUPS_PRINT_SERVER_CONNECTION_ERROR}, {"printServerConfigurationErrorMessage", IDS_SETTINGS_PRINTING_CUPS_PRINT_SERVER_REACHABLE_BUT_CANNOT_ADD}, + {"printerStatusDeviceError", + IDS_SETTINGS_PRINTING_PRINTER_STATUS_DEVICE_ERROR}, + {"printerStatusDoorOpen", IDS_SETTINGS_PRINTING_PRINTER_STATUS_DOOR_OPEN}, + {"printerStatusLowOnInk", + IDS_SETTINGS_PRINTING_PRINTER_STATUS_LOW_ON_INK}, + {"printerStatusLowOnPaper", + IDS_SETTINGS_PRINTING_PRINTER_STATUS_LOW_ON_PAPER}, + {"printerStatusOutOfInk", + IDS_SETTINGS_PRINTING_PRINTER_STATUS_OUT_OF_INK}, + {"printerStatusOutOfPaper", + IDS_SETTINGS_PRINTING_PRINTER_STATUS_OUT_OF_PAPER}, + {"printerStatusOutputAlmostFull", + IDS_SETTINGS_PRINTING_PRINTER_STATUS_OUPUT_ALMOST_FULL}, + {"printerStatusOutputFull", + IDS_SETTINGS_PRINTING_PRINTER_STATUS_OUPUT_FULL}, + {"printerStatusPaperJam", IDS_SETTINGS_PRINTING_PRINTER_STATUS_PAPER_JAM}, + {"printerStatusPaused", IDS_SETTINGS_PRINTING_PRINTER_STATUS_PAUSED}, + {"printerStatusPrinterQueueFull", + IDS_SETTINGS_PRINTING_PRINTER_STATUS_PRINTER_QUEUE_FULL}, + {"printerStatusPrinterUnreachable", + IDS_SETTINGS_PRINTING_PRINTER_STATUS_PRINTER_UNREACHABLE}, + {"printerStatusStopped", IDS_SETTINGS_PRINTING_PRINTER_STATUS_STOPPED}, + {"printerStatusTrayMissing", + IDS_SETTINGS_PRINTING_PRINTER_STATUS_TRAY_MISSING}, }; html_source->AddLocalizedStrings(kLocalizedStrings); @@ -287,9 +317,10 @@ void PrintingSection::AddLoadTimeData(content::WebUIDataSource* html_source) { html_source->AddString( "printingCUPSPrintPpdLearnMoreUrl", GetHelpUrlWithBoard(chrome::kCupsPrintPPDLearnMoreURL)); - html_source->AddBoolean("isViewPpdEnabled", features::IsViewPpdEnabled()); html_source->AddBoolean("isPrinterSettingsRevampEnabled", features::IsPrinterSettingsRevampEnabled()); + html_source->AddBoolean("isPrinterSettingsPrinterStatusEnabled", + features::IsPrinterSettingsPrinterStatusEnabled()); } void PrintingSection::AddHandlers(content::WebUI* web_ui) { diff --git a/chromium/chrome/browser/ui/webui/settings/ash/privacy_hub_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/ash/privacy_hub_handler_unittest.cc index da20c1b2d2d..f8f5a6c2d2b 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/privacy_hub_handler_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/privacy_hub_handler_unittest.cc @@ -6,6 +6,7 @@ #include "ash/constants/ash_features.h" #include "base/containers/adapters.h" +#include "base/ranges/algorithm.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "chrome/browser/ash/privacy_hub/privacy_hub_hats_trigger.h" diff --git a/chromium/chrome/browser/ui/webui/settings/ash/privacy_section.cc b/chromium/chrome/browser/ui/webui/settings/ash/privacy_section.cc index 5ccdfaf869d..57aea46c694 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/privacy_section.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/privacy_section.cc @@ -402,6 +402,10 @@ void PrivacySection::AddLoadTimeData(content::WebUIDataSource* html_source) { IDS_OS_SETTINGS_PRIVACY_HUB_MICROPHONE_TOGGLE_SUBTEXT}, {"noMicrophoneConnectedText", IDS_OS_SETTINGS_PRIVACY_HUB_NO_MICROPHONE_CONNECTED_TEXT}, + {"speakOnMuteDetectionToggleTitle", + IDS_OS_SETTINGS_PRIVACY_HUB_SPEAK_ON_MUTE_DETECTION_TOGGLE_TITLE}, + {"speakOnMuteDetectionToggleSubtext", + IDS_OS_SETTINGS_PRIVACY_HUB_SPEAK_ON_MUTE_DETECTION_TOGGLE_SUBTEXT}, {"geolocationToggleTitle", IDS_OS_SETTINGS_PRIVACY_HUB_GEOLOCATION_TOGGLE_TITLE}, {"geolocationToggleDesc", @@ -426,6 +430,8 @@ void PrivacySection::AddLoadTimeData(content::WebUIDataSource* html_source) { ash::features::IsCrosPrivacyHubV1Enabled()); html_source->AddBoolean("showPrivacyHubFuturePage", ash::features::IsCrosPrivacyHubV2Enabled()); + html_source->AddBoolean("showSpeakOnMuteDetectionPage", + ash::features::IsVideoConferenceEnabled()); html_source->AddString( "smartPrivacyDesc", @@ -443,6 +449,12 @@ void PrivacySection::AddLoadTimeData(content::WebUIDataSource* html_source) { html_source->AddString("peripheralDataAccessLearnMoreURL", chrome::kPeripheralDataAccessHelpURL); + html_source->AddString("speakOnMuteDetectionLearnMoreURL", + chrome::kSpeakOnMuteDetectionLearnMoreURL); + + html_source->AddString("geolocationToggleLearnMoreURL", + chrome::kGeolocationToggleLearnMoreURL); + html_source->AddBoolean("showSecureDnsSetting", IsSecureDnsAvailable()); html_source->AddBoolean("showSecureDnsOsSettingLink", false); @@ -512,6 +524,7 @@ void PrivacySection::RegisterHierarchy(HierarchyGenerator* generator) const { mojom::Setting::kLockScreenV2, mojom::Setting::kChangeAuthPinV2, mojom::Setting::kPeripheralDataAccessProtection, + mojom::Setting::kLockScreenNotification, }; RegisterNestedSettingBulk(mojom::Subpage::kSecurityAndSignInV2, kSecurityAndSignInSettings, generator); @@ -564,7 +577,8 @@ void PrivacySection::RegisterHierarchy(HierarchyGenerator* generator) const { RegisterNestedSettingBulk( mojom::Subpage::kPrivacyHub, {{mojom::Setting::kCameraOnOff, mojom::Setting::kMicrophoneOnOff, - mojom::Setting::kGeolocationOnOff}}, + mojom::Setting::kGeolocationOnOff, + mojom::Setting::kSpeakOnMuteDetectionOnOff}}, generator); } diff --git a/chromium/chrome/browser/ui/webui/settings/ash/search/BUILD.gn b/chromium/chrome/browser/ui/webui/settings/ash/search/BUILD.gn index 0beca303f84..6f2027b16af 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/search/BUILD.gn +++ b/chromium/chrome/browser/ui/webui/settings/ash/search/BUILD.gn @@ -19,6 +19,6 @@ mojom("mojo_bindings") { "//mojo/public/mojom/base", ] - webui_module_path = "/search" + webui_module_path = "/" use_typescript_sources = true } diff --git a/chromium/chrome/browser/ui/webui/settings/ash/search/per_session_settings_user_action_tracker.cc b/chromium/chrome/browser/ui/webui/settings/ash/search/per_session_settings_user_action_tracker.cc index 4e29e582871..efbb6e34add 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/search/per_session_settings_user_action_tracker.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/search/per_session_settings_user_action_tracker.cc @@ -5,6 +5,10 @@ #include "chrome/browser/ui/webui/settings/ash/search/per_session_settings_user_action_tracker.h" #include "base/metrics/histogram_functions.h" +#include "base/strings/string_number_conversions.h" +#include "chrome/browser/ash/login/login_pref_names.h" +#include "chrome/common/pref_names.h" +#include "components/prefs/scoped_user_pref_update.h" namespace ash::settings { @@ -25,6 +29,10 @@ constexpr base::TimeDelta kMinSubsequentChange = base::Milliseconds(200); constexpr base::TimeDelta kMinDurationMetric = base::Milliseconds(100); constexpr base::TimeDelta kMaxDurationMetric = base::Minutes(10); +// Used to check whether it has been one week since the user has finished OOBE +// onboarding. +constexpr base::TimeDelta kOneWeek = base::Days(7); + void LogDurationMetric(const char* metric_name, base::TimeDelta duration) { base::UmaHistogramCustomTimes(metric_name, duration, kMinDurationMetric, kMaxDurationMetric, /*buckets=*/50); @@ -32,19 +40,91 @@ void LogDurationMetric(const char* metric_name, base::TimeDelta duration) { } // namespace -PerSessionSettingsUserActionTracker::PerSessionSettingsUserActionTracker() - : metric_start_time_(base::TimeTicks::Now()) {} +PerSessionSettingsUserActionTracker::PerSessionSettingsUserActionTracker( + PrefService* pref_service) + : metric_start_time_(base::TimeTicks::Now()), + window_last_active_timestamp_(base::TimeTicks::Now()), + pref_service_(pref_service) {} + +PerSessionSettingsUserActionTracker::~PerSessionSettingsUserActionTracker() { + RecordPageActiveTime(); + LogDurationMetric("ChromeOS.Settings.WindowTotalActiveDuration", + total_time_session_active_); + + base::UmaHistogramCounts1000( + "ChromeOS.Settings.NumUniqueSettingsChanged.PerSession", + changed_settings_.size()); + + // The pref kHasResetFirst7DaysSettingsUsedCount indicates whether the pref + // kTotalUniqueOsSettingsChanged has been cleared once after 1 week has passed + // since OOBE. If the pref kHasResetFirst7DaysSettingsUsedCount is False and + // it has been over 7 days since the user has taken OOBE, it means that this + // is the first time since one week after OOBE that the user has opened and + // changed Settings. In this case, clear the pref + // kTotalUniqueOsSettingsChanged to prepare it for the + // ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime.SubsequentWeeks + // histogram. + // NOTE: prefs::kOobeOnboardingTime does not exist for users in guest mode. + if (!pref_service_->GetBoolean( + ::prefs::kHasResetFirst7DaysSettingsUsedCount) && + pref_service_->HasPrefPath(prefs::kOobeOnboardingTime) && + !IsTodayInFirst7Days()) { + pref_service_->SetBoolean(::prefs::kHasResetFirst7DaysSettingsUsedCount, + true); + ClearTotalUniqueSettingsChangedPref(); + } + + // Record number of unique settings changed in this session. + absl::optional<int> total_unique_settings_changed_count = + UpdateSettingsPrefTotalUniqueChanged(); + + // If the number of total unique setting used increased, flagged by the + // optional variable total_unique_settings_changed_count having a value, add + // the datapoint to the histogram. + // NOTE: prefs::kOobeOnboardingTime does not exist for users in guest mode. + if (pref_service_->HasPrefPath(prefs::kOobeOnboardingTime) && + total_unique_settings_changed_count.has_value()) { + if (IsTodayInFirst7Days()) { + base::UmaHistogramCounts1000( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime.FirstWeek", + total_unique_settings_changed_count.value()); + } else { + base::UmaHistogramCounts1000( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime." + "SubsequentWeeks", + total_unique_settings_changed_count.value()); + } + // Store the total unique Settings changed in .DeviceLifetime histogram. + base::UmaHistogramCounts1000( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime.Total", + total_unique_settings_changed_count.value()); + } +} + +bool PerSessionSettingsUserActionTracker::IsTodayInFirst7Days() { + // The pref kOobeOnboardingTime does not get set for users in guest mode. + // Because we are accessing the value of the pref, we must ensure that it does + // exist. + DCHECK(pref_service_->HasPrefPath(prefs::kOobeOnboardingTime)); + return base::Time::Now() - + pref_service_->GetTime(::ash::prefs::kOobeOnboardingTime) <= + kOneWeek; +} -PerSessionSettingsUserActionTracker::~PerSessionSettingsUserActionTracker() = - default; +void PerSessionSettingsUserActionTracker:: + ClearTotalUniqueSettingsChangedPref() { + pref_service_->ClearPref(::prefs::kTotalUniqueOsSettingsChanged); +} void PerSessionSettingsUserActionTracker::RecordPageFocus() { + const base::TimeTicks now = base::TimeTicks::Now(); + window_last_active_timestamp_ = now; + if (last_blur_timestamp_.is_null()) return; // Log the duration of being blurred. - const base::TimeDelta blurred_duration = - base::TimeTicks::Now() - last_blur_timestamp_; + const base::TimeDelta blurred_duration = now - last_blur_timestamp_; LogDurationMetric("ChromeOS.Settings.BlurredWindowDuration", blurred_duration); @@ -57,8 +137,17 @@ void PerSessionSettingsUserActionTracker::RecordPageFocus() { } } +void PerSessionSettingsUserActionTracker::RecordPageActiveTime() { + if (window_last_active_timestamp_ != base::TimeTicks()) { + total_time_session_active_ += + base::TimeTicks::Now() - window_last_active_timestamp_; + } + window_last_active_timestamp_ = base::TimeTicks(); +} + void PerSessionSettingsUserActionTracker::RecordPageBlur() { last_blur_timestamp_ = base::TimeTicks::Now(); + RecordPageActiveTime(); } void PerSessionSettingsUserActionTracker::RecordClick() { @@ -73,7 +162,12 @@ void PerSessionSettingsUserActionTracker::RecordSearch() { ++num_searches_since_start_time_; } -void PerSessionSettingsUserActionTracker::RecordSettingChange() { +void PerSessionSettingsUserActionTracker::RecordSettingChange( + absl::optional<chromeos::settings::mojom::Setting> setting) { + if (setting.has_value()) { + changed_settings_.insert( + base::NumberToString(static_cast<int>(setting.value()))); + } base::TimeTicks now = base::TimeTicks::Now(); if (!last_record_setting_changed_timestamp_.is_null()) { @@ -119,4 +213,34 @@ void PerSessionSettingsUserActionTracker::ResetMetricsCountersAndTimestamp() { num_searches_since_start_time_ = 0u; } +absl::optional<int> +PerSessionSettingsUserActionTracker::UpdateSettingsPrefTotalUniqueChanged() { + // Fetch the dictionary from the pref. + ScopedDictPrefUpdate total_unique_settings_changed_( + pref_service_, ::prefs::kTotalUniqueOsSettingsChanged); + base::Value::Dict& pref_data = total_unique_settings_changed_.Get(); + int current_count = pref_data.size(); + + // Set the dictionary. + // Value is a constant 1 since we only want to know which Setting has been + // used, not how many times it has been used. + constexpr int value = 1; + for (const std::string& setting_string : changed_settings_) { + if (!pref_data.contains(setting_string)) { + pref_data.Set(setting_string, value); + } + } + + int new_count = pref_data.size(); + + // If the new size of the pref dictionary is the same as before, we do not + // want to record that in UMA so we will return a nullopt to flag not to add + // to histogram bucket. + // + // The value of pref_data will automatically get stored to pref_service_ upon + // destruction. + return current_count == new_count ? absl::nullopt + : absl::optional<int>{new_count}; +} + } // namespace ash::settings diff --git a/chromium/chrome/browser/ui/webui/settings/ash/search/per_session_settings_user_action_tracker.h b/chromium/chrome/browser/ui/webui/settings/ash/search/per_session_settings_user_action_tracker.h index de21202069a..1bf9a1d1644 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/search/per_session_settings_user_action_tracker.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/search/per_session_settings_user_action_tracker.h @@ -5,7 +5,12 @@ #ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_SEARCH_PER_SESSION_SETTINGS_USER_ACTION_TRACKER_H_ #define CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_SEARCH_PER_SESSION_SETTINGS_USER_ACTION_TRACKER_H_ +#include <set> + #include "base/time/time.h" +#include "chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom.h" +#include "components/prefs/pref_service.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace ash::settings { @@ -15,25 +20,60 @@ namespace ash::settings { // should be created for that new session. class PerSessionSettingsUserActionTracker { public: - PerSessionSettingsUserActionTracker(); + explicit PerSessionSettingsUserActionTracker(PrefService* pref_service); PerSessionSettingsUserActionTracker( const PerSessionSettingsUserActionTracker& other) = delete; PerSessionSettingsUserActionTracker& operator=( const PerSessionSettingsUserActionTracker& other) = delete; ~PerSessionSettingsUserActionTracker(); + void RecordPageActiveTime(); void RecordPageFocus(); void RecordPageBlur(); void RecordClick(); void RecordNavigation(); void RecordSearch(); - void RecordSettingChange(); + // TODO (b/282233232): make 'setting' a required parameter once the + // corresponding function 'RecordSettingChange()' in ts files have been + // backfilled with the information on what specific Setting has been changed. + // In the meantime, this parameter is optional, and if it is not provided, it + // will be set to nullopt to indicate that it has not been initialized. + void RecordSettingChange(absl::optional<chromeos::settings::mojom::Setting> + setting = absl::nullopt); + + const std::set<std::string>& GetChangedSettingsForTesting() { + return changed_settings_; + } + const base::TimeDelta& GetTotalTimeSessionActiveForTesting() { + return total_time_session_active_; + } + const base::TimeTicks& GetWindowLastActiveTimeStampForTesting() { + return window_last_active_timestamp_; + } private: friend class PerSessionSettingsUserActionTrackerTest; + // Clears the pref kTotalUniqueOsSettingsChanged after 7 days have passed + // since the user finished OOBE. We will track the changes made within the + // first week in + // ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime.FirstWeek, and + // ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime.SubsequentWeeks + // for the weeks following the first week. + void ClearTotalUniqueSettingsChangedPref(); + + // Checks whether it has been 7 days since the user has completed + // OOBE. It utilized the currently existing pref called kOobeOnboardingTime, + // which is set once the user finished the OOBE. + bool IsTodayInFirst7Days(); + void ResetMetricsCountersAndTimestamp(); + // Returns the size of the pref dict if it changes. Otherwise, no value will + // get returned if if there were no new unique settings changed in the + // session. + absl::optional<int> UpdateSettingsPrefTotalUniqueChanged(); + // 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 @@ -56,6 +96,18 @@ class PerSessionSettingsUserActionTracker { // 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_; + + // Tracks which settings have been changed in this user session + std::set<std::string> changed_settings_; + + // Total time the Settings page has been active and in focus from the opening + // of the page to closing. Blur events pause the timer. + base::TimeDelta total_time_session_active_; + + // The point in time which the Settings page was last active and in focus. + base::TimeTicks window_last_active_timestamp_; + + raw_ptr<PrefService> pref_service_; }; } // namespace ash::settings diff --git a/chromium/chrome/browser/ui/webui/settings/ash/search/per_session_settings_user_action_tracker_unittest.cc b/chromium/chrome/browser/ui/webui/settings/ash/search/per_session_settings_user_action_tracker_unittest.cc index aa678f3103b..ddc32391b90 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/search/per_session_settings_user_action_tracker_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/search/per_session_settings_user_action_tracker_unittest.cc @@ -5,31 +5,65 @@ #include "chrome/browser/ui/webui/settings/ash/search/per_session_settings_user_action_tracker.h" #include "base/test/metrics/histogram_tester.h" -#include "base/test/task_environment.h" #include "base/time/time.h" +#include "chrome/browser/ash/login/login_pref_names.h" +#include "chrome/test/base/browser_with_test_window_test.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 "testing/gtest/include/gtest/gtest.h" +using chromeos::settings::mojom::Setting; + namespace ash::settings { +constexpr char kProfileName[] = "user@gmail.com"; + class PerSessionSettingsUserActionTrackerTest : public testing::Test { protected: PerSessionSettingsUserActionTrackerTest() = default; ~PerSessionSettingsUserActionTrackerTest() override = default; - base::test::TaskEnvironment task_environment_{ + void SetUp() override { + profile_manager_ = std::make_unique<TestingProfileManager>( + TestingBrowserProcess::GetGlobal()); + ASSERT_TRUE(profile_manager_->SetUp()); + testing_profile_ = profile_manager_->CreateTestingProfile(kProfileName); + test_pref_service_ = testing_profile_->GetPrefs(); + tracker_ = std::make_unique<PerSessionSettingsUserActionTracker>( + test_pref_service_); + } + + void TearDown() override { + if (tracker_) { + tracker_.reset(); + } + profile_manager_->DeleteTestingProfile(kProfileName); + testing_profile_ = nullptr; + profile_manager_.reset(); + } + + std::string SettingAsIntString(Setting setting) { + return base::NumberToString(static_cast<int>(setting)); + } + + content::BrowserTaskEnvironment task_environment_{ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; base::HistogramTester histogram_tester_; - PerSessionSettingsUserActionTracker tracker_; + TestingProfile* testing_profile_; + raw_ptr<PrefService> test_pref_service_; + std::unique_ptr<TestingProfileManager> profile_manager_; + std::unique_ptr<PerSessionSettingsUserActionTracker> tracker_; }; TEST_F(PerSessionSettingsUserActionTrackerTest, TestRecordMetrics) { // Focus the page, perform some tasks, and change a setting. - tracker_.RecordPageFocus(); - tracker_.RecordClick(); - tracker_.RecordNavigation(); - tracker_.RecordSearch(); + tracker_->RecordPageFocus(); + tracker_->RecordClick(); + tracker_->RecordNavigation(); + tracker_->RecordSearch(); task_environment_.FastForwardBy(base::Seconds(10)); - tracker_.RecordSettingChange(); + tracker_->RecordSettingChange(); // The "first change" metrics should have been logged. histogram_tester_.ExpectTotalCount( @@ -48,11 +82,11 @@ TEST_F(PerSessionSettingsUserActionTrackerTest, TestRecordMetrics) { // Without leaving the page, perform some more tasks, and change another // setting. - tracker_.RecordClick(); - tracker_.RecordNavigation(); - tracker_.RecordSearch(); + tracker_->RecordClick(); + tracker_->RecordNavigation(); + tracker_->RecordSearch(); task_environment_.FastForwardBy(base::Seconds(10)); - tracker_.RecordSettingChange(); + tracker_->RecordSettingChange(); // The "subsequent change" metrics should have been logged. histogram_tester_.ExpectTotalCount( @@ -71,11 +105,11 @@ TEST_F(PerSessionSettingsUserActionTrackerTest, TestRecordMetrics) { // 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(); + tracker_->RecordClick(); + tracker_->RecordNavigation(); + tracker_->RecordSearch(); task_environment_.FastForwardBy(base::Milliseconds(100)); - tracker_.RecordSettingChange(); + tracker_->RecordSettingChange(); // No additional logging should have occurred, so make the same verifications // as above. @@ -94,11 +128,11 @@ TEST_F(PerSessionSettingsUserActionTrackerTest, TestRecordMetrics) { /*count=*/1); // Repeat this once more, and verify that the counts increased. - tracker_.RecordClick(); - tracker_.RecordNavigation(); - tracker_.RecordSearch(); + tracker_->RecordClick(); + tracker_->RecordNavigation(); + tracker_->RecordSearch(); task_environment_.FastForwardBy(base::Seconds(10)); - tracker_.RecordSettingChange(); + tracker_->RecordSettingChange(); // The "subsequent change" metrics should have been logged. histogram_tester_.ExpectTotalCount( @@ -118,10 +152,10 @@ TEST_F(PerSessionSettingsUserActionTrackerTest, TestRecordMetrics) { TEST_F(PerSessionSettingsUserActionTrackerTest, TestBlurAndFocus) { // Focus the page, click, and change a setting. - tracker_.RecordPageFocus(); - tracker_.RecordClick(); + tracker_->RecordPageFocus(); + tracker_->RecordClick(); task_environment_.FastForwardBy(base::Seconds(1)); - tracker_.RecordSettingChange(); + tracker_->RecordSettingChange(); histogram_tester_.ExpectTotalCount( "ChromeOS.Settings.NumClicksUntilChange.FirstChange", /*count=*/1); @@ -133,11 +167,11 @@ TEST_F(PerSessionSettingsUserActionTrackerTest, TestBlurAndFocus) { // 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(); + tracker_->RecordPageBlur(); task_environment_.FastForwardBy(base::Seconds(59)); - tracker_.RecordPageFocus(); - tracker_.RecordClick(); - tracker_.RecordSettingChange(); + tracker_->RecordPageFocus(); + tracker_->RecordClick(); + tracker_->RecordSettingChange(); histogram_tester_.ExpectTimeBucketCount( "ChromeOS.Settings.BlurredWindowDuration", /*sample=*/base::Seconds(59), @@ -152,12 +186,12 @@ TEST_F(PerSessionSettingsUserActionTrackerTest, TestBlurAndFocus) { // 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(); + tracker_->RecordPageBlur(); task_environment_.FastForwardBy(base::Minutes(1)); - tracker_.RecordPageFocus(); + tracker_->RecordPageFocus(); task_environment_.FastForwardBy(base::Seconds(5)); - tracker_.RecordClick(); - tracker_.RecordSettingChange(); + tracker_->RecordClick(); + tracker_->RecordSettingChange(); histogram_tester_.ExpectTimeBucketCount( "ChromeOS.Settings.BlurredWindowDuration", /*sample=*/base::Minutes(1), @@ -171,4 +205,436 @@ TEST_F(PerSessionSettingsUserActionTrackerTest, TestBlurAndFocus) { /*count=*/1); } +TEST_F(PerSessionSettingsUserActionTrackerTest, TestEndSessionWithBlur) { + // fast forward the time by 30 seconds. Total window active time does not get + // changed as we have not blurred the session. + tracker_->RecordPageFocus(); + task_environment_.FastForwardBy(base::Seconds(30)); + EXPECT_EQ(base::TimeDelta(), tracker_->GetTotalTimeSessionActiveForTesting()); + + // Total window active time changes to 30 seconds as the page is no longer in + // focus. + tracker_->RecordPageBlur(); + EXPECT_EQ(base::Seconds(30), tracker_->GetTotalTimeSessionActiveForTesting()); + // the window is no longer active, so the timer resets. + EXPECT_EQ(base::TimeTicks(), + tracker_->GetWindowLastActiveTimeStampForTesting()); +} + +TEST_F(PerSessionSettingsUserActionTrackerTest, TestUniqueChangedSettings) { + std::set<std::string> expected_set; + + // Flip the WiFi toggle in Settings, this is a unique Setting that is changing + // so the number of unique settings that have been changed increases by 1 for + // a total of 1 + tracker_->RecordSettingChange(Setting::kWifiOnOff); + expected_set = {SettingAsIntString(Setting::kWifiOnOff)}; + EXPECT_EQ(expected_set, tracker_->GetChangedSettingsForTesting()); + + // Destruct tracker_ to trigger recording the data to the histogram. + tracker_.reset(); + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.PerSession", + /*sample=*/1, + /*count=*/1); + + // Create a new PerSessionSettingsUserActionTracker to imitate a newly opened + // Settings page. + tracker_ = + std::make_unique<PerSessionSettingsUserActionTracker>(test_pref_service_); + + // test that the set has been destructed and cleared appropriately + expected_set = {}; + EXPECT_EQ(expected_set, tracker_->GetChangedSettingsForTesting()); + + // Flip the Do Not Disturb and WiFi toggles in Settings, this is a unique + // Setting that is changing so the number of unique settings that have been + // changed increases by 1 for a total of 2 + tracker_->RecordSettingChange(Setting::kDoNotDisturbOnOff); + tracker_->RecordSettingChange(Setting::kWifiOnOff); + expected_set = {SettingAsIntString(Setting::kDoNotDisturbOnOff), + SettingAsIntString(Setting::kWifiOnOff)}; + EXPECT_EQ(expected_set, tracker_->GetChangedSettingsForTesting()); + + // Destruct tracker_ to trigger recording the data to the histogram. + tracker_.reset(); + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.PerSession", + /*sample=*/2, + /*count=*/1); + + // Create a new PerSessionSettingsUserActionTracker to imitate a newly opened + // Settings page. + tracker_ = + std::make_unique<PerSessionSettingsUserActionTracker>(test_pref_service_); + + // Flip the Do Not Disturb and WiFi toggles. Flip Do Not Disturb toggle again + // in Settings, this is not a unique Setting that is changing so the number of + // unique settings that have been changed does not increase. The bucket sample + // 2 should now have 2 counts. + tracker_->RecordSettingChange(Setting::kDoNotDisturbOnOff); + tracker_->RecordSettingChange(Setting::kWifiOnOff); + tracker_->RecordSettingChange(Setting::kDoNotDisturbOnOff); + // expected_set will not change + EXPECT_EQ(expected_set, tracker_->GetChangedSettingsForTesting()); + + // Destruct tracker_ to trigger recording the data to the histogram. + tracker_.reset(); + + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.PerSession", + /*sample=*/2, + /*count=*/2); + + // bucket 1 will still reflect the correct number of count added to it + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.PerSession", + /*sample=*/1, + /*count=*/1); +} + +TEST_F(PerSessionSettingsUserActionTrackerTest, + TestTotalUniqueChangedSettings) { + // Simulate that the user has taken OOBE. + test_pref_service_->SetTime(::ash::prefs::kOobeOnboardingTime, + base::Time::Now()); + + std::set<std::string> expected_set; + + // Flip the WiFi toggle in Settings, this is a unique Setting that is changing + // so the number of unique settings that have been changed increases by 1 for + // a total of 1. + tracker_->RecordSettingChange(Setting::kWifiOnOff); + expected_set = {SettingAsIntString(Setting::kWifiOnOff)}; + EXPECT_EQ(expected_set, tracker_->GetChangedSettingsForTesting()); + + // Destruct tracker_ to trigger recording the data to the histogram. + tracker_.reset(); + // The time is still in the first week, so the data gets recorded to + // .FirstWeek histogram. + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime.FirstWeek", + /*sample=*/1, + /*count=*/1); + // There are no data in the .SubsequentWeeks histogram. + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime." + "SubsequentWeeks", + /*sample=*/1, + /*count=*/0); + // Overall total unique Settings changed in the lifetime of the Device. + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime.Total", + /*sample=*/1, + /*count=*/1); + + // Fast forward the time for 7 days and 1 second. We will now record data to + // .SubsequentWeeks instead of .FirstWeek. + task_environment_.FastForwardBy(base::Days(7)); + task_environment_.FastForwardBy(base::Seconds(1)); + + // Create a new PerSessionSettingsUserActionTracker to imitate a newly opened + // Settings page. + tracker_ = + std::make_unique<PerSessionSettingsUserActionTracker>(test_pref_service_); + + // test that the set has been destructed and cleared appropriately + expected_set = {}; + EXPECT_EQ(expected_set, tracker_->GetChangedSettingsForTesting()); + + // Flip the Do Not Disturb toggle twice in Settings. Now that more than 7 days + // has passed since the user has taken OOBE, this change is a unique Setting + // that is changing so the number of unique settings in .SubsequentWeeks + // should increases by 1. + tracker_->RecordSettingChange(Setting::kDoNotDisturbOnOff); + expected_set = {SettingAsIntString(Setting::kDoNotDisturbOnOff)}; + EXPECT_EQ(expected_set, tracker_->GetChangedSettingsForTesting()); + + // Destruct tracker_ to trigger recording the data to the histogram. + tracker_.reset(); + // .FirstWeek will not change + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime.FirstWeek", + /*sample=*/1, + /*count=*/1); + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime." + "SubsequentWeeks", + /*sample=*/1, + /*count=*/1); + // Overall total unique Settings changed in the lifetime of the Device. + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime.Total", + /*sample=*/1, + /*count=*/2); + + // Create a new PerSessionSettingsUserActionTracker to imitate a newly opened + // Settings page. + tracker_ = + std::make_unique<PerSessionSettingsUserActionTracker>(test_pref_service_); + + // test that the set has been destructed and cleared appropriately + expected_set = {}; + EXPECT_EQ(expected_set, tracker_->GetChangedSettingsForTesting()); + + // Flip the Do Not Disturb and WiFi toggles in Settings, this is a unique + // Setting that is changing so the number of unique settings that have been + // changed increases by 1. Note that we are still past the 1 week point, so we + // will add the data to .SubsequentWeeks histogram. + tracker_->RecordSettingChange(Setting::kDoNotDisturbOnOff); + tracker_->RecordSettingChange(Setting::kWifiOnOff); + expected_set = {SettingAsIntString(Setting::kDoNotDisturbOnOff), + SettingAsIntString(Setting::kWifiOnOff)}; + EXPECT_EQ(expected_set, tracker_->GetChangedSettingsForTesting()); + + // Destruct tracker_ to trigger recording the data to the histogram. + tracker_.reset(); + // .FirstWeek will not change + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime.FirstWeek", + /*sample=*/1, + /*count=*/1); + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime." + "SubsequentWeeks", + /*sample=*/1, + /*count=*/1); + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime." + "SubsequentWeeks", + /*sample=*/2, + /*count=*/1); + // Overall total unique Settings changed in the lifetime of the Device. + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime.Total", + /*sample=*/1, + /*count=*/2); + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime.Total", + /*sample=*/2, + /*count=*/1); + + // Create a new PerSessionSettingsUserActionTracker to imitate a newly opened + // Settings page. + tracker_ = + std::make_unique<PerSessionSettingsUserActionTracker>(test_pref_service_); + + // Flip the Do Not Disturb and WiFi toggles. Flip Do Not Disturb toggle again + // in Settings, this is not a unique Setting that is changing so the number of + // unique settings that have been changed does not increase. The bucket sample + // 2 should now have 2 counts. + tracker_->RecordSettingChange(Setting::kDoNotDisturbOnOff); + tracker_->RecordSettingChange(Setting::kWifiOnOff); + tracker_->RecordSettingChange(Setting::kDoNotDisturbOnOff); + // expected_set will not change + EXPECT_EQ(expected_set, tracker_->GetChangedSettingsForTesting()); + + // Destruct tracker_ to trigger recording the data to the histogram. + tracker_.reset(); + + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime.FirstWeek", + /*sample=*/1, + /*count=*/1); + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime." + "SubsequentWeeks", + /*sample=*/1, + /*count=*/1); + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime." + "SubsequentWeeks", + /*sample=*/2, + /*count=*/1); + // Overall total unique Settings changed in the lifetime of the Device. + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime.Total", + /*sample=*/1, + /*count=*/2); + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime.Total", + /*sample=*/2, + /*count=*/1); +} + +TEST_F(PerSessionSettingsUserActionTrackerTest, + TestTotalUniqueChangedSettingsWithinFirstWeek) { + // Simulate that the user has taken OOBE. + test_pref_service_->SetTime(::ash::prefs::kOobeOnboardingTime, + base::Time::Now()); + std::set<std::string> expected_set; + + // Flip the Do Not Disturb and WiFi toggles in Settings, these are unique + // Settings that are changing so the number of unique settings that have been + // changed is 2. + tracker_->RecordSettingChange(Setting::kDoNotDisturbOnOff); + tracker_->RecordSettingChange(Setting::kWifiOnOff); + expected_set = {SettingAsIntString(Setting::kDoNotDisturbOnOff), + SettingAsIntString(Setting::kWifiOnOff)}; + EXPECT_EQ(expected_set, tracker_->GetChangedSettingsForTesting()); + + // Destruct tracker_ to trigger recording the data to the histogram. + tracker_.reset(); + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime.FirstWeek", + /*sample=*/2, + /*count=*/1); + // This is within the first week, no data should be recorded in the + // .SubsequentWeeks histogram + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime." + "SubsequentWeeks", + /*sample=*/2, + /*count=*/0); + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime.Total", + /*sample=*/2, + /*count=*/1); +} + +TEST_F(PerSessionSettingsUserActionTrackerTest, + TestTotalUniqueChangedSettingsAfterFirstWeek) { + // Simulate that the user has taken OOBE. + test_pref_service_->SetTime(::ash::prefs::kOobeOnboardingTime, + base::Time::Now()); + std::set<std::string> expected_set; + // Fast forward the time for 7 days and 1 second. We will now record data to + // .SubsequentWeeks instead of .FirstWeek. + task_environment_.FastForwardBy(base::Days(16)); + + // Flip the Do Not Disturb and WiFi toggles in Settings, these are unique + // Settings that are changing so the number of unique settings that have been + // changed is 2. + tracker_->RecordSettingChange(Setting::kDoNotDisturbOnOff); + tracker_->RecordSettingChange(Setting::kWifiOnOff); + expected_set = {SettingAsIntString(Setting::kDoNotDisturbOnOff), + SettingAsIntString(Setting::kWifiOnOff)}; + EXPECT_EQ(expected_set, tracker_->GetChangedSettingsForTesting()); + + // Destruct tracker_ to trigger recording the data to the histogram. + tracker_.reset(); + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime." + "SubsequentWeeks", + /*sample=*/2, + /*count=*/1); + // This is after the first week, no data should be recorded in the + // .FirstWeek histogram + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime.FirstWeek", + /*sample=*/2, + /*count=*/0); + histogram_tester_.ExpectBucketCount( + "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime.Total", + /*sample=*/2, + /*count=*/1); +} + +TEST_F(PerSessionSettingsUserActionTrackerTest, + TestNoTimeDeltaOpenCloseSettings) { + // Focus on page, close the page immediately. total_time_session_active_ + // should be 0 seconds. + tracker_->RecordPageFocus(); + + // Destruct tracker_ to trigger recording the data to the histogram. + tracker_.reset(); + + histogram_tester_.ExpectTimeBucketCount( + "ChromeOS.Settings.WindowTotalActiveDuration", + /*sample=*/base::Seconds(0), + /*count=*/1); +} + +TEST_F(PerSessionSettingsUserActionTrackerTest, + TestTotalTimeSessionActiveWithBlurAndFocus) { + // Focus on page, wait for 16 seconds to pass, and blur the page. + // total active time should be 16 seconds. + tracker_->RecordPageFocus(); + task_environment_.FastForwardBy(base::Seconds(16)); + tracker_->RecordPageBlur(); + EXPECT_EQ(base::TimeTicks(), + tracker_->GetWindowLastActiveTimeStampForTesting()); + EXPECT_EQ(base::Seconds(16), tracker_->GetTotalTimeSessionActiveForTesting()); + + // When the page is blurred, fast forwarding the time would not increase the + // total active time as the session is not active. + task_environment_.FastForwardBy(base::Seconds(59)); + EXPECT_EQ(base::TimeTicks(), + tracker_->GetWindowLastActiveTimeStampForTesting()); + EXPECT_EQ(base::Seconds(16), tracker_->GetTotalTimeSessionActiveForTesting()); + + // Focus back on the page, the timer should start up again. wait for 1 minute, + // now total active time should accumulate to 16 + 60 = 76 seconds. + tracker_->RecordPageFocus(); + task_environment_.FastForwardBy(base::Minutes(1)); + tracker_->RecordPageBlur(); + EXPECT_EQ(base::TimeTicks(), + tracker_->GetWindowLastActiveTimeStampForTesting()); + EXPECT_EQ(base::Seconds(76), tracker_->GetTotalTimeSessionActiveForTesting()); + tracker_->RecordPageFocus(); + + // Destruct tracker_ to trigger recording the data to the histogram. + tracker_.reset(); + + // Histogram should have 1 count in the 76 seconds bucket. + histogram_tester_.ExpectTimeBucketCount( + "ChromeOS.Settings.WindowTotalActiveDuration", + /*sample=*/base::Seconds(76), + /*count=*/1); +} + +TEST_F(PerSessionSettingsUserActionTrackerTest, + TestMultipleTotalTimeSessionActive) { + // Focus on page, wait for 22 seconds to pass. + tracker_->RecordPageFocus(); + task_environment_.FastForwardBy(base::Seconds(22)); + + // Destruct tracker_ to trigger recording the data to the histogram. + tracker_.reset(); + + // Histogram should have 1 count in the 22 seconds bucket. + histogram_tester_.ExpectTimeBucketCount( + "ChromeOS.Settings.WindowTotalActiveDuration", + /*sample=*/base::Seconds(22), + /*count=*/1); + + // Create a new tracker, focus on page, wait for another 22 seconds to + // pass. + tracker_ = + std::make_unique<PerSessionSettingsUserActionTracker>(test_pref_service_); + tracker_->RecordPageFocus(); + task_environment_.FastForwardBy(base::Seconds(22)); + + // Destruct tracker_ to trigger recording the data to the histogram. + tracker_.reset(); + + // Histogram should have 2 counts in the 22 seconds bucket. + histogram_tester_.ExpectTimeBucketCount( + "ChromeOS.Settings.WindowTotalActiveDuration", + /*sample=*/base::Seconds(22), + /*count=*/2); + + // Create a new tracker, focus on page, this time wait for 3 seconds to + // pass. + tracker_ = + std::make_unique<PerSessionSettingsUserActionTracker>(test_pref_service_); + tracker_->RecordPageFocus(); + task_environment_.FastForwardBy(base::Seconds(3)); + + // Destruct tracker_ to trigger recording the data to the histogram. + tracker_.reset(); + + // Histogram should have 1 count in the 3 seconds bucket, 2 counts in 22 + // seconds bucket. + histogram_tester_.ExpectTimeBucketCount( + "ChromeOS.Settings.WindowTotalActiveDuration", + /*sample=*/base::Seconds(3), + /*count=*/1); + + histogram_tester_.ExpectTimeBucketCount( + "ChromeOS.Settings.WindowTotalActiveDuration", + /*sample=*/base::Seconds(22), + /*count=*/2); +} + } // namespace ash::settings diff --git a/chromium/chrome/browser/ui/webui/settings/ash/settings_user_action_tracker.cc b/chromium/chrome/browser/ui/webui/settings/ash/settings_user_action_tracker.cc index a45bac0e539..e8cc3546686 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/settings_user_action_tracker.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/settings_user_action_tracker.cc @@ -15,8 +15,9 @@ namespace ash::settings { SettingsUserActionTracker::SettingsUserActionTracker( Hierarchy* hierarchy, - OsSettingsSections* sections) - : hierarchy_(hierarchy), sections_(sections) {} + OsSettingsSections* sections, + PrefService* pref_service) + : hierarchy_(hierarchy), sections_(sections), pref_service_(pref_service) {} SettingsUserActionTracker::~SettingsUserActionTracker() = default; @@ -31,16 +32,17 @@ void SettingsUserActionTracker::BindInterface( // New session started, so create a new per session tracker. per_session_tracker_ = - std::make_unique<PerSessionSettingsUserActionTracker>(); + std::make_unique<PerSessionSettingsUserActionTracker>(pref_service_); } void SettingsUserActionTracker::EndCurrentSession() { - // Session ended, so delete the per session tracker. + // reset the pointers per_session_tracker_.reset(); receiver_.reset(); } void SettingsUserActionTracker::OnBindingDisconnected() { + // Settings window is closed by the user, ending the current session. EndCurrentSession(); } @@ -72,7 +74,7 @@ void SettingsUserActionTracker::RecordSettingChange() { void SettingsUserActionTracker::RecordSettingChangeWithDetails( chromeos::settings::mojom::Setting setting, mojom::SettingChangeValuePtr value) { - per_session_tracker_->RecordSettingChange(); + per_session_tracker_->RecordSettingChange(setting); // Get the primary section location of the changed setting and log the metric. chromeos::settings::mojom::Section section_id = diff --git a/chromium/chrome/browser/ui/webui/settings/ash/settings_user_action_tracker.h b/chromium/chrome/browser/ui/webui/settings/ash/settings_user_action_tracker.h index f97388209b6..127689400e5 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/settings_user_action_tracker.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/settings_user_action_tracker.h @@ -11,6 +11,7 @@ #include "base/memory/raw_ptr.h" #include "chrome/browser/ui/webui/settings/ash/search/per_session_settings_user_action_tracker.h" #include "chrome/browser/ui/webui/settings/ash/search/user_action_recorder.mojom.h" +#include "components/prefs/pref_service.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver.h" @@ -24,7 +25,9 @@ class OsSettingsSections; // a per section tracker to record metrics in each section. class SettingsUserActionTracker : public mojom::UserActionRecorder { public: - SettingsUserActionTracker(Hierarchy* hierarchy, OsSettingsSections* sections); + SettingsUserActionTracker(Hierarchy* hierarchy, + OsSettingsSections* sections, + PrefService* pref_service); SettingsUserActionTracker(const SettingsUserActionTracker& other) = delete; SettingsUserActionTracker& operator=(const SettingsUserActionTracker& other) = delete; @@ -66,6 +69,7 @@ class SettingsUserActionTracker : public mojom::UserActionRecorder { raw_ptr<Hierarchy, ExperimentalAsh> hierarchy_; raw_ptr<OsSettingsSections, ExperimentalAsh> sections_; + raw_ptr<PrefService> pref_service_; std::unique_ptr<PerSessionSettingsUserActionTracker> per_session_tracker_; mojo::Receiver<mojom::UserActionRecorder> receiver_{this}; diff --git a/chromium/chrome/browser/ui/webui/settings/ash/settings_user_action_tracker_unittest.cc b/chromium/chrome/browser/ui/webui/settings/ash/settings_user_action_tracker_unittest.cc index 5bba5360c14..574a9cb166f 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/settings_user_action_tracker_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/settings_user_action_tracker_unittest.cc @@ -12,10 +12,16 @@ #include "chrome/browser/ui/webui/settings/ash/search/per_session_settings_user_action_tracker.h" #include "chrome/browser/ui/webui/settings/ash/search/user_action_recorder.mojom.h" #include "chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom.h" +#include "chrome/test/base/browser_with_test_window_test.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 "testing/gtest/include/gtest/gtest.h" namespace ash::settings { +constexpr char kProfileName[] = "user@gmail.com"; + namespace mojom { using ::chromeos::settings::mojom::Section; using ::chromeos::settings::mojom::Setting; @@ -25,14 +31,28 @@ class SettingsUserActionTrackerTest : public testing::Test { protected: SettingsUserActionTrackerTest() : fake_hierarchy_(&fake_sections_), - tracker_(&fake_hierarchy_, &fake_sections_) { + tracker_(&fake_hierarchy_, &fake_sections_, GetTestProfilePref()) { // Initialize per_session_tracker_ manually since BindInterface is never // called on tracker_. tracker_.per_session_tracker_ = - std::make_unique<PerSessionSettingsUserActionTracker>(); + std::make_unique<PerSessionSettingsUserActionTracker>( + testing_profile_->GetPrefs()); } ~SettingsUserActionTrackerTest() override = default; + void SetUpTestingProfile() { + profile_manager_ = std::make_unique<TestingProfileManager>( + TestingBrowserProcess::GetGlobal()); + ASSERT_TRUE(profile_manager_->SetUp()); + testing_profile_ = profile_manager_->CreateTestingProfile(kProfileName); + } + + PrefService* GetTestProfilePref() { + SetUpTestingProfile(); + test_pref_service_ = testing_profile_->GetPrefs(); + return test_pref_service_; + } + // testing::Test: void SetUp() override { fake_hierarchy_.AddSettingMetadata(mojom::Section::kBluetooth, @@ -49,10 +69,18 @@ class SettingsUserActionTrackerTest : public testing::Test { mojom::Setting::kWifiAddNetwork); } + void TearDown() override { tracker_.per_session_tracker_.reset(); } + + // TestingProfile is bound to the IO thread: + // CurrentlyOn(content::BrowserThread::UI). + content::BrowserTaskEnvironment task_environment_; base::HistogramTester histogram_tester_; FakeOsSettingsSections fake_sections_; + raw_ptr<PrefService> test_pref_service_; FakeHierarchy fake_hierarchy_; + std::unique_ptr<TestingProfileManager> profile_manager_; SettingsUserActionTracker tracker_; + TestingProfile* testing_profile_; }; TEST_F(SettingsUserActionTrackerTest, TestRecordSettingChangedBool) { diff --git a/chromium/chrome/browser/ui/webui/settings/ash/tts_handler.cc b/chromium/chrome/browser/ui/webui/settings/ash/tts_handler.cc index 6398b9cdc05..987de613a82 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/tts_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/ash/tts_handler.cc @@ -5,6 +5,7 @@ #include "chrome/browser/ui/webui/settings/ash/tts_handler.h" #include "base/functional/bind.h" +#include "base/i18n/rtl.h" #include "base/json/json_reader.h" #include "base/values.h" #include "chrome/browser/browser_process.h" @@ -68,6 +69,29 @@ void TtsHandler::HandleGetTtsExtensions(const base::Value::List& args) { FireWebUIListener("tts-extensions-updated", responses); } +void TtsHandler::HandleGetDisplayNameForLocale(const base::Value::List& args) { + CHECK_EQ(2U, args.size()); + const std::string callback_id = args[0].GetString(); + const std::string locale = args[1].GetString(); + + const std::u16string display_name = l10n_util::GetDisplayNameForLocale( + locale, g_browser_process->GetApplicationLocale(), true); + + AllowJavascript(); + ResolveJavascriptCallback(callback_id, base::UTF16ToUTF8(display_name)); +} + +void TtsHandler::HandleGetApplicationLocale(const base::Value::List& args) { + CHECK_EQ(1U, args.size()); + const std::string callback_id = args[0].GetString(); + + const std::string& application_locale = + g_browser_process->GetApplicationLocale(); + + AllowJavascript(); + ResolveJavascriptCallback(callback_id, application_locale); +} + void TtsHandler::OnVoicesChanged() { content::TtsController* tts_controller = content::TtsController::GetInstance(); @@ -113,6 +137,14 @@ void TtsHandler::RegisterMessages() { base::BindRepeating(&TtsHandler::HandleGetTtsExtensions, base::Unretained(this))); web_ui()->RegisterMessageCallback( + "getDisplayNameForLocale", + base::BindRepeating(&TtsHandler::HandleGetDisplayNameForLocale, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "getApplicationLocale", + base::BindRepeating(&TtsHandler::HandleGetApplicationLocale, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( "previewTtsVoice", base::BindRepeating(&SettingsWithTtsPreviewHandler::HandlePreviewTtsVoice, base::Unretained(this))); diff --git a/chromium/chrome/browser/ui/webui/settings/ash/tts_handler.h b/chromium/chrome/browser/ui/webui/settings/ash/tts_handler.h index 27f7bf01ef1..a3f81e2a627 100644 --- a/chromium/chrome/browser/ui/webui/settings/ash/tts_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/ash/tts_handler.h @@ -23,6 +23,8 @@ class TtsHandler : public SettingsWithTtsPreviewHandler { void HandleGetAllTtsVoiceData(const base::Value::List& args); void HandleGetTtsExtensions(const base::Value::List& args); + void HandleGetDisplayNameForLocale(const base::Value::List& args); + void HandleGetApplicationLocale(const base::Value::List& args); // SettingsPageUIHandler implementation. void RegisterMessages() override; diff --git a/chromium/chrome/browser/ui/webui/settings/captions_handler.cc b/chromium/chrome/browser/ui/webui/settings/captions_handler.cc index a70e9562636..c3a94da8ae1 100644 --- a/chromium/chrome/browser/ui/webui/settings/captions_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/captions_handler.cc @@ -4,7 +4,9 @@ #include "chrome/browser/ui/webui/settings/captions_handler.h" +#include "base/containers/contains.h" #include "base/functional/bind.h" +#include "base/strings/string_split.h" #include "base/values.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" @@ -33,6 +35,15 @@ namespace { constexpr char kCodeKey[] = "code"; constexpr char kDisplayNameKey[] = "displayName"; constexpr char kNativeDisplayNameKey[] = "nativeDisplayName"; + +// Gets a list of locales enabled by the Finch flag. +std::vector<std::string> GetEnabledLanguages() { + return base::SplitString( + base::GetFieldTrialParamValueByFeature(media::kLiveCaptionMultiLanguage, + "available_languages"), + ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); +} + } // namespace namespace settings { @@ -138,9 +149,11 @@ void CaptionsHandler::HandleInstallLanguagePacks( } base::Value::List CaptionsHandler::GetAvailableLanguagePacks() { + auto enabled_languages = GetEnabledLanguages(); base::Value::List available_language_packs; for (const auto& config : speech::kLanguageComponentConfigs) { - if (config.language_code != speech::LanguageCode::kNone) { + if (config.language_code != speech::LanguageCode::kNone && + base::Contains(enabled_languages, config.language_name)) { base::Value::Dict available_language_pack; available_language_pack.Set(kCodeKey, config.language_name); available_language_pack.Set( diff --git a/chromium/chrome/browser/ui/webui/settings/chrome_cleanup_handler_win.cc b/chromium/chrome/browser/ui/webui/settings/chrome_cleanup_handler_win.cc deleted file mode 100644 index e0daa4e0757..00000000000 --- a/chromium/chrome/browser/ui/webui/settings/chrome_cleanup_handler_win.cc +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright 2017 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/webui/settings/chrome_cleanup_handler_win.h" - -#include <memory> -#include <set> -#include <string> -#include <utility> - -#include "base/command_line.h" -#include "base/feature_list.h" -#include "base/functional/bind.h" -#include "base/metrics/histogram_macros.h" -#include "base/metrics/user_metrics.h" -#include "base/metrics/user_metrics_action.h" -#include "base/strings/string_util.h" -#include "base/synchronization/lock.h" -#include "base/values.h" -#include "build/branding_buildflags.h" -#include "build/build_config.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h" -#include "chrome/grit/generated_resources.h" -#include "components/component_updater/pref_names.h" -#include "components/prefs/pref_service.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_ui.h" -#include "content/public/browser/web_ui_message_handler.h" -#include "ui/base/l10n/l10n_util.h" - -using safe_browsing::ChromeCleanerController; - -namespace settings { - -namespace { - -// Returns a base::Value::List containing a copy of the file paths stored in -// |files|. -base::Value::List GetFilesAsListStorage(const std::set<base::FilePath>& files) { - base::Value::List value; - for (const base::FilePath& path : files) { - base::Value::Dict item; - item.Set("dirname", path.DirName().AsEndingWithSeparator().AsUTF8Unsafe()); - item.Set("basename", path.BaseName().AsUTF8Unsafe()); - value.Append(std::move(item)); - } - return value; -} - -// Returns a base::Value::List containing a copy of the strings stored in -// |string_set|. -base::Value::List GetStringSetAsListStorage( - const std::set<std::wstring>& string_set) { - base::Value::List value; - for (const std::wstring& string : string_set) - value.Append(base::AsString16(string)); - - return value; -} - -base::Value::Dict GetScannerResultsAsDictionary( - const safe_browsing::ChromeCleanerScannerResults& scanner_results, - Profile* profile) { - base::Value::Dict value; - value.Set("files", GetFilesAsListStorage(scanner_results.files_to_delete())); - value.Set("registryKeys", - GetStringSetAsListStorage(scanner_results.registry_keys())); - return value; -} - -std::string IdleReasonToString( - ChromeCleanerController::IdleReason idle_reason) { - switch (idle_reason) { - case ChromeCleanerController::IdleReason::kInitial: - return "initial"; - case ChromeCleanerController::IdleReason::kReporterFoundNothing: - return "reporter_found_nothing"; - case ChromeCleanerController::IdleReason::kReporterFailed: - return "reporter_failed"; - case ChromeCleanerController::IdleReason::kScanningFoundNothing: - return "scanning_found_nothing"; - case ChromeCleanerController::IdleReason::kScanningFailed: - return "scanning_failed"; - case ChromeCleanerController::IdleReason::kConnectionLost: - return "connection_lost"; - case ChromeCleanerController::IdleReason::kUserDeclinedCleanup: - return "user_declined_cleanup"; - case ChromeCleanerController::IdleReason::kCleaningFailed: - return "cleaning_failed"; - case ChromeCleanerController::IdleReason::kCleaningSucceeded: - return "cleaning_succeeded"; - case ChromeCleanerController::IdleReason::kCleanerDownloadFailed: - return "cleaner_download_failed"; - } - NOTREACHED(); - return ""; -} - -} // namespace - -ChromeCleanupHandler::ChromeCleanupHandler(Profile* profile) - : controller_(ChromeCleanerController::GetInstance()), profile_(profile) {} - -ChromeCleanupHandler::~ChromeCleanupHandler() { - controller_->RemoveObserver(this); -} - -void ChromeCleanupHandler::RegisterMessages() { - web_ui()->RegisterMessageCallback( - "registerChromeCleanerObserver", - base::BindRepeating( - &ChromeCleanupHandler::HandleRegisterChromeCleanerObserver, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "startScanning", - base::BindRepeating(&ChromeCleanupHandler::HandleStartScanning, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "restartComputer", - base::BindRepeating(&ChromeCleanupHandler::HandleRestartComputer, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "startCleanup", - base::BindRepeating(&ChromeCleanupHandler::HandleStartCleanup, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "notifyShowDetails", - base::BindRepeating(&ChromeCleanupHandler::HandleNotifyShowDetails, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "notifyChromeCleanupLearnMoreClicked", - base::BindRepeating( - &ChromeCleanupHandler::HandleNotifyChromeCleanupLearnMoreClicked, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "getMoreItemsPluralString", - base::BindRepeating(&ChromeCleanupHandler::HandleGetMoreItemsPluralString, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "getItemsToRemovePluralString", - base::BindRepeating( - &ChromeCleanupHandler::HandleGetItemsToRemovePluralString, - base::Unretained(this))); -} - -void ChromeCleanupHandler::OnJavascriptAllowed() { - controller_->AddObserver(this); -} - -void ChromeCleanupHandler::OnJavascriptDisallowed() { - controller_->RemoveObserver(this); -} - -void ChromeCleanupHandler::OnIdle( - ChromeCleanerController::IdleReason idle_reason) { - FireWebUIListener("chrome-cleanup-on-idle", - base::Value(IdleReasonToString(idle_reason))); -} - -void ChromeCleanupHandler::OnScanning() { - FireWebUIListener("chrome-cleanup-on-scanning"); -} - -void ChromeCleanupHandler::OnReporterRunning() { - FireWebUIListener("chrome-cleanup-on-reporter-running"); -} - -void ChromeCleanupHandler::OnInfected( - bool is_powered_by_partner, - const safe_browsing::ChromeCleanerScannerResults& scanner_results) { - FireWebUIListener("chrome-cleanup-on-infected", - base::Value(is_powered_by_partner), - GetScannerResultsAsDictionary(scanner_results, profile_)); -} - -void ChromeCleanupHandler::OnCleaning( - bool is_powered_by_partner, - const safe_browsing::ChromeCleanerScannerResults& scanner_results) { - FireWebUIListener("chrome-cleanup-on-cleaning", - base::Value(is_powered_by_partner), - GetScannerResultsAsDictionary(scanner_results, profile_)); -} - -void ChromeCleanupHandler::OnRebootRequired() { - FireWebUIListener("chrome-cleanup-on-reboot-required"); -} - -void ChromeCleanupHandler::HandleRegisterChromeCleanerObserver( - const base::Value::List& args) { - DCHECK_EQ(0U, args.size()); - - base::RecordAction( - base::UserMetricsAction("SoftwareReporter.CleanupWebui_Shown")); - AllowJavascript(); - - FireWebUIListener("chrome-cleanup-enabled-change", - base::Value(controller_->IsAllowedByPolicy())); -} - -void ChromeCleanupHandler::HandleStartScanning(const base::Value::List& args) { - CHECK_EQ(1U, args.size()); - bool allow_logs_upload = false; - if (args[0].is_bool()) - allow_logs_upload = args[0].GetBool(); - - // If this operation is not allowed the UI should be disabled. - CHECK(controller_->IsAllowedByPolicy()); - - // The state is propagated to all open tabs and should be consistent. - DCHECK_EQ(controller_->logs_enabled(profile_), allow_logs_upload); - - controller_->RequestUserInitiatedScan(profile_); - - base::RecordAction( - base::UserMetricsAction("SoftwareReporter.CleanupWebui_StartScanning")); -} - -void ChromeCleanupHandler::HandleRestartComputer( - const base::Value::List& args) { - DCHECK_EQ(0U, args.size()); - - base::RecordAction( - base::UserMetricsAction("SoftwareReporter.CleanupWebui_RestartComputer")); - - controller_->Reboot(); -} - -void ChromeCleanupHandler::HandleStartCleanup(const base::Value::List& args) { - CHECK_EQ(1U, args.size()); - bool allow_logs_upload = false; - if (args[0].is_bool()) - allow_logs_upload = args[0].GetBool(); - - // The state is propagated to all open tabs and should be consistent. - DCHECK_EQ(controller_->logs_enabled(profile_), allow_logs_upload); - - base::RecordAction( - base::UserMetricsAction("SoftwareReporter.CleanupWebui_StartCleanup")); - - controller_->ReplyWithUserResponse( - profile_, - allow_logs_upload - ? ChromeCleanerController::UserResponse::kAcceptedWithLogs - : ChromeCleanerController::UserResponse::kAcceptedWithoutLogs); -} - -void ChromeCleanupHandler::HandleNotifyShowDetails( - const base::Value::List& args) { - CHECK_EQ(1U, args.size()); - bool details_section_visible = false; - if (args[0].is_bool()) - details_section_visible = args[0].GetBool(); - - if (details_section_visible) { - base::RecordAction( - base::UserMetricsAction("SoftwareReporter.CleanupWebui_ShowDetails")); - } else { - base::RecordAction( - base::UserMetricsAction("SoftwareReporter.CleanupWebui_HideDetails")); - } -} - -void ChromeCleanupHandler::HandleNotifyChromeCleanupLearnMoreClicked( - const base::Value::List& args) { - CHECK_EQ(0U, args.size()); - - base::RecordAction( - base::UserMetricsAction("SoftwareReporter.CleanupWebui_LearnMore")); -} - -void ChromeCleanupHandler::HandleGetMoreItemsPluralString( - const base::Value::List& args) { -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - GetPluralString(IDS_SETTINGS_RESET_CLEANUP_DETAILS_MORE, args); -#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -} - -void ChromeCleanupHandler::HandleGetItemsToRemovePluralString( - const base::Value::List& args) { -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - GetPluralString(IDS_SETTINGS_RESET_CLEANUP_DETAILS_ITEMS_TO_BE_REMOVED, args); -#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -} - -void ChromeCleanupHandler::GetPluralString(int id, - const base::Value::List& args) { - const auto& list = args; - CHECK_EQ(2U, list.size()); - - std::string callback_id = list[0].GetString(); - - int num_items = list[1].GetIfInt().value_or(0); - - const std::u16string plural_string = - num_items > 0 ? l10n_util::GetPluralStringFUTF16(id, num_items) - : std::u16string(); - ResolveJavascriptCallback(base::Value(callback_id), - base::Value(plural_string)); -} - -} // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/chrome_cleanup_handler_win.h b/chromium/chrome/browser/ui/webui/settings/chrome_cleanup_handler_win.h deleted file mode 100644 index e79cfd62430..00000000000 --- a/chromium/chrome/browser/ui/webui/settings/chrome_cleanup_handler_win.h +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2017 The Chromium Authors -// 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_CHROME_CLEANUP_HANDLER_WIN_H_ -#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROME_CLEANUP_HANDLER_WIN_H_ - -#include "base/memory/raw_ptr.h" -#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h" -#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_scanner_results_win.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 ChromeCleanerController; -} - -namespace settings { - -// Chrome Cleanup settings page UI handler. -class ChromeCleanupHandler - : public SettingsPageUIHandler, - public safe_browsing::ChromeCleanerController::Observer { - public: - explicit ChromeCleanupHandler(Profile* profile); - - ChromeCleanupHandler(const ChromeCleanupHandler&) = delete; - ChromeCleanupHandler& operator=(const ChromeCleanupHandler&) = delete; - - ~ChromeCleanupHandler() override; - - // SettingsPageUIHandler implementation. - void RegisterMessages() override; - void OnJavascriptAllowed() override; - void OnJavascriptDisallowed() override; - - // ChromeCleanerController::Observer implementation. - void OnIdle( - safe_browsing::ChromeCleanerController::IdleReason idle_reason) override; - void OnReporterRunning() override; - void OnScanning() override; - void OnInfected(bool is_powered_by_partner, - const safe_browsing::ChromeCleanerScannerResults& - reported_results) override; - void OnCleaning(bool is_powered_by_partner, - const safe_browsing::ChromeCleanerScannerResults& - reported_results) override; - void OnRebootRequired() override; - - private: - // Callback for the "registerChromeCleanerObserver" message. This registers - // this object as an observer of the Chrome Cleanup global state and - // and retrieves the current cleanup state. - void HandleRegisterChromeCleanerObserver(const base::Value::List& args); - - // Callback for the "startScanning" message to start scanning the user's - // system to detect unwanted software. - void HandleStartScanning(const base::Value::List& args); - - // Callback for the "restartComputer" message to finalize the cleanup with a - // system restart. - void HandleRestartComputer(const base::Value::List& args); - - // Callback for the "startCleanup" message to start removing unwanted - // software from the user's computer. - void HandleStartCleanup(const base::Value::List& args); - - // Callback for the "showDetails" message that notifies Chrome about whether - // the user expanded or closed the details section of the page. - void HandleNotifyShowDetails(const base::Value::List& args); - - // Callback for the "chromeCleanupLearnMore" message that notifies Chrome that - // the "learn more" link was clicked. - void HandleNotifyChromeCleanupLearnMoreClicked(const base::Value::List& args); - - // Callback for the "getMoreItemsPluralString" message, that obtains the text - // string for the "show more" items on the detailed view. - void HandleGetMoreItemsPluralString(const base::Value::List& args); - - // Callback for the "getItemsToRemovePluralString" message, that obtains the - // text string for the detailed view when user-initiated cleanups are enabled. - void HandleGetItemsToRemovePluralString(const base::Value::List& args); - - void GetPluralString(int id, const base::Value::List& args); - - // Raw pointer to a singleton. Must outlive this object. - raw_ptr<safe_browsing::ChromeCleanerController> controller_; - - raw_ptr<Profile> profile_; -}; - -} // namespace settings - -#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROME_CLEANUP_HANDLER_WIN_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/OWNERS b/chromium/chrome/browser/ui/webui/settings/chromeos/OWNERS index 96f54b2cb48..7942dfa92ff 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/OWNERS +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/OWNERS @@ -1 +1 @@ -file://chrome/browser/resources/settings/chromeos/OWNERS +file://chrome/browser/resources/ash/settings/OWNERS diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom b/chromium/chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom index dfa3307a923..fb28c8abb20 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom @@ -4,9 +4,10 @@ module chromeos.settings.mojom; -// Chrome OS Settings sections (i.e., top-level navigation items). Each section -// has a corresponding path string listed below. Numerical values are used for -// metrics; do not change or reuse values. +// ChromeOS Settings sections (i.e., top-level pages & their navigation items). +// Each section has a corresponding path string listed below. Numerical values +// are used for metrics. +// DO NOT change or reuse values. enum Section { kNetwork = 0, kBluetooth = 1, @@ -45,6 +46,7 @@ enum Subpage { kVpnDetails = 7, kApn = 8, kHotspotDetails = 9, + kPasspointDetails = 10, // Bluetooth section. kBluetoothDevices = 100, @@ -85,6 +87,7 @@ enum Subpage { kPerDeviceTouchpad = 411, kPerDevicePointingStick = 412, kPerDeviceKeyboardRemapKeys = 413, + kGraphicsTablet = 414, // Personalization section. // 500 was used for kChangePicture. Do not reuse. @@ -148,6 +151,7 @@ enum Subpage { kNetworkFileShares = 1300, kOfficeFiles = 1301, kGoogleDrive = 1302, + kOneDrive = 1303, // Printing section. kPrintingDetails = 1400, @@ -178,16 +182,18 @@ enum Subpage { // Network section. const string kNetworkSectionPath = "internet"; const string kEthernetDetailsSubpagePath = "networkDetail"; +const string kNetworksSubpageBasePath = "networks"; const string kWifiNetworksSubpagePath = "networks?type=WiFi"; -const string kWifiDetailsSubpagePath = "networkDetail"; -const string kKnownNetworksSubpagePath = "knownNetworks"; const string kCellularNetworksSubpagePath = "networks?type=Cellular"; const string kMobileDataNetworksSubpagePath = "networks?type=Tether"; +const string kKnownNetworksSubpagePath = "knownNetworks"; +const string kWifiDetailsSubpagePath = "networkDetail"; const string kCellularDetailsSubpagePath = "networkDetail"; const string kTetherDetailsSubpagePath = "networkDetail"; const string kVpnDetailsSubpagePath = "networkDetail"; const string kApnSubpagePath = "apn"; const string kHotspotSubpagePath = "hotspotDetail"; +const string kPasspointDetailSubpagePath = "passpointDetail"; // Bluetooth section. const string kBluetoothSectionPath = "bluetooth"; @@ -223,6 +229,7 @@ const string kAudioSubpagePath = "audio"; const string kStorageSubpagePath = "storage"; const string kExternalStorageSubpagePath = "storage/externalStoragePreferences"; const string kPowerSubpagePath = "power"; +const string kGraphicsTabletSubpagePath = "graphics-tablet"; // Personalization section. const string kPersonalizationSectionPath = "personalization"; @@ -285,8 +292,9 @@ const string kJapaneseManageUserDictionarySubpagePath = // Files section. const string kFilesSectionPath = "files"; const string kGoogleDriveSubpagePath = "googleDrive"; -const string kNetworkFileSharesSubpagePath = "smbShares"; +const string kOneDriveSubpagePath = "oneDrive"; const string kOfficeFilesSubpagePath = "officeFiles"; +const string kNetworkFileSharesSubpagePath = "smbShares"; // Printing section. const string kPrintingSectionPath = "osPrinting"; diff --git a/chromium/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom b/chromium/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom index c4f71859a82..02bfa2e447d 100644 --- a/chromium/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom +++ b/chromium/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom @@ -144,6 +144,9 @@ enum Setting { kAdaptiveCharging = 440, kKeyboardBlockMetaFkeyRewrites = 441, kKeyboardRemapKeys = 442, + kChargingSounds = 443, + kLowBatterySound = 444, + kBatterySaver = 445, // Personalization section. kOpenWallpaper = 500, @@ -215,6 +218,8 @@ enum Setting { kCameraOnOff = 1116, kMicrophoneOnOff = 1117, kGeolocationOnOff = 1118, + kLockScreenNotification = 1119, + kSpeakOnMuteDetectionOnOff = 1120, // Languages and Input section. kAddLanguage = 1200, diff --git a/chromium/chrome/browser/ui/webui/settings/downloads_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/downloads_handler_unittest.cc index 1befd7801a7..ac9c7dc9c9e 100644 --- a/chromium/chrome/browser/ui/webui/settings/downloads_handler_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/downloads_handler_unittest.cc @@ -81,7 +81,8 @@ class DownloadsHandlerTest : public testing::Test { raw_ptr<DownloadCoreService> service_; raw_ptr<content::MockDownloadManager> download_manager_; // Owned by |profile_|. - raw_ptr<ChromeDownloadManagerDelegate> chrome_download_manager_delegate_; + raw_ptr<ChromeDownloadManagerDelegate, DanglingUntriaged> + chrome_download_manager_delegate_; bool connection_policy_enabled_; std::string account_name_, account_login_, folder_name_, folder_id_; diff --git a/chromium/chrome/browser/ui/webui/settings/extensions_safety_check_handler.cc b/chromium/chrome/browser/ui/webui/settings/extensions_safety_check_handler.cc deleted file mode 100644 index f44a00e9aaa..00000000000 --- a/chromium/chrome/browser/ui/webui/settings/extensions_safety_check_handler.cc +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/webui/settings/extensions_safety_check_handler.h" - -#include "chrome/grit/generated_resources.h" -#include "ui/base/l10n/l10n_util.h" - -namespace settings { - -ExtensionsSafetyCheckHandler::ExtensionsSafetyCheckHandler() = default; - -ExtensionsSafetyCheckHandler::~ExtensionsSafetyCheckHandler() = default; - -void ExtensionsSafetyCheckHandler::HandleGetExtensionsThatNeedReview( - const base::Value::List& args) { - const base::Value& callback_id = args[0]; - AllowJavascript(); - ResolveJavascriptCallback(callback_id, - base::Value(GetExtensionsThatNeedReview())); -} - -std::u16string ExtensionsSafetyCheckHandler::GetExtensionsThatNeedReview() { - // TODO(psarouthakis): Replace skeleton code to return real number of - // extensions that need to be reviewed via the CWSInfoService and - // update the string ID to use new extensions safety check strings. - return (l10n_util::GetPluralStringFUTF16( - IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_BLOCKLISTED_OFF, 1)); -} - -void ExtensionsSafetyCheckHandler::OnJavascriptAllowed() {} - -void ExtensionsSafetyCheckHandler::OnJavascriptDisallowed() {} - -void ExtensionsSafetyCheckHandler::RegisterMessages() { - // Usage of base::Unretained(this) is safe, because web_ui() owns `this` and - // won't release ownership until destruction. - web_ui()->RegisterMessageCallback( - "getExtensionsThatNeedReview", - base::BindRepeating( - &ExtensionsSafetyCheckHandler::HandleGetExtensionsThatNeedReview, - base::Unretained(this))); -} - -} // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/extensions_safety_check_handler.h b/chromium/chrome/browser/ui/webui/settings/extensions_safety_check_handler.h deleted file mode 100644 index d53037d0902..00000000000 --- a/chromium/chrome/browser/ui/webui/settings/extensions_safety_check_handler.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2023 The Chromium Authors -// 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_EXTENSIONS_SAFETY_CHECK_HANDLER_H_ -#define CHROME_BROWSER_UI_WEBUI_SETTINGS_EXTENSIONS_SAFETY_CHECK_HANDLER_H_ - -#include "base/memory/raw_ptr.h" -#include "base/memory/weak_ptr.h" -#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" - -namespace settings { - -// Settings page UI handler that checks for any extensions that trigger -// a review by the safety check. -class ExtensionsSafetyCheckHandler : public settings::SettingsPageUIHandler { - public: - ExtensionsSafetyCheckHandler(); - ~ExtensionsSafetyCheckHandler() override; - - protected: - // Return the display string that represents how many extensions - // need to be reviewed by the user. - std::u16string GetExtensionsThatNeedReview(); - - private: - // Calculate the number of extensions that need to be reviewed by the - // user. - void HandleGetExtensionsThatNeedReview(const base::Value::List& args); - - // SettingsPageUIHandler implementation. - void OnJavascriptDisallowed() override; - void OnJavascriptAllowed() override; - - // WebUIMessageHandler implementation. - void RegisterMessages() override; - - base::WeakPtrFactory<ExtensionsSafetyCheckHandler> weak_ptr_factory_{this}; -}; - -} // namespace settings - -#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_EXTENSIONS_SAFETY_CHECK_HANDLER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/extensions_safety_check_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/extensions_safety_check_handler_unittest.cc deleted file mode 100644 index 30958e0c9ad..00000000000 --- a/chromium/chrome/browser/ui/webui/settings/extensions_safety_check_handler_unittest.cc +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/webui/settings/extensions_safety_check_handler.h" - -#include <string> - -#include "chrome/test/base/testing_profile.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { -class TestingExtensionsSafetyCheckHandler - : public settings::ExtensionsSafetyCheckHandler { - public: - using ExtensionsSafetyCheckHandler::AllowJavascript; - using ExtensionsSafetyCheckHandler::DisallowJavascript; - using ExtensionsSafetyCheckHandler::GetExtensionsThatNeedReview; -}; - -} // namespace - -class ExtensionsSafetyCheckHandlerTest : public testing::Test { - protected: - std::unique_ptr<TestingProfile> profile_; - std::unique_ptr<TestingExtensionsSafetyCheckHandler> entry_point_handler_; - base::test::ScopedFeatureList feature_list_; -}; - -TEST_F(ExtensionsSafetyCheckHandlerTest, GetExtensionsThatNeedReviewTest) { - // Display string for 1 triggering extension. - std::u16string display_string = - u"1 potentially harmful extension is off. You can also remove it."; - EXPECT_EQ(display_string, - entry_point_handler_->GetExtensionsThatNeedReview()); -} diff --git a/chromium/chrome/browser/ui/webui/settings/hats_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/hats_handler_unittest.cc index 14701e76e20..54c4e57cea4 100644 --- a/chromium/chrome/browser/ui/webui/settings/hats_handler_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/hats_handler_unittest.cc @@ -80,8 +80,9 @@ class HatsHandlerTest : public ChromeRenderViewHostTestHarness { content::TestWebUI* web_ui() { return web_ui_.get(); } HatsHandler* handler() { return handler_.get(); } - raw_ptr<MockHatsService> mock_hats_service_; - raw_ptr<MockTrustSafetySentimentService> mock_sentiment_service_; + raw_ptr<MockHatsService, DanglingUntriaged> mock_hats_service_; + raw_ptr<MockTrustSafetySentimentService, DanglingUntriaged> + mock_sentiment_service_; protected: // This should only be accessed in the test constructor, to avoid race diff --git a/chromium/chrome/browser/ui/webui/settings/metrics_reporting_handler.cc b/chromium/chrome/browser/ui/webui/settings/metrics_reporting_handler.cc index dceb42b0b3e..7c87022bd5b 100644 --- a/chromium/chrome/browser/ui/webui/settings/metrics_reporting_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/metrics_reporting_handler.cc @@ -104,7 +104,7 @@ void MetricsReportingHandler::HandleSetMetricsReportingEnabled( if (!lacros_chrome_service) return; // The metrics reporting API was added in Chrome OS 89. - if (!lacros_chrome_service->IsMetricsReportingAvailable()) { + if (!lacros_chrome_service->IsSupported<crosapi::mojom::MetricsReporting>()) { LOG(WARNING) << "MetricsReporting API not available"; return; } diff --git a/chromium/chrome/browser/ui/webui/settings/people_handler.cc b/chromium/chrome/browser/ui/webui/settings/people_handler.cc index 16e81bb2922..77ebeea4178 100644 --- a/chromium/chrome/browser/ui/webui/settings/people_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/people_handler.cc @@ -54,8 +54,8 @@ #include "components/strings/grit/components_strings.h" #include "components/sync/base/passphrase_enums.h" #include "components/sync/base/user_selectable_type.h" -#include "components/sync/driver/sync_service_utils.h" -#include "components/sync/driver/sync_user_settings.h" +#include "components/sync/service/sync_service_utils.h" +#include "components/sync/service/sync_user_settings.h" #include "components/unified_consent/unified_consent_metrics.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" @@ -433,10 +433,6 @@ void PeopleHandler::HandleSetDatatypes(const base::Value::List& args) { // Choosing data types to sync never fails. ResolveJavascriptCallback(*callback_id, base::Value(kConfigurePageStatus)); - - ProfileMetrics::LogProfileSyncInfo(ProfileMetrics::SYNC_CUSTOMIZE); - if (!configuration.sync_everything) - ProfileMetrics::LogProfileSyncInfo(ProfileMetrics::SYNC_CHOOSE); } void PeopleHandler::HandleGetStoredAccounts(const base::Value::List& args) { @@ -546,8 +542,6 @@ void PeopleHandler::HandleSetEncryptionPassphrase( } else { sync_user_settings->SetEncryptionPassphrase(passphrase); successfully_set = true; - ProfileMetrics::LogProfileSyncInfo( - ProfileMetrics::SYNC_CREATED_NEW_PASSPHRASE); } ResolveJavascriptCallback(callback_id, base::Value(successfully_set)); } @@ -573,10 +567,6 @@ void PeopleHandler::HandleSetDecryptionPassphrase( bool successfully_set = false; if (!passphrase.empty() && sync_user_settings->IsPassphraseRequired()) { successfully_set = sync_user_settings->SetDecryptionPassphrase(passphrase); - if (successfully_set) { - ProfileMetrics::LogProfileSyncInfo( - ProfileMetrics::SYNC_ENTERED_EXISTING_PASSPHRASE); - } } ResolveJavascriptCallback(callback_id, base::Value(successfully_set)); } @@ -782,15 +772,16 @@ void PeopleHandler::CloseSyncSetup() { // (i.e. if the user is running in guest mode in cros and brings up settings). LoginUIService* service = GetLoginUIService(); if (service) { + auto self_weak_ptr = weak_factory_.GetWeakPtr(); syncer::SyncService* sync_service = GetSyncService(); // Don't log a cancel event if the sync setup dialog is being // automatically closed due to an auth error. if ((service->current_login_ui() == this) && - (!sync_service || - (!sync_service->GetUserSettings()->IsFirstSetupComplete() && - sync_service->GetAuthError().state() == - GoogleServiceAuthError::NONE))) { + (!sync_service || (!sync_service->GetUserSettings() + ->IsInitialSyncFeatureSetupComplete() && + sync_service->GetAuthError().state() == + GoogleServiceAuthError::NONE))) { if (configuring_sync_) { // If the user clicked "Cancel" while setting up sync, disable sync // because we don't want the sync engine to remain in the @@ -805,7 +796,8 @@ void PeopleHandler::CloseSyncSetup() { #if !BUILDFLAG(IS_CHROMEOS_ASH) // Revoke sync consent on desktop Chrome if they click cancel during // initial setup or close sync setup without confirming sync. - if (!sync_service->GetUserSettings()->IsFirstSetupComplete()) { + if (!sync_service->GetUserSettings() + ->IsInitialSyncFeatureSetupComplete()) { IdentityManagerFactory::GetForProfile(profile_) ->GetPrimaryAccountMutator() ->RevokeSyncConsent( @@ -818,6 +810,14 @@ void PeopleHandler::CloseSyncSetup() { } service->LoginUIClosed(this); + + // The call to RevokeSyncConsent() above may delete the current browser that + // owns `this` if force signin is enabled. Accessing instance members caused + // crashes (see https://crbug.com/1441820) which we guard against by + // checking a weak pointer to the current instance. + if (!self_weak_ptr) { + return; + } } // Alert the sync service anytime the sync setup dialog is closed. This can @@ -894,7 +894,7 @@ void PeopleHandler::BeforeUnloadDialogCancelled() { signin::ConsentLevel::kSync)); syncer::SyncService* service = GetSyncService(); DCHECK(service && service->IsSetupInProgress() && - !service->GetUserSettings()->IsFirstSetupComplete()); + !service->GetUserSettings()->IsInitialSyncFeatureSetupComplete()); base::RecordAction( base::UserMetricsAction("Signin_Signin_CancelAbortAdvancedSyncSettings")); @@ -909,15 +909,10 @@ base::Value::Dict PeopleHandler::GetSyncStatusDictionary() const { } sync_status.Set("supervisedUser", profile_->IsChild()); - sync_status.Set("childUser", profile_->IsChild()); auto* identity_manager = IdentityManagerFactory::GetForProfile(profile_); DCHECK(identity_manager); - // TODO(crbug.com/1369982): |domain| is used to show the profile deletion - // dialog on turn off sync. This is no longer needed since users are allowed - // to turn off sync. Enterprise team to decide whether to show the delete - // profile dialog on signout. if (identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSignin)) { CoreAccountInfo primary_account_info = identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin); @@ -942,7 +937,7 @@ base::Value::Dict PeopleHandler::GetSyncStatusDictionary() const { sync_status.Set( "firstSetupInProgress", service && !disallowed_by_policy && service->IsSetupInProgress() && - !service->GetUserSettings()->IsFirstSetupComplete() && + !service->GetUserSettings()->IsInitialSyncFeatureSetupComplete() && identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync)); const SyncStatusLabels status_labels = GetSyncStatusLabels(profile_); @@ -1081,15 +1076,16 @@ void PeopleHandler::MarkFirstSetupComplete() { service->SetSyncFeatureRequested(); // If the first-time setup is already complete, there's nothing else to do. - if (service->GetUserSettings()->IsFirstSetupComplete()) + if (service->GetUserSettings()->IsInitialSyncFeatureSetupComplete()) { return; + } unified_consent::metrics::RecordSyncSetupDataTypesHistrogam( service->GetUserSettings(), profile_->GetPrefs()); // We're done configuring, so notify SyncService that it is OK to start // syncing. - service->GetUserSettings()->SetFirstSetupComplete( + service->GetUserSettings()->SetInitialSyncFeatureSetupComplete( syncer::SyncFirstSetupCompleteSource::ADVANCED_FLOW_CONFIRM); FireWebUIListener("sync-settings-saved"); } diff --git a/chromium/chrome/browser/ui/webui/settings/people_handler.h b/chromium/chrome/browser/ui/webui/settings/people_handler.h index 09d2ab80866..5c6ec3870af 100644 --- a/chromium/chrome/browser/ui/webui/settings/people_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/people_handler.h @@ -20,8 +20,8 @@ #include "components/prefs/pref_change_registrar.h" #include "components/signin/public/base/signin_buildflags.h" #include "components/signin/public/identity_manager/identity_manager.h" -#include "components/sync/driver/sync_service.h" -#include "components/sync/driver/sync_service_observer.h" +#include "components/sync/service/sync_service.h" +#include "components/sync/service/sync_service_observer.h" #include "content/public/browser/web_contents_observer.h" class LoginUIService; @@ -233,7 +233,7 @@ class PeopleHandler : public SettingsPageUIHandler, void InitializeSyncBlocker(); // Weak pointer. - raw_ptr<Profile> profile_; + raw_ptr<Profile, DanglingUntriaged> profile_; // Prevents Sync from running until configuration is complete. std::unique_ptr<syncer::SyncSetupInProgressHandle> sync_blocker_; 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 adb1ed37d8a..11918015874 100644 --- a/chromium/chrome/browser/ui/webui/settings/people_handler_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/people_handler_unittest.cc @@ -48,7 +48,7 @@ #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/sync_user_settings_impl.h" +#include "components/sync/service/sync_user_settings_impl.h" #include "components/sync/test/mock_sync_service.h" #include "components/sync/test/sync_user_settings_mock.h" #include "content/public/browser/web_contents.h" @@ -112,8 +112,6 @@ std::string GetConfiguration(SyncAllDataConfig sync_all, result.Set("themesSynced", types.Has(syncer::UserSelectableType::kThemes)); result.Set("typedUrlsSynced", types.Has(syncer::UserSelectableType::kHistory)); - result.Set("wifiConfigurationsSynced", - types.Has(syncer::UserSelectableType::kWifiConfigurations)); result.Set("paymentsIntegrationEnabled", false); // Reading list doesn't really have a UI and is supported on ios only. @@ -166,8 +164,6 @@ void CheckConfigDataTypeArguments(const base::Value::Dict& dictionary, types.Has(syncer::UserSelectableType::kThemes)); ExpectHasBoolKey(dictionary, "typedUrlsSynced", types.Has(syncer::UserSelectableType::kHistory)); - ExpectHasBoolKey(dictionary, "wifiConfigurationsSynced", - types.Has(syncer::UserSelectableType::kWifiConfigurations)); } std::unique_ptr<KeyedService> BuildMockSyncService( @@ -366,7 +362,7 @@ class PeopleHandlerTest : public ChromeRenderViewHostTestHarness { testing::NiceMock<base::MockCallback<base::RepeatingClosure>> mock_on_setup_in_progress_handle_destroyed_; - raw_ptr<syncer::MockSyncService> mock_sync_service_; + raw_ptr<syncer::MockSyncService, DanglingUntriaged> mock_sync_service_; std::unique_ptr<IdentityTestEnvironmentProfileAdaptor> identity_test_env_adaptor_; content::TestWebUI web_ui_; @@ -384,8 +380,10 @@ TEST_F(PeopleHandlerTest, DisplayBasicLogin) { handler_->DisallowJavascript(); ON_CALL(*mock_sync_service_, GetDisableReasons()) - .WillByDefault(Return(syncer::SyncService::DISABLE_REASON_NOT_SIGNED_IN)); - ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsFirstSetupComplete()) + .WillByDefault(Return(syncer::SyncService::DisableReasonSet( + {syncer::SyncService::DISABLE_REASON_NOT_SIGNED_IN}))); + ON_CALL(*mock_sync_service_->GetMockUserSettings(), + IsInitialSyncFeatureSetupComplete()) .WillByDefault(Return(false)); // Ensure that the user is not signed in before calling |HandleStartSignin()|. identity_test_env()->ClearPrimaryAccount(); @@ -411,7 +409,8 @@ TEST_F(PeopleHandlerTest, DisplayConfigureWithEngineDisabledAndCancel) { CreatePeopleHandler(); ON_CALL(*mock_sync_service_, GetDisableReasons()) .WillByDefault(Return(syncer::SyncService::DisableReasonSet())); - ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsFirstSetupComplete()) + ON_CALL(*mock_sync_service_->GetMockUserSettings(), + IsInitialSyncFeatureSetupComplete()) .WillByDefault(Return(false)); ON_CALL(*mock_sync_service_, GetTransportState()) .WillByDefault(Return(syncer::SyncService::TransportState::INITIALIZING)); @@ -442,7 +441,8 @@ TEST_F(PeopleHandlerTest, DisplayConfigureWithEngineDisabledAndSyncStartupCompleted) { SigninUser(); CreatePeopleHandler(); - ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsFirstSetupComplete()) + ON_CALL(*mock_sync_service_->GetMockUserSettings(), + IsInitialSyncFeatureSetupComplete()) .WillByDefault(Return(false)); ON_CALL(*mock_sync_service_, GetDisableReasons()) .WillByDefault(Return(syncer::SyncService::DisableReasonSet())); @@ -484,7 +484,8 @@ TEST_F(PeopleHandlerTest, CreatePeopleHandler(); ON_CALL(*mock_sync_service_, GetDisableReasons()) .WillByDefault(Return(syncer::SyncService::DisableReasonSet())); - ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsFirstSetupComplete()) + ON_CALL(*mock_sync_service_->GetMockUserSettings(), + IsInitialSyncFeatureSetupComplete()) .WillByDefault(Return(false)); EXPECT_CALL(*mock_sync_service_, GetTransportState()) .WillOnce(Return(syncer::SyncService::TransportState::INITIALIZING)) @@ -511,20 +512,24 @@ TEST_F(PeopleHandlerTest, 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()) - .WillByDefault(Return(syncer::SyncService::DISABLE_REASON_USER_CHOICE)); +#if BUILDFLAG(IS_CHROMEOS_ASH) + ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard()) + .WillByDefault(Return(true)); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) ON_CALL(*mock_sync_service_, GetTransportState()) .WillByDefault(Return(syncer::SyncService::TransportState::DISABLED)); // Attempting to open the setup UI should restart sync. EXPECT_CALL(*mock_sync_service_, SetSyncFeatureRequested()) .WillOnce([&]() { - // SetSyncFeatureRequested() clears DISABLE_REASON_USER_CHOICE, and - // immediately starts initializing the engine. + // SetSyncFeatureRequested() clears IsSyncFeatureDisabledViaDashboard() + // and immediately starts initializing the engine. ON_CALL(*mock_sync_service_, GetDisableReasons()) .WillByDefault(Return(syncer::SyncService::DisableReasonSet())); +#if BUILDFLAG(IS_CHROMEOS_ASH) + ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard()) + .WillByDefault(Return(false)); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) ON_CALL(*mock_sync_service_, GetTransportState()) .WillByDefault( Return(syncer::SyncService::TransportState::INITIALIZING)); @@ -540,21 +545,25 @@ 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. - ON_CALL(*mock_sync_service_, GetDisableReasons()) - .WillByDefault(Return(syncer::SyncService::DISABLE_REASON_USER_CHOICE)); + +#if BUILDFLAG(IS_CHROMEOS_ASH) + // Clearing sync from the dashboard results in + // IsSyncFeatureDisabledViaDashboard() returning true. Nevertheless, + // the sync engine has restarted in standalone transport mode. + ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard()) + .WillByDefault(Return(true)); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + ON_CALL(*mock_sync_service_, GetTransportState()) .WillByDefault(Return(syncer::SyncService::TransportState::ACTIVE)); // Attempting to open the setup UI should re-enable sync-the-feature. EXPECT_CALL(*mock_sync_service_, SetSyncFeatureRequested()) .WillOnce([&]() { - // SetSyncFeatureRequested() 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::DisableReasonSet())); +#if BUILDFLAG(IS_CHROMEOS_ASH) + ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard()) + .WillByDefault(Return(false)); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) ON_CALL(*mock_sync_service_, GetTransportState()) .WillByDefault( Return(syncer::SyncService::TransportState::CONFIGURING)); @@ -603,9 +612,10 @@ TEST_F(PeopleHandlerTest, UnrecoverableErrorInitializingSync) { SigninUser(); CreatePeopleHandler(); ON_CALL(*mock_sync_service_, GetDisableReasons()) - .WillByDefault( - Return(syncer::SyncService::DISABLE_REASON_UNRECOVERABLE_ERROR)); - ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsFirstSetupComplete()) + .WillByDefault(Return(syncer::SyncService::DisableReasonSet( + {syncer::SyncService::DISABLE_REASON_UNRECOVERABLE_ERROR}))); + ON_CALL(*mock_sync_service_->GetMockUserSettings(), + IsInitialSyncFeatureSetupComplete()) .WillByDefault(Return(false)); // Open the web UI. handler_->HandleShowSyncSetupUI(base::Value::List()); @@ -617,8 +627,10 @@ 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()) + .WillByDefault(Return(syncer::SyncService::DisableReasonSet( + {syncer::SyncService::DISABLE_REASON_NOT_SIGNED_IN}))); + ON_CALL(*mock_sync_service_->GetMockUserSettings(), + IsInitialSyncFeatureSetupComplete()) .WillByDefault(Return(false)); // Open the web UI. handler_->HandleShowSyncSetupUI(base::Value::List()); @@ -916,7 +928,7 @@ TEST_F(PeopleHandlerTest, ShowSetupSyncForAllTypesIndividually) { ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsSyncEverythingEnabled()) .WillByDefault(Return(false)); - syncer::UserSelectableTypeSet types(type); + const syncer::UserSelectableTypeSet types = {type}; ON_CALL(*mock_sync_service_->GetMockUserSettings(), GetSelectedTypes()) .WillByDefault(Return(types)); @@ -1114,12 +1126,16 @@ TEST_F(PeopleHandlerTest, DashboardClearWhileSettingsOpen_ConfirmSoon) { handler_->HandleShowSyncSetupUI(base::Value::List()); +#if BUILDFLAG(IS_CHROMEOS_ASH) // Now sync gets reset from the dashboard (the user clicked the "Manage synced - // data" link), which results in the sync-requested and first-setup-complete - // bits being cleared. - ON_CALL(*mock_sync_service_, GetDisableReasons()) - .WillByDefault(Return(syncer::SyncService::DISABLE_REASON_USER_CHOICE)); - ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsFirstSetupComplete()) + // data" link), which results in the first-setup-complete bit being cleared. + // While first-setup isn't completed, IsSyncFeatureDisabledViaDashboard() also + // returns false. + ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard()) + .WillByDefault(Return(false)); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + ON_CALL(*mock_sync_service_->GetMockUserSettings(), + IsInitialSyncFeatureSetupComplete()) .WillByDefault(Return(false)); // Sync will eventually start again in transport mode. ON_CALL(*mock_sync_service_, GetTransportState()) @@ -1132,21 +1148,17 @@ TEST_F(PeopleHandlerTest, DashboardClearWhileSettingsOpen_ConfirmSoon) { // and the first-setup-complete bits. EXPECT_CALL(*mock_sync_service_, SetSyncFeatureRequested()) .WillOnce([&]() { - // SetSyncFeatureRequested() clears DISABLE_REASON_USER_CHOICE, and - // immediately starts initializing the engine. - ON_CALL(*mock_sync_service_, GetDisableReasons()) - .WillByDefault(Return(syncer::SyncService::DisableReasonSet())); ON_CALL(*mock_sync_service_, GetTransportState()) .WillByDefault( Return(syncer::SyncService::TransportState::INITIALIZING)); NotifySyncStateChanged(); }); EXPECT_CALL(*mock_sync_service_->GetMockUserSettings(), - SetFirstSetupComplete( + SetInitialSyncFeatureSetupComplete( syncer::SyncFirstSetupCompleteSource::ADVANCED_FLOW_CONFIRM)) .WillOnce([&](syncer::SyncFirstSetupCompleteSource) { ON_CALL(*mock_sync_service_->GetMockUserSettings(), - IsFirstSetupComplete()) + IsInitialSyncFeatureSetupComplete()) .WillByDefault(Return(true)); NotifySyncStateChanged(); }); @@ -1164,12 +1176,16 @@ TEST_F(PeopleHandlerTest, DashboardClearWhileSettingsOpen_ConfirmLater) { handler_->HandleShowSyncSetupUI(base::Value::List()); +#if BUILDFLAG(IS_CHROMEOS_ASH) // Now sync gets reset from the dashboard (the user clicked the "Manage synced - // data" link), which results in the sync-requested and first-setup-complete - // bits being cleared. - ON_CALL(*mock_sync_service_, GetDisableReasons()) - .WillByDefault(Return(syncer::SyncService::DISABLE_REASON_USER_CHOICE)); - ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsFirstSetupComplete()) + // data" link), which results in the first-setup-complete bit being cleared. + // While first-setup isn't completed, IsSyncFeatureDisabledViaDashboard() also + // returns false. + ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard()) + .WillByDefault(Return(false)); +#endif + ON_CALL(*mock_sync_service_->GetMockUserSettings(), + IsInitialSyncFeatureSetupComplete()) .WillByDefault(Return(false)); // Sync will eventually start again in transport mode. ON_CALL(*mock_sync_service_, GetTransportState()) @@ -1182,12 +1198,12 @@ TEST_F(PeopleHandlerTest, DashboardClearWhileSettingsOpen_ConfirmLater) { // transport mode. ON_CALL(*mock_sync_service_, GetTransportState()) .WillByDefault(Return(syncer::SyncService::TransportState::ACTIVE)); - // On some platforms (e.g. ChromeOS), the first-setup-complete bit gets set - // automatically during engine startup. - if (browser_defaults::kSyncAutoStarts) { - ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsFirstSetupComplete()) - .WillByDefault(Return(true)); - } +#if BUILDFLAG(IS_CHROMEOS_ASH) + // The first-setup-complete bit gets set automatically during engine startup. + ON_CALL(*mock_sync_service_->GetMockUserSettings(), + IsInitialSyncFeatureSetupComplete()) + .WillByDefault(Return(true)); +#endif NotifySyncStateChanged(); // Now the user confirms sync again. This should set the sync-requested bit @@ -1195,27 +1211,22 @@ TEST_F(PeopleHandlerTest, DashboardClearWhileSettingsOpen_ConfirmLater) { // first-setup-complete bit. EXPECT_CALL(*mock_sync_service_, SetSyncFeatureRequested()) .WillOnce([&]() { - // SetSyncFeatureRequested() clears DISABLE_REASON_USER_CHOICE, and - // immediately starts initializing the engine. - ON_CALL(*mock_sync_service_, GetDisableReasons()) - .WillByDefault(Return(syncer::SyncService::DisableReasonSet())); ON_CALL(*mock_sync_service_, GetTransportState()) .WillByDefault( Return(syncer::SyncService::TransportState::INITIALIZING)); NotifySyncStateChanged(); }); - if (!browser_defaults::kSyncAutoStarts) { - EXPECT_CALL( - *mock_sync_service_->GetMockUserSettings(), - SetFirstSetupComplete( - syncer::SyncFirstSetupCompleteSource::ADVANCED_FLOW_CONFIRM)) - .WillOnce([&](syncer::SyncFirstSetupCompleteSource) { - ON_CALL(*mock_sync_service_->GetMockUserSettings(), - IsFirstSetupComplete()) - .WillByDefault(Return(true)); - NotifySyncStateChanged(); - }); - } +#if !BUILDFLAG(IS_CHROMEOS_ASH) + EXPECT_CALL(*mock_sync_service_->GetMockUserSettings(), + SetInitialSyncFeatureSetupComplete( + syncer::SyncFirstSetupCompleteSource::ADVANCED_FLOW_CONFIRM)) + .WillOnce([&](syncer::SyncFirstSetupCompleteSource) { + ON_CALL(*mock_sync_service_->GetMockUserSettings(), + IsInitialSyncFeatureSetupComplete()) + .WillByDefault(Return(true)); + NotifySyncStateChanged(); + }); +#endif base::Value::List did_abort; did_abort.Append(false); diff --git a/chromium/chrome/browser/ui/webui/settings/performance_handler.cc b/chromium/chrome/browser/ui/webui/settings/performance_handler.cc index c149f5518ea..f3fed823b21 100644 --- a/chromium/chrome/browser/ui/webui/settings/performance_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/performance_handler.cc @@ -6,12 +6,18 @@ #include "base/feature_list.h" #include "base/functional/bind.h" #include "base/values.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/chrome_pages.h" #include "components/performance_manager/public/features.h" #include "components/url_matcher/url_util.h" +#include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" +#include "url/gurl.h" + +using content::WebContents; namespace settings { @@ -38,6 +44,10 @@ void PerformanceHandler::RegisterMessages() { base::BindRepeating( &PerformanceHandler::HandleValidateTabDiscardExceptionRule, base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "getCurrentOpenSites", + base::BindRepeating(&PerformanceHandler::HandleGetCurrentOpenSites, + base::Unretained(this))); } void PerformanceHandler::OnJavascriptAllowed() { @@ -55,6 +65,49 @@ void PerformanceHandler::OnDeviceHasBatteryChanged(bool device_has_battery) { FireWebUIListener("device-has-battery-changed", device_has_battery); } +base::Value PerformanceHandler::GetCurrentOpenSites() { + base::Value::List hosts; + std::set<std::pair<base::TimeTicks, std::string>, std::greater<>> + last_active_time_host_pairs; + const Profile* profile = Profile::FromWebUI(web_ui()); + for (auto* browser : *BrowserList::GetInstance()) { + // Exclude browsers not signed into the current profile + if (browser->profile() != profile) { + continue; + } + + TabStripModel* tab_strip_model = browser->tab_strip_model(); + + for (int tab_index = 0; tab_index < tab_strip_model->count(); ++tab_index) { + WebContents* web_contents = tab_strip_model->GetWebContentsAt(tab_index); + const GURL url = web_contents->GetLastCommittedURL(); + if (url.is_valid() && url.SchemeIsHTTPOrHTTPS()) { + last_active_time_host_pairs.insert( + std::make_pair(web_contents->GetLastActiveTime(), url.host())); + } + } + } + + std::unordered_set<std::string> added_hosts; + for (auto& [last_active_time, host] : last_active_time_host_pairs) { + if (!base::Contains(added_hosts, host)) { + added_hosts.insert(host); + hosts.Append(host); + } + } + + return base::Value(std::move(hosts)); +} + +void PerformanceHandler::HandleGetCurrentOpenSites( + const base::Value::List& args) { + CHECK_EQ(1U, args.size()); + const base::Value& callback_id = args[0]; + + AllowJavascript(); + ResolveJavascriptCallback(callback_id, GetCurrentOpenSites()); +} + void PerformanceHandler::HandleGetDeviceHasBattery( const base::Value::List& args) { CHECK_EQ(1U, args.size()); diff --git a/chromium/chrome/browser/ui/webui/settings/performance_handler.h b/chromium/chrome/browser/ui/webui/settings/performance_handler.h index 8915b9ab218..0c7fcc34329 100644 --- a/chromium/chrome/browser/ui/webui/settings/performance_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/performance_handler.h @@ -27,6 +27,9 @@ class PerformanceHandler : public SettingsPageUIHandler, void OnJavascriptDisallowed() override; private: + friend class PerformanceHandlerTest; + FRIEND_TEST_ALL_PREFIXES(PerformanceHandlerTest, GetCurrentOpenSites); + base::ScopedObservation< performance_manager::user_tuning::UserPerformanceTuningManager, performance_manager::user_tuning::UserPerformanceTuningManager::Observer> @@ -36,6 +39,12 @@ class PerformanceHandler : public SettingsPageUIHandler, void OnDeviceHasBatteryChanged(bool device_has_battery) override; /** + * Returns a list of currently opened tabs' urls in order of most recently used. + */ + base::Value GetCurrentOpenSites(); + void HandleGetCurrentOpenSites(const base::Value::List& args); + + /** * This function is called from the frontend in order to get the initial * state of the battery, and also has the side effect of notifying the handler * that it is ready to receive updates for future battery status changes. diff --git a/chromium/chrome/browser/ui/webui/settings/performance_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/performance_handler_unittest.cc new file mode 100644 index 00000000000..36e210003da --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/performance_handler_unittest.cc @@ -0,0 +1,112 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/settings/performance_handler.h" + +#include "base/values.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/test/base/browser_with_test_window_test.h" +#include "chrome/test/base/testing_profile.h" +#include "content/public/browser/visibility.h" +#include "content/public/browser/web_contents.h" +#include "content/public/test/test_renderer_host.h" +#include "content/public/test/test_web_ui.h" +#include "content/public/test/web_contents_tester.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace settings { + +class PerformanceHandlerTest : public BrowserWithTestWindowTest { + public: + PerformanceHandlerTest() = default; + + void SetUp() override { + web_contents_ = content::WebContentsTester::CreateTestWebContents(profile(), nullptr); + web_ui_ = std::make_unique<content::TestWebUI>(); + web_ui_->set_web_contents(web_contents_.get()); + handler_ = std::make_unique<PerformanceHandler>(); + handler_->set_web_ui(web_ui()); + + incognito_profile_ = TestingProfile::Builder().BuildIncognito(profile()); + } + + void TearDown() override { + handler_->set_web_ui(nullptr); + handler_.reset(); + web_ui_.reset(); + + for (auto& browser : browsers_) { + browser->tab_strip_model()->CloseAllTabs(); + } + } + + content::TestWebUI* web_ui() { return web_ui_.get(); } + PerformanceHandler* handler() { return handler_.get(); } + TestingProfile* profile() { return &profile_; } + TestingProfile* incognito_profile() { return incognito_profile_; } + + Browser* AddBrowser(Profile* profile) { + Browser::CreateParams params(profile, true); + std::unique_ptr<Browser> browser = + CreateBrowserWithTestWindowForParams(params); + Browser* browser_ptr = browser.get(); + browsers_.emplace_back(std::move(browser)); + return browser_ptr; + } + + content::WebContents* AddTabToBrowser(Browser* browser, GURL url) { + AddTab(browser, url); + return browser->tab_strip_model()->GetActiveWebContents(); + } + + void ExpectCurrentOpenSitesEquals(std::vector<std::string> expected_sites, + base::Value actual) { + ASSERT_TRUE(actual.is_list()); + base::Value::List* actual_sites = actual.GetIfList(); + EXPECT_EQ(expected_sites.size(), actual_sites->size()); + for (size_t i = 0; i < expected_sites.size(); i++) { + const base::Value& actual_site_value = (*actual_sites)[i]; + ASSERT_TRUE(actual_site_value.is_string()); + const std::string actual_site = actual_site_value.GetString(); + EXPECT_EQ(expected_sites[i], actual_site); + } + } + + private: + content::RenderViewHostTestEnabler render_view_host_test_enabler_; + std::unique_ptr<content::TestWebUI> web_ui_; + std::unique_ptr<PerformanceHandler> handler_; + TestingProfile profile_; + raw_ptr<TestingProfile, DanglingUntriaged> incognito_profile_ = nullptr; + std::unique_ptr<content::WebContents> web_contents_; + std::vector<std::unique_ptr<Browser>> browsers_; +}; + +TEST_F(PerformanceHandlerTest, GetCurrentOpenSites) { + Browser* first_browser = AddBrowser(profile()); + AddTabToBrowser(first_browser, GURL("https://www.foo.com/ignorethispart")); + content::WebContents* bar_tab = + AddTabToBrowser(first_browser, GURL("https://bar.com")); + AddTabToBrowser(first_browser, GURL("chrome://version")); + + Browser* second_browser = AddBrowser(profile()); + AddTabToBrowser(second_browser, + GURL("https://www.foo.com/ignorethispartaswell")); + AddTabToBrowser(second_browser, GURL("http://www.baz.com")); + + Browser* incognito_browser = AddBrowser(incognito_profile()); + AddTabToBrowser(incognito_browser, + GURL("https://www.toshowthiswouldbeaprivacyviolation.com")); + + ExpectCurrentOpenSitesEquals({"www.baz.com", "www.foo.com", "bar.com"}, + handler()->GetCurrentOpenSites()); + + bar_tab->UpdateWebContentsVisibility(content::Visibility::VISIBLE); + ExpectCurrentOpenSitesEquals({"bar.com", "www.baz.com", "www.foo.com"}, + handler()->GetCurrentOpenSites()); +} + +} // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/performance_settings_interactive_uitest.cc b/chromium/chrome/browser/ui/webui/settings/performance_settings_interactive_uitest.cc index 8a30468b6d1..65db12188ea 100644 --- a/chromium/chrome/browser/ui/webui/settings/performance_settings_interactive_uitest.cc +++ b/chromium/chrome/browser/ui/webui/settings/performance_settings_interactive_uitest.cc @@ -8,16 +8,19 @@ #include "base/test/power_monitor_test_utils.h" #include "base/test/scoped_feature_list.h" #include "build/branding_buildflags.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/ui/webui/feedback/feedback_dialog.h" #include "chrome/common/url_constants.h" #include "chrome/test/base/ui_test_utils.h" #include "chrome/test/interaction/interactive_browser_test.h" +#include "chrome/test/interaction/webcontents_interaction_test_util.h" #include "components/performance_manager/public/features.h" #include "components/performance_manager/public/user_tuning/prefs.h" #include "content/public/test/browser_test.h" #include "url/gurl.h" using performance_manager::user_tuning::prefs::BatterySaverModeState; +using performance_manager::user_tuning::prefs::HighEfficiencyModeState; namespace { DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kPerformanceSettingsPage); @@ -28,6 +31,14 @@ constexpr char kCheckJsElementIsChecked[] = "(el) => { return el.checked; }"; constexpr char kCheckJsElementIsNotChecked[] = "(el) => { return !el.checked; }"; +const WebContentsInteractionTestUtil::DeepQuery kHighEfficiencyToggleQuery = { + "settings-ui", + "settings-main", + "settings-basic-page", + "settings-performance-page", + "settings-toggle-button", + "cr-toggle#control"}; + class PerformanceSettingsInteractiveTest : public InteractiveBrowserTest { public: void SetUp() override { @@ -78,14 +89,23 @@ class PerformanceSettingsInteractiveTest : public InteractiveBrowserTest { return CheckResult(get_tab_count, expected_tab_count); } - auto CheckHighEffiencyModeLogged( - bool high_efficiency_enabled, + auto CheckHighEfficiencyModePrefState(HighEfficiencyModeState state) { + return CheckResult(base::BindLambdaForTesting([]() { + return performance_manager::user_tuning::prefs:: + GetCurrentHighEfficiencyModeState( + g_browser_process->local_state()); + }), + state); + } + + auto CheckHighEfficiencyModeLogged( + HighEfficiencyModeState state, int expected_count, const base::HistogramTester& histogram_tester) { return Do(base::BindLambdaForTesting([=, &histogram_tester]() { histogram_tester.ExpectBucketCount( - "PerformanceControls.HighEfficiency.SettingsChangeMode", - high_efficiency_enabled, expected_count); + "PerformanceControls.HighEfficiency.SettingsChangeMode2", + static_cast<int>(state), expected_count); })); } @@ -124,6 +144,7 @@ class PerformanceSettingsInteractiveTest : public InteractiveBrowserTest { return WaitForStateChange(contents_id, element_renders); } + private: raw_ptr<base::test::TestSamplingEventSource, DanglingUntriaged> sampling_source_; raw_ptr<base::test::TestBatteryLevelProvider, DanglingUntriaged> @@ -132,6 +153,31 @@ class PerformanceSettingsInteractiveTest : public InteractiveBrowserTest { }; IN_PROC_BROWSER_TEST_F(PerformanceSettingsInteractiveTest, + HighEfficiencyPrefChanged) { + RunTestSequence( + InstrumentTab(kPerformanceSettingsPage), + NavigateWebContents(kPerformanceSettingsPage, + GURL(chrome::kChromeUIPerformanceSettingsURL)), + WaitForElementToRender(kPerformanceSettingsPage, + kHighEfficiencyToggleQuery), + CheckJsResultAt(kPerformanceSettingsPage, kHighEfficiencyToggleQuery, + kCheckJsElementIsChecked), + + // Turn Off High Efficiency Mode + ClickElement(kPerformanceSettingsPage, kHighEfficiencyToggleQuery), + WaitForButtonStateChange(kPerformanceSettingsPage, + kHighEfficiencyToggleQuery, false), + CheckHighEfficiencyModePrefState(HighEfficiencyModeState::kDisabled), + + // Turn High Efficiency Mode back on + ClickElement(kPerformanceSettingsPage, kHighEfficiencyToggleQuery), + WaitForButtonStateChange(kPerformanceSettingsPage, + kHighEfficiencyToggleQuery, true), + CheckHighEfficiencyModePrefState( + HighEfficiencyModeState::kEnabledOnTimer)); +} + +IN_PROC_BROWSER_TEST_F(PerformanceSettingsInteractiveTest, HighEfficiencyLearnMoreLinkNavigates) { DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kLearnMorePage); const DeepQuery high_efficiency_learn_more = {"settings-ui", @@ -172,34 +218,30 @@ IN_PROC_BROWSER_TEST_F(PerformanceSettingsInteractiveTest, IN_PROC_BROWSER_TEST_F(PerformanceSettingsInteractiveTest, HighEfficiencyMetricsShouldLogOnToggle) { - const DeepQuery high_efficiency_toggle = {"settings-ui", - "settings-main", - "settings-basic-page", - "settings-performance-page", - "settings-toggle-button", - "cr-toggle#control"}; - base::HistogramTester histogram_tester; RunTestSequence( InstrumentTab(kPerformanceSettingsPage), NavigateWebContents(kPerformanceSettingsPage, GURL(chrome::kChromeUIPerformanceSettingsURL)), - WaitForElementToRender(kPerformanceSettingsPage, high_efficiency_toggle), - CheckJsResultAt(kPerformanceSettingsPage, high_efficiency_toggle, + WaitForElementToRender(kPerformanceSettingsPage, + kHighEfficiencyToggleQuery), + CheckJsResultAt(kPerformanceSettingsPage, kHighEfficiencyToggleQuery, kCheckJsElementIsChecked), // Turn Off High Efficiency Mode - ClickElement(kPerformanceSettingsPage, high_efficiency_toggle), - WaitForButtonStateChange(kPerformanceSettingsPage, high_efficiency_toggle, - false), - CheckHighEffiencyModeLogged(false, 1, histogram_tester), + ClickElement(kPerformanceSettingsPage, kHighEfficiencyToggleQuery), + WaitForButtonStateChange(kPerformanceSettingsPage, + kHighEfficiencyToggleQuery, false), + CheckHighEfficiencyModeLogged(HighEfficiencyModeState::kDisabled, 1, + histogram_tester), // Turn High Efficiency Mode back on - ClickElement(kPerformanceSettingsPage, high_efficiency_toggle), - WaitForButtonStateChange(kPerformanceSettingsPage, high_efficiency_toggle, - true), - CheckHighEffiencyModeLogged(true, 1, histogram_tester)); + ClickElement(kPerformanceSettingsPage, kHighEfficiencyToggleQuery), + WaitForButtonStateChange(kPerformanceSettingsPage, + kHighEfficiencyToggleQuery, true), + CheckHighEfficiencyModeLogged(HighEfficiencyModeState::kEnabledOnTimer, 1, + histogram_tester)); } IN_PROC_BROWSER_TEST_F(PerformanceSettingsInteractiveTest, @@ -275,8 +317,9 @@ IN_PROC_BROWSER_TEST_F(PerformanceSettingsInteractiveTest, } #if BUILDFLAG(GOOGLE_CHROME_BRANDING) +// TODO(http://b/281528238): reenable the test. IN_PROC_BROWSER_TEST_F(PerformanceSettingsInteractiveTest, - HighEfficiencySendFeedbackDialogOpens) { + DISABLED_HighEfficiencySendFeedbackDialogOpens) { const DeepQuery high_efficiency_feedback = { "settings-ui", "settings-main", "settings-basic-page", "settings-section#performanceSettingsSection", "cr-icon-button#feedback"}; @@ -289,8 +332,9 @@ IN_PROC_BROWSER_TEST_F(PerformanceSettingsInteractiveTest, InAnyContext(WaitForShow(FeedbackDialog::kFeedbackDialogForTesting))); } +// TODO(http://b/281528238): reenable the test. IN_PROC_BROWSER_TEST_F(PerformanceSettingsInteractiveTest, - BatterySaverSendFeedbackDialogOpens) { + DISABLED_BatterySaverSendFeedbackDialogOpens) { const DeepQuery battery_saver_feedback = { "settings-ui", "settings-main", "settings-basic-page", "settings-section#batterySettingsSection", "cr-icon-button#feedback"}; diff --git a/chromium/chrome/browser/ui/webui/settings/privacy_sandbox_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/privacy_sandbox_handler_unittest.cc index 9c050602484..42f836a240a 100644 --- a/chromium/chrome/browser/ui/webui/settings/privacy_sandbox_handler_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/privacy_sandbox_handler_unittest.cc @@ -26,6 +26,8 @@ using Topic = browsing_topics::Topic; constexpr char kCallbackId1[] = "test-callback-id"; constexpr char kCallbackId2[] = "test-callback-id-2"; +constexpr int kTestTaxonomyVersion = 1; + class MockPrivacySandboxService : public PrivacySandboxService { public: MOCK_METHOD(void, @@ -220,8 +222,8 @@ TEST_F(PrivacySandboxHandlerTestMockService, GetFledgeState) { TEST_F(PrivacySandboxHandlerTestMockService, SetTopicAllowed) { // Confirm that the handler correctly constructs the CanonicalTopic and // passes it to the PrivacySandboxService. - const privacy_sandbox::CanonicalTopic kTestTopic( - Topic(1), privacy_sandbox::CanonicalTopic::AVAILABLE_TAXONOMY); + const privacy_sandbox::CanonicalTopic kTestTopic(Topic(1), + kTestTaxonomyVersion); EXPECT_CALL(*mock_privacy_sandbox_service(), SetTopicAllowed(kTestTopic, false)) .Times(1); @@ -234,15 +236,11 @@ TEST_F(PrivacySandboxHandlerTestMockService, SetTopicAllowed) { TEST_F(PrivacySandboxHandlerTestMockService, GetTopicsState) { const std::vector<privacy_sandbox::CanonicalTopic> kBlockedTopics = { - privacy_sandbox::CanonicalTopic( - Topic(1), privacy_sandbox::CanonicalTopic::AVAILABLE_TAXONOMY), - privacy_sandbox::CanonicalTopic( - Topic(2), privacy_sandbox::CanonicalTopic::AVAILABLE_TAXONOMY)}; + privacy_sandbox::CanonicalTopic(Topic(1), kTestTaxonomyVersion), + privacy_sandbox::CanonicalTopic(Topic(2), kTestTaxonomyVersion)}; const std::vector<privacy_sandbox::CanonicalTopic> kTopTopics = { - privacy_sandbox::CanonicalTopic( - Topic(3), privacy_sandbox::CanonicalTopic::AVAILABLE_TAXONOMY), - privacy_sandbox::CanonicalTopic( - Topic(4), privacy_sandbox::CanonicalTopic::AVAILABLE_TAXONOMY)}; + privacy_sandbox::CanonicalTopic(Topic(3), kTestTaxonomyVersion), + privacy_sandbox::CanonicalTopic(Topic(4), kTestTaxonomyVersion)}; EXPECT_CALL(*mock_privacy_sandbox_service(), GetCurrentTopTopics()) .Times(1) diff --git a/chromium/chrome/browser/ui/webui/settings/protocol_handlers_handler.h b/chromium/chrome/browser/ui/webui/settings/protocol_handlers_handler.h index f3ecf96e50a..cc0e76540fd 100644 --- a/chromium/chrome/browser/ui/webui/settings/protocol_handlers_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/protocol_handlers_handler.h @@ -11,12 +11,12 @@ #include "base/scoped_observation.h" #include "base/values.h" #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" -#include "chrome/browser/web_applications/app_registrar_observer.h" #include "chrome/browser/web_applications/web_app_id.h" #include "chrome/browser/web_applications/web_app_install_manager.h" #include "chrome/browser/web_applications/web_app_install_manager_observer.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/browser/web_applications/web_app_registrar.h" +#include "chrome/browser/web_applications/web_app_registrar_observer.h" #include "components/custom_handlers/protocol_handler_registry.h" //////////////////////////////////////////////////////////////////////////////// @@ -32,7 +32,7 @@ namespace settings { class ProtocolHandlersHandler : public SettingsPageUIHandler, public custom_handlers::ProtocolHandlerRegistry::Observer, - public web_app::AppRegistrarObserver, + public web_app::WebAppRegistrarObserver, public web_app::WebAppInstallManagerObserver { public: explicit ProtocolHandlersHandler(Profile* profile); @@ -56,7 +56,7 @@ class ProtocolHandlersHandler webapps::WebappUninstallSource uninstall_source) override; void OnWebAppInstallManagerDestroyed() override; - // web_app::AppRegistrarObserver: + // web_app::WebAppRegistrarObserver: void OnWebAppProtocolSettingsChanged() override; void OnAppRegistrarDestroyed() override; @@ -135,7 +135,7 @@ class ProtocolHandlersHandler const raw_ptr<web_app::WebAppProvider> web_app_provider_; base::ScopedObservation<web_app::WebAppRegistrar, - web_app::AppRegistrarObserver> + web_app::WebAppRegistrarObserver> app_observation_{this}; base::ScopedObservation<web_app::WebAppInstallManager, web_app::WebAppInstallManagerObserver> diff --git a/chromium/chrome/browser/ui/webui/settings/recent_site_settings_helper.cc b/chromium/chrome/browser/ui/webui/settings/recent_site_settings_helper.cc index dc3427f34b9..eb1d2bcdd39 100644 --- a/chromium/chrome/browser/ui/webui/settings/recent_site_settings_helper.cc +++ b/chromium/chrome/browser/ui/webui/settings/recent_site_settings_helper.cc @@ -60,7 +60,7 @@ std::map<GURL, std::vector<TimestampedSetting>> GetAllSettingsForProfile( site_settings::GetSingleOriginExceptionsForContentType( content_settings_map, content_type); for (const auto& e : exceptions_for_type) { - auto last_modified = e.metadata.last_modified; + auto last_modified = e.metadata.last_modified(); if (last_modified.is_null()) { continue; } diff --git a/chromium/chrome/browser/ui/webui/settings/recent_site_settings_helper_unittest.cc b/chromium/chrome/browser/ui/webui/settings/recent_site_settings_helper_unittest.cc index 0dbccafb004..297c18b4ce5 100644 --- a/chromium/chrome/browser/ui/webui/settings/recent_site_settings_helper_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/recent_site_settings_helper_unittest.cc @@ -34,7 +34,7 @@ base::Time GetSettingLastModifiedDate(HostContentSettingsMap* map, ContentSettingsType type) { content_settings::SettingInfo info; map->GetWebsiteSetting(primary_url, secondary_url, type, &info); - return info.metadata.last_modified; + return info.metadata.last_modified(); } } // namespace diff --git a/chromium/chrome/browser/ui/webui/settings/safety_check_extensions_handler.cc b/chromium/chrome/browser/ui/webui/settings/safety_check_extensions_handler.cc new file mode 100644 index 00000000000..5b7c3a01fae --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/safety_check_extensions_handler.cc @@ -0,0 +1,112 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/settings/safety_check_extensions_handler.h" + +#include "chrome/browser/extensions/cws_info_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/grit/generated_resources.h" +#include "extensions/browser/extension_prefs.h" +#include "extensions/browser/extension_prefs_factory.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/common/extension_id.h" +#include "extensions/common/manifest.h" + +namespace settings { + +namespace { + +// `kPrefAcknowledgeSafetyCheckWarning` should mirror the definition in +// chrome/browser/extensions/api/developer_private/developer_private_api.h. +constexpr extensions::PrefMap kPrefAcknowledgeSafetyCheckWarning = { + "ack_safety_check_warning", extensions::PrefType::kBool, + extensions::PrefScope::kExtensionSpecific}; + +} // namespace + +SafetyCheckExtensionsHandler::SafetyCheckExtensionsHandler(Profile* profile) + : profile_(profile) {} + +SafetyCheckExtensionsHandler::~SafetyCheckExtensionsHandler() = default; + +void SafetyCheckExtensionsHandler::HandleGetNumberOfExtensionsThatNeedReview( + const base::Value::List& args) { + const base::Value& callback_id = args[0]; + AllowJavascript(); + ResolveJavascriptCallback(callback_id, + base::Value(GetNumberOfExtensionsThatNeedReview())); +} + +void SafetyCheckExtensionsHandler::SetCWSInfoServiceForTest( + extensions::CWSInfoService* cws_info_service) { + cws_info_service_ = cws_info_service; +} + +int SafetyCheckExtensionsHandler::GetNumberOfExtensionsThatNeedReview() { + int num_extensions_that_need_review = 0; + if (!base::FeatureList::IsEnabled(extensions::kCWSInfoService)) { + return num_extensions_that_need_review; + } + + if (cws_info_service_ == nullptr) { + cws_info_service_ = extensions::CWSInfoService::Get(profile_); + } + + extensions::ExtensionPrefs* extension_prefs = + extensions::ExtensionPrefsFactory::GetForBrowserContext(profile_); + + for (const auto& extension_id : extension_prefs->GetExtensions()) { + const extensions::Extension* extension = + extensions::ExtensionRegistry::Get(profile_)->GetExtensionById( + extension_id, extensions::ExtensionRegistry::EVERYTHING); + // Check if the extension is installed by a policy. + if (!extension || + extensions::Manifest::IsPolicyLocation(extension->location())) { + continue; + } + bool warning_acked = false; + extension_prefs->ReadPrefAsBoolean( + extension->id(), kPrefAcknowledgeSafetyCheckWarning, &warning_acked); + // If the user has previously acknowledged the warning on this + // extension and chosen to keep it, we will not show an additional + // safety hub warning. + if (warning_acked) { + continue; + } + absl::optional<extensions::CWSInfoService::CWSInfo> extension_info = + cws_info_service_->GetCWSInfo(*extension); + if (extension_info.has_value() && extension_info->is_present) { + switch (extension_info->violation_type) { + case extensions::CWSInfoService::CWSViolationType::kMalware: + case extensions::CWSInfoService::CWSViolationType::kPolicy: + num_extensions_that_need_review++; + break; + case extensions::CWSInfoService::CWSViolationType::kNone: + case extensions::CWSInfoService::CWSViolationType::kMinorPolicy: + case extensions::CWSInfoService::CWSViolationType::kUnknown: + if (extension_info->unpublished_long_ago) { + num_extensions_that_need_review++; + } + break; + } + } + } + return num_extensions_that_need_review; +} + +void SafetyCheckExtensionsHandler::OnJavascriptAllowed() {} + +void SafetyCheckExtensionsHandler::OnJavascriptDisallowed() {} + +void SafetyCheckExtensionsHandler::RegisterMessages() { + // Usage of base::Unretained(this) is safe, because web_ui() owns `this` and + // won't release ownership until destruction. + web_ui()->RegisterMessageCallback( + "getNumberOfExtensionsThatNeedReview", + base::BindRepeating(&SafetyCheckExtensionsHandler:: + HandleGetNumberOfExtensionsThatNeedReview, + base::Unretained(this))); +} + +} // namespace settings diff --git a/chromium/chrome/browser/ui/webui/settings/safety_check_extensions_handler.h b/chromium/chrome/browser/ui/webui/settings/safety_check_extensions_handler.h new file mode 100644 index 00000000000..7d05c9b113f --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/safety_check_extensions_handler.h @@ -0,0 +1,59 @@ +// Copyright 2023 The Chromium Authors +// 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_SAFETY_CHECK_EXTENSIONS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_SAFETY_CHECK_EXTENSIONS_HANDLER_H_ + +#include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" + +class Profile; + +namespace extensions { +class CWSInfoService; +class SafetyCheckExtensionsHandlerTest; +} // namespace extensions + +namespace settings { + +// Settings page UI handler that checks for any extensions that trigger +// a review by the safety check. +class SafetyCheckExtensionsHandler : public settings::SettingsPageUIHandler { + public: + explicit SafetyCheckExtensionsHandler(Profile* profile); + ~SafetyCheckExtensionsHandler() override; + + void SetCWSInfoServiceForTest(extensions::CWSInfoService* cws_info_service); + + private: + friend class extensions::SafetyCheckExtensionsHandlerTest; + + // Calculate the number of extensions that need to be reviewed by the + // user. + void HandleGetNumberOfExtensionsThatNeedReview(const base::Value::List& args); + + // Return the number of extensions that should be reviewed by the user. + // There are currently three triggers the `SafetyCheckExtensionsHandler` + // tracks: + // -- Extension Malware Violation + // -- Extension Policy Violation + // -- Extension Unpublished by the developer + int GetNumberOfExtensionsThatNeedReview(); + + // SettingsPageUIHandler implementation. + void OnJavascriptDisallowed() override; + void OnJavascriptAllowed() override; + + // WebUIMessageHandler implementation. + void RegisterMessages() override; + + raw_ptr<Profile> profile_ = nullptr; + raw_ptr<extensions::CWSInfoService> cws_info_service_ = nullptr; + base::WeakPtrFactory<SafetyCheckExtensionsHandler> weak_ptr_factory_{this}; +}; + +} // namespace settings + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_SAFETY_CHECK_EXTENSIONS_HANDLER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/safety_check_extensions_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/safety_check_extensions_handler_unittest.cc new file mode 100644 index 00000000000..665bd203ad6 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/safety_check_extensions_handler_unittest.cc @@ -0,0 +1,174 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/settings/safety_check_extensions_handler.h" + +#include <string> + +#include "chrome/browser/extensions/cws_info_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/test/base/testing_profile.h" +#include "components/crx_file/id_util.h" +#include "content/public/test/browser_task_environment.h" +#include "extensions/browser/extension_prefs.h" +#include "extensions/browser/extension_prefs_factory.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/common/extension_builder.h" +#include "extensions/common/extension_id.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace extensions { + +using mojom::ManifestLocation; + +namespace { + +const char kAllHostsPermission[] = "*://*/*"; + +// These `cws_info` variables are used to test the various +// `safety_check_extensions_handler` states. +// Will trigger the extension handler due to the malware violation. +static extensions::CWSInfoService::CWSInfo cws_info_malware{ + true, + false, + base::Time::Now(), + extensions::CWSInfoService::CWSViolationType::kMalware, + false, + false}; +// Will trigger the extension handler due to the policy violation. +static extensions::CWSInfoService::CWSInfo cws_info_policy{ + true, + false, + base::Time::Now(), + extensions::CWSInfoService::CWSViolationType::kPolicy, + false, + false}; +// Will trigger the extension handler due to being unpublished. +static extensions::CWSInfoService::CWSInfo cws_info_unpublished{ + true, + false, + base::Time::Now(), + extensions::CWSInfoService::CWSViolationType::kNone, + true, + false}; +// Will trigger the extension handler due to multiple triggers. +static extensions::CWSInfoService::CWSInfo cws_info_multi{ + true, + false, + base::Time::Now(), + extensions::CWSInfoService::CWSViolationType::kMalware, + true, + false}; +// Will not trigger the extension handler. +static extensions::CWSInfoService::CWSInfo cws_info_no_trigger{ + true, + false, + base::Time::Now(), + extensions::CWSInfoService::CWSViolationType::kNone, + false, + false}; +// Will not trigger the extension handler. +static extensions::CWSInfoService::CWSInfo cws_info_no_data{ + false, + false, + base::Time::Now(), + extensions::CWSInfoService::CWSViolationType::kMalware, + false, + false}; + +class MockCWSInfoService : public extensions::CWSInfoService { + public: + MOCK_METHOD(absl::optional<bool>, + IsLiveInCWS, + (const extensions::Extension&), + (const, override)); + MOCK_METHOD(absl::optional<CWSInfoServiceInterface::CWSInfo>, + GetCWSInfo, + (const extensions::Extension&), + (const, override)); + MOCK_METHOD(void, CheckAndMaybeFetchInfo, (), (override)); + MOCK_METHOD(void, + AddObserver, + (CWSInfoServiceInterface::Observer*), + (override)); + MOCK_METHOD(void, + RemoveObserver, + (CWSInfoServiceInterface::Observer*), + (override)); +}; + +} // namespace + +class SafetyCheckExtensionsHandlerTest : public testing::Test { + public: + void SetUp() override; + + int GetNumberOfExtensionsThatNeedReview() { + return safety_check_handler_->GetNumberOfExtensionsThatNeedReview(); + } + + protected: + void AddExtension(const std::string& name, mojom::ManifestLocation location) { + const std::string kId = crx_file::id_util::GenerateId(name); + scoped_refptr<const Extension> extension = + ExtensionBuilder() + .SetManifest(base::Value::Dict() + .Set("name", name) + .Set("description", "an extension") + .Set("manifest_version", 3) + .Set("version", "1.0.0") + .Set("permissions", base::Value::List().Append( + kAllHostsPermission))) + .SetLocation(location) + .SetID(kId) + .Build(); + extensions::ExtensionPrefs::Get(profile_.get()) + ->OnExtensionInstalled(extension.get(), + extensions::Extension::State::ENABLED, + syncer::StringOrdinal(), ""); + extensions::ExtensionRegistry::Get(profile_.get())->AddEnabled(extension); + } + + content::BrowserTaskEnvironment browser_task_environment_; + std::unique_ptr<TestingProfile> profile_; + testing::NiceMock<MockCWSInfoService> mock_cws_info_service_; + std::unique_ptr<settings::SafetyCheckExtensionsHandler> safety_check_handler_; +}; + +void SafetyCheckExtensionsHandlerTest::SetUp() { + TestingProfile::Builder builder; + profile_ = builder.Build(); +} + +TEST_F(SafetyCheckExtensionsHandlerTest, + GetNumberOfExtensionsThatNeedReviewTest) { + // Create fake extensions for our pref service to load. + AddExtension("TestExtension1", ManifestLocation::kInternal); + AddExtension("TestExtension2", ManifestLocation::kInternal); + AddExtension("TestExtension3", ManifestLocation::kInternal); + AddExtension("TestExtension4", ManifestLocation::kInternal); + AddExtension("TestExtension5", ManifestLocation::kInternal); + AddExtension("TestExtension6", ManifestLocation::kInternal); + // Extensions installed by policies will be ignored by the safety + // check. So extension 7 will not trigger the handler. + AddExtension("TestExtension7", ManifestLocation::kExternalPolicyDownload); + safety_check_handler_ = + std::make_unique<settings::SafetyCheckExtensionsHandler>(profile_.get()); + safety_check_handler_->SetCWSInfoServiceForTest(&mock_cws_info_service_); + // Ensure that the mock CWSInfo service returns the needed information. + EXPECT_CALL(mock_cws_info_service_, GetCWSInfo) + .Times(6) + .WillOnce(testing::Return(cws_info_malware)) + .WillOnce(testing::Return(cws_info_policy)) + .WillOnce(testing::Return(cws_info_unpublished)) + .WillOnce(testing::Return(cws_info_multi)) + .WillOnce(testing::Return(cws_info_no_data)) + .WillOnce(testing::Return(cws_info_no_trigger)); + // There should be 4 triggering extensions based on the various cws_info + // variables. + EXPECT_EQ(4, GetNumberOfExtensionsThatNeedReview()); +} + +} // namespace extensions 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 a98a668cebc..d64f64f4fdd 100644 --- a/chromium/chrome/browser/ui/webui/settings/safety_check_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/safety_check_handler.cc @@ -24,6 +24,7 @@ #include "chrome/browser/ui/webui/version/version_ui.h" #include "chrome/common/channel_info.h" #include "chrome/common/chrome_features.h" +#include "chrome/common/extensions/api/passwords_private.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "chrome/grit/chromium_strings.h" @@ -78,6 +79,9 @@ SafetyCheckHandler::UpdateStatus ConvertToUpdateStatus( return SafetyCheckHandler::UpdateStatus::kRelaunch; case VersionUpdater::DISABLED_BY_ADMIN: return SafetyCheckHandler::UpdateStatus::kDisabledByAdmin; + case VersionUpdater::UPDATE_TO_ROLLBACK_VERSION_DISALLOWED: + return SafetyCheckHandler::UpdateStatus:: + kUpdateToRollbackVersionDisallowed; // The disabled state can only be returned on non Chrome-branded browsers. case VersionUpdater::DISABLED: return SafetyCheckHandler::UpdateStatus::kUnknown; @@ -114,6 +118,16 @@ bool IsCredentialWeak( }); } +bool IsCredentialReused( + const extensions::api::passwords_private::PasswordUiEntry& entry) { + DCHECK(entry.compromised_info); + return base::ranges::any_of( + entry.compromised_info->compromise_types, [](auto type) { + return type == + extensions::api::passwords_private::COMPROMISE_TYPE_REUSED; + }); +} + } // namespace base::Time TimestampDelegate::GetSystemTime() { @@ -147,8 +161,8 @@ void SafetyCheckHandler::SendSafetyCheckStartedWebUiUpdates() { GetStringForUpdates(update_status_)); FireBasicSafetyCheckWebUiListener( kPasswordsEvent, static_cast<int>(passwords_status_), - GetStringForPasswords(passwords_status_, Compromised(0), Weak(0), Done(0), - Total(0))); + GetStringForPasswords(passwords_status_, Compromised(0), Weak(0), + Reused(0), Done(0), Total(0))); FireBasicSafetyCheckWebUiListener( kSafeBrowsingEvent, static_cast<int>(safe_browsing_status_), GetStringForSafeBrowsing(safe_browsing_status_)); @@ -350,15 +364,16 @@ void SafetyCheckHandler::OnUpdateCheckResult(UpdateStatus status) { void SafetyCheckHandler::OnPasswordsCheckResult(PasswordsStatus status, Compromised compromised, Weak weak, + Reused reused, Done done, Total total) { base::Value::Dict event; event.Set(kNewState, static_cast<int>(status)); - event.Set(kDisplayString, - GetStringForPasswords(status, compromised, weak, done, total)); + event.Set(kDisplayString, GetStringForPasswords(status, compromised, weak, + reused, done, total)); FireWebUIListener(kPasswordsEvent, event); if (status != PasswordsStatus::kChecking) { - base::UmaHistogramEnumeration("Settings.SafetyCheck.PasswordsResult", + base::UmaHistogramEnumeration("Settings.SafetyCheck.PasswordsResult2", status); } passwords_status_ = status; @@ -416,6 +431,10 @@ std::u16string SafetyCheckHandler::GetStringForUpdates(UpdateStatus status) { return l10n_util::GetStringFUTF16( IDS_SETTINGS_SAFETY_CHECK_UPDATES_DISABLED_BY_ADMIN, base::ASCIIToUTF16(chrome::kWhoIsMyAdministratorHelpURL)); + // This status is only used in ChromeOS. + case UpdateStatus::kUpdateToRollbackVersionDisallowed: + return l10n_util::GetStringUTF16( + IDS_SETTINGS_UPDATE_TO_ROLLBACK_VERSION_DISALLOWED); case UpdateStatus::kFailedOffline: return l10n_util::GetStringUTF16( IDS_SETTINGS_SAFETY_CHECK_UPDATES_FAILED_OFFLINE); @@ -464,6 +483,7 @@ std::u16string SafetyCheckHandler::GetStringForPasswords( PasswordsStatus status, Compromised compromised, Weak weak, + Reused reused, Done done, Total total) { switch (status) { @@ -480,25 +500,37 @@ std::u16string SafetyCheckHandler::GetStringForPasswords( return l10n_util::GetPluralStringFUTF16( IDS_SETTINGS_COMPROMISED_PASSWORDS_COUNT, 0); case PasswordsStatus::kCompromisedExist: - if (weak.value() == 0) { - // Only compromised passwords, no weak passwords. - return l10n_util::GetPluralStringFUTF16( + case PasswordsStatus::kWeakPasswordsExist: + case PasswordsStatus::kReusedPasswordsExist: + case PasswordsStatus::kMutedCompromisedExist: { + // Keep the order since compromised issues should come first, then weak, + // then reused. + std::vector<std::u16string> issues; + if (compromised.value()) { + issues.push_back(l10n_util::GetPluralStringFUTF16( IDS_SETTINGS_COMPROMISED_PASSWORDS_COUNT_SHORT, - compromised.value()); - } else { - // Both compromised and weak passwords. - return l10n_util::GetStringFUTF16( - IDS_CONCAT_TWO_STRINGS_WITH_COMMA, - l10n_util::GetPluralStringFUTF16( - IDS_SETTINGS_COMPROMISED_PASSWORDS_COUNT_SHORT, - compromised.value()), - l10n_util::GetPluralStringFUTF16( - IDS_SETTINGS_WEAK_PASSWORDS_COUNT_SHORT, weak.value())); + compromised.value())); } - case PasswordsStatus::kWeakPasswordsExist: - // Only weak passwords. - return l10n_util::GetPluralStringFUTF16( - IDS_SETTINGS_WEAK_PASSWORDS_COUNT_SHORT, weak.value()); + if (weak.value()) { + issues.push_back(l10n_util::GetPluralStringFUTF16( + IDS_SETTINGS_WEAK_PASSWORDS_COUNT_SHORT, weak.value())); + } + if (reused.value()) { + issues.push_back(l10n_util::GetPluralStringFUTF16( + IDS_SETTINGS_REUSED_PASSWORDS_COUNT_SHORT, reused.value())); + } + + CHECK(!issues.empty()); + if (issues.size() == 1) { + return issues[0]; + } + if (issues.size() == 2) { + return l10n_util::GetStringFUTF16(IDS_CONCAT_TWO_STRINGS_WITH_COMMA, + issues[0], issues[1]); + } + return l10n_util::GetStringFUTF16(IDS_CONCAT_THREE_STRINGS_WITH_COMMA, + issues[0], issues[1], issues[2]); + } case PasswordsStatus::kOffline: return l10n_util::GetStringUTF16( IDS_SETTINGS_CHECK_PASSWORDS_ERROR_OFFLINE); @@ -634,7 +666,7 @@ void SafetyCheckHandler::DetermineIfNoPasswordsOrSafe( passwords) { OnPasswordsCheckResult(passwords.empty() ? PasswordsStatus::kNoPasswords : PasswordsStatus::kSafe, - Compromised(0), Weak(0), Done(0), Total(0)); + Compromised(0), Weak(0), Reused(0), Done(0), Total(0)); } void SafetyCheckHandler::UpdatePasswordsResultOnCheckIdle() { @@ -643,8 +675,25 @@ void SafetyCheckHandler::UpdatePasswordsResultOnCheckIdle() { insecure_credentials, &IsUnmutedCompromisedCredential); size_t num_weak = base::ranges::count_if(insecure_credentials, &IsCredentialWeak); + size_t num_reused = + base::ranges::count_if(insecure_credentials, &IsCredentialReused); - if (num_compromised == 0 && num_weak == 0) { + if (num_compromised > 0) { + // At least one compromised password. Treat as compromises. + OnPasswordsCheckResult(PasswordsStatus::kCompromisedExist, + Compromised(num_compromised), Weak(num_weak), + Reused(num_reused), Done(0), Total(0)); + } else if (num_weak > 0) { + // No compromised but weak passwords. Treat as weak passwords only. + OnPasswordsCheckResult(PasswordsStatus::kWeakPasswordsExist, + Compromised(num_compromised), Weak(num_weak), + Reused(num_reused), Done(0), Total(0)); + } else if (num_reused > 0) { + // No weak or compromised but reused passwords. + OnPasswordsCheckResult(PasswordsStatus::kReusedPasswordsExist, + Compromised(num_compromised), Weak(num_weak), + Reused(num_reused), Done(0), Total(0)); + } else { // If there are no |OnCredentialDone| callbacks with is_leaked = true, no // need to wait for InsecureCredentialsManager callbacks any longer, since // there should be none for the current password check. @@ -654,16 +703,6 @@ void SafetyCheckHandler::UpdatePasswordsResultOnCheckIdle() { passwords_delegate_->GetSavedPasswordsList( base::BindOnce(&SafetyCheckHandler::DetermineIfNoPasswordsOrSafe, base::Unretained(this))); - } else if (num_compromised > 0) { - // At least one compromised password. Treat as compromises. - OnPasswordsCheckResult(PasswordsStatus::kCompromisedExist, - Compromised(num_compromised), Weak(num_weak), - Done(0), Total(0)); - } else { - // No compromised but weak passwords. Treat as weak passwords only. - OnPasswordsCheckResult(PasswordsStatus::kWeakPasswordsExist, - Compromised(num_compromised), Weak(num_weak), - Done(0), Total(0)); } } @@ -695,29 +734,30 @@ void SafetyCheckHandler::OnStateChanged( } case BulkLeakCheckService::State::kRunning: OnPasswordsCheckResult(PasswordsStatus::kChecking, Compromised(0), - Weak(0), Done(0), Total(0)); + Weak(0), Reused(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), - Weak(0), Done(0), Total(0)); + Weak(0), Reused(0), Done(0), Total(0)); break; case BulkLeakCheckService::State::kNetworkError: OnPasswordsCheckResult(PasswordsStatus::kOffline, Compromised(0), Weak(0), - Done(0), Total(0)); + Reused(0), Done(0), Total(0)); break; case BulkLeakCheckService::State::kQuotaLimit: OnPasswordsCheckResult(PasswordsStatus::kQuotaLimit, Compromised(0), - Weak(0), Done(0), Total(0)); + Weak(0), Reused(0), Done(0), Total(0)); break; case BulkLeakCheckService::State::kTokenRequestFailure: OnPasswordsCheckResult(PasswordsStatus::kFeatureUnavailable, - Compromised(0), Weak(0), Done(0), Total(0)); + Compromised(0), Weak(0), Reused(0), Done(0), + Total(0)); break; case BulkLeakCheckService::State::kHashingFailure: case BulkLeakCheckService::State::kServiceError: OnPasswordsCheckResult(PasswordsStatus::kError, Compromised(0), Weak(0), - Done(0), Total(0)); + Reused(0), Done(0), Total(0)); break; } @@ -744,7 +784,7 @@ void SafetyCheckHandler::OnCredentialDone( Done done = Done(*(status.already_processed)); Total total = Total(*(status.remaining_in_queue) + done.value()); OnPasswordsCheckResult(PasswordsStatus::kChecking, Compromised(0), Weak(0), - done, total); + Reused(0), done, total); } } 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 388e6213bb2..cee9b68a3f7 100644 --- a/chromium/chrome/browser/ui/webui/settings/safety_check_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/safety_check_handler.h @@ -129,6 +129,7 @@ class SafetyCheckHandler // check methods. using Compromised = base::StrongAlias<class CompromisedTag, int>; using Weak = base::StrongAlias<class WeakTag, int>; + using Reused = base::StrongAlias<class ReusedTag, int>; using Done = base::StrongAlias<class DoneTag, int>; using Total = base::StrongAlias<class TotalTag, int>; using Blocklisted = base::StrongAlias<class BlocklistedTag, int>; @@ -160,6 +161,7 @@ class SafetyCheckHandler void OnPasswordsCheckResult(PasswordsStatus status, Compromised compromised, Weak weak, + Reused reused, Done done, Total total); void OnExtensionsCheckResult(ExtensionsStatus status, @@ -175,6 +177,7 @@ class SafetyCheckHandler std::u16string GetStringForPasswords(PasswordsStatus status, Compromised compromised, Weak weak, + Reused reused, Done done, Total total); std::u16string GetStringForExtensions(ExtensionsStatus status, 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 fec4bb2ae6b..f38ecf0cc1b 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 @@ -168,6 +168,10 @@ class TestPasswordsDelegate : public extensions::TestPasswordsPrivateDelegate { weak_password_count_ = weak_password_count; } + void SetNumReusedCredentials(int reused_password_count) { + reused_password_count_ = reused_password_count; + } + void SetPasswordCheckState( extensions::api::passwords_private::PasswordCheckState state) { state_ = state; @@ -218,6 +222,11 @@ class TestPasswordsDelegate : public extensions::TestPasswordsPrivateDelegate { insecure.size(), extensions::api::passwords_private::COMPROMISE_TYPE_WEAK)); } + for (int i = 0; i < reused_password_count_; ++i) { + insecure.push_back(CreateInsecureCredential( + insecure.size(), + extensions::api::passwords_private::COMPROMISE_TYPE_REUSED)); + } return insecure; } @@ -245,6 +254,7 @@ class TestPasswordsDelegate : public extensions::TestPasswordsPrivateDelegate { int muted_leaked_password_count_ = 0; int phished_password_count_ = 0; int weak_password_count_ = 0; + int reused_password_count_ = 0; int done_ = 0; int total_ = 0; int test_credential_counter_ = 0; @@ -324,8 +334,9 @@ class SafetyCheckHandlerTest : public testing::Test { content::BrowserTaskEnvironment browser_task_environment_; std::unique_ptr<TestingProfile> profile_; std::unique_ptr<content::WebContents> web_contents_; - raw_ptr<safety_check::TestUpdateCheckHelper> update_helper_ = nullptr; - raw_ptr<TestVersionUpdater> version_updater_ = nullptr; + raw_ptr<safety_check::TestUpdateCheckHelper, DanglingUntriaged> + update_helper_ = nullptr; + raw_ptr<TestVersionUpdater, DanglingUntriaged> version_updater_ = nullptr; std::unique_ptr<password_manager::BulkLeakCheckService> test_leak_service_; scoped_refptr<TestPasswordsDelegate> test_passwords_delegate_; raw_ptr<extensions::ExtensionPrefs> test_extension_prefs_ = nullptr; @@ -584,6 +595,23 @@ TEST_F(SafetyCheckHandlerTest, CheckUpdates_DestroyedOnJavascriptDisallowed) { EXPECT_TRUE(TestDestructionVersionUpdater::GetDestructorInvoked()); } +TEST_F(SafetyCheckHandlerTest, CheckUpdates_UpdateToRollbackVersionDisallowed) { + version_updater_->SetReturnedStatus( + VersionUpdater::Status::UPDATE_TO_ROLLBACK_VERSION_DISALLOWED); + safety_check_->PerformSafetyCheck(); + const base::Value::Dict* event = GetSafetyCheckStatusChangedWithDataIfExists( + kUpdates, static_cast<int>(SafetyCheckHandler::UpdateStatus:: + kUpdateToRollbackVersionDisallowed)); + ASSERT_TRUE(event); + VerifyDisplayString( + event, + "You reverted to a previous version of ChromeOS. " + "To get updates, wait until the next version is available."); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.UpdatesResult", + SafetyCheckHandler::UpdateStatus::kUpdateToRollbackVersionDisallowed, 1); +} + TEST_F(SafetyCheckHandlerTest, CheckSafeBrowsing_EnabledStandard) { TestingProfile::FromWebUI(&test_web_ui_) ->AsTestingProfile() @@ -730,7 +758,8 @@ TEST_F(SafetyCheckHandlerTest, CheckPasswords_ObserverRemovedAfterError) { static_cast<int>(SafetyCheckHandler::PasswordsStatus::kChecking)); ASSERT_TRUE(event); VerifyDisplayString(event, u""); - histogram_tester_.ExpectTotalCount("Settings.SafetyCheck.PasswordsResult", 0); + histogram_tester_.ExpectTotalCount("Settings.SafetyCheck.PasswordsResult2", + 0); // Second, an "offline" state. test_leak_service_->set_state_and_notify( password_manager::BulkLeakCheckService::State::kNetworkError); @@ -742,7 +771,7 @@ TEST_F(SafetyCheckHandlerTest, CheckPasswords_ObserverRemovedAfterError) { "Browser can't check your passwords. Try checking your " "internet connection."); histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.PasswordsResult", + "Settings.SafetyCheck.PasswordsResult2", SafetyCheckHandler::PasswordsStatus::kOffline, 1); // Another error, but since the previous state is terminal, the handler // should no longer be observing the BulkLeakCheckService state. @@ -753,7 +782,7 @@ TEST_F(SafetyCheckHandlerTest, CheckPasswords_ObserverRemovedAfterError) { static_cast<int>(SafetyCheckHandler::PasswordsStatus::kOffline)); ASSERT_TRUE(event3); histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.PasswordsResult", + "Settings.SafetyCheck.PasswordsResult2", SafetyCheckHandler::PasswordsStatus::kOffline, 1); } @@ -792,7 +821,7 @@ TEST_F(SafetyCheckHandlerTest, CheckPasswords_InterruptedAndRefreshed) { "Browser can't check your passwords because you're not " "signed in"); histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.PasswordsResult", + "Settings.SafetyCheck.PasswordsResult2", SafetyCheckHandler::PasswordsStatus::kSignedOut, 1); } @@ -817,7 +846,7 @@ TEST_F(SafetyCheckHandlerTest, CheckPasswords_StartedTwice) { "Browser can't check your passwords. Try checking your " "internet connection."); histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.PasswordsResult", + "Settings.SafetyCheck.PasswordsResult2", SafetyCheckHandler::PasswordsStatus::kOffline, 1); } @@ -855,7 +884,7 @@ TEST_F(SafetyCheckHandlerTest, CheckPasswords_Safe) { EXPECT_TRUE(event); VerifyDisplayString(event, "No compromised passwords found"); histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.PasswordsResult", + "Settings.SafetyCheck.PasswordsResult2", SafetyCheckHandler::PasswordsStatus::kSafe, 1); } @@ -955,7 +984,7 @@ TEST_F(SafetyCheckHandlerTest, CheckPasswords_OnlyLeakedExist) { VerifyDisplayString(event2, base::NumberToString(kLeaked) + " compromised passwords"); histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.PasswordsResult", + "Settings.SafetyCheck.PasswordsResult2", SafetyCheckHandler::PasswordsStatus::kCompromisedExist, 1); } @@ -979,7 +1008,7 @@ TEST_F(SafetyCheckHandlerTest, CheckPasswords_OnlyPhishedExist) { VerifyDisplayString( event2, base::NumberToString(kPhished) + " compromised passwords"); histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.PasswordsResult", + "Settings.SafetyCheck.PasswordsResult2", SafetyCheckHandler::PasswordsStatus::kCompromisedExist, 1); } @@ -1004,7 +1033,7 @@ TEST_F(SafetyCheckHandlerTest, CheckPasswords_LeakedAndPhishedExist) { VerifyDisplayString(event2, base::NumberToString(kLeaked + kPhished) + " compromised passwords"); histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.PasswordsResult", + "Settings.SafetyCheck.PasswordsResult2", SafetyCheckHandler::PasswordsStatus::kCompromisedExist, 1); } @@ -1031,10 +1060,96 @@ TEST_F(SafetyCheckHandlerTest, CheckPasswords_CompromisedAndWeakExist) { event2, base::NumberToString(kCompromised) + " compromised passwords, " + base::NumberToString(kWeak) + " weak passwords"); histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.PasswordsResult", + "Settings.SafetyCheck.PasswordsResult2", + SafetyCheckHandler::PasswordsStatus::kCompromisedExist, 1); +} + +TEST_F(SafetyCheckHandlerTest, CheckPasswords_CompromisedAndReusedExist) { + constexpr int kCompromised = 7; + constexpr int kReused = 13; + test_passwords_delegate_->SetNumLeakedCredentials(kCompromised); + test_passwords_delegate_->SetNumReusedCredentials(kReused); + 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::Value::Dict* event2 = GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>(SafetyCheckHandler::PasswordsStatus::kCompromisedExist)); + ASSERT_TRUE(event2); + VerifyDisplayString( + event2, base::NumberToString(kCompromised) + " compromised passwords, " + + base::NumberToString(kReused) + " reused passwords"); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.PasswordsResult2", + SafetyCheckHandler::PasswordsStatus::kCompromisedExist, 1); +} + +TEST_F(SafetyCheckHandlerTest, + CheckPasswords_CompromisedAndWeakAndReusedExist) { + constexpr int kCompromised = 7; + constexpr int kWeak = 13; + constexpr int kReused = 6; + test_passwords_delegate_->SetNumLeakedCredentials(kCompromised); + test_passwords_delegate_->SetNumWeakCredentials(kWeak); + test_passwords_delegate_->SetNumReusedCredentials(kReused); + 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::Value::Dict* event2 = GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>(SafetyCheckHandler::PasswordsStatus::kCompromisedExist)); + ASSERT_TRUE(event2); + VerifyDisplayString( + event2, base::NumberToString(kCompromised) + " compromised passwords, " + + base::NumberToString(kWeak) + " weak passwords, " + + base::NumberToString(kReused) + " reused passwords"); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.PasswordsResult2", SafetyCheckHandler::PasswordsStatus::kCompromisedExist, 1); } +TEST_F(SafetyCheckHandlerTest, CheckPasswords_WeakAndReusedExist) { + constexpr int kWeak = 13; + constexpr int kReused = 6; + test_passwords_delegate_->SetNumWeakCredentials(kWeak); + test_passwords_delegate_->SetNumReusedCredentials(kReused); + 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::Value::Dict* event2 = GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>( + SafetyCheckHandler::PasswordsStatus::kWeakPasswordsExist)); + ASSERT_TRUE(event2); + VerifyDisplayString(event2, + base::NumberToString(kWeak) + " weak passwords, " + + base::NumberToString(kReused) + " reused passwords"); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.PasswordsResult2", + SafetyCheckHandler::PasswordsStatus::kWeakPasswordsExist, 1); +} + TEST_F(SafetyCheckHandlerTest, CheckPasswords_OnlyWeakExist) { constexpr int kWeak = 13; test_passwords_delegate_->SetNumWeakCredentials(kWeak); @@ -1055,10 +1170,35 @@ TEST_F(SafetyCheckHandlerTest, CheckPasswords_OnlyWeakExist) { ASSERT_TRUE(event2); VerifyDisplayString(event2, base::NumberToString(kWeak) + " weak passwords"); histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.PasswordsResult", + "Settings.SafetyCheck.PasswordsResult2", SafetyCheckHandler::PasswordsStatus::kWeakPasswordsExist, 1); } +TEST_F(SafetyCheckHandlerTest, CheckPasswords_OnlyReusedExist) { + constexpr int kReused = 13; + test_passwords_delegate_->SetNumReusedCredentials(kReused); + 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::Value::Dict* event = GetSafetyCheckStatusChangedWithDataIfExists( + kPasswords, + static_cast<int>( + SafetyCheckHandler::PasswordsStatus::kReusedPasswordsExist)); + ASSERT_TRUE(event); + VerifyDisplayString(event, + base::NumberToString(kReused) + " reused passwords"); + histogram_tester_.ExpectBucketCount( + "Settings.SafetyCheck.PasswordsResult2", + SafetyCheckHandler::PasswordsStatus::kReusedPasswordsExist, 1); +} + TEST_F(SafetyCheckHandlerTest, CheckPasswords_Error) { safety_check_->PerformSafetyCheck(); EXPECT_TRUE(test_passwords_delegate_->StartPasswordCheckTriggered()); @@ -1074,7 +1214,7 @@ TEST_F(SafetyCheckHandlerTest, CheckPasswords_Error) { "Browser can't check your passwords. Try again " "later."); histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.PasswordsResult", + "Settings.SafetyCheck.PasswordsResult2", SafetyCheckHandler::PasswordsStatus::kError, 1); } @@ -1099,7 +1239,7 @@ TEST_F(SafetyCheckHandlerTest, CheckPasswords_MutedCompromisedExist) { VerifyDisplayString(event2, base::NumberToString(kCompromised - kMuted) + " compromised passwords"); histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.PasswordsResult", + "Settings.SafetyCheck.PasswordsResult2", SafetyCheckHandler::PasswordsStatus::kCompromisedExist, 1); } @@ -1120,7 +1260,7 @@ TEST_F(SafetyCheckHandlerTest, CheckPasswords_AllMutedCompromisedCredentials) { kPasswords, static_cast<int>(SafetyCheckHandler::PasswordsStatus::kSafe)); ASSERT_TRUE(event); histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.PasswordsResult", + "Settings.SafetyCheck.PasswordsResult2", SafetyCheckHandler::PasswordsStatus::kSafe, 1); } @@ -1139,7 +1279,7 @@ TEST_F(SafetyCheckHandlerTest, CheckPasswords_Error_FutureEventsIgnored) { "Browser can't check your passwords. Try again " "later."); histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.PasswordsResult", + "Settings.SafetyCheck.PasswordsResult2", SafetyCheckHandler::PasswordsStatus::kError, 1); // At some point later, the service discovers compromised passwords and goes // idle. @@ -1176,7 +1316,7 @@ TEST_F(SafetyCheckHandlerTest, CheckPasswords_FeatureUnavailable) { ASSERT_TRUE(event); VerifyDisplayString(event, "Password check is not available in Chromium"); histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.PasswordsResult", + "Settings.SafetyCheck.PasswordsResult2", SafetyCheckHandler::PasswordsStatus::kFeatureUnavailable, 1); } @@ -1193,7 +1333,7 @@ TEST_F(SafetyCheckHandlerTest, CheckPasswords_RunningOneCompromised) { ASSERT_TRUE(event); VerifyDisplayString(event, "1 compromised password"); histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.PasswordsResult", + "Settings.SafetyCheck.PasswordsResult2", SafetyCheckHandler::PasswordsStatus::kCompromisedExist, 1); } @@ -1210,7 +1350,7 @@ TEST_F(SafetyCheckHandlerTest, CheckPasswords_NoPasswords) { "No saved passwords. Chrome can check your passwords " "when you save them."); histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.PasswordsResult", + "Settings.SafetyCheck.PasswordsResult2", SafetyCheckHandler::PasswordsStatus::kNoPasswords, 1); } diff --git a/chromium/chrome/browser/ui/webui/settings/safety_hub_handler.cc b/chromium/chrome/browser/ui/webui/settings/safety_hub_handler.cc new file mode 100644 index 00000000000..b29fba3d6b1 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/safety_hub_handler.cc @@ -0,0 +1,424 @@ +// Copyright 2022 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/settings/safety_hub_handler.h" +#include <memory> + +#include "base/check.h" +#include "base/json/values_util.h" +#include "base/metrics/histogram_functions.h" +#include "base/strings/utf_string_conversions.h" +#include "base/threading/thread_checker.h" +#include "base/time/default_clock.h" +#include "base/time/time.h" +#include "base/values.h" +#include "chrome/browser/content_settings/host_content_settings_map_factory.h" +#include "chrome/browser/permissions/notification_permission_review_service_factory.h" +#include "chrome/browser/permissions/unused_site_permissions_service_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/settings/site_settings_helper.h" +#include "chrome/common/chrome_features.h" +#include "chrome/grit/generated_resources.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_pattern.h" +#include "components/content_settings/core/common/features.h" +#include "components/permissions/constants.h" +#include "components/permissions/unused_site_permissions_service.h" +#include "components/site_engagement/content/site_engagement_service.h" +#include "ui/base/l10n/l10n_util.h" +#include "url/gurl.h" + +namespace { +// Key of the expiration time in the |UnusedSitePermissions| object. Indicates +// the time after which the associated origin and permissions are no longer +// shown in the UI. +constexpr char kExpirationKey[] = "expiration"; +// Key of the lifetime in the |UnusedSitePermissions| object. +constexpr char kLifetimeKey[] = "lifetime"; + +// Get values from |UnusedSitePermission| object in +// safety_hub_browser_proxy.ts. +std::tuple<url::Origin, + std::set<ContentSettingsType>, + content_settings::ContentSettingConstraints> +GetUnusedSitePermissionsFromDict( + const base::Value::Dict& unused_site_permissions) { + const std::string* origin_str = + unused_site_permissions.FindString(site_settings::kOrigin); + CHECK(origin_str); + const auto url = GURL(*origin_str); + CHECK(url.is_valid()); + const url::Origin origin = url::Origin::Create(url); + + const base::Value::List* permissions = + unused_site_permissions.FindList(site_settings::kPermissions); + CHECK(permissions); + std::set<ContentSettingsType> permission_types; + for (const auto& permission : *permissions) { + CHECK(permission.is_string()); + const std::string& type_string = permission.GetString(); + ContentSettingsType type = + site_settings::ContentSettingsTypeFromGroupName(type_string); + CHECK(type != ContentSettingsType::DEFAULT) + << type_string << " is not expected to have a UI representation."; + permission_types.insert(type); + } + + const base::Value* js_expiration = + unused_site_permissions.Find(kExpirationKey); + CHECK(js_expiration); + base::Time expiration = base::ValueToTime(js_expiration).value(); + + const base::Value* js_lifetime = unused_site_permissions.Find(kLifetimeKey); + // TODO(https://crbug.com/1455435): The use of ComputeLifetime here should be + // temporary. Once all persisted RuleMetaData instances include lifetimes, we + // can remove this, and just use the stored lifetime directly. We can do this + // after all lifetime-less settings have expired. Realistically this will take + // only one or two milestones, so this can safely be removed in M118 or M119. + base::TimeDelta lifetime = content_settings::RuleMetaData::ComputeLifetime( + /*lifetime=*/js_lifetime ? base::ValueToTimeDelta(js_lifetime).value() + : base::TimeDelta(), + /*expiration=*/expiration); + + content_settings::ContentSettingConstraints constraints = + content_settings::ContentSettingConstraints(expiration - lifetime); + constraints.set_lifetime(lifetime); + + return std::make_tuple(origin, permission_types, constraints); +} +} // namespace + +SafetyHubHandler::SafetyHubHandler(Profile* profile) + : profile_(profile), clock_(base::DefaultClock::GetInstance()) {} +SafetyHubHandler::~SafetyHubHandler() = default; + +// static +std::unique_ptr<SafetyHubHandler> SafetyHubHandler::GetForProfile( + Profile* profile) { + return std::make_unique<SafetyHubHandler>(profile); +} + +void SafetyHubHandler::HandleGetRevokedUnusedSitePermissionsList( + const base::Value::List& args) { + AllowJavascript(); + + CHECK_EQ(1U, args.size()); + const base::Value& callback_id = args[0]; + + base::Value::List result = PopulateUnusedSitePermissionsData(); + + ResolveJavascriptCallback(callback_id, base::Value(std::move(result))); +} + +void SafetyHubHandler::HandleAllowPermissionsAgainForUnusedSite( + const base::Value::List& args) { + CHECK_EQ(1U, args.size()); + CHECK(args[0].is_string()); + const std::string& origin_str = args[0].GetString(); + + permissions::UnusedSitePermissionsService* service = + UnusedSitePermissionsServiceFactory::GetForProfile(profile_); + + url::Origin origin = url::Origin::Create(GURL(origin_str)); + + service->RegrantPermissionsForOrigin(origin); + SendUnusedSitePermissionsReviewList(); +} + +void SafetyHubHandler::HandleUndoAllowPermissionsAgainForUnusedSite( + const base::Value::List& args) { + CHECK_EQ(1U, args.size()); + CHECK(args[0].is_dict()); + + auto [origin, permissions, constraints] = + GetUnusedSitePermissionsFromDict(args[0].GetDict()); + permissions::UnusedSitePermissionsService* service = + UnusedSitePermissionsServiceFactory::GetForProfile(profile_); + + service->UndoRegrantPermissionsForOrigin(permissions, constraints, origin); + + SendUnusedSitePermissionsReviewList(); +} + +void SafetyHubHandler::HandleAcknowledgeRevokedUnusedSitePermissionsList( + const base::Value::List& args) { + permissions::UnusedSitePermissionsService* service = + UnusedSitePermissionsServiceFactory::GetForProfile(profile_); + service->ClearRevokedPermissionsList(); + + SendUnusedSitePermissionsReviewList(); +} + +void SafetyHubHandler::HandleUndoAcknowledgeRevokedUnusedSitePermissionsList( + const base::Value::List& args) { + CHECK_EQ(1U, args.size()); + CHECK(args[0].is_list()); + + const base::Value::List& unused_site_permissions_list = args[0].GetList(); + permissions::UnusedSitePermissionsService* service = + UnusedSitePermissionsServiceFactory::GetForProfile(profile_); + + for (const auto& unused_site_permissions_js : unused_site_permissions_list) { + CHECK(unused_site_permissions_js.is_dict()); + auto [origin, permissions, constraints] = + GetUnusedSitePermissionsFromDict(unused_site_permissions_js.GetDict()); + + service->StorePermissionInRevokedPermissionSetting(permissions, constraints, + origin); + } + + SendUnusedSitePermissionsReviewList(); +} + +base::Value::List SafetyHubHandler::PopulateUnusedSitePermissionsData() { + base::Value::List result; + if (!base::FeatureList::IsEnabled( + content_settings::features::kSafetyCheckUnusedSitePermissions)) { + return result; + } + + HostContentSettingsMap* hcsm = + HostContentSettingsMapFactory::GetForProfile(profile_); + + ContentSettingsForOneType settings; + hcsm->GetSettingsForOneType( + ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS, &settings); + + for (const auto& revoked_permissions : settings) { + base::Value::Dict revoked_permission_value; + revoked_permission_value.Set( + site_settings::kOrigin, revoked_permissions.primary_pattern.ToString()); + const base::Value& stored_value = revoked_permissions.setting_value; + DCHECK(stored_value.is_dict()); + + // The revoked permissions list should be reachable by given key. + DCHECK(stored_value.GetDict().FindList(permissions::kRevokedKey)); + + auto type_list = + stored_value.GetDict().FindList(permissions::kRevokedKey)->Clone(); + base::Value::List permissions_value_list; + for (base::Value& type : type_list) { + base::StringPiece permission_str = + site_settings::ContentSettingsTypeToGroupName( + static_cast<ContentSettingsType>(type.GetInt())); + if (!permission_str.empty()) { + permissions_value_list.Append(permission_str); + } + } + + // Some permissions have no readable name, although Safety Hub revokes them. + // To prevent crashes, if there is no permission to be shown in the UI, the + // origin will not be added to the revoked permissions list. + // TODO(crbug.com/1459305): Remove this after adding check for + // ContentSettingsTypeToGroupName. + if (permissions_value_list.empty()) { + continue; + } + + revoked_permission_value.Set( + site_settings::kPermissions, + base::Value(std::move(permissions_value_list))); + + revoked_permission_value.Set( + kExpirationKey, + base::TimeToValue(revoked_permissions.metadata.expiration())); + + revoked_permission_value.Set( + kLifetimeKey, + base::TimeDeltaToValue(revoked_permissions.metadata.lifetime())); + + result.Append(std::move(revoked_permission_value)); + } + return result; +} + +void SafetyHubHandler::HandleGetNotificationPermissionReviewList( + const base::Value::List& args) { + AllowJavascript(); + + const base::Value& callback_id = args[0]; + + base::Value::List result = + site_settings::PopulateNotificationPermissionReviewData(profile_); + + ResolveJavascriptCallback(callback_id, base::Value(std::move(result))); +} + +void SafetyHubHandler::HandleIgnoreOriginsForNotificationPermissionReview( + const base::Value::List& args) { + CHECK_EQ(1U, args.size()); + const base::Value::List& origins = args[0].GetList(); + + auto* service = + NotificationPermissionsReviewServiceFactory::GetForProfile(profile_); + DCHECK(service); + + for (const auto& origin : origins) { + const ContentSettingsPattern primary_pattern = + ContentSettingsPattern::FromString(origin.GetString()); + service->AddPatternToNotificationPermissionReviewBlocklist( + primary_pattern, ContentSettingsPattern::Wildcard()); + } + + SendNotificationPermissionReviewList(); +} + +void SafetyHubHandler::HandleResetNotificationPermissionForOrigins( + const base::Value::List& args) { + CHECK_EQ(1U, args.size()); + + const base::Value::List& origins = args[0].GetList(); + + HostContentSettingsMap* map = + HostContentSettingsMapFactory::GetForProfile(profile_); + + for (const auto& origin : origins) { + map->SetContentSettingCustomScope( + ContentSettingsPattern::FromString(origin.GetString()), + ContentSettingsPattern::Wildcard(), ContentSettingsType::NOTIFICATIONS, + CONTENT_SETTING_DEFAULT); + } + + SendNotificationPermissionReviewList(); +} + +void SafetyHubHandler::HandleBlockNotificationPermissionForOrigins( + const base::Value::List& args) { + CHECK_EQ(1U, args.size()); + const base::Value::List& origins = args[0].GetList(); + + HostContentSettingsMap* map = + HostContentSettingsMapFactory::GetForProfile(profile_); + for (const auto& origin : origins) { + map->SetContentSettingCustomScope( + ContentSettingsPattern::FromString(origin.GetString()), + ContentSettingsPattern::Wildcard(), ContentSettingsType::NOTIFICATIONS, + CONTENT_SETTING_BLOCK); + } + + SendNotificationPermissionReviewList(); +} + +void SafetyHubHandler::HandleAllowNotificationPermissionForOrigins( + const base::Value::List& args) { + CHECK_EQ(1U, args.size()); + const base::Value::List& origins = args[0].GetList(); + + HostContentSettingsMap* map = + HostContentSettingsMapFactory::GetForProfile(profile_); + + for (const auto& origin : origins) { + map->SetContentSettingCustomScope( + ContentSettingsPattern::FromString(origin.GetString()), + ContentSettingsPattern::Wildcard(), ContentSettingsType::NOTIFICATIONS, + CONTENT_SETTING_ALLOW); + } + + SendNotificationPermissionReviewList(); +} + +void SafetyHubHandler::HandleUndoIgnoreOriginsForNotificationPermissionReview( + const base::Value::List& args) { + CHECK_EQ(1U, args.size()); + const base::Value::List& origins = args[0].GetList(); + auto* service = + NotificationPermissionsReviewServiceFactory::GetForProfile(profile_); + DCHECK(service); + + for (const auto& origin : origins) { + const ContentSettingsPattern& primary_pattern = + ContentSettingsPattern::FromString(origin.GetString()); + service->RemovePatternFromNotificationPermissionReviewBlocklist( + primary_pattern, ContentSettingsPattern::Wildcard()); + } + SendNotificationPermissionReviewList(); +} + +void SafetyHubHandler::RegisterMessages() { + // Usage of base::Unretained(this) is safe, because web_ui() owns `this` and + // won't release ownership until destruction. + web_ui()->RegisterMessageCallback( + "getRevokedUnusedSitePermissionsList", + base::BindRepeating( + &SafetyHubHandler::HandleGetRevokedUnusedSitePermissionsList, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "allowPermissionsAgainForUnusedSite", + base::BindRepeating( + &SafetyHubHandler::HandleAllowPermissionsAgainForUnusedSite, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "undoAllowPermissionsAgainForUnusedSite", + base::BindRepeating( + &SafetyHubHandler::HandleUndoAllowPermissionsAgainForUnusedSite, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "acknowledgeRevokedUnusedSitePermissionsList", + base::BindRepeating( + &SafetyHubHandler::HandleAcknowledgeRevokedUnusedSitePermissionsList, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "undoAcknowledgeRevokedUnusedSitePermissionsList", + base::BindRepeating( + &SafetyHubHandler:: + HandleUndoAcknowledgeRevokedUnusedSitePermissionsList, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "getNotificationPermissionReview", + base::BindRepeating( + &SafetyHubHandler::HandleGetNotificationPermissionReviewList, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "ignoreNotificationPermissionReviewForOrigins", + base::BindRepeating( + &SafetyHubHandler::HandleIgnoreOriginsForNotificationPermissionReview, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "resetNotificationPermissionForOrigins", + base::BindRepeating( + &SafetyHubHandler::HandleResetNotificationPermissionForOrigins, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "blockNotificationPermissionForOrigins", + base::BindRepeating( + &SafetyHubHandler::HandleBlockNotificationPermissionForOrigins, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "allowNotificationPermissionForOrigins", + base::BindRepeating( + &SafetyHubHandler::HandleAllowNotificationPermissionForOrigins, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "undoIgnoreNotificationPermissionReviewForOrigins", + base::BindRepeating( + &SafetyHubHandler:: + HandleUndoIgnoreOriginsForNotificationPermissionReview, + base::Unretained(this))); +} + +void SafetyHubHandler::SendUnusedSitePermissionsReviewList() { + // Notify observers that the unused site permission review list could have + // changed. Note that the list is not guaranteed to have changed. In places + // where determining whether the list has changed is cause for performance + // concerns, an unchanged list may be sent. + FireWebUIListener("unused-permission-review-list-maybe-changed", + PopulateUnusedSitePermissionsData()); +} + +void SafetyHubHandler::SendNotificationPermissionReviewList() { + // Notify observers that the permission review list could have changed. Note + // that the list is not guaranteed to have changed. + FireWebUIListener( + site_settings::kNotificationPermissionsReviewListMaybeChangedEvent, + site_settings::PopulateNotificationPermissionReviewData(profile_)); +} + +void SafetyHubHandler::SetClockForTesting(base::Clock* clock) { + clock_ = clock; +} + +void SafetyHubHandler::OnJavascriptAllowed() {} + +void SafetyHubHandler::OnJavascriptDisallowed() {} diff --git a/chromium/chrome/browser/ui/webui/settings/safety_hub_handler.h b/chromium/chrome/browser/ui/webui/settings/safety_hub_handler.h new file mode 100644 index 00000000000..c073b42d778 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/safety_hub_handler.h @@ -0,0 +1,132 @@ +// Copyright 2022 The Chromium Authors +// 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_SAFETY_HUB_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_SAFETY_HUB_HANDLER_H_ + +#include "base/gtest_prod_util.h" +#include "base/memory/raw_ptr.h" +#include "base/time/clock.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" +#include "components/content_settings/core/common/content_settings_constraints.h" +#include "components/content_settings/core/common/content_settings_types.h" +#include "url/origin.h" + +/** + * This handler deals with the permission-related operations on the site + * settings page. + */ + +class SafetyHubHandler : public settings::SettingsPageUIHandler { + public: + explicit SafetyHubHandler(Profile* profile); + + ~SafetyHubHandler() override; + + static std::unique_ptr<SafetyHubHandler> GetForProfile(Profile* profile); + + private: + friend class SafetyHubHandlerTest; + FRIEND_TEST_ALL_PREFIXES(SafetyHubHandlerTest, + PopulateUnusedSitePermissionsData); + FRIEND_TEST_ALL_PREFIXES(SafetyHubHandlerTest, + HandleAllowPermissionsAgainForUnusedSite); + FRIEND_TEST_ALL_PREFIXES(SafetyHubHandlerTest, + HandleAcknowledgeRevokedUnusedSitePermissionsList); + FRIEND_TEST_ALL_PREFIXES(SafetyHubHandlerTest, + HandleIgnoreOriginsForNotificationPermissionReview); + FRIEND_TEST_ALL_PREFIXES(SafetyHubHandlerTest, + HandleBlockNotificationPermissionForOrigins); + FRIEND_TEST_ALL_PREFIXES(SafetyHubHandlerTest, + HandleAllowNotificationPermissionForOrigins); + FRIEND_TEST_ALL_PREFIXES(SafetyHubHandlerTest, + HandleResetNotificationPermissionForOrigins); + FRIEND_TEST_ALL_PREFIXES(SafetyHubHandlerTest, + PopulateNotificationPermissionReviewData); + FRIEND_TEST_ALL_PREFIXES( + SafetyHubHandlerTest, + HandleUndoIgnoreOriginsForNotificationPermissionReview); + FRIEND_TEST_ALL_PREFIXES(SafetyHubHandlerTest, + SendNotificationPermissionReviewList_FeatureEnabled); + FRIEND_TEST_ALL_PREFIXES( + SafetyHubHandlerTest, + SendNotificationPermissionReviewList_FeatureDisabled); + FRIEND_TEST_ALL_PREFIXES(SafetyHubHandlerTest, RevokeAllContentSettingTypes); + + // SettingsPageUIHandler implementation. + void OnJavascriptAllowed() override; + void OnJavascriptDisallowed() override; + + // WebUIMessageHandler implementation. + void RegisterMessages() override; + + // Returns the list of revoked permissions to be used in + // "Unused site permissions" module. + void HandleGetRevokedUnusedSitePermissionsList(const base::Value::List& args); + + // Re-grant the revoked permissions and remove the given origin from the + // revoked permissions list. + void HandleAllowPermissionsAgainForUnusedSite(const base::Value::List& args); + + // Reverse the changes made by |HandleAllowPermissionsAgainForUnusedSite| for + // the given |UnusedSitePermission| object. + void HandleUndoAllowPermissionsAgainForUnusedSite( + const base::Value::List& args); + + // Clear the list of revoked permissions so they are not shown again. + // Permission settings themselves are not affected by this. + void HandleAcknowledgeRevokedUnusedSitePermissionsList( + const base::Value::List& args); + + // Reverse the changes made by + // |HandleAcknowledgeRevokedUnusedSitePermissionsList| for the given list of + // |UnusedSitePermission| objects. List of revoked + // permissions is repopulated. Permission settings are not changed. + void HandleUndoAcknowledgeRevokedUnusedSitePermissionsList( + const base::Value::List& args); + + // Returns the list of revoked permissions that belongs to origins which + // haven't been visited recently. + base::Value::List PopulateUnusedSitePermissionsData(); + + // Sends the list of unused site permissions to review to the WebUI. + void SendUnusedSitePermissionsReviewList(); + + // Returns the list of notification permissions that needs to be reviewed. + void HandleGetNotificationPermissionReviewList(const base::Value::List& args); + + // Handles ignoring origins for the review notification permissions feature. + void HandleIgnoreOriginsForNotificationPermissionReview( + const base::Value::List& args); + + // Handles resetting a notification permission for given origins. + void HandleResetNotificationPermissionForOrigins( + const base::Value::List& args); + + // Handles blocking notification permissions for multiple origins. + void HandleBlockNotificationPermissionForOrigins( + const base::Value::List& args); + + // Handles allowing notification permissions for multiple origins. + void HandleAllowNotificationPermissionForOrigins( + const base::Value::List& args); + + // Handles reverting the action of ignoring origins for review notification + // permissions feature by removing them from the notification permission + // verification blocklist. + void HandleUndoIgnoreOriginsForNotificationPermissionReview( + const base::Value::List& args); + + // Sends the list of notification permissions to review to the WebUI. + void SendNotificationPermissionReviewList(); + + const raw_ptr<Profile, DanglingUntriaged> profile_; + + raw_ptr<base::Clock> clock_; + + void SetClockForTesting(base::Clock* clock); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_SAFETY_HUB_HANDLER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/safety_hub_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/safety_hub_handler_unittest.cc new file mode 100644 index 00000000000..eff41a3c8b1 --- /dev/null +++ b/chromium/chrome/browser/ui/webui/settings/safety_hub_handler_unittest.cc @@ -0,0 +1,390 @@ +// Copyright 2022 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <ctime> +#include <memory> + +#include "base/memory/scoped_refptr.h" +#include "base/test/simple_test_clock.h" +#include "base/time/clock.h" +#include "chrome/browser/content_settings/host_content_settings_map_factory.h" +#include "chrome/browser/history/history_service_factory.h" +#include "chrome/browser/permissions/notification_permission_review_service_factory.h" +#include "chrome/browser/ui/webui/settings/safety_hub_handler.h" +#include "chrome/browser/ui/webui/settings/site_settings_helper.h" +#include "chrome/common/chrome_features.h" +#include "chrome/test/base/testing_profile.h" +#include "components/content_settings/core/browser/content_settings_registry.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_pattern.h" +#include "components/content_settings/core/common/content_settings_types.h" +#include "components/content_settings/core/common/features.h" +#include "components/permissions/constants.h" +#include "components/permissions/unused_site_permissions_service.h" +#include "content/public/browser/storage_partition.h" +#include "content/public/common/content_features.h" +#include "content/public/test/browser_task_environment.h" +#include "content/public/test/test_web_ui.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +constexpr char kUnusedTestSite[] = "https://example1.com"; +constexpr char kUsedTestSite[] = "https://example2.com"; +constexpr ContentSettingsType kUnusedPermission = + ContentSettingsType::GEOLOCATION; + +class SafetyHubHandlerTest : public testing::Test { + public: + SafetyHubHandlerTest() { + feature_list_.InitAndEnableFeature( + content_settings::features::kSafetyCheckUnusedSitePermissions); + } + + void SetUp() override { + // Fully initialize |profile_| in the constructor since some children + // classes need it right away for SetUp(). + TestingProfile::Builder profile_builder; + profile_builder.AddTestingFactory( + HistoryServiceFactory::GetInstance(), + HistoryServiceFactory::GetDefaultFactory()); + profile_ = profile_builder.Build(); + + // Set clock for HostContentSettingsMap. + base::Time time; + ASSERT_TRUE(base::Time::FromString("2022-09-07 13:00", &time)); + clock_.SetNow(time); + hcsm_ = HostContentSettingsMapFactory::GetForProfile(profile()); + hcsm_->SetClockForTesting(&clock_); + + handler_ = std::make_unique<SafetyHubHandler>(profile()); + handler()->set_web_ui(web_ui()); + handler()->AllowJavascript(); + + // Create a revoked permission. + base::Value::Dict dict = base::Value::Dict(); + base::Value::List permission_type_list = base::Value::List(); + permission_type_list.Append( + static_cast<int32_t>(ContentSettingsType::GEOLOCATION)); + dict.Set(permissions::kRevokedKey, + base::Value::List(std::move(permission_type_list))); + + hcsm()->SetWebsiteSettingDefaultScope( + GURL(kUnusedTestSite), GURL(kUnusedTestSite), + ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS, + base::Value(dict.Clone())); + + // There should be only an unused URL in the revoked permissions list. + const auto& revoked_permissions = + handler()->PopulateUnusedSitePermissionsData(); + EXPECT_EQ(revoked_permissions.size(), 1UL); + EXPECT_EQ(GURL(kUnusedTestSite), + GURL(*revoked_permissions[0].GetDict().FindString( + site_settings::kOrigin))); + } + + void TearDown() override { + if (profile_) { + auto* partition = profile_->GetDefaultStoragePartition(); + if (partition) { + partition->WaitForDeletionTasksForTesting(); + } + } + } + + void ExpectRevokedPermission() { + ContentSettingsForOneType revoked_permissions_list; + hcsm()->GetSettingsForOneType( + ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS, + &revoked_permissions_list); + EXPECT_EQ(1U, revoked_permissions_list.size()); + EXPECT_EQ( + ContentSetting::CONTENT_SETTING_ASK, + hcsm()->GetContentSetting(GURL(kUnusedTestSite), GURL(kUnusedTestSite), + kUnusedPermission)); + } + + void ValidateNotificationPermissionUpdate() { + const content::TestWebUI::CallData& data = *web_ui()->call_data().back(); + EXPECT_EQ("cr.webUIListenerCallback", data.function_name()); + + ASSERT_TRUE(data.arg1()->is_string()); + EXPECT_EQ("notification-permission-review-list-maybe-changed", + data.arg1()->GetString()); + + ASSERT_TRUE(data.arg2()->is_list()); + } + + base::Value::List GetOriginList(int size) { + base::Value::List origins; + for (int i = 0; i < size; i++) { + origins.Append("https://example" + base::NumberToString(i) + ".org:443"); + } + return origins; + } + + TestingProfile* profile() { return profile_.get(); } + content::TestWebUI* web_ui() { return &web_ui_; } + SafetyHubHandler* handler() { return handler_.get(); } + HostContentSettingsMap* hcsm() { return hcsm_.get(); } + base::SimpleTestClock* clock() { return &clock_; } + + private: + base::test::ScopedFeatureList feature_list_; + content::BrowserTaskEnvironment task_environment_; + std::unique_ptr<SafetyHubHandler> handler_; + std::unique_ptr<TestingProfile> profile_; + content::TestWebUI web_ui_; + scoped_refptr<HostContentSettingsMap> hcsm_; + base::SimpleTestClock clock_; +}; + +TEST_F(SafetyHubHandlerTest, PopulateUnusedSitePermissionsData) { + // Add GEOLOCATION setting for url but do not add to revoked list. + content_settings::ContentSettingConstraints constraint; + constraint.set_track_last_visit_for_autoexpiration(true); + hcsm()->SetContentSettingDefaultScope( + GURL(kUsedTestSite), GURL(kUsedTestSite), + ContentSettingsType::GEOLOCATION, ContentSetting::CONTENT_SETTING_ALLOW, + constraint); + + // Revoked permissions list should still only contain the initial unused site. + const auto& revoked_permissions = + handler()->PopulateUnusedSitePermissionsData(); + EXPECT_EQ(revoked_permissions.size(), 1UL); + EXPECT_EQ(GURL(kUnusedTestSite), + GURL(*revoked_permissions[0].GetDict().FindString( + site_settings::kOrigin))); +} + +TEST_F(SafetyHubHandlerTest, HandleAllowPermissionsAgainForUnusedSite) { + base::Value::List initial_unused_site_permissions = + handler()->PopulateUnusedSitePermissionsData(); + ExpectRevokedPermission(); + + // Allow the revoked permission for the unused site again. + base::Value::List args; + args.Append(base::Value(kUnusedTestSite)); + handler()->HandleAllowPermissionsAgainForUnusedSite(args); + + // Check there is no origin in revoked permissions list. + ContentSettingsForOneType revoked_permissions_list; + hcsm()->GetSettingsForOneType( + ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS, + &revoked_permissions_list); + EXPECT_EQ(0U, revoked_permissions_list.size()); + // Check if the permissions of url is regranted. + EXPECT_EQ( + ContentSetting::CONTENT_SETTING_ALLOW, + hcsm()->GetContentSetting(GURL(kUnusedTestSite), GURL(kUnusedTestSite), + kUnusedPermission)); + + // Undoing restores the initial state. + handler()->HandleUndoAllowPermissionsAgainForUnusedSite( + std::move(initial_unused_site_permissions)); + ExpectRevokedPermission(); +} + +TEST_F(SafetyHubHandlerTest, + HandleAcknowledgeRevokedUnusedSitePermissionsList) { + const auto& revoked_permissions_before = + handler()->PopulateUnusedSitePermissionsData(); + EXPECT_GT(revoked_permissions_before.size(), 0U); + // Acknowledging revoked permissions from unused sites clears the list. + base::Value::List args; + handler()->HandleAcknowledgeRevokedUnusedSitePermissionsList(args); + const auto& revoked_permissions_after = + handler()->PopulateUnusedSitePermissionsData(); + EXPECT_EQ(revoked_permissions_after.size(), 0U); + + // Undo reverts the list to its initial state. + base::Value::List undo_args; + undo_args.Append(revoked_permissions_before.Clone()); + handler()->HandleUndoAcknowledgeRevokedUnusedSitePermissionsList(undo_args); + EXPECT_EQ(revoked_permissions_before, + handler()->PopulateUnusedSitePermissionsData()); +} + +TEST_F(SafetyHubHandlerTest, + HandleIgnoreOriginsForNotificationPermissionReview) { + base::test::ScopedFeatureList scoped_feature; + scoped_feature.InitAndEnableFeature( + ::features::kSafetyCheckNotificationPermissions); + + HostContentSettingsMap* content_settings = + HostContentSettingsMapFactory::GetForProfile(profile()); + ContentSettingsForOneType ignored_patterns; + content_settings->GetSettingsForOneType( + ContentSettingsType::NOTIFICATION_PERMISSION_REVIEW, &ignored_patterns); + ASSERT_EQ(0U, ignored_patterns.size()); + + base::Value::List args; + args.Append(GetOriginList(1)); + handler()->HandleIgnoreOriginsForNotificationPermissionReview(args); + + // Check there is 1 origin in ignore list. + content_settings->GetSettingsForOneType( + ContentSettingsType::NOTIFICATION_PERMISSION_REVIEW, &ignored_patterns); + ASSERT_EQ(1U, ignored_patterns.size()); + + ValidateNotificationPermissionUpdate(); +} + +TEST_F(SafetyHubHandlerTest, + HandleUndoIgnoreOriginsForNotificationPermissionReview) { + base::Value::List args; + args.Append(GetOriginList(1)); + handler()->HandleIgnoreOriginsForNotificationPermissionReview(args); + + // Check there is 1 origin in ignore list. + HostContentSettingsMap* content_settings = + HostContentSettingsMapFactory::GetForProfile(profile()); + ContentSettingsForOneType ignored_patterns; + ASSERT_EQ(0U, ignored_patterns.size()); + content_settings->GetSettingsForOneType( + ContentSettingsType::NOTIFICATION_PERMISSION_REVIEW, &ignored_patterns); + ASSERT_EQ(1U, ignored_patterns.size()); + + // Check there are no origins in ignore list. + handler()->HandleUndoIgnoreOriginsForNotificationPermissionReview(args); + content_settings->GetSettingsForOneType( + ContentSettingsType::NOTIFICATION_PERMISSION_REVIEW, &ignored_patterns); + ASSERT_EQ(0U, ignored_patterns.size()); +} + +TEST_F(SafetyHubHandlerTest, HandleAllowNotificationPermissionForOrigins) { + base::test::ScopedFeatureList scoped_feature; + scoped_feature.InitAndEnableFeature( + ::features::kSafetyCheckNotificationPermissions); + + base::Value::List args; + base::Value::List origins = GetOriginList(2); + args.Append(origins.Clone()); + handler()->HandleAllowNotificationPermissionForOrigins(args); + + // Check the permission for the two origins is allow. + HostContentSettingsMap* content_settings = + HostContentSettingsMapFactory::GetForProfile(profile()); + ContentSettingsForOneType notification_permissions; + content_settings->GetSettingsForOneType(ContentSettingsType::NOTIFICATIONS, + ¬ification_permissions); + auto type = content_settings->GetContentSetting( + GURL(origins[0].GetString()), GURL(), ContentSettingsType::NOTIFICATIONS); + ASSERT_EQ(CONTENT_SETTING_ALLOW, type); + + type = content_settings->GetContentSetting( + GURL(origins[1].GetString()), GURL(), ContentSettingsType::NOTIFICATIONS); + ASSERT_EQ(CONTENT_SETTING_ALLOW, type); + + ValidateNotificationPermissionUpdate(); +} + +TEST_F(SafetyHubHandlerTest, HandleBlockNotificationPermissionForOrigins) { + base::test::ScopedFeatureList scoped_feature; + scoped_feature.InitAndEnableFeature( + ::features::kSafetyCheckNotificationPermissions); + + base::Value::List args; + base::Value::List origins = GetOriginList(2); + args.Append(origins.Clone()); + + handler()->HandleBlockNotificationPermissionForOrigins(args); + + // Check the permission for the two origins is block. + HostContentSettingsMap* content_settings = + HostContentSettingsMapFactory::GetForProfile(profile()); + ContentSettingsForOneType notification_permissions; + content_settings->GetSettingsForOneType(ContentSettingsType::NOTIFICATIONS, + ¬ification_permissions); + auto type = content_settings->GetContentSetting( + GURL(origins[0].GetString()), GURL(), ContentSettingsType::NOTIFICATIONS); + ASSERT_EQ(CONTENT_SETTING_BLOCK, type); + + type = content_settings->GetContentSetting( + GURL(origins[1].GetString()), GURL(), ContentSettingsType::NOTIFICATIONS); + ASSERT_EQ(CONTENT_SETTING_BLOCK, type); + + ValidateNotificationPermissionUpdate(); +} + +TEST_F(SafetyHubHandlerTest, HandleResetNotificationPermissionForOrigins) { + base::test::ScopedFeatureList scoped_feature; + scoped_feature.InitAndEnableFeature( + ::features::kSafetyCheckNotificationPermissions); + + HostContentSettingsMap* content_settings = + HostContentSettingsMapFactory::GetForProfile(profile()); + base::Value::List args; + base::Value::List origins = GetOriginList(1); + args.Append(origins.Clone()); + + content_settings->SetContentSettingCustomScope( + ContentSettingsPattern::FromString(origins[0].GetString()), + ContentSettingsPattern::Wildcard(), ContentSettingsType::NOTIFICATIONS, + CONTENT_SETTING_ALLOW); + + handler()->HandleResetNotificationPermissionForOrigins(args); + + // Check the permission for the origin is reset. + auto type = content_settings->GetContentSetting( + GURL(origins[0].GetString()), GURL(), ContentSettingsType::NOTIFICATIONS); + ASSERT_EQ(CONTENT_SETTING_ASK, type); + + ValidateNotificationPermissionUpdate(); +} + +// Test that revocation is happen correctly for all content setting types. +TEST_F(SafetyHubHandlerTest, RevokeAllContentSettingTypes) { + // TODO(crbug.com/1459305): Remove this after adding names for those + // types. + std::list<ContentSettingsType> no_name_types = { + ContentSettingsType::MIDI, + ContentSettingsType::DURABLE_STORAGE, + ContentSettingsType::ACCESSIBILITY_EVENTS, + ContentSettingsType::NFC, + ContentSettingsType::FILE_SYSTEM_READ_GUARD, + ContentSettingsType::CAMERA_PAN_TILT_ZOOM, + ContentSettingsType::TOP_LEVEL_STORAGE_ACCESS}; + + // Add all content settings in the content setting registry to revoked + // permissions list. + auto* content_settings_registry = + content_settings::ContentSettingsRegistry::GetInstance(); + for (const content_settings::ContentSettingsInfo* info : + *content_settings_registry) { + ContentSettingsType type = info->website_settings_info()->type(); + + // If the permission can not be tracked, then also can not be revoked. + if (!content_settings::CanTrackLastVisit(type)) { + continue; + } + + // If the permission can not set to ALLOW, then also can not be revoked. + if (!content_settings_registry->Get(type)->IsSettingValid( + ContentSetting::CONTENT_SETTING_ALLOW)) { + continue; + } + + // Add the permission to revoked permission list. + auto dict = base::Value::Dict().Set( + permissions::kRevokedKey, + base::Value::List().Append(static_cast<int32_t>(type))); + hcsm()->SetWebsiteSettingDefaultScope( + GURL(kUnusedTestSite), GURL(kUnusedTestSite), + ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS, + base::Value(dict.Clone())); + + // Unless the permission in no_name_types, it should be shown on the UI. + const auto& revoked_permissions = + handler()->PopulateUnusedSitePermissionsData(); + bool is_no_name_type = + (std::find(no_name_types.begin(), no_name_types.end(), type) != + no_name_types.end()); + if (is_no_name_type) { + EXPECT_EQ(revoked_permissions.size(), 0U); + } else { + EXPECT_EQ(revoked_permissions.size(), 1U); + } + } +} 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 dfa635a69b8..8a977423e5e 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 @@ -239,6 +239,9 @@ void ClearBrowsingDataHandler::HandleClearBrowsingData( "History.ClearBrowsingData.UserDeletedCookieOrCacheFromDialog", choice, content::BrowsingDataRemover::MAX_CHOICE_VALUE); + browsing_data::RecordDeleteBrowsingDataAction( + browsing_data::DeleteBrowsingDataAction::kClearBrowsingDataDialog); + // Record the circumstances under which passwords are deleted. if (data_types.find(BrowsingDataType::PASSWORDS) != data_types.end()) { static const BrowsingDataType other_types[] = { 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 9848f2bedef..6f83a03a224 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 @@ -22,7 +22,7 @@ #include "components/search/search_provider_observer.h" #include "components/search_engines/template_url_service_observer.h" #include "components/signin/core/browser/account_reconcilor.h" -#include "components/sync/driver/sync_service.h" +#include "components/sync/service/sync_service.h" namespace content { class WebUI; diff --git a/chromium/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler_unittest.cc index 66e526091c4..6b6e8750c81 100644 --- a/chromium/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler_unittest.cc @@ -6,6 +6,7 @@ #include "base/memory/raw_ptr.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/search_engines/template_url_service_factory_test_util.h" @@ -64,6 +65,10 @@ class ClearBrowsingDataHandlerUnitTest : public testing::Test { std::unique_ptr<TestingClearBrowsingDataHandler> handler_; std::unique_ptr<TemplateURLServiceFactoryTestUtil> dse_factory_util_; raw_ptr<TemplateURLService> template_url_service; + + const content::TestWebUI::CallData& GetCallData() { + return *test_web_ui_.call_data().back(); + } }; void ClearBrowsingDataHandlerUnitTest::SetUp() { @@ -85,6 +90,7 @@ void ClearBrowsingDataHandlerUnitTest::SetUp() { handler_ = std::make_unique<TestingClearBrowsingDataHandler>(&test_web_ui_, profile_.get()); handler_->set_web_ui(&test_web_ui_); + handler_->RegisterMessages(); handler_->AllowJavascript(); browser_task_environment_.RunUntilIdle(); @@ -144,6 +150,25 @@ TemplateURL* ClearBrowsingDataHandlerUnitTest::AddSearchEngine( return url; } +TEST_F(ClearBrowsingDataHandlerUnitTest, + ClearBrowsingData_EmmitsDeleteMetrics) { + base::HistogramTester histogram_tester; + base::Value::List args; + + args.Append("fooCallback"); + args.Append(base::Value::List()); + args.Append(1); + + test_web_ui_.HandleReceivedMessage("clearBrowsingData", args); + + const content::TestWebUI::CallData& call_data = GetCallData(); + ASSERT_EQ(3u, call_data.args().size()); + + histogram_tester.ExpectBucketCount( + "Privacy.DeleteBrowsingData.Action", + browsing_data::DeleteBrowsingDataAction::kClearBrowsingDataDialog, 1); +} + TEST_F(ClearBrowsingDataHandlerUnitTest, UpdateSyncState_GoogleDse) { handler_->UpdateSyncState(); VerifySearchHistoryWebUIUpdate(false, u""); 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 6d488e842bb..ba144779fd6 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 @@ -36,6 +36,7 @@ #include "chrome/browser/signin/account_consistency_mode_manager_factory.h" #include "chrome/browser/signin/signin_features.h" #include "chrome/browser/sync/sync_service_factory.h" +#include "chrome/browser/ui/managed_ui.h" #include "chrome/browser/ui/passwords/ui_utils.h" #include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/webui/management/management_ui.h" @@ -70,10 +71,12 @@ #include "components/device_reauth/device_authenticator.h" #include "components/dom_distiller/core/dom_distiller_features.h" #include "components/google/core/common/google_util.h" +#include "components/history/core/common/pref_names.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/performance_manager/public/features.h" #include "components/prefs/pref_service.h" #include "components/privacy_sandbox/privacy_sandbox_features.h" #include "components/safe_browsing/core/common/safe_browsing_prefs.h" @@ -82,10 +85,11 @@ #include "components/strings/grit/components_chromium_strings.h" #include "components/strings/grit/components_strings.h" #include "components/subresource_filter/core/browser/subresource_filter_features.h" +#include "components/supervised_user/core/common/features.h" #include "components/sync/base/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/sync/service/sync_service.h" +#include "components/sync/service/sync_service_utils.h" +#include "components/sync/service/sync_user_settings.h" #include "components/zoom/page_zoom_constants.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui_data_source.h" @@ -102,6 +106,7 @@ #include "ui/accessibility/accessibility_switches.h" #include "ui/base/accelerators/accelerator.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/l10n/time_format.h" #include "ui/base/webui/web_ui_util.h" #include "ui/strings/grit/ui_strings.h" @@ -158,6 +163,11 @@ #include "net/base/features.h" #endif +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) +#include "chrome/browser/supervised_user/supervised_user_service_factory.h" +#include "components/supervised_user/core/browser/supervised_user_service.h" +#endif + namespace settings { namespace { @@ -238,6 +248,12 @@ void AddCommonStrings(content::WebUIDataSource* html_source, Profile* profile) { #endif html_source->AddBoolean("isChildAccount", profile->IsChild()); + + html_source->AddBoolean( + "clearingCookiesKeepsSupervisedUsersSignedIn", + base::FeatureList::IsEnabled( + supervised_user::kClearingCookiesKeepsSupervisedUsersSignedIn)); + #if BUILDFLAG(IS_LINUX) bool allow_qt_theme = base::FeatureList::IsEnabled(ui::kAllowQt); #else @@ -314,8 +330,16 @@ void AddAboutStrings(content::WebUIDataSource* html_source, Profile* profile) { }; html_source->AddLocalizedStrings(kLocalizedStrings); - html_source->AddString("managementPage", - ManagementUI::GetManagementPageSubtitle(profile)); + html_source->AddString( + "managementPage", +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) + base::FeatureList::IsEnabled(supervised_user::kEnableManagedByParentUi) + ? chrome::GetDeviceManagedUiHelpLabel(profile) + : ManagementUI::GetManagementPageSubtitle(profile) +#else + ManagementUI::GetManagementPageSubtitle(profile) +#endif + ); html_source->AddString( "aboutUpgradeUpToDate", #if BUILDFLAG(IS_CHROMEOS_ASH) @@ -366,6 +390,7 @@ void AddAppearanceStrings(content::WebUIDataSource* html_source, {"chromeColors", IDS_SETTINGS_CHROME_COLORS}, {"showHomeButton", IDS_SETTINGS_SHOW_HOME_BUTTON}, {"showBookmarksBar", IDS_SETTINGS_SHOW_BOOKMARKS_BAR}, + {"showHoverCardImages", IDS_SETTINGS_SHOW_HOVER_CARD_IMAGES}, {"sidePanel", IDS_SETTINGS_SIDE_PANEL}, {"homePageNtp", IDS_SETTINGS_HOME_PAGE_NTP}, {"changeHomePage", IDS_SETTINGS_CHANGE_HOME_PAGE}, @@ -413,6 +438,9 @@ void AddAppearanceStrings(content::WebUIDataSource* html_source, html_source->AddBoolean("showReaderModeOption", dom_distiller::OfferReaderModeInSettings()); html_source->AddBoolean("showSidePanelOptions", true); + html_source->AddBoolean( + "showHoverCardImagesOption", + base::FeatureList::IsEnabled(features::kTabHoverCardImageSettings)); // TODO(crbug.com/1052397): Revisit the macro expression once build flag switch // of lacros-chrome is complete. @@ -451,6 +479,8 @@ void AddClearBrowsingDataStrings(content::WebUIDataSource* html_source, {"clearCookiesSummarySignedInMainProfile", IDS_SETTINGS_CLEAR_COOKIES_AND_SITE_DATA_SUMMARY_BASIC_MAIN_PROFILE}, #endif + {"clearCookiesSummarySignedInSupervisedProfile", + IDS_SETTINGS_CLEAR_COOKIES_AND_SITE_DATA_SUMMARY_BASIC_SUPERVISED_PROFILE}, {"clearCookiesCounter", IDS_DEL_COOKIES_COUNTER}, {"clearPasswords", IDS_SETTINGS_CLEAR_PASSWORDS}, {"clearFormData", IDS_SETTINGS_CLEAR_FORM_DATA}, @@ -544,98 +574,6 @@ void AddGetTheMostOutOfChromeStrings(content::WebUIDataSource* html_source) { #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -void AddChromeCleanupStrings(content::WebUIDataSource* html_source) { - const char16_t kUnwantedSoftwareProtectionWhitePaperUrl[] = - u"https://www.google.ca/chrome/browser/privacy/" - u"whitepaper.html#unwantedsoftware"; - - static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"chromeCleanupPageTitle", - IDS_SETTINGS_RESET_CLEAN_UP_COMPUTER_PAGE_TITLE}, - {"chromeCleanupDetailsFilesAndPrograms", - IDS_SETTINGS_RESET_CLEANUP_DETAILS_FILES_AND_PROGRAMS}, - {"chromeCleanupDetailsRegistryEntries", - IDS_SETTINGS_RESET_CLEANUP_DETAILS_REGISTRY_ENTRIES}, - {"chromeCleanupExplanationCleanupError", - IDS_SETTINGS_RESET_CLEANUP_EXPLANATION_CLEANUP_ERROR}, - {"chromeCleanupExplanationFindAndRemove", - IDS_SETTINGS_RESET_CLEANUP_EXPLANATION_FIND_AND_REMOVE}, - {"chromeCleanupExplanationNoInternet", - IDS_SETTINGS_RESET_CLEANUP_EXPLANATION_NO_INTERNET_CONNECTION}, - {"chromeCleanupExplanationPermissionsNeeded", - IDS_SETTINGS_RESET_CLEANUP_EXPLANATION_PERMISSIONS_NEEDED}, - {"chromeCleanupExplanationRemove", - // Note: removal explanation should be the same as used in the prompt - // dialog. Reusing the string to ensure they will not diverge. - IDS_CHROME_CLEANUP_PROMPT_EXPLANATION}, - {"chromeCleanupExplanationRemoving", - IDS_SETTINGS_RESET_CLEANUP_EXPLANATION_CURRENTLY_REMOVING}, - {"chromeCleanupExplanationScanError", - IDS_SETTINGS_RESET_CLEANUP_EXPLANATION_SCAN_ERROR}, - {"chromeCleanupFindButtonLabel", - IDS_SETTINGS_RESET_CLEANUP_FIND_BUTTON_LABEL}, - {"chromeCleanupLinkShowItems", - IDS_SETTINGS_RESET_CLEANUP_LINK_SHOW_FILES}, - {"chromeCleanupRemoveButtonLabel", - IDS_SETTINGS_RESET_CLEANUP_REMOVE_BUTTON_LABEL}, - {"chromeCleanupRestartButtonLabel", - IDS_SETTINGS_RESET_CLEANUP_RESTART_BUTTON_LABEL}, - {"chromeCleanupTitleErrorCantRemove", - IDS_SETTINGS_RESET_CLEANUP_TITLE_ERROR_CANT_REMOVE}, - {"chromeCleanupTitleErrorPermissions", - IDS_SETTINGS_RESET_CLEANUP_TITLE_ERROR_PERMISSIONS_NEEDED}, - {"chromeCleanupTitleFindAndRemove", - IDS_SETTINGS_RESET_CLEANUP_TITLE_FIND_HARMFUL_SOFTWARE}, - {"chromeCleanupTitleNoInternet", - IDS_SETTINGS_RESET_CLEANUP_TITLE_NO_INTERNET_CONNECTION}, - {"chromeCleanupTitleNothingFound", - IDS_SETTINGS_RESET_CLEANUP_TITLE_NOTHING_FOUND}, - {"chromeCleanupTitleRemove", IDS_SETTINGS_RESET_CLEANUP_TITLE_REMOVE}, - {"chromeCleanupTitleRemoved", IDS_SETTINGS_RESET_CLEANUP_TITLE_DONE}, - {"chromeCleanupTitleRemoving", IDS_SETTINGS_RESET_CLEANUP_TITLE_REMOVING}, - {"chromeCleanupTitleRestart", IDS_SETTINGS_RESET_CLEANUP_TITLE_RESTART}, - {"chromeCleanupTitleScanning", IDS_SETTINGS_RESET_CLEANUP_TITLE_SCANNING}, - {"chromeCleanupTitleScanningFailed", - IDS_SETTINGS_RESET_CLEANUP_TITLE_ERROR_SCANNING_FAILED}, - {"chromeCleanupTitleTryAgainButtonLabel", - IDS_SETTINGS_RESET_CLEANUP_TRY_AGAIN_BUTTON_LABEL}, - {"chromeCleanupExplanationLogsPermissionPref", - IDS_SETTINGS_RESET_CLEANUP_LOGS_PERMISSION_PREF}, - {"chromeCleanupTitleCleanupUnavailable", - IDS_SETTINGS_RESET_CLEANUP_TITLE_CLEANUP_UNAVAILABLE}, - {"chromeCleanupExplanationCleanupUnavailable", - IDS_SETTINGS_RESET_CLEANUP_EXPLANATION_CLEANUP_UNAVAILABLE}, - }; - - html_source->AddLocalizedStrings(kLocalizedStrings); - const std::string cleanup_learn_more_url = - google_util::AppendGoogleLocaleParam( - GURL(chrome::kChromeCleanerLearnMoreURL), - g_browser_process->GetApplicationLocale()) - .spec(); - html_source->AddString("chromeCleanupLearnMoreUrl", cleanup_learn_more_url); - - // The "powered by" footer contains an HTML fragment with the SVG logo of the - // partner. The logo is added directly to the DOM, rather than as an <img> - // src, to make sure that screen readers can find accessibility tags inside - // the SVG. - const std::string powered_by_element = base::StrCat( - {"<span id='powered-by-logo'>", - ui::ResourceBundle::GetSharedInstance().LoadDataResourceString( - IDR_CHROME_CLEANUP_PARTNER), - "</span>"}); - const std::u16string powered_by_html = - l10n_util::GetStringFUTF16(IDS_SETTINGS_RESET_CLEANUP_FOOTER_POWERED_BY, - base::UTF8ToUTF16(powered_by_element)); - html_source->AddString("chromeCleanupPoweredByHtml", powered_by_html); - - const std::u16string cleanup_details_explanation = - l10n_util::GetStringFUTF16(IDS_SETTINGS_RESET_CLEANUP_DETAILS_EXPLANATION, - kUnwantedSoftwareProtectionWhitePaperUrl); - html_source->AddString("chromeCleanupDetailsExplanation", - cleanup_details_explanation); -} - void AddIncompatibleApplicationsStrings(content::WebUIDataSource* html_source) { static constexpr webui::LocalizedString kLocalizedStrings[] = { {"incompatibleApplicationsResetCardTitle", @@ -739,6 +677,16 @@ void AddPerformanceStrings(content::WebUIDataSource* html_source) { IDS_SETTINGS_PERFORMANCE_HIGH_EFFICIENCY_MODE_SETTING}, {"highEfficiencyModeDescription", IDS_SETTINGS_PERFORMANCE_HIGH_EFFICIENCY_MODE_SETTING_DESCRIPTION}, + {"highEfficiencyModeHeuristicsLabel", + IDS_SETTINGS_PERFORMANCE_HIGH_EFFICIENCY_MODE_HEURISTICS_LABEL}, + {"highEfficiencyModeRecommendedBadge", + IDS_SETTINGS_PERFORMANCE_HIGH_EFFICIENCY_MODE_RECOMMENDED_BADGE}, + {"highEfficiencyModeOnTimerLabel", + IDS_SETTINGS_PERFORMANCE_HIGH_EFFICIENCY_MODE_ON_TIMER_LABEL}, + {"highEfficiencyModeRadioGroupAriaLabel", + IDS_SETTINGS_PERFORMANCE_HIGH_EFFICIENCY_MODE_RADIO_GROUP_ARIA_LABEL}, + {"highEfficiencyChooseDiscardTimeAriaLabel", + IDS_SETTINGS_PERFORMANCE_HIGH_EFFICIENCY_MODE_CHOOSE_DISCARD_TIME_ARIA_LABEL}, {"batteryPageTitle", IDS_SETTINGS_BATTERY_PAGE_TITLE}, {"batterySaverModeLabel", IDS_SETTINGS_PERFORMANCE_BATTERY_SAVER_MODE_SETTING}, @@ -756,9 +704,56 @@ void AddPerformanceStrings(content::WebUIDataSource* html_source) { IDS_SETTINGS_PERFORMANCE_TAB_DISCARDING_EXCEPTIONS_HEADER}, {"tabDiscardingExceptionsAdditionalSites", IDS_SETTINGS_PERFORMANCE_TAB_DISCARDING_EXCEPTIONS_ADDITIONAL_SITES}, + {"tabDiscardingExceptionsAddDialogCurrentTabs", + IDS_SETTINGS_PERFORMANCE_TAB_DISCARDING_EXCEPTIONS_ADD_DIALOG_CURRENT_TABS}, + {"tabDiscardingExceptionsAddDialogManual", + IDS_SETTINGS_PERFORMANCE_TAB_DISCARDING_EXCEPTIONS_ADD_DIALOG_MANUAL}, + {"tabDiscardingExceptionsActiveSiteAriaDescription", + IDS_SETTINGS_PERFORMANCE_TAB_DISCARDING_EXCEPTIONS_ACTIVE_SITE_ARIA_DESCRIPTION}, }; html_source->AddLocalizedStrings(kLocalizedStrings); + html_source->AddBoolean( + "highEfficiencyDefaultHeuristicMode", + performance_manager::features::kHighEfficiencyDefaultHeuristicMode.Get()); + + html_source->AddString( + "tabDiscardTimerFiveMinutes", + ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, + ui::TimeFormat::LENGTH_LONG, base::Minutes(5))); + html_source->AddString( + "tabDiscardTimerFifteenMinutes", + ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, + ui::TimeFormat::LENGTH_LONG, base::Minutes(15))); + html_source->AddString( + "tabDiscardTimerThirtyMinutes", + ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, + ui::TimeFormat::LENGTH_LONG, base::Minutes(30))); + html_source->AddString( + "tabDiscardTimerOneHour", + ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, + ui::TimeFormat::LENGTH_LONG, base::Hours(1))); + html_source->AddString( + "tabDiscardTimerTwoHours", + ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, + ui::TimeFormat::LENGTH_LONG, base::Hours(2))); + html_source->AddString( + "tabDiscardTimerFourHours", + ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, + ui::TimeFormat::LENGTH_LONG, base::Hours(4))); + html_source->AddString( + "tabDiscardTimerEightHours", + ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, + ui::TimeFormat::LENGTH_LONG, base::Hours(8))); + html_source->AddString( + "tabDiscardTimerSixteenHours", + ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, + ui::TimeFormat::LENGTH_LONG, base::Hours(16))); + html_source->AddString( + "tabDiscardTimerTwentyFourHours", + ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, + ui::TimeFormat::LENGTH_LONG, base::Hours(24))); + html_source->AddString( "batterySaverModeEnabledBelowThresholdLabel", l10n_util::GetStringFUTF16( @@ -766,6 +761,11 @@ void AddPerformanceStrings(content::WebUIDataSource* html_source) { base::NumberToString16( performance_manager::user_tuning::UserPerformanceTuningManager:: kLowBatteryThresholdPercent))); + html_source->AddString( + "tabDiscardingExceptionsAddDialogHelp", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_PERFORMANCE_TAB_DISCARDING_EXCEPTIONS_ADD_DIALOG_HELP, + base::ASCIIToUTF16(chrome::kHighEfficiencyModeTabDiscardingHelpUrl))); html_source->AddString("highEfficiencyLearnMoreUrl", chrome::kHighEfficiencyModeLearnMoreUrl); @@ -1011,11 +1011,13 @@ void AddAutofillStrings(content::WebUIDataSource* html_source, {"addressPhone", IDS_SETTINGS_AUTOFILL_ADDRESSES_PHONE}, {"addressEmail", IDS_SETTINGS_AUTOFILL_ADDRESSES_EMAIL}, {"honorificLabel", IDS_SETTINGS_AUTOFILL_ADDRESS_HONORIFIC_LABEL}, + {"creditCardDescription", IDS_SETTINGS_AUTOFILL_CARD_DESCRIPTION}, + {"creditCardA11yLabeled", IDS_SETTINGS_AUTOFILL_CARD_A11Y_LABELED}, + {"creditCardExpDateA11yLabeled", + IDS_SETTINGS_AUTOFILL_CARD_EXP_DATE_A11Y_LABELED}, {"moreActionsForAddress", IDS_SETTINGS_AUTOFILL_MORE_ACTIONS_FOR_ADDRESS}, {"moreActionsForCreditCard", IDS_SETTINGS_AUTOFILL_MORE_ACTIONS_FOR_CREDIT_CARD}, - {"moreActionsCreditCardDescription", - IDS_SETTINGS_AUTOFILL_MORE_ACTIONS_CARD_DESCRIPTION}, {"removeAddress", IDS_SETTINGS_ADDRESS_REMOVE}, {"removeAddressConfirmationTitle", IDS_SETTINGS_ADDRESS_REMOVE_CONFIRMATION_TITLE}, @@ -1159,18 +1161,10 @@ void AddAutofillStrings(content::WebUIDataSource* html_source, IDS_SETTINGS_PASSWORD_MOVE_PASSWORDS_TO_ACCOUNT_DIALOG_BODY_TEXT}, {"passwordMovePasswordsToAccountDialogTitle", IDS_SETTINGS_PASSWORD_MOVE_PASSWORDS_TO_ACCOUNT_DIALOG_TITLE}, - {"passwordMoveToAccountDialogTitle", - IDS_SETTINGS_PASSWORD_MOVE_TO_ACCOUNT_DIALOG_TITLE}, - {"passwordMoveToAccountDialogBody", - IDS_SETTINGS_PASSWORD_MOVE_TO_ACCOUNT_DIALOG_BODY}, {"passwordMoveMultiplePasswordsToAccountDialogMoveButtonText", IDS_SETTINGS_PASSWORD_MOVE_MULTIPLE_PASSWORDS_TO_ACCOUNT_DIALOG_MOVE_BUTTON_TEXT}, {"passwordMoveMultiplePasswordsToAccountDialogCancelButtonText", IDS_SETTINGS_PASSWORD_MOVE_MULTIPLE_PASSWORDS_TO_ACCOUNT_DIALOG_CANCEL_BUTTON_TEXT}, - {"passwordMoveToAccountDialogMoveButtonText", - IDS_SETTINGS_PASSWORD_MOVE_TO_ACCOUNT_DIALOG_MOVE_BUTTON_TEXT}, - {"passwordMoveToAccountDialogCancelButtonText", - IDS_SETTINGS_PASSWORD_MOVE_TO_ACCOUNT_DIALOG_CANCEL_BUTTON_TEXT}, {"passwordOpenMoveMultiplePasswordsToAccountDialogButtonText", IDS_SETTINGS_PASSWORD_OPEN_MOVE_MULTIPLE_PASSWORDS_TO_ACCOUNT_DIALOG_BUTTON_TEXT}, {"passwordRemoveDialogTitle", IDS_SETTINGS_PASSWORD_REMOVE_DIALOG_TITLE}, @@ -1209,7 +1203,6 @@ void AddAutofillStrings(content::WebUIDataSource* html_source, IDS_SETTINGS_PASSWORDS_IMPORT_MISSING_PASSWORD}, {"importPasswordsMissingURL", IDS_SETTINGS_PASSWORDS_IMPORT_MISSING_URL}, {"importPasswordsInvalidURL", IDS_SETTINGS_PASSWORDS_IMPORT_INVALID_URL}, - {"importPasswordsNonASCIIURL", IDS_SETTINGS_PASSWORDS_IMPORT_NON_ASCII_URL}, {"importPasswordsLongURL", IDS_SETTINGS_PASSWORDS_IMPORT_LONG_URL}, {"importPasswordsLongPassword", IDS_SETTINGS_PASSWORDS_IMPORT_LONG_PASSWORD}, @@ -1503,20 +1496,32 @@ void AddSignOutDialogStrings(content::WebUIDataSource* html_source, 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}, - {"syncAdvancedPageTitle", IDS_SETTINGS_NEW_SYNC_ADVANCED_PAGE_TITLE}, + {"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}, + +#if !BUILDFLAG(IS_CHROMEOS_LACROS) + {"syncAdvancedPageTitle", IDS_SETTINGS_NEW_SYNC_ADVANCED_PAGE_TITLE}, +#endif + }; + html_source->AddLocalizedStrings(kLocalizedStrings); + +#if BUILDFLAG(IS_CHROMEOS_LACROS) + html_source->AddLocalizedString( + "syncAdvancedPageTitle", + base::FeatureList::IsEnabled(syncer::kSyncChromeOSAppsToggleSharing) + ? IDS_SETTINGS_NEW_SYNC_ADVANCED_BROWSER_PAGE_TITLE + : IDS_SETTINGS_NEW_SYNC_ADVANCED_PAGE_TITLE); +#endif } void AddPersonalizationOptionsStrings(content::WebUIDataSource* html_source) { @@ -1587,6 +1592,17 @@ void AddBrowserSyncPageStrings(content::WebUIDataSource* html_source) { BuildOSSettingsUrl(chromeos::settings::mojom::kSyncSetupSubpagePath)); #endif +#if BUILDFLAG(IS_CHROMEOS_ASH) + html_source->AddString( + "osPrivacySettingsUrl", + BuildOSSettingsUrl( + chromeos::settings::mojom::kPrivacyAndSecuritySectionPath)); + + html_source->AddBoolean( + "osDeprecateSyncMetricsToggle", + ash::features::IsOsSettingsDeprecateSyncMetricsToggleEnabled()); +#endif + #if BUILDFLAG(IS_CHROMEOS) html_source->AddString( "osSyncSettingsUrl", @@ -1596,21 +1612,24 @@ void AddBrowserSyncPageStrings(content::WebUIDataSource* html_source) { 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}, - {"wifiConfigurationsCheckboxLabel", - IDS_SETTINGS_WIFI_CONFIGURATIONS_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}, + {"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}, + {"wifiConfigurationsCheckboxLabel", + IDS_SETTINGS_WIFI_CONFIGURATIONS_CHECKBOX_LABEL}, + {"syncEverythingCheckboxLabel", + IDS_SETTINGS_SYNC_EVERYTHING_CHECKBOX_LABEL}, + {"appCheckboxLabel", IDS_SETTINGS_APPS_CHECKBOX_LABEL}, +#if BUILDFLAG(IS_CHROMEOS_LACROS) + {"appCheckboxSublabel", IDS_SETTINGS_APPS_CHECKBOX_SUBLABEL}, +#endif + {"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}, }; html_source->AddLocalizedStrings(kLocalizedStrings); } @@ -2054,6 +2073,8 @@ void AddPrivacySandboxStrings(content::WebUIDataSource* html_source, IDS_SETTINGS_PRIVACY_SANDBOX_SPAM_AND_FRAUD_DIALOG_DESCRIPTION_3}, {"adPrivacyLinkRowLabel", IDS_SETTINGS_AD_PRIVACY_LINK_ROW_LABEL}, {"adPrivacyLinkRowSubLabel", IDS_SETTINGS_AD_PRIVACY_LINK_ROW_SUB_LABEL}, + {"adPrivacyRestrictedLinkRowSubLabel", + IDS_SETTINGS_AD_PRIVACY_RESTRICTED_LINK_ROW_SUB_LABEL}, {"adPrivacyPageTitle", IDS_SETTINGS_AD_PRIVACY_PAGE_TITLE}, {"adPrivacyPageTopicsLinkRowLabel", IDS_SETTINGS_AD_PRIVACY_PAGE_TOPICS_LINK_ROW_LABEL}, @@ -2090,8 +2111,6 @@ void AddPrivacySandboxStrings(content::WebUIDataSource* html_source, IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_1}, {"topicsPageLearnMoreBullet2", IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_2}, - {"topicsPageLearnMoreBullet3", - IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_3}, {"topicsPageCurrentTopicsDescriptionDisabled", IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_DISABLED}, {"topicsPageCurrentTopicsDescriptionEmpty", @@ -2149,8 +2168,6 @@ void AddPrivacySandboxStrings(content::WebUIDataSource* html_source, IDS_SETTINGS_FLEDGE_PAGE_LEARN_MORE_BULLET_1}, {"fledgePageLearnMoreBullet2", IDS_SETTINGS_FLEDGE_PAGE_LEARN_MORE_BULLET_2}, - {"fledgePageLearnMoreBullet3", - IDS_SETTINGS_FLEDGE_PAGE_LEARN_MORE_BULLET_3}, {"fledgePageCurrentSitesDescriptionLearnMoreA11yLabel", IDS_SETTINGS_FLEDGE_PAGE_CURRENT_SITES_DESCRIPTION_LEARN_MORE_A11Y_LABEL}, {"adMeasurementPageTitle", IDS_SETTINGS_AD_MEASUREMENT_PAGE_TITLE}, @@ -2188,6 +2205,25 @@ void AddPrivacySandboxStrings(content::WebUIDataSource* html_source, l10n_util::GetStringFUTF16( IDS_SETTINGS_PRIVACY_SANDBOX_AD_MEASUREMENT_DIALOG_CONTROL_MEASUREMENT, base::ASCIIToUTF16(chrome::kChromeUIHistoryURL))); + + // Topics and fledge link to help center articles in their learn more dialog. + html_source->AddString( + "topicsPageLearnMoreBullet3", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_TOPICS_PAGE_LEARN_MORE_BULLET_3, + base::ASCIIToUTF16(google_util::AppendGoogleLocaleParam( + GURL(chrome::kAdPrivacyLearnMoreURL), + g_browser_process->GetApplicationLocale()) + .spec()))); + html_source->AddString( + "fledgePageLearnMoreBullet3", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_FLEDGE_PAGE_LEARN_MORE_BULLET_3, + base::ASCIIToUTF16(google_util::AppendGoogleLocaleParam( + GURL(chrome::kAdPrivacyLearnMoreURL), + g_browser_process->GetApplicationLocale()) + .spec()))); + // Topics and fledge both link to the cookies setting page and cross-link // each other in the footers. html_source->AddString( @@ -2454,7 +2490,6 @@ void AddSearchStrings(content::WebUIDataSource* html_source) { void AddSearchEnginesStrings(content::WebUIDataSource* html_source) { static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"searchEnginesPageTitle", IDS_SETTINGS_SEARCH_ENGINES}, {"searchEnginesPageExplanation", IDS_SETTINGS_SEARCH_ENGINES_PAGE_EXPLANATION}, {"searchEnginesAddSearchEngine", @@ -2466,7 +2501,6 @@ void AddSearchEnginesStrings(content::WebUIDataSource* html_source) { {"searchEnginesDeleteConfirmationDescription", IDS_SETTINGS_SEARCH_ENGINES_DELETE_CONFIRMATION_DESCRIPTION}, {"searchEngines", IDS_SETTINGS_SEARCH_ENGINES}, - {"searchEnginesDefault", IDS_SETTINGS_SEARCH_ENGINES_DEFAULT_ENGINES}, {"searchEnginesSearchEngines", IDS_SETTINGS_SEARCH_ENGINES_SEARCH_ENGINES}, {"searchEnginesSearchEnginesExplanation", @@ -2477,8 +2511,6 @@ void AddSearchEnginesStrings(content::WebUIDataSource* html_source) { {"searchEnginesNoSitesAdded", IDS_SETTINGS_SEARCH_ENGINES_NO_SITES_ADDED}, {"searchEnginesInactiveShortcuts", IDS_SETTINGS_SEARCH_ENGINES_INACTIVE_SHORTCUTS}, - {"searchEnginesNoInactiveShortcuts", - IDS_SETTINGS_SEARCH_ENGINES_NO_INACTIVE_SHORTCUTS}, {"searchEnginesNoOtherEngines", IDS_SETTINGS_SEARCH_ENGINES_NO_OTHER_ENGINES}, {"searchEnginesExtension", IDS_SETTINGS_SEARCH_ENGINES_EXTENSION_ENGINES}, @@ -2487,7 +2519,6 @@ void AddSearchEnginesStrings(content::WebUIDataSource* html_source) { {"searchEnginesSearch", IDS_SETTINGS_SEARCH_ENGINES_SEARCH}, {"searchEnginesSearchEngine", IDS_SETTINGS_SEARCH_ENGINES_SEARCH_ENGINE}, {"searchEnginesSiteOrPage", IDS_SETTINGS_SEARCH_ENGINES_SITE_OR_PAGE}, - {"searchEnginesInactiveSite", IDS_SETTINGS_SEARCH_ENGINES_INACTIVE_SITE}, {"searchEnginesShortcut", IDS_SETTINGS_SEARCH_ENGINES_SHORTCUT}, {"searchEnginesQueryURL", IDS_SETTINGS_SEARCH_ENGINES_QUERY_URL}, {"searchEnginesQueryURLExplanation", @@ -2495,8 +2526,6 @@ void AddSearchEnginesStrings(content::WebUIDataSource* html_source) { {"searchEnginesMakeDefault", IDS_SETTINGS_SEARCH_ENGINES_MAKE_DEFAULT}, {"searchEnginesActivate", IDS_SETTINGS_SEARCH_ENGINES_ACTIVATE}, {"searchEnginesDeactivate", IDS_SETTINGS_SEARCH_ENGINES_DEACTIVATE}, - {"searchEnginesRemoveFromList", - IDS_SETTINGS_SEARCH_ENGINES_REMOVE_FROM_LIST}, {"searchEnginesManageExtension", IDS_SETTINGS_SEARCH_ENGINES_MANAGE_EXTENSION}, {"searchEnginesKeyboardShortcutsTitle", @@ -2511,8 +2540,6 @@ void AddSearchEnginesStrings(content::WebUIDataSource* html_source) { IDS_SETTINGS_SEARCH_ENGINES_ADDITIONAL_SITES}, {"searchEnginesAdditionalInactiveSites", IDS_SETTINGS_SEARCH_ENGINES_ADDITIONAL_INACTIVE_SITES}, - {"searchEnginesAdditionalExtensions", - IDS_SETTINGS_SEARCH_ENGINES_ADDITIONAL_EXTENSIONS}, }; html_source->AddLocalizedStrings(kLocalizedStrings); } @@ -2522,49 +2549,13 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, static constexpr webui::LocalizedString kLocalizedStrings[] = { {"addSite", IDS_SETTINGS_ADD_SITE}, {"addSiteTitle", IDS_SETTINGS_ADD_SITE_TITLE}, + {"addSitesTitle", IDS_SETTINGS_ADD_SITES_TITLE}, #if BUILDFLAG(IS_CHROMEOS_ASH) {"androidSmsNote", IDS_SETTINGS_ANDROID_SMS_NOTE}, #endif - {"cookieCacheStorage", IDS_SETTINGS_COOKIES_CACHE_STORAGE}, - {"cookieDatabaseStorage", IDS_SETTINGS_COOKIES_DATABASE_STORAGE}, - {"cookieFileSystem", IDS_SETTINGS_COOKIES_FILE_SYSTEM}, - {"cookieFlashLso", IDS_SETTINGS_COOKIES_FLASH_LSO}, - {"cookieLocalStorage", IDS_SETTINGS_COOKIES_LOCAL_STORAGE}, - {"cookieServiceWorker", IDS_SETTINGS_COOKIES_SERVICE_WORKER}, - {"cookieSharedWorker", IDS_SETTINGS_COOKIES_SHARED_WORKER}, - {"cookieQuotaStorage", IDS_SETTINGS_COOKIES_QUOTA_STORAGE}, {"embeddedOnAnyHost", IDS_SETTINGS_EXCEPTIONS_EMBEDDED_ON_ANY_HOST}, {"embeddedOnHost", IDS_SETTINGS_EXCEPTIONS_EMBEDDED_ON_HOST}, {"editSiteTitle", IDS_SETTINGS_EDIT_SITE_TITLE}, - {"cacheStorageLastModified", - IDS_SETTINGS_COOKIES_LOCAL_STORAGE_LAST_MODIFIED_LABEL}, - {"cacheStorageOrigin", IDS_SETTINGS_COOKIES_LOCAL_STORAGE_ORIGIN_LABEL}, - {"cacheStorageSize", IDS_SETTINGS_COOKIES_LOCAL_STORAGE_SIZE_ON_DISK_LABEL}, - {"cookieAccessibleToScript", - IDS_SETTINGS_COOKIES_COOKIE_ACCESSIBLE_TO_SCRIPT_LABEL}, - {"cookieContent", IDS_SETTINGS_COOKIES_COOKIE_CONTENT_LABEL}, - {"cookieCreated", IDS_SETTINGS_COOKIES_COOKIE_CREATED_LABEL}, - {"cookieDomain", IDS_SETTINGS_COOKIES_COOKIE_DOMAIN_LABEL}, - {"cookieExpires", IDS_SETTINGS_COOKIES_COOKIE_EXPIRES_LABEL}, - {"cookieName", IDS_SETTINGS_COOKIES_COOKIE_NAME_LABEL}, - {"cookiePath", IDS_SETTINGS_COOKIES_COOKIE_PATH_LABEL}, - {"cookieSendFor", IDS_SETTINGS_COOKIES_COOKIE_SENDFOR_LABEL}, - {"databaseOrigin", IDS_SETTINGS_COOKIES_LOCAL_STORAGE_ORIGIN_LABEL}, - {"fileSystemOrigin", IDS_SETTINGS_COOKIES_LOCAL_STORAGE_ORIGIN_LABEL}, - {"fileSystemPersistentUsage", - IDS_SETTINGS_COOKIES_FILE_SYSTEM_PERSISTENT_USAGE_LABEL}, - {"fileSystemTemporaryUsage", - IDS_SETTINGS_COOKIES_FILE_SYSTEM_TEMPORARY_USAGE_LABEL}, - {"indexedDbSize", IDS_SETTINGS_COOKIES_LOCAL_STORAGE_SIZE_ON_DISK_LABEL}, - {"indexedDbLastModified", - IDS_SETTINGS_COOKIES_LOCAL_STORAGE_LAST_MODIFIED_LABEL}, - {"indexedDbOrigin", IDS_SETTINGS_COOKIES_LOCAL_STORAGE_ORIGIN_LABEL}, - {"localStorageLastModified", - IDS_SETTINGS_COOKIES_LOCAL_STORAGE_LAST_MODIFIED_LABEL}, - {"localStorageOrigin", IDS_SETTINGS_COOKIES_LOCAL_STORAGE_ORIGIN_LABEL}, - {"localStorageSize", IDS_SETTINGS_COOKIES_LOCAL_STORAGE_SIZE_ON_DISK_LABEL}, - {"quotaOrigin", IDS_SETTINGS_COOKIES_LOCAL_STORAGE_ORIGIN_LABEL}, - {"quotaSize", IDS_SETTINGS_COOKIES_LOCAL_STORAGE_SIZE_ON_DISK_LABEL}, {"noBluetoothDevicesFound", IDS_SETTINGS_NO_BLUETOOTH_DEVICES_FOUND}, {"noHidDevicesFound", IDS_SETTINGS_NO_HID_DEVICES_FOUND}, {"noSerialPortsFound", IDS_SETTINGS_NO_SERIAL_PORTS_FOUND}, @@ -2574,12 +2565,6 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, {"resetSerialPortsConfirmation", IDS_SETTINGS_RESET_SERIAL_PORTS_CONFIRMATION}, {"resetUsbConfirmation", IDS_SETTINGS_RESET_USB_CONFIRMATION}, - {"serviceWorkerOrigin", IDS_SETTINGS_COOKIES_LOCAL_STORAGE_ORIGIN_LABEL}, - {"serviceWorkerSize", - IDS_SETTINGS_COOKIES_LOCAL_STORAGE_SIZE_ON_DISK_LABEL}, - {"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_SITE_SETTINGS_TYPE_CAMERA}, @@ -2672,9 +2657,6 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, {"cookiePageBlockExceptions", IDS_SETTINGS_COOKIES_BLOCK_EXCEPTIONS}, {"cookiePageSessionOnlyExceptions", IDS_SETTINGS_COOKIES_SESSION_ONLY_EXCEPTIONS}, - {"cookiesManageSiteSpecificExceptions", - IDS_SETTINGS_COOKIES_SITE_SPECIFIC_EXCEPTIONS}, - {"siteSettingsCategoryCookies", IDS_SITE_SETTINGS_TYPE_COOKIES}, {"siteSettingsCategoryFederatedIdentityApi", IDS_SITE_SETTINGS_TYPE_FEDERATED_IDENTITY_API}, {"siteSettingsCategoryHandlers", IDS_SITE_SETTINGS_TYPE_HANDLERS}, @@ -2686,12 +2668,6 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, {"siteSettingsCategoryMicrophone", IDS_SITE_SETTINGS_TYPE_MIC}, {"siteSettingsMicrophoneLabel", IDS_SITE_SETTINGS_TYPE_MIC}, {"siteSettingsCategoryNotifications", IDS_SITE_SETTINGS_TYPE_NOTIFICATIONS}, - {"siteSettingsNotificationsAsk", - IDS_SETTINGS_SITE_SETTINGS_NOTIFICATIONS_ASK}, - {"siteSettingsNotificationsBlock", - IDS_SETTINGS_SITE_SETTINGS_NOTIFICATIONS_BLOCK}, - {"siteSettingsEnableQuietNotificationPrompts", - IDS_SETTINGS_SITE_SETTINGS_ENABLE_QUIET_NOTIFICATION_PROMPTS}, {"siteSettingsCategoryPopups", IDS_SITE_SETTINGS_TYPE_POPUPS_REDIRECTS}, {"siteSettingsCategoryZoomLevels", IDS_SITE_SETTINGS_TYPE_ZOOM_LEVELS}, {"siteSettingsAllSites", IDS_SETTINGS_SITE_SETTINGS_ALL_SITES}, @@ -2709,8 +2685,12 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, IDS_SETTINGS_SITE_SETTINGS_FILE_SYSTEM_SITE_LIST_EDIT_HEADER}, {"siteSettingsFileSystemSiteListRemoveGrantLabel", IDS_SETTINGS_SITE_SETTINGS_FILE_SYSTEM_SITE_LIST_REMOVE_GRANT_LABEL}, + {"siteSettingsFileSystemSiteListRemoveGrants", + IDS_SETTINGS_SITE_SETTINGS_FILE_SYSTEM_SITE_LIST_REMOVE_GRANTS}, {"siteSettingsFileSystemSiteListViewHeader", IDS_SETTINGS_SITE_SETTINGS_FILE_SYSTEM_SITE_LIST_VIEW_HEADER}, + {"siteSettingsFileSystemSiteListViewSiteDetails", + IDS_SETTINGS_SITE_SETTINGS_FILE_SYSTEM_SITE_LIST_VIEW_SITE_DETAILS}, {"siteSettingsSiteEntryPartitionedLabel", IDS_SETTINGS_SITE_SETTINGS_SITE_ENTRY_PARTITIONED_LABEL}, {"siteSettingsSiteRepresentationSeparator", @@ -2734,10 +2714,6 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, {"siteSettingsClipboard", IDS_SITE_SETTINGS_TYPE_CLIPBOARD}, {"siteSettingsClipboardMidSentence", IDS_SITE_SETTINGS_TYPE_CLIPBOARD_MID_SENTENCE}, - {"siteSettingsClipboardAsk", IDS_SETTINGS_SITE_SETTINGS_CLIPBOARD_ASK}, - {"siteSettingsClipboardAskRecommended", - IDS_SETTINGS_SITE_SETTINGS_CLIPBOARD_ASK_RECOMMENDED}, - {"siteSettingsClipboardBlock", IDS_SETTINGS_SITE_SETTINGS_CLIPBOARD_BLOCK}, {"siteSettingsCookies", IDS_SITE_SETTINGS_TYPE_COOKIES}, {"siteSettingsCookiesMidSentence", IDS_SITE_SETTINGS_TYPE_COOKIES_MID_SENTENCE}, @@ -2765,8 +2741,6 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, IDS_SITE_SETTINGS_TYPE_JAVASCRIPT_MID_SENTENCE}, {"siteSettingsSound", IDS_SITE_SETTINGS_TYPE_SOUND}, {"siteSettingsSoundMidSentence", IDS_SITE_SETTINGS_TYPE_SOUND_MID_SENTENCE}, - {"siteSettingsSoundAllowRecommended", - IDS_SETTINGS_SITE_SETTINGS_SOUND_ALLOW_RECOMMENDED}, {"siteSettingsPdfDocuments", IDS_SITE_SETTINGS_TYPE_PDF_DOCUMENTS}, {"siteSettingsPdfDownloadPdfs", IDS_SETTINGS_SITE_SETTINGS_PDF_DOWNLOAD_PDFS}, @@ -2775,8 +2749,6 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, IDS_SITE_SETTINGS_TYPE_PROTECTED_MEDIA_ID_MID_SENTENCE}, {"siteSettingsProtectedContentIdentifiers", IDS_SITE_SETTINGS_TYPE_PROTECTED_MEDIA_ID}, - {"siteSettingsProtectedContentEnable", - IDS_SETTINGS_SITE_SETTINGS_PROTECTED_CONTENT_ENABLE}, {"siteSettingsProtectedContentDescription", IDS_SETTINGS_SITE_SETTINGS_PROTECTED_CONTENT_DESCRIPTION}, {"siteSettingsProtectedContentAllowed", @@ -2788,8 +2760,6 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN) {"siteSettingsProtectedContentIdentifiersExplanation", IDS_SETTINGS_SITE_SETTINGS_PROTECTED_CONTENT_IDENTIFIERS_EXPLANATION}, - {"siteSettingsProtectedContentEnableIdentifiers", - IDS_SETTINGS_SITE_SETTINGS_PROTECTED_CONTENT_ENABLE_IDENTIFIERS}, {"siteSettingsProtectedContentIdentifiersAllowed", IDS_SETTINGS_SITE_SETTINGS_PROTECTED_CONTENT_IDENTIFIERS_ALLOWED}, {"siteSettingsProtectedContentIdentifiersBlocked", @@ -2812,76 +2782,42 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, {"siteSettingsHidDevicesMidSentence", IDS_SITE_SETTINGS_TYPE_HID_DEVICES_MID_SENTENCE}, {"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_SITE_SETTINGS_TYPE_MIDI_SYSEX}, {"siteSettingsMidiDevicesMidSentence", IDS_SITE_SETTINGS_TYPE_MIDI_SYSEX_MID_SENTENCE}, - {"siteSettingsMidiDevicesAskRecommended", - IDS_SETTINGS_SITE_SETTINGS_MIDI_DEVICES_ASK_RECOMMENDED}, {"siteSettingsSerialPorts", IDS_SITE_SETTINGS_TYPE_SERIAL_PORTS}, {"siteSettingsSerialPortsMidSentence", IDS_SITE_SETTINGS_TYPE_SERIAL_PORTS_MID_SENTENCE}, {"siteSettingsUsbDevices", IDS_SITE_SETTINGS_TYPE_USB_DEVICES}, {"siteSettingsUsbDevicesMidSentence", IDS_SITE_SETTINGS_TYPE_USB_DEVICES_MID_SENTENCE}, - {"siteSettingsUsbDevicesAskRecommended", - IDS_SETTINGS_SITE_SETTINGS_USB_DEVICES_ASK_RECOMMENDED}, {"siteSettingsBluetoothDevices", IDS_SITE_SETTINGS_TYPE_BLUETOOTH_DEVICES}, {"siteSettingsBluetoothDevicesMidSentence", IDS_SITE_SETTINGS_TYPE_BLUETOOTH_DEVICES_MID_SENTENCE}, - {"siteSettingsBluetoothDevicesAskRecommended", - IDS_SETTINGS_SITE_SETTINGS_BLUETOOTH_DEVICES_ASK_RECOMMENDED}, {"siteSettingsFileSystemWrite", IDS_SITE_SETTINGS_TYPE_FILE_SYSTEM_ACCESS_WRITE}, {"siteSettingsFileSystemWriteMidSentence", IDS_SITE_SETTINGS_TYPE_FILE_SYSTEM_ACCESS_WRITE_MID_SENTENCE}, - {"siteSettingsFileSystemWriteAskRecommended", - IDS_SETTINGS_SITE_SETTINGS_FILE_SYSTEM_ACCESS_WRITE_ASK_RECOMMENDED}, {"siteSettingsRemoveZoomLevel", IDS_SETTINGS_SITE_SETTINGS_REMOVE_ZOOM_LEVEL}, {"siteSettingsZoomLevels", IDS_SITE_SETTINGS_TYPE_ZOOM_LEVELS}, {"siteSettingsZoomLevelsMidSentence", IDS_SITE_SETTINGS_TYPE_ZOOM_LEVELS_MID_SENTENCE}, {"siteSettingsNoZoomedSites", IDS_SETTINGS_SITE_SETTINGS_NO_ZOOMED_SITES}, - {"siteSettingsMaySaveCookies", IDS_SETTINGS_SITE_SETTINGS_MAY_SAVE_COOKIES}, - {"siteSettingsAskFirst", IDS_SETTINGS_SITE_SETTINGS_ASK_FIRST}, - {"siteSettingsAskFirstRecommended", - IDS_SETTINGS_SITE_SETTINGS_ASK_FIRST_RECOMMENDED}, - {"siteSettingsAskBeforeAccessingRecommended", - IDS_SETTINGS_SITE_SETTINGS_ASK_BEFORE_ACCESSING_RECOMMENDED}, {"siteSettingsAskBeforeSending", IDS_SETTINGS_SITE_SETTINGS_ASK_BEFORE_SENDING}, - {"siteSettingsAskBeforeSendingRecommended", - IDS_SETTINGS_SITE_SETTINGS_ASK_BEFORE_SENDING_RECOMMENDED}, - {"siteSettingsAllowRecentlyClosedSitesRecommended", - IDS_SETTINGS_SITE_SETTINGS_ALLOW_RECENTLY_CLOSED_SITES_RECOMMENDED}, - {"siteSettingsBackgroundSyncBlock", - IDS_SETTINGS_SITE_SETTINGS_BACKGROUND_SYNC_BLOCK}, {"siteSettingsHandlersAskRecommended", IDS_SETTINGS_SITE_SETTINGS_HANDLERS_ASK_RECOMMENDED}, {"siteSettingsHandlersBlocked", IDS_SETTINGS_SITE_SETTINGS_HANDLERS_BLOCKED}, - {"siteSettingsAutoDownloadAskRecommended", - IDS_SETTINGS_SITE_SETTINGS_AUTOMATIC_DOWNLOAD_ASK_RECOMMENDED}, - {"siteSettingsShowAllRecommended", - IDS_SETTINGS_SITE_SETTINGS_SHOW_ALL_RECOMMENDED}, {"siteSettingsCookiesAllowed", IDS_SETTINGS_SITE_SETTINGS_COOKIES_ALLOW_SITES}, - {"siteSettingsCookiesAllowedRecommended", - IDS_SETTINGS_SITE_SETTINGS_COOKIES_ALLOW_SITES_RECOMMENDED}, {"siteSettingsAllow", IDS_SETTINGS_SITE_SETTINGS_ALLOW}, {"siteSettingsBlock", IDS_SETTINGS_SITE_SETTINGS_BLOCK}, - {"siteSettingsBlockSound", IDS_SETTINGS_SITE_SETTINGS_BLOCK_SOUND}, {"siteSettingsSessionOnly", IDS_SETTINGS_SITE_SETTINGS_SESSION_ONLY}, - {"siteSettingsAllowedRecommended", - IDS_SETTINGS_SITE_SETTINGS_ALLOWED_RECOMMENDED}, {"siteSettingsBlocked", IDS_SETTINGS_SITE_SETTINGS_BLOCKED}, - {"siteSettingsBlockedRecommended", - IDS_SETTINGS_SITE_SETTINGS_BLOCKED_RECOMMENDED}, - {"siteSettingsSiteUrl", IDS_SETTINGS_SITE_SETTINGS_SITE_URL}, {"siteSettingsActionAskDefault", IDS_SETTINGS_SITE_SETTINGS_ASK_DEFAULT_MENU}, {"siteSettingsActionAllowDefault", @@ -2964,16 +2900,12 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, IDS_SETTINGS_SITE_SETTINGS_CLEAR_DISPLAYED_STORAGE_SIGN_OUT}, {"siteSettingsSiteDetailsSubpageAccessibilityLabel", IDS_SETTINGS_SITE_SETTINGS_SITE_DETAILS_SUBPAGE_ACCESSIBILITY_LABEL}, - {"firstPartySetsMembershipLabel", - IDS_SETTINGS_SITE_SETTINGS_FIRST_PARTY_SETS_MEMBERSHIP_LABEL}, {"firstPartySetsMoreActionsTitle", IDS_SETTINGS_SITE_SETTINGS_FIRST_PARTY_SETS_MORE_ACTIONS_TITLE}, {"firstPartySetsShowRelatedSitesButton", IDS_SETTINGS_SITE_SETTINGS_FIRST_PARTY_SETS_SHOW_RELATED_SITES_BUTTON}, {"firstPartySetsSiteClearStorageButton", IDS_SETTINGS_SITE_SETTINGS_FIRST_PARTY_SETS_SITE_CLEAR_STORAGE_BUTTON}, - {"siteSettingsSiteGroupDeleteConfirmationInstalledPlural", - IDS_SETTINGS_SITE_SETTINGS_SITE_GROUP_DELETE_CONFIRMATION_INSTALLED_PLURAL}, {"siteSettingsSiteClearStorage", IDS_SETTINGS_SITE_SETTINGS_SITE_CLEAR_STORAGE}, {"siteSettingsSiteClearStorageConfirmation", @@ -2988,28 +2920,9 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, IDS_SETTINGS_SITE_SETTINGS_SITE_CLEAR_STORAGE_OFFLINE_DATA}, {"siteSettingsRemoveSiteAdPersonalization", IDS_SETTINGS_SITE_SETTINGS_REMOVE_SITE_AD_PERSONALIZATION}, - {"siteSettingsSiteClearStorageApps", - IDS_SETTINGS_SITE_SETTINGS_SITE_CLEAR_STORAGE_APPS}, {"siteSettingsSiteGroupDelete", IDS_SETTINGS_SITE_SETTINGS_GROUP_DELETE}, - {"siteSettingsSiteGroupDeleteDialogTitle", - IDS_SETTINGS_SITE_SETTINGS_SITE_GROUP_DELETE_DIALOG_TITLE}, - {"siteSettingsSiteGroupDeleteConfirmation", - 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", IDS_SETTINGS_SITE_SETTINGS_SITE_GROUP_DELETE_OFFLINE_DATA}, - {"siteSettingsSiteGroupDeleteApps", - IDS_SETTINGS_SITE_SETTINGS_SITE_GROUP_DELETE_APPS}, - {"siteSettingsSiteGroupReset", IDS_SETTINGS_SITE_SETTINGS_GROUP_RESET}, - {"siteSettingsSiteGroupResetDialogTitle", - IDS_SETTINGS_SITE_SETTINGS_SITE_GROUP_RESET_DIALOG_TITLE}, - {"siteSettingsSiteGroupResetConfirmation", - IDS_SETTINGS_SITE_SETTINGS_SITE_GROUP_RESET_CONFIRMATION}, {"siteSettingsSiteResetAll", IDS_SETTINGS_SITE_SETTINGS_SITE_RESET_ALL}, {"siteSettingsSiteResetConfirmation", IDS_SETTINGS_SITE_SETTINGS_SITE_RESET_CONFIRMATION}, @@ -3308,13 +3221,9 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, IDS_SETTINGS_SITE_SETTINGS_ZOOM_LEVELS_DESCRIPTION}, {"siteSettingsAds", IDS_SITE_SETTINGS_TYPE_ADS}, {"siteSettingsAdsMidSentence", IDS_SITE_SETTINGS_TYPE_ADS_MID_SENTENCE}, - {"siteSettingsAdsBlockRecommended", - IDS_SETTINGS_SITE_SETTINGS_ADS_BLOCK_RECOMMENDED}, {"siteSettingsPaymentHandler", IDS_SITE_SETTINGS_TYPE_PAYMENT_HANDLER}, {"siteSettingsPaymentHandlerMidSentence", IDS_SITE_SETTINGS_TYPE_PAYMENT_HANDLER_MID_SENTENCE}, - {"siteSettingsPaymentHandlerAllowRecommended", - IDS_SETTINGS_SITE_SETTINGS_PAYMENT_HANDLER_ALLOW_RECOMMENDED}, {"siteSettingsBlockAutoplaySetting", IDS_SETTINGS_SITE_SETTINGS_BLOCK_AUTOPLAY}, {"emptyAllSitesPage", IDS_SETTINGS_SITE_SETTINGS_EMPTY_ALL_SITES_PAGE}, @@ -3336,13 +3245,9 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, {"siteSettingsAr", IDS_SITE_SETTINGS_TYPE_AR}, {"siteSettingsArMidSentence", IDS_SITE_SETTINGS_TYPE_AR_MID_SENTENCE}, {"siteSettingsArAsk", IDS_SETTINGS_SITE_SETTINGS_AR_ASK}, - {"siteSettingsArAskRecommended", - IDS_SETTINGS_SITE_SETTINGS_AR_ASK_RECOMMENDED}, {"siteSettingsArBlock", IDS_SETTINGS_SITE_SETTINGS_AR_BLOCK}, {"siteSettingsVr", IDS_SITE_SETTINGS_TYPE_VR}, {"siteSettingsVrMidSentence", IDS_SITE_SETTINGS_TYPE_VR_MID_SENTENCE}, - {"siteSettingsVrAskRecommended", - IDS_SETTINGS_SITE_SETTINGS_VR_ASK_RECOMMENDED}, {"siteSettingsWindowManagement", IDS_SITE_SETTINGS_TYPE_WINDOW_MANAGEMENT}, {"siteSettingsWindowManagementMidSentence", IDS_SITE_SETTINGS_TYPE_WINDOW_MANAGEMENT_MID_SENTENCE}, @@ -3361,8 +3266,6 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, {"siteSettingsIdleDetection", IDS_SITE_SETTINGS_TYPE_IDLE_DETECTION}, {"siteSettingsIdleDetectionMidSentence", IDS_SITE_SETTINGS_TYPE_IDLE_DETECTION_MID_SENTENCE}, - {"siteSettingsIdleDetectionBlock", - IDS_SETTINGS_SITE_SETTINGS_IDLE_DETECTION_BLOCK}, {"siteSettingsExtensionIdDescription", IDS_SETTINGS_SITE_SETTINGS_EXTENSION_ID_DESCRIPTION}, {"siteSettingsSiteDataAllowedSubLabel", @@ -3444,6 +3347,22 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source, html_source->AddString("addSiteExceptionPlaceholder", "[*.]example.com"); } +void AddStorageAccessStrings(content::WebUIDataSource* html_source) { + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"siteSettingsStorageAccess", IDS_SITE_SETTINGS_TYPE_STORAGE_ACCESS}, + {"siteSettingsStorageAccessMidSentence", + IDS_SITE_SETTINGS_TYPE_STORAGE_ACCESS_MID_SENTENCE}, + {"storageAccessDescription", IDS_SETTINGS_STORAGE_ACCESS_DESCRIPTION}, + {"storageAccessAllowed", IDS_SETTINGS_STORAGE_ACCESS_ALLOWED}, + {"storageAccessBlocked", IDS_SETTINGS_STORAGE_ACCESS_BLOCKED}, + {"storageAccessAllowedExceptions", + IDS_SETTINGS_STORAGE_ACCESS_ALLOWED_EXCEPTIONS}, + {"storageAccessBlockedExceptions", + IDS_SETTINGS_STORAGE_ACCESS_BLOCKED_EXCEPTIONS}, + }; + html_source->AddLocalizedStrings(kLocalizedStrings); +} + void AddSiteDataPageStrings(content::WebUIDataSource* html_source, Profile* profile) { static constexpr webui::LocalizedString kLocalizedStrings[] = { @@ -3563,10 +3482,6 @@ void AddSecurityKeysStrings(content::WebUIDataSource* html_source) { {"securityKeysBioEnrollmentNameLabelTooLong", IDS_SETTINGS_SECURITY_KEYS_BIO_NAME_LABEL_TOO_LONG}, {"securityKeysConfirmPIN", IDS_SETTINGS_SECURITY_KEYS_CONFIRM_PIN}, - {"securityKeysNoCredentialManagement", - IDS_SETTINGS_SECURITY_KEYS_NO_CREDENTIAL_MANAGEMENT}, - {"securityKeysCredentialManagementRemoved", - IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_REMOVED}, {"securityKeysCredentialManagementDesc", IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_DESC}, {"securityKeysCredentialManagementConfirmDeleteTitle", @@ -3583,20 +3498,10 @@ void AddSecurityKeysStrings(content::WebUIDataSource* html_source) { IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_DISPLAYNAME_LABEL}, {"securityKeysCredentialManagementLabel", IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_LABEL}, - {"securityKeysCredentialManagementDeleteSuccess", - IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_DELETE_SUCCESS}, - {"securityKeysCredentialManagementDeleteFailed", - IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_DELETE_FAILED}, - {"securityKeysCredentialManagementUpdateSuccess", - IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_UPDATE_SUCCESS}, - {"securityKeysCredentialManagementUpdateFailed", - IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_UPDATE_FAILED}, {"securityKeysCredentialManagementConfirmDeleteCredential", IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_CONFIRM_DELETE_CREDENTIAL}, {"securityKeysInputTooLong", IDS_SETTINGS_SECURITY_KEYS_INPUT_ERROR_TOO_LONG}, - {"securityKeysCredentialManagementNoCredentials", - IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_NO_CREDENTIALS}, {"securityKeysCurrentPIN", IDS_SETTINGS_SECURITY_KEYS_CURRENT_PIN}, {"securityKeysCurrentPINIntro", IDS_SETTINGS_SECURITY_KEYS_CURRENT_PIN_INTRO}, @@ -3690,7 +3595,6 @@ void AddLocalizedStrings(content::WebUIDataSource* html_source, #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - AddChromeCleanupStrings(html_source); AddIncompatibleApplicationsStrings(html_source); #endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) @@ -3712,6 +3616,7 @@ void AddLocalizedStrings(content::WebUIDataSource* html_source, AddSearchStrings(html_source); AddSiteSettingsStrings(html_source, profile); AddSiteDataPageStrings(html_source, profile); + AddStorageAccessStrings(html_source); #if !BUILDFLAG(IS_CHROMEOS) AddDefaultBrowserStrings(html_source); diff --git a/chromium/chrome/browser/ui/webui/settings/settings_manage_profile_handler.cc b/chromium/chrome/browser/ui/webui/settings/settings_manage_profile_handler.cc index 6340c1e4ff1..f9f09c625df 100644 --- a/chromium/chrome/browser/ui/webui/settings/settings_manage_profile_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/settings_manage_profile_handler.cc @@ -4,6 +4,7 @@ #include "chrome/browser/ui/webui/settings/settings_manage_profile_handler.h" +#include <cstdint> #include <utility> #include "base/functional/bind.h" @@ -153,7 +154,7 @@ void ManageProfileHandler::HandleSetProfileIconToGaiaAvatar( // Only log if they changed to the GAIA photo. // Selection of GAIA photo as avatar is logged as part of the function // below. - ProfileMetrics::LogProfileSwitchGaia(ProfileMetrics::GAIA_OPT_IN); + ProfileMetrics::LogProfileAvatarSelection(SIZE_MAX); } ProfileMetrics::LogProfileUpdate(profile_->GetPath()); 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 index 25a9aa31406..a4b7db93f2a 100644 --- 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 @@ -431,9 +431,8 @@ IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, SecureDnsTemplates) { } #if BUILDFLAG(IS_CHROMEOS_ASH) -// TODO(crbug.com/1415758): Flaky. IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, - DISABLED_SecureDnsTemplatesWithIdentifiers) { + SecureDnsTemplatesWithIdentifiers) { std::string templatesWithIdentifier = "https://foo.test-${USER_EMAIL}/dns-query{?dns}"; std::string templatesWithIdentifierDisplay = 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 6e3d1c08f40..c205a2310e3 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 @@ -12,7 +12,6 @@ #include "base/containers/contains.h" #include "base/functional/bind.h" #include "base/functional/callback.h" -#include "base/metrics/histogram_functions.h" #include "base/ranges/algorithm.h" #include "base/strings/string_number_conversions.h" #include "build/build_config.h" @@ -1119,7 +1118,9 @@ PasskeysHandler::PasskeysHandler( PasskeysHandler::~PasskeysHandler() = default; void PasskeysHandler::OnJavascriptAllowed() {} -void PasskeysHandler::OnJavascriptDisallowed() {} +void PasskeysHandler::OnJavascriptDisallowed() { + weak_factory_.InvalidateWeakPtrs(); +} void PasskeysHandler::RegisterMessages() { web_ui()->RegisterMessageCallback( @@ -1207,6 +1208,7 @@ void PasskeysHandler::HandleDelete(const base::Value::List& args) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_EQ(2u, args.size()); + AllowJavascript(); std::vector<uint8_t> credential_id; const bool ok = base::HexStringToBytes(args[1].GetString(), &credential_id); DCHECK(ok); @@ -1218,7 +1220,6 @@ void PasskeysHandler::HandleDelete(const base::Value::List& args) { } void PasskeysHandler::OnDeleteComplete(std::string callback_id, bool ok) { - base::UmaHistogramBoolean("WebAuthentication.PasskeyManagement.Delete", ok); // The ok parameter is ignored. If it were false, it would mean // Windows/Mac failed to delete the passkey. This can happen if API support // is missing but no passkeys will be shown at all in that case so that @@ -1232,6 +1233,7 @@ void PasskeysHandler::HandleEdit(const base::Value::List& args) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_EQ(3u, args.size()); + AllowJavascript(); std::vector<uint8_t> credential_id; const bool ok = base::HexStringToBytes(args[1].GetString(), &credential_id); DCHECK(ok); @@ -1244,7 +1246,6 @@ void PasskeysHandler::HandleEdit(const base::Value::List& args) { } void PasskeysHandler::OnEditComplete(std::string callback_id, bool ok) { - base::UmaHistogramBoolean("WebAuthentication.PasskeyManagement.Edit", ok); // The ok parameter is ignored. If it were false, it would mean // Windows/Mac failed to edit the passkey. DoEnumerate(std::move(callback_id)); diff --git a/chromium/chrome/browser/ui/webui/settings/settings_security_key_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/settings_security_key_handler_unittest.cc index bd8ee36d20b..9bd166c708e 100644 --- a/chromium/chrome/browser/ui/webui/settings/settings_security_key_handler_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/settings_security_key_handler_unittest.cc @@ -7,7 +7,6 @@ #include <memory> #include "base/test/gmock_callback_support.h" -#include "base/test/metrics/histogram_tester.h" #include "base/values.h" #include "chrome/browser/webauthn/local_credential_management.h" #include "chrome/grit/generated_resources.h" @@ -409,7 +408,6 @@ class PasskeysHandlerTest : public ChromeRenderViewHostTestHarness { TEST_F(PasskeysHandlerTest, TestHandleEdit) { device::test::TestCallbackReceiver<bool> callback; - base::HistogramTester histogram_tester; std::vector<uint8_t> credential_id = device::fido_parsing_utils::Materialize(kCredentialID); std::string credential_id_hex = base::HexEncode(credential_id); @@ -446,12 +444,9 @@ TEST_F(PasskeysHandlerTest, TestHandleEdit) { EXPECT_EQ(*web_ui_->call_data()[0]->arg3()->GetList()[0].GetDict().FindString( "userName"), "new-username"); - histogram_tester.ExpectUniqueSample( - "WebAuthentication.PasskeyManagement.Edit", true, 1); } TEST_F(PasskeysHandlerTest, TestRecordPasskeyDelete) { - base::HistogramTester histogram_tester; device::test::TestCallbackReceiver<bool> callback; std::vector<uint8_t> credential_id = device::fido_parsing_utils::Materialize(kCredentialID); @@ -475,8 +470,6 @@ TEST_F(PasskeysHandlerTest, TestRecordPasskeyDelete) { handler_->SimulateDelete(credential_id_hex); EXPECT_EQ(web_ui_->call_data()[0]->arg1()->GetString(), "passkeysDelete"); EXPECT_EQ(web_ui_->call_data()[0]->arg2()->GetBool(), true); - histogram_tester.ExpectUniqueSample( - "WebAuthentication.PasskeyManagement.Delete", true, 1); } #endif diff --git a/chromium/chrome/browser/ui/webui/settings/settings_startup_pages_handler.cc b/chromium/chrome/browser/ui/webui/settings/settings_startup_pages_handler.cc index 4a49f279937..66d3c8f1c8b 100644 --- a/chromium/chrome/browser/ui/webui/settings/settings_startup_pages_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/settings_startup_pages_handler.cc @@ -82,7 +82,11 @@ void StartupPagesHandler::OnModelChanged() { for (size_t i = 0; i < page_count; ++i) { base::Value::Dict entry; entry.Set("title", startup_custom_pages_table_model_.GetText(i, 0)); - entry.Set("url", urls[i].spec()); + std::string spec; + if (urls[i].is_valid()) { + spec = urls[i].spec(); + } + entry.Set("url", std::move(spec)); entry.Set("tooltip", startup_custom_pages_table_model_.GetTooltip(i)); entry.Set("modelIndex", base::checked_cast<int>(i)); startup_pages.Append(std::move(entry)); diff --git a/chromium/chrome/browser/ui/webui/settings/settings_ui.cc b/chromium/chrome/browser/ui/webui/settings/settings_ui.cc index 771d2e5bfe4..6003e415372 100644 --- a/chromium/chrome/browser/ui/webui/settings/settings_ui.cc +++ b/chromium/chrome/browser/ui/webui/settings/settings_ui.cc @@ -52,7 +52,9 @@ #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/safety_check_extensions_handler.h" #include "chrome/browser/ui/webui/settings/safety_check_handler.h" +#include "chrome/browser/ui/webui/settings/safety_hub_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_localized_strings_provider.h" @@ -63,7 +65,6 @@ #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/settings/site_settings_permissions_handler.h" #include "chrome/browser/ui/webui/webui_util.h" #include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" @@ -79,6 +80,7 @@ #include "components/favicon_base/favicon_url_parser.h" #include "components/password_manager/core/common/password_manager_features.h" #include "components/performance_manager/public/features.h" +#include "components/permissions/features.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_service.h" #include "components/privacy_sandbox/privacy_sandbox_features.h" @@ -99,16 +101,11 @@ #include "chrome/grit/settings_shared_resources_map.h" #endif -#if BUILDFLAG(IS_WIN) -#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h" -#include "chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.h" -#include "chrome/browser/ui/webui/settings/chrome_cleanup_handler_win.h" -#if BUILDFLAG(GOOGLE_CHROME_BRANDING) +#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) #include "chrome/browser/ui/webui/settings/incompatible_applications_handler_win.h" #include "chrome/browser/win/conflicts/incompatible_applications_updater.h" #include "chrome/browser/win/conflicts/token_util.h" -#endif -#endif // BUILDFLAG(IS_WIN) +#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/ui/webui/settings/languages_handler.h" @@ -213,8 +210,9 @@ SettingsUI::SettingsUI(content::WebUI* web_ui) AddSettingsPageUIHandler( std::make_unique<ClearBrowsingDataHandler>(web_ui, profile)); AddSettingsPageUIHandler(std::make_unique<SafetyCheckHandler>()); + AddSettingsPageUIHandler(std::make_unique<SafetyHubHandler>(profile)); AddSettingsPageUIHandler( - std::make_unique<SiteSettingsPermissionsHandler>(profile)); + std::make_unique<SafetyCheckExtensionsHandler>(profile)); AddSettingsPageUIHandler(std::make_unique<DownloadsHandler>(profile)); AddSettingsPageUIHandler(std::make_unique<ExtensionControlHandler>()); AddSettingsPageUIHandler(std::make_unique<FontHandler>(profile)); @@ -271,10 +269,6 @@ SettingsUI::SettingsUI(content::WebUI* web_ui) #endif -#if BUILDFLAG(IS_WIN) - AddSettingsPageUIHandler(std::make_unique<ChromeCleanupHandler>(profile)); -#endif // BUILDFLAG(IS_WIN) - #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) bool has_incompatible_applications = IncompatibleApplicationsUpdater::HasCachedApplications(); @@ -309,13 +303,6 @@ SettingsUI::SettingsUI(content::WebUI* web_ui) html_source->AddBoolean( "enablePasswordViewPage", !enable_new_password_manager_page && - (base::FeatureList::IsEnabled( - password_manager::features::kPasswordViewPageInSettings) || - base::FeatureList::IsEnabled(syncer::kPasswordNotesWithBackup))); - - html_source->AddBoolean( - "enablePasswordNotes", - !enable_new_password_manager_page && base::FeatureList::IsEnabled(syncer::kPasswordNotesWithBackup)); html_source->AddBoolean("enableSendPasswords", @@ -361,16 +348,14 @@ SettingsUI::SettingsUI(content::WebUI* web_ui) html_source->AddBoolean("userCannotManuallyEnterPassword", false); #endif // !BUILDFLAG(IS_CHROMEOS_LACROS) -#if BUILDFLAG(IS_CHROMEOS) - html_source->AddBoolean( - "useSystemAuthenticationForPasswordManager", - chromeos::features::IsPasswordManagerSystemAuthenticationEnabled()); -#endif - bool show_privacy_guide = !chrome::ShouldDisplayManagedUi(profile) && !profile->IsChild(); html_source->AddBoolean("showPrivacyGuide", show_privacy_guide); + html_source->AddBoolean( + "enableExtendedSettingsDescriptions", + base::FeatureList::IsEnabled(features::kExtendedSettingsDescriptions)); + html_source->AddBoolean("esbSettingsImprovementsEnabled", base::FeatureList::IsEnabled( safe_browsing::kEsbIphBubbleAndCollapseSettings)); @@ -433,6 +418,9 @@ SettingsUI::SettingsUI(content::WebUI* web_ui) "importPasswordsFailuresSummary", IDS_SETTINGS_PASSWORDS_IMPORT_FAILURES_SUMMARY); plural_string_handler->AddLocalizedString( + "safetyCheckExtensionsReviewLabel", + IDS_SETTINGS_SAFETY_CHECK_REVIEW_EXTENSIONS); + plural_string_handler->AddLocalizedString( "safetyCheckNotificationPermissionReviewHeaderLabel", IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_HEADER_LABEL); plural_string_handler->AddLocalizedString( @@ -470,6 +458,7 @@ SettingsUI::SettingsUI(content::WebUI* web_ui) base::make_span(kSettingsSharedResources, kSettingsSharedResourcesSize)); #endif + webui::SetupChromeRefresh2023(html_source); AddLocalizedStrings(html_source, profile, web_ui->GetWebContents()); ManagedUIHandler::Initialize(web_ui, html_source); @@ -511,8 +500,28 @@ SettingsUI::SettingsUI(content::WebUI* web_ui) base::FeatureList::IsEnabled( content_settings::features::kSafetyCheckUnusedSitePermissions)); + html_source->AddBoolean( + "safetyCheckExtensionsReviewEnabled", + base::FeatureList::IsEnabled(features::kSafetyCheckExtensions)); + + html_source->AddBoolean("enableSafetyHub", + base::FeatureList::IsEnabled(features::kSafetyHub)); + // Performance AddSettingsPageUIHandler(std::make_unique<PerformanceHandler>()); + html_source->AddBoolean( + "isHighEfficiencyMultistateModeEnabled", + base::FeatureList::IsEnabled( + performance_manager::features::kHighEfficiencyMultistateMode)); + html_source->AddBoolean( + "isDiscardExceptionsImprovementsEnabled", + base::FeatureList::IsEnabled( + performance_manager::features::kDiscardExceptionsImprovements)); + + html_source->AddBoolean( + "enablePermissionStorageAccessApi", + base::FeatureList::IsEnabled( + permissions::features::kPermissionStorageAccessAPI)); TryShowHatsSurveyWithTimeout(); } diff --git a/chromium/chrome/browser/ui/webui/settings/settings_utils_mac.mm b/chromium/chrome/browser/ui/webui/settings/settings_utils_mac.mm index 816f9de96e9..68c89f0688d 100644 --- a/chromium/chrome/browser/ui/webui/settings/settings_utils_mac.mm +++ b/chromium/chrome/browser/ui/webui/settings/settings_utils_mac.mm @@ -16,6 +16,10 @@ #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace { void ValidateFontFamily(PrefService* prefs, const char* family_pref_name) { // The native font settings dialog saved fonts by the font name, rather @@ -25,10 +29,10 @@ void ValidateFontFamily(PrefService* prefs, const char* family_pref_name) { // the webui settings window, we will fix the saved preference if necessary. NSString* family_name = base::SysUTF8ToNSString(prefs->GetString(family_pref_name)); - NSFont* font = [NSFont fontWithName:family_name size:[NSFont systemFontSize]]; + NSFont* font = [NSFont fontWithName:family_name size:NSFont.systemFontSize]; if (font && - [[font familyName] caseInsensitiveCompare:family_name] != NSOrderedSame) { - std::string new_family_name = base::SysNSStringToUTF8([font familyName]); + [font.familyName caseInsensitiveCompare:family_name] != NSOrderedSame) { + std::string new_family_name = base::SysNSStringToUTF8(font.familyName); prefs->SetString(family_pref_name, new_family_name); } } 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 index 17b38fe2de7..b1429fa4f30 100644 --- 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 @@ -118,6 +118,8 @@ void AddCaptionSubpageStrings(content::WebUIDataSource* html_source) { {"captionsLanguage", IDS_SETTINGS_CAPTIONS_LANGUAGE}, {"captionsManageLanguagesTitle", IDS_SETTINGS_CAPTIONS_MANAGE_LANGUAGES_TITLE}, + {"captionsManageLanguagesSubtitle", + IDS_SETTINGS_CAPTIONS_MANAGE_LANGUAGES_SUBTITLE}, {"captionsLiveTranslateTargetLanguage", IDS_SETTINGS_CAPTIONS_LIVE_TRANSLATE_TARGET_LANGUAGE}, {"removeLanguageAriaLabel", @@ -192,8 +194,10 @@ void AddSharedSyncPageStrings(content::WebUIDataSource* html_source) { {"sync", IDS_SETTINGS_SYNC}, {"manageSyncedDataTitle", IDS_SETTINGS_NEW_MANAGE_SYNCED_DATA_TITLE_UNIFIED_CONSENT}, +#if BUILDFLAG(IS_CHROMEOS_ASH) {"manageSyncedDataSubtitle", IDS_SETTINGS_NEW_MANAGE_SYNCED_DATA_SUBTITLE_UNIFIED_CONSENT}, +#endif {"manageBrowserSyncedDataTitle", IDS_SETTINGS_NEW_MANAGE_BROWSER_SYNCED_DATA_TITLE}, {"syncAdvancedDevicePageTitle", @@ -216,6 +220,14 @@ void AddSharedSyncPageStrings(content::WebUIDataSource* html_source) { }; html_source->AddLocalizedStrings(kLocalizedStrings); +#if BUILDFLAG(IS_CHROMEOS_LACROS) + if (base::FeatureList::IsEnabled(syncer::kSyncChromeOSAppsToggleSharing)) { + html_source->AddLocalizedString( + "manageSyncedDataSubtitle", + IDS_SETTINGS_NEW_MANAGE_SYNCED_DATA_SUBTITLE_UNIFIED_CONSENT); + } +#endif + std::string sync_dashboard_url = google_util::AppendGoogleLocaleParam( GURL(chrome::kSyncGoogleDashboardURL), @@ -256,6 +268,9 @@ void AddSharedSyncPageStrings(content::WebUIDataSource* html_source) { #elif BUILDFLAG(IS_CHROMEOS_LACROS) html_source->AddBoolean("shouldShowLacrosSideBySideWarning", ShouldShowLacrosSideBySideWarningInLacros()); + html_source->AddBoolean( + "showSyncSettingsRevamp", + base::FeatureList::IsEnabled(syncer::kSyncChromeOSAppsToggleSharing)); #endif html_source->AddString("syncErrorsHelpUrl", chrome::kSyncErrorsHelpURL); 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 b6da61c9f64..18e8059ce26 100644 --- a/chromium/chrome/browser/ui/webui/settings/site_settings_handler.cc +++ b/chromium/chrome/browser/ui/webui/settings/site_settings_handler.cc @@ -23,13 +23,13 @@ #include "base/metrics/user_metrics.h" #include "base/no_destructor.h" #include "base/ranges/algorithm.h" +#include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/bluetooth/bluetooth_chooser_context_factory.h" -#include "chrome/browser/browsing_data/access_context_audit_service_factory.h" #include "chrome/browser/browsing_data/chrome_browsing_data_model_delegate.h" #include "chrome/browser/browsing_data/cookies_tree_model.h" #include "chrome/browser/browsing_topics/browsing_topics_service_factory.h" @@ -40,7 +40,6 @@ #include "chrome/browser/hid/hid_chooser_context.h" #include "chrome/browser/hid/hid_chooser_context_factory.h" #include "chrome/browser/media/unified_autoplay_config.h" -#include "chrome/browser/permissions/notification_permission_review_service_factory.h" #include "chrome/browser/permissions/permission_decision_auto_blocker_factory.h" #include "chrome/browser/privacy_sandbox/privacy_sandbox_service.h" #include "chrome/browser/privacy_sandbox/privacy_sandbox_service_factory.h" @@ -50,13 +49,18 @@ #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/url_identity.h" #include "chrome/browser/ui/webui/settings/recent_site_settings_helper.h" #include "chrome/browser/ui/webui/settings/site_settings_helper.h" #include "chrome/browser/usb/usb_chooser_context.h" #include "chrome/browser/usb/usb_chooser_context_factory.h" +#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h" +#include "chrome/browser/web_applications/web_app_provider.h" +#include "chrome/browser/web_applications/web_app_registrar.h" #include "chrome/common/chrome_features.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" #include "chrome/common/pref_names.h" +#include "chrome/common/url_constants.h" #include "chrome/grit/generated_resources.h" #include "components/browsing_data/content/browsing_data_model.h" #include "components/browsing_topics/browsing_topics_service.h" @@ -125,6 +129,9 @@ constexpr char kIsValidKey[] = "isValid"; constexpr char kReasonKey[] = "reason"; constexpr char kEffectiveTopLevelDomainPlus1Name[] = "etldPlus1"; +constexpr char kGroupingKey[] = "groupingKey"; +constexpr char kGroupingKeyEtldPrefix[] = "etld:"; +constexpr char kGroupingKeyOriginPrefix[] = "origin:"; constexpr char kOriginList[] = "origins"; constexpr char kNumCookies[] = "numCookies"; constexpr char kHasPermissionSettings[] = "hasPermissionSettings"; @@ -423,25 +430,26 @@ std::string GetCookieSettingDescription(Profile* profile) { NOTREACHED(); } -// Removes all nodes from |model| which match |origin| and |etld_plus1|. At -// least one of |origin| or |etld_plus1| must be set. If only |origin| is set, -// then unpartitioned storage for that origin is removed. If only |etld_plus1| -// is set, then any unpartitioned storage which matches that etld + 1, or -// partitioned storage where it is the partitioning site, is removed. If both -// |origin| and |etld_plus1| is set, then only storage for |origin| partitioned -// by |etld_plus1| is removed. +// Removes all nodes from |model| which match |origin| and/or belong to +// |grouping_key|. At least one of |origin| or |grouping_key| must be set. If +// only |origin| is set, then unpartitioned storage for that origin is removed. +// If only |grouping_key| is set, then any unpartitioned storage belonging to +// that group, or partitioned storage where it is the partitioning site, is +// removed. If both |origin| and |grouping_key| are set, then only storage for +// |origin| partitioned by |grouping_key| is removed. void RemoveMatchingNodes(CookiesTreeModel* model, - absl::optional<std::string> origin, - absl::optional<std::string> etld_plus1) { - DCHECK(origin || etld_plus1); + absl::optional<url::Origin> origin, + absl::optional<GroupingKey> grouping_key) { + DCHECK(origin || grouping_key); + absl::optional<std::string> group_etld_plus1 = + grouping_key.has_value() ? grouping_key->GetEtldPlusOne() : absl::nullopt; std::vector<CookieTreeNode*> nodes_to_delete; for (const auto& host_node : model->GetRoot()->children()) { bool origin_matches = - origin && - *origin == host_node->GetDetailedInfo().origin.GetURL().spec(); + origin.has_value() && *origin == host_node->GetDetailedInfo().origin; - if (origin && !origin_matches) { + if (origin.has_value() && !origin_matches) { // If the origin is set, host nodes which do not match that origin cannot // contain storage targeted for removal. continue; @@ -452,17 +460,18 @@ void RemoveMatchingNodes(CookiesTreeModel* model, base::UTF16ToUTF8(host_node->GetTitle()), net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); - bool etld_plus1_matches = etld_plus1 && *etld_plus1 == host_node_etld_plus1; + bool group_etld_plus1_matches = group_etld_plus1.has_value() && + *group_etld_plus1 == host_node_etld_plus1; for (const auto& storage_type_node : host_node->children()) { if (storage_type_node->GetDetailedInfo().node_type != CookieTreeNode::DetailedInfo::TYPE_COOKIES) { - // Non cookie storage cannot (currently) be partitioned. - if (origin && etld_plus1) { + // Non-cookie storage cannot (currently) be partitioned. + if (origin.has_value() && group_etld_plus1.has_value()) { continue; } - if (origin_matches || etld_plus1_matches) { + if (origin_matches || group_etld_plus1_matches) { nodes_to_delete.push_back(storage_type_node.get()); continue; } @@ -473,8 +482,8 @@ void RemoveMatchingNodes(CookiesTreeModel* model, for (const auto& cookie_node : storage_type_node->children()) { const auto& cookie = cookie_node->GetDetailedInfo().cookie; if (!cookie->IsPartitioned() && - (origin_matches || etld_plus1_matches) && - (!origin || !etld_plus1)) { + (origin_matches || group_etld_plus1_matches) && + (!origin.has_value() || !group_etld_plus1.has_value())) { nodes_to_delete.push_back(cookie_node.get()); continue; } @@ -484,9 +493,10 @@ void RemoveMatchingNodes(CookiesTreeModel* model, // If an origin has been set, it must match the origin of the // current node, which means it can be ignored. - DCHECK(!origin || origin_matches); + DCHECK(!origin.has_value() || origin_matches); - if (etld_plus1 && partition_site == *etld_plus1) { + if (group_etld_plus1.has_value() && + partition_site == *group_etld_plus1) { nodes_to_delete.push_back(cookie_node.get()); } } @@ -580,7 +590,7 @@ void ConvertSiteGroupMapToList( for (const auto& entry : site_group_map) { base::Value::Dict site_group; const GroupingKey& grouping_key = entry.first; - site_group.Set(kEffectiveTopLevelDomainPlus1Name, grouping_key.Serialize()); + site_group.Set(kGroupingKey, grouping_key.Serialize()); // eTLD+1 is the effective top level domain + 1. absl::optional<std::string> etld_plus1 = grouping_key.GetEtldPlusOne(); @@ -592,6 +602,9 @@ void ConvertSiteGroupMapToList( : site_settings::GetDisplayNameForGURL( profile, group_origin->GetURL(), /*hostname_only=*/false)); + if (etld_plus1.has_value()) { + site_group.Set(kEffectiveTopLevelDomainPlus1Name, *etld_plus1); + } bool has_installed_pwa = false; base::Value::List origin_list; @@ -606,7 +619,7 @@ void ConvertSiteGroupMapToList( origin_object.Set("isPartitioned", is_partitioned); origin_object.Set("engagement", engagement_service->GetScore(origin.GetURL())); - origin_object.Set("usage", 0); + origin_object.Set("usage", 0.0); origin_object.Set(kNumCookies, 0); bool is_installed = installed_origins.contains(origin); @@ -633,32 +646,22 @@ void ConvertSiteGroupMapToList( } } -bool ShouldAddToNotificationPermissionReviewList( - site_engagement::SiteEngagementService* service, - GURL url, - int notification_count) { - // The notification permission should be added to the list if one of the - // criteria below holds: - // - Site engagement level is NONE OR MINIMAL and average daily notification - // count is more than 0. - // - Site engamment level is LOW and average daily notification count is - // more than 3. Otherwise, the notification permission should not be added - // to review list. - double score = service->GetScore(url); - int low_engagement_notification_limit = - features::kSafetyCheckNotificationPermissionsLowEnagementLimit.Get(); - bool is_low_engagement = - !site_engagement::SiteEngagementService::IsEngagementAtLeast( - score, blink::mojom::EngagementLevel::MEDIUM) && - notification_count > low_engagement_notification_limit; - int min_engagement_notification_limit = - features::kSafetyCheckNotificationPermissionsMinEnagementLimit.Get(); - bool is_minimal_engagement = - !site_engagement::SiteEngagementService::IsEngagementAtLeast( - score, blink::mojom::EngagementLevel::LOW) && - notification_count > min_engagement_notification_limit; - - return is_minimal_engagement || is_low_engagement; +base::Value::Dict CreateZoomLevelException( + const std::string& host_or_spec, + const std::string& origin_for_favicon, + const std::string& display_name, + double zoom) { + base::Value::Dict exception; + exception.Set(site_settings::kHostOrSpec, host_or_spec); + exception.Set(site_settings::kOriginForFavicon, origin_for_favicon); + exception.Set(site_settings::kDisplayName, display_name); + + // Calculate the zoom percent from the factor. Round up to the nearest + // whole number. + int zoom_percent = + static_cast<int>(blink::PageZoomLevelToZoomFactor(zoom) * 100 + 0.5); + exception.Set(kZoom, base::FormatPercent(zoom_percent)); + return exception; } } // namespace @@ -676,6 +679,17 @@ GroupingKey GroupingKey::CreateFromEtldPlus1(const std::string& etld_plus1) { return GroupingKey(etld_plus1); } +// static +GroupingKey GroupingKey::Deserialize(const std::string& serialized) { + if (base::StartsWith(serialized, kGroupingKeyEtldPrefix)) { + return GroupingKey::CreateFromEtldPlus1( + serialized.substr(sizeof(kGroupingKeyEtldPrefix) - 1)); + } + CHECK(base::StartsWith(serialized, kGroupingKeyOriginPrefix)); + GURL url(serialized.substr(sizeof(kGroupingKeyOriginPrefix) - 1)); + return GroupingKey::Create(url::Origin::Create(url)); +} + GroupingKey::GroupingKey(const absl::variant<std::string, url::Origin>& value) : value_(value) {} @@ -684,11 +698,15 @@ GroupingKey& GroupingKey::operator=(const GroupingKey& other) = default; GroupingKey::~GroupingKey() = default; std::string GroupingKey::Serialize() const { - return absl::visit( - base::Overloaded{ - [](const std::string& etld_plus1) { return etld_plus1; }, - [](const url::Origin& origin) { return origin.GetURL().spec(); }}, - value_); + return absl::visit(base::Overloaded{[](const std::string& etld_plus1) { + return kGroupingKeyEtldPrefix + + etld_plus1; + }, + [](const url::Origin& origin) { + return kGroupingKeyOriginPrefix + + origin.GetURL().spec(); + }}, + value_); } absl::optional<std::string> GroupingKey::GetEtldPlusOne() const { @@ -709,7 +727,7 @@ url::Origin GroupingKey::ToOrigin() const { return absl::visit( base::Overloaded{[](const std::string& etld_plus1) { return ConvertEtldToOrigin(etld_plus1, - /*secure=*/true); + /*secure=*/false); }, [](const url::Origin& origin) { return origin; }}, value_); @@ -799,11 +817,6 @@ void SiteSettingsHandler::RegisterMessages() { base::BindRepeating(&SiteSettingsHandler::HandleGetChooserExceptionList, base::Unretained(this))); web_ui()->RegisterMessageCallback( - "getNotificationPermissionReview", - base::BindRepeating( - &SiteSettingsHandler::HandleGetNotificationPermissionReviewList, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( "getOriginPermissions", base::BindRepeating(&SiteSettingsHandler::HandleGetOriginPermissions, base::Unretained(this))); @@ -827,33 +840,6 @@ void SiteSettingsHandler::RegisterMessages() { &SiteSettingsHandler::HandleResetChooserExceptionForSite, base::Unretained(this))); web_ui()->RegisterMessageCallback( - "ignoreNotificationPermissionReviewForOrigins", - base::BindRepeating( - &SiteSettingsHandler:: - HandleIgnoreOriginsForNotificationPermissionReview, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "resetNotificationPermissionForOrigins", - base::BindRepeating( - &SiteSettingsHandler::HandleResetNotificationPermissionForOrigins, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "blockNotificationPermissionForOrigins", - base::BindRepeating( - &SiteSettingsHandler::HandleBlockNotificationPermissionForOrigins, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "allowNotificationPermissionForOrigins", - base::BindRepeating( - &SiteSettingsHandler::HandleAllowNotificationPermissionForOrigins, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "undoIgnoreNotificationPermissionReviewForOrigins", - base::BindRepeating( - &SiteSettingsHandler:: - HandleUndoIgnoreOriginsForNotificationPermissionReview, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( "isOriginValid", base::BindRepeating(&SiteSettingsHandler::HandleIsOriginValid, base::Unretained(this))); @@ -882,9 +868,9 @@ void SiteSettingsHandler::RegisterMessages() { base::BindRepeating(&SiteSettingsHandler::HandleFetchBlockAutoplayStatus, base::Unretained(this))); web_ui()->RegisterMessageCallback( - "clearEtldPlus1DataAndCookies", + "clearSiteGroupDataAndCookies", base::BindRepeating( - &SiteSettingsHandler::HandleClearEtldPlus1DataAndCookies, + &SiteSettingsHandler::HandleClearSiteGroupDataAndCookies, base::Unretained(this))); web_ui()->RegisterMessageCallback( "recordAction", @@ -906,15 +892,22 @@ void SiteSettingsHandler::OnJavascriptAllowed() { ObserveSourcesForProfile(primary_otr_profile); } - // Here we only subscribe to the HostZoomMap for the default storage partition - // since we don't allow the user to manage the zoom levels for apps. - // We're only interested in zoom-levels that are persisted, since the user - // is given the opportunity to view/delete these in the content-settings page. - host_zoom_map_subscription_ = + // Listen for zoom changes in the default StoragePartition and the primary + // StoragePartition of all installed Isolated Web Apps. + auto zoom_changed_callback = base::BindRepeating( + &SiteSettingsHandler::OnZoomLevelChanged, base::Unretained(this)); + host_zoom_map_subscriptions_.push_back( content::HostZoomMap::GetDefaultForBrowserContext(profile_) - ->AddZoomLevelChangedCallback( - base::BindRepeating(&SiteSettingsHandler::OnZoomLevelChanged, - base::Unretained(this))); + ->AddZoomLevelChangedCallback(zoom_changed_callback)); + for (const web_app::IsolatedWebAppUrlInfo& iwa_url_info : + site_settings::GetInstalledIsolatedWebApps(profile_)) { + content::StoragePartition* iwa_storage_partition = + profile_->GetStoragePartition( + iwa_url_info.storage_partition_config(profile_)); + host_zoom_map_subscriptions_.push_back( + content::HostZoomMap::GetForStoragePartition(iwa_storage_partition) + ->AddZoomLevelChangedCallback(zoom_changed_callback)); + } pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>(); pref_change_registrar_->Init(profile_->GetPrefs()); @@ -935,7 +928,7 @@ void SiteSettingsHandler::OnJavascriptAllowed() { void SiteSettingsHandler::OnJavascriptDisallowed() { observations_.RemoveAllObservations(); chooser_observations_.RemoveAllObservations(); - host_zoom_map_subscription_ = {}; + host_zoom_map_subscriptions_.clear(); pref_change_registrar_->Remove(prefs::kBlockAutoplayEnabled); pref_change_registrar_->Remove(prefs::kCookieControlsMode); observed_profiles_.RemoveAllObservations(); @@ -1009,7 +1002,8 @@ void SiteSettingsHandler::OnGetUsageInfo() { for (const BrowsingDataModel::BrowsingDataEntryView& entry : *browsing_data_model_) { - if (*entry.primary_host != usage_hostname) { + auto usage_origin = url::Origin::Create(GURL(usage_origin_)); + if (!entry.Matches(usage_origin)) { continue; } size += entry.data_details->storage_size; @@ -1131,8 +1125,7 @@ void SiteSettingsHandler::HandleGetFpsMembershipLabel( void SiteSettingsHandler::HandleClearUnpartitionedUsage( const base::Value::List& args) { CHECK_EQ(1U, args.size()); - const std::string& origin_string = args[0].GetString(); - auto origin = url::Origin::Create(GURL(origin_string)); + auto origin = url::Origin::Create(GURL(args[0].GetString())); if (origin.opaque()) return; AllowJavascript(); @@ -1143,7 +1136,7 @@ void SiteSettingsHandler::HandleClearUnpartitionedUsage( DCHECK(browsing_data_model_); DCHECK(cookies_tree_model_); - RemoveMatchingNodes(cookies_tree_model_.get(), origin_string, absl::nullopt); + RemoveMatchingNodes(cookies_tree_model_.get(), origin, absl::nullopt); // The scheme for some sites detail page is http on // chrome://settings/content/all. Cookies or site data might not cleared if @@ -1162,8 +1155,7 @@ void SiteSettingsHandler::HandleClearUnpartitionedUsage( // avoid confusion when cookies already exist when refreshing clear site // data page. Notes: this also means HTTPS sites cookie will be cleared when // user clear HTTP scheme Cookie. - RemoveMatchingNodes(cookies_tree_model_.get(), https_origin.GetURL().spec(), - absl::nullopt); + RemoveMatchingNodes(cookies_tree_model_.get(), https_origin, absl::nullopt); affected_origins.emplace_back(https_origin); } @@ -1173,10 +1165,10 @@ void SiteSettingsHandler::HandleClearUnpartitionedUsage( void SiteSettingsHandler::HandleClearPartitionedUsage( const base::Value::List& args) { CHECK_EQ(2U, args.size()); - const std::string& origin = args[0].GetString(); - const std::string& etld_plus1 = args[1].GetString(); + auto origin = url::Origin::Create(GURL(args[0].GetString())); + auto grouping_key = GroupingKey::Deserialize(args[1].GetString()); - RemoveMatchingNodes(cookies_tree_model_.get(), origin, etld_plus1); + RemoveMatchingNodes(cookies_tree_model_.get(), origin, grouping_key); } void SiteSettingsHandler::HandleSetDefaultValueForContentType( @@ -1330,7 +1322,6 @@ void SiteSettingsHandler::HandleGetCategoryList(const base::Value::List& args) { CHECK_EQ(2U, args.size()); std::string callback_id = args[0].GetString(); - GURL origin(args[1].GetString()); base::Value::List result; for (ContentSettingsType content_type : @@ -1413,15 +1404,18 @@ base::Value::List SiteSettingsHandler::PopulateCookiesAndUsageData( base::Value::Dict& site_group = item.GetDict(); base::Value::List& origin_list = *site_group.FindList(kOriginList); int cookie_num = 0; - const std::string& etld_plus1 = - *site_group.FindString(kEffectiveTopLevelDomainPlus1Name); - const auto& etld_plus1_cookie_num_it = - host_cookie_map.find({etld_plus1, absl::nullopt}); + auto grouping_key = + GroupingKey::Deserialize(*site_group.FindString(kGroupingKey)); // Add the number of eTLD+1 scoped cookies. - if (etld_plus1_cookie_num_it != host_cookie_map.end()) { - cookie_num = etld_plus1_cookie_num_it->second; + absl::optional<std::string> etld_plus1 = grouping_key.GetEtldPlusOne(); + if (etld_plus1.has_value()) { + const auto& etld_plus1_cookie_num_it = + std::as_const(host_cookie_map).find({*etld_plus1, absl::nullopt}); + if (etld_plus1_cookie_num_it != host_cookie_map.end()) { + cookie_num += etld_plus1_cookie_num_it->second; + } } - // Iterate over the origins for the ETLD+1, and set their usage and cookie + // Iterate over the origins for the group, and set their usage and cookie // numbers. for (base::Value& value : origin_list) { base::Value::Dict& origin_info = value.GetDict(); @@ -1436,12 +1430,10 @@ base::Value::List SiteSettingsHandler::PopulateCookiesAndUsageData( origin_info.Set("usage", static_cast<double>(size_info_it->second)); } const auto& host_cookie_num_it = host_cookie_map.find( - {origin.host(), - (is_partitioned ? absl::optional<std::string>(etld_plus1) - : absl::nullopt)}); + {origin.host(), (is_partitioned ? etld_plus1 : absl::nullopt)}); if (host_cookie_num_it != host_cookie_map.end()) { origin_info.Set(kNumCookies, host_cookie_num_it->second); - // Add cookies numbers for origins that isn't an eTLD+1. + // Add cookies numbers for origins that aren't an eTLD+1. if (origin.host() != etld_plus1 || is_partitioned) { cookie_num += host_cookie_num_it->second; } @@ -1547,9 +1539,9 @@ void SiteSettingsHandler::HandleGetOriginPermissions( HostContentSettingsMap* map = HostContentSettingsMapFactory::GetForProfile(profile_); - std::string source_string, display_name; + std::string source_string; ContentSetting content_setting = site_settings::GetContentSettingForOrigin( - profile_, map, origin_url, content_type, &source_string, &display_name); + profile_, map, origin_url, content_type, &source_string); std::string content_setting_string = content_settings::ContentSettingToString(content_setting); @@ -1558,36 +1550,30 @@ void SiteSettingsHandler::HandleGetOriginPermissions( raw_site_exception.Set(site_settings::kIncognito, profile_->IsOffTheRecord()); raw_site_exception.Set(site_settings::kOrigin, origin); - absl::optional<std::string> extension_name = - site_settings::GetExtensionDisplayName(profile_, origin_url); - if (extension_name.has_value()) { - raw_site_exception.Set(site_settings::kExtensionNameWithId, - l10n_util::GetStringFUTF8( - IDS_SETTINGS_EXTENSION_DISPLAY_NAME, - base::UTF8ToUTF16(extension_name.value()), - base::UTF8ToUTF16(origin_url.host_piece()))); - } - raw_site_exception.Set(site_settings::kDisplayName, display_name); raw_site_exception.Set(site_settings::kSetting, content_setting_string); raw_site_exception.Set(site_settings::kSource, source_string); + UrlIdentity identity = site_settings::GetUrlIdentityForGURL( + profile_, origin_url, /*hostname_only=*/false); + std::string display_name; + if (identity.type == UrlIdentity::Type::kChromeExtension || + identity.type == UrlIdentity::Type::kIsolatedWebApp) { + // Append " (ID: <id>)" to extensions and IWA names as the user could have + // multiple extensions/IWAs installed with the same name. + display_name = l10n_util::GetStringFUTF8( + IDS_SETTINGS_EXTENSION_OR_APP_DISPLAY_NAME, identity.name, + base::UTF8ToUTF16(origin_url.host_piece())); + } else { + display_name = base::UTF16ToUTF8(identity.name); + } + raw_site_exception.Set(site_settings::kDisplayName, display_name); + exceptions.Append(std::move(raw_site_exception)); } ResolveJavascriptCallback(callback_id, exceptions); } -void SiteSettingsHandler::HandleGetNotificationPermissionReviewList( - const base::Value::List& args) { - AllowJavascript(); - - const base::Value& callback_id = args[0]; - - base::Value::List result = PopulateNotificationPermissionReviewData(); - - ResolveJavascriptCallback(callback_id, base::Value(std::move(result))); -} - void SiteSettingsHandler::HandleGetFileSystemGrants( const base::Value::List& args) { CHECK_EQ(1U, args.size()); @@ -1728,6 +1714,10 @@ void SiteSettingsHandler::HandleSetOriginPermissions( "SoundContentSetting.UnmuteBy.SiteSettings")); } } + + permissions::PermissionUmaUtil::RecordPermissionRegrantForUnusedSites( + origin, content_type, permissions::PermissionSourceUI::SITE_SETTINGS, + profile_, base::Time::Now()); } // Show an infobar reminding the user to reload tabs where their site @@ -1894,104 +1884,13 @@ void SiteSettingsHandler::HandleResetChooserExceptionForSite( site_settings::ChooserTypeFromGroupName(chooser_type_str); CHECK(chooser_type); - const std::string& origin_str = args[1].GetString(); - GURL origin(origin_str); - CHECK(origin.is_valid()); + auto origin_url = GURL(args[1].GetString()); + CHECK(origin_url.is_valid()); + auto origin = url::Origin::Create(origin_url); permissions::ObjectPermissionContextBase* chooser_context = chooser_type->get_context(profile_); - chooser_context->RevokeObjectPermission(url::Origin::Create(origin), args[2]); -} - -void SiteSettingsHandler::HandleIgnoreOriginsForNotificationPermissionReview( - const base::Value::List& args) { - CHECK_EQ(1U, args.size()); - const base::Value::List& origins = args[0].GetList(); - - auto* service = - NotificationPermissionsReviewServiceFactory::GetForProfile(profile_); - DCHECK(service); - - for (const auto& origin : origins) { - const ContentSettingsPattern primary_pattern = - ContentSettingsPattern::FromString(origin.GetString()); - service->AddPatternToNotificationPermissionReviewBlocklist( - primary_pattern, ContentSettingsPattern::Wildcard()); - } - - SendNotificationPermissionReviewList(); -} - -void SiteSettingsHandler::HandleResetNotificationPermissionForOrigins( - const base::Value::List& args) { - CHECK_EQ(1U, args.size()); - - const base::Value::List& origins = args[0].GetList(); - - HostContentSettingsMap* map = - HostContentSettingsMapFactory::GetForProfile(profile_); - - for (const auto& origin : origins) { - map->SetContentSettingCustomScope( - ContentSettingsPattern::FromString(origin.GetString()), - ContentSettingsPattern::Wildcard(), ContentSettingsType::NOTIFICATIONS, - CONTENT_SETTING_DEFAULT); - } - - SendNotificationPermissionReviewList(); -} - -void SiteSettingsHandler::HandleBlockNotificationPermissionForOrigins( - const base::Value::List& args) { - CHECK_EQ(1U, args.size()); - const base::Value::List& origins = args[0].GetList(); - - HostContentSettingsMap* map = - HostContentSettingsMapFactory::GetForProfile(profile_); - for (const auto& origin : origins) { - map->SetContentSettingCustomScope( - ContentSettingsPattern::FromString(origin.GetString()), - ContentSettingsPattern::Wildcard(), ContentSettingsType::NOTIFICATIONS, - CONTENT_SETTING_BLOCK); - } - - SendNotificationPermissionReviewList(); -} - -void SiteSettingsHandler::HandleAllowNotificationPermissionForOrigins( - const base::Value::List& args) { - CHECK_EQ(1U, args.size()); - const base::Value::List& origins = args[0].GetList(); - - HostContentSettingsMap* map = - HostContentSettingsMapFactory::GetForProfile(profile_); - - for (const auto& origin : origins) { - map->SetContentSettingCustomScope( - ContentSettingsPattern::FromString(origin.GetString()), - ContentSettingsPattern::Wildcard(), ContentSettingsType::NOTIFICATIONS, - CONTENT_SETTING_ALLOW); - } - - SendNotificationPermissionReviewList(); -} - -void SiteSettingsHandler:: - HandleUndoIgnoreOriginsForNotificationPermissionReview( - const base::Value::List& args) { - CHECK_EQ(1U, args.size()); - const base::Value::List& origins = args[0].GetList(); - auto* service = - NotificationPermissionsReviewServiceFactory::GetForProfile(profile_); - DCHECK(service); - - for (const auto& origin : origins) { - const ContentSettingsPattern& primary_pattern = - ContentSettingsPattern::FromString(origin.GetString()); - service->RemovePatternFromNotificationPermissionReviewBlocklist( - primary_pattern, ContentSettingsPattern::Wildcard()); - } - SendNotificationPermissionReviewList(); + chooser_context->RevokeObjectPermission(origin, args[2].GetDict()); } void SiteSettingsHandler::HandleIsOriginValid(const base::Value::List& args) { @@ -2045,6 +1944,40 @@ void SiteSettingsHandler::SendZoomLevels() { base::Value::List zoom_levels_exceptions; + // Show any non-default Isolated Web App zoom levels at the top of the page. + auto* web_app_provider = web_app::WebAppProvider::GetForWebApps(profile_); + if (web_app_provider) { + const web_app::WebAppRegistrar& registrar = + web_app_provider->registrar_unsafe(); + for (const web_app::IsolatedWebAppUrlInfo& iwa_url_info : + site_settings::GetInstalledIsolatedWebApps(profile_)) { + content::StoragePartition* iwa_storage_partition = + profile_->GetStoragePartition( + iwa_url_info.storage_partition_config(profile_)); + auto* host_zoom_map = + content::HostZoomMap::GetForStoragePartition(iwa_storage_partition); + double iwa_zoom = host_zoom_map->GetZoomLevelForHostAndScheme( + chrome::kIsolatedAppScheme, iwa_url_info.origin().host()); + if (iwa_zoom == host_zoom_map->GetDefaultZoomLevel()) { + continue; + } + + zoom_levels_exceptions.Append(CreateZoomLevelException( + iwa_url_info.origin().Serialize(), iwa_url_info.origin().Serialize(), + registrar.GetAppShortName(iwa_url_info.app_id()), iwa_zoom)); + } + + // Sort by app name. + std::sort(zoom_levels_exceptions.begin(), zoom_levels_exceptions.end(), + [](const base::Value& a, const base::Value& b) { + const std::string& name_a = + *a.GetDict().FindString(site_settings::kDisplayName); + const std::string& name_b = + *b.GetDict().FindString(site_settings::kDisplayName); + return name_a < name_b; + }); + } + content::HostZoomMap* host_zoom_map = content::HostZoomMap::GetDefaultForBrowserContext(profile_); content::HostZoomMap::ZoomLevelVector zoom_levels( @@ -2059,32 +1992,35 @@ void SiteSettingsHandler::SendZoomLevels() { const content::HostZoomMap::ZoomLevelChange& b) { return a.host == b.host ? a.scheme < b.scheme : a.host < b.host; }); + GURL unreachable_web_data_url(content::kUnreachableWebDataURL); for (const auto& zoom_level : zoom_levels) { base::Value::Dict exception; switch (zoom_level.mode) { case content::HostZoomMap::ZOOM_CHANGED_FOR_HOST: { - std::string host = zoom_level.host; - if (host == content::kUnreachableWebDataURL) { - host = + std::string host_or_spec = zoom_level.host; + std::string origin_for_favicon = host_or_spec; + std::string display_name = host_or_spec; + + if (host_or_spec == unreachable_web_data_url.host()) { + display_name = l10n_util::GetStringUTF8(IDS_ZOOMLEVELS_CHROME_ERROR_PAGES_LABEL); } - exception.Set(site_settings::kOrigin, host); - std::string display_name = host; - std::string origin_for_favicon = host; // As an optimization, only check hosts that could be an extension. - if (crx_file::id_util::IdIsValid(host)) { + if (crx_file::id_util::IdIsValid(host_or_spec)) { // Look up the host as an extension, if found then it is an extension. const extensions::Extension* extension = extension_registry->GetExtensionById( - host, extensions::ExtensionRegistry::EVERYTHING); + host_or_spec, extensions::ExtensionRegistry::EVERYTHING); if (extension) { origin_for_favicon = extension->url().spec(); display_name = extension->name(); } } - exception.Set(site_settings::kDisplayName, display_name); - exception.Set(site_settings::kOriginForFavicon, origin_for_favicon); + + zoom_levels_exceptions.Append( + CreateZoomLevelException(host_or_spec, origin_for_favicon, + display_name, zoom_level.zoom_level)); break; } case content::HostZoomMap::ZOOM_CHANGED_FOR_SCHEME_AND_HOST: @@ -2094,23 +2030,6 @@ void SiteSettingsHandler::SendZoomLevels() { case content::HostZoomMap::ZOOM_CHANGED_TEMPORARY_ZOOM: NOTREACHED(); } - - std::string setting_string = - content_settings::ContentSettingToString(CONTENT_SETTING_DEFAULT); - DCHECK(!setting_string.empty()); - - exception.Set(site_settings::kSetting, setting_string); - - // Calculate the zoom percent from the factor. Round up to the nearest whole - // number. - int zoom_percent = static_cast<int>( - blink::PageZoomLevelToZoomFactor(zoom_level.zoom_level) * 100 + 0.5); - exception.Set(kZoom, base::FormatPercent(zoom_percent)); - exception.Set(site_settings::kSource, - site_settings::SiteSettingSourceToString( - site_settings::SiteSettingSource::kPreference)); - // Append the new entry to the list and map. - zoom_levels_exceptions.Append(std::move(exception)); } FireWebUIListener("onZoomLevelsChanged", zoom_levels_exceptions); @@ -2119,17 +2038,29 @@ void SiteSettingsHandler::SendZoomLevels() { void SiteSettingsHandler::HandleRemoveZoomLevel(const base::Value::List& args) { CHECK_EQ(1U, args.size()); - std::string origin = args[0].GetString(); + std::string host_or_spec = args[0].GetString(); - if (origin == - l10n_util::GetStringUTF8(IDS_ZOOMLEVELS_CHROME_ERROR_PAGES_LABEL)) { - origin = content::kUnreachableWebDataURL; + GURL url(host_or_spec); + if (url.is_valid() && url.scheme() == chrome::kIsolatedAppScheme) { + base::expected<web_app::IsolatedWebAppUrlInfo, std::string> iwa_url_info = + web_app::IsolatedWebAppUrlInfo::Create(url); + if (!iwa_url_info.has_value()) { + return; + } + content::StoragePartition* iwa_storage_partition = + profile_->GetStoragePartition( + iwa_url_info->storage_partition_config(profile_)); + auto* host_zoom_map = + content::HostZoomMap::GetForStoragePartition(iwa_storage_partition); + double default_level = host_zoom_map->GetDefaultZoomLevel(); + host_zoom_map->SetZoomLevelForHost(url.host(), default_level); + return; } - content::HostZoomMap* host_zoom_map; - host_zoom_map = content::HostZoomMap::GetDefaultForBrowserContext(profile_); + content::HostZoomMap* host_zoom_map = + content::HostZoomMap::GetDefaultForBrowserContext(profile_); double default_level = host_zoom_map->GetDefaultZoomLevel(); - host_zoom_map->SetZoomLevelForHost(origin, default_level); + host_zoom_map->SetZoomLevelForHost(host_or_spec, default_level); } void SiteSettingsHandler::HandleFetchBlockAutoplayStatus( @@ -2316,10 +2247,14 @@ void SiteSettingsHandler::GetOriginStorage( if (entry.data_details->storage_size == 0) continue; - // Convert the primary host to an HTTPS url to match expecations for this - // code. - url::Origin origin = - ConvertEtldToOrigin(*entry.primary_host, /*secure=*/true); + url::Origin origin = absl::visit( + base::Overloaded{[](const std::string& host) { + // Convert the primary host to an HTTPS url to match + // expecations for this code. + return ConvertEtldToOrigin(host, /*secure=*/true); + }, + [](const url::Origin& origin) { return origin; }}, + *entry.data_owner); UpdateDataFromModel(all_sites_map, origin_size_map, origin, entry.data_details->storage_size); } @@ -2371,16 +2306,15 @@ void SiteSettingsHandler::GetHostCookies( } } -void SiteSettingsHandler::HandleClearEtldPlus1DataAndCookies( +void SiteSettingsHandler::HandleClearSiteGroupDataAndCookies( const base::Value::List& args) { CHECK_EQ(1U, args.size()); - const std::string& etld_plus1 = args[0].GetString(); - auto grouping_key = GroupingKey::CreateFromEtldPlus1(etld_plus1); + auto grouping_key = GroupingKey::Deserialize(args[0].GetString()); AllowJavascript(); - RemoveMatchingNodes(cookies_tree_model_.get(), absl::nullopt, etld_plus1); + RemoveMatchingNodes(cookies_tree_model_.get(), absl::nullopt, grouping_key); - // Retrieve all of the origin entries grouped under this eTLD + 1. + // Retrieve all of the origin entries grouped under this group. std::vector<url::Origin> affected_origins; for (const auto& origin_is_partitioned : all_sites_map_[grouping_key]) { // Ignore entries which are partitioned, as no non-cookie tree storage is @@ -2400,8 +2334,10 @@ void SiteSettingsHandler::HandleClearEtldPlus1DataAndCookies( // if the existing entry was https, otherwise a new http entry would be // created for the placeholder. Hence, we need only additionally include the // HTTPS version of the eTLD+1 as an origin. - affected_origins.emplace_back( - ConvertEtldToOrigin(etld_plus1, /*secure=*/true)); + if (auto etld_plus1 = grouping_key.GetEtldPlusOne(); etld_plus1.has_value()) { + affected_origins.emplace_back( + ConvertEtldToOrigin(*etld_plus1, /*secure=*/true)); + } RemoveNonTreeModelData(affected_origins); } @@ -2532,61 +2468,6 @@ void SiteSettingsHandler::SendCookieSettingDescription() { base::Value(GetCookieSettingDescription(profile_))); } -base::Value::List -SiteSettingsHandler::PopulateNotificationPermissionReviewData() { - base::Value::List result; - if (!base::FeatureList::IsEnabled( - features::kSafetyCheckNotificationPermissions)) - return result; - - auto* service = - NotificationPermissionsReviewServiceFactory::GetForProfile(profile_); - if (!service) - return result; - - auto notification_permissions = service->GetNotificationSiteListForReview(); - - site_engagement::SiteEngagementService* engagement_service = - site_engagement::SiteEngagementService::Get(profile_); - - // Sort notification permissions by their priority for surfacing to the user. - auto notification_permission_ordering = - [](const permissions::NotificationPermissions& left, - const permissions::NotificationPermissions& right) { - return left.notification_count > right.notification_count; - }; - std::sort(notification_permissions.begin(), notification_permissions.end(), - notification_permission_ordering); - - for (const auto& notification_permission : notification_permissions) { - // Converting primary pattern to GURL should always be valid, since - // Notification Permission Review list only contains single origins. Those - // are filtered in - // NotificationPermissionsReviewService::GetNotificationSiteListForReview. - GURL url = GURL(notification_permission.primary_pattern.ToString()); - DCHECK(url.is_valid()); - if (!ShouldAddToNotificationPermissionReviewList( - engagement_service, url, - notification_permission.notification_count)) { - continue; - } - - base::Value::Dict permission; - permission.Set(site_settings::kOrigin, - notification_permission.primary_pattern.ToString()); - - std::string notification_info_string = - base::UTF16ToUTF8(l10n_util::GetPluralStringFUTF16( - IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_COUNT_LABEL, - notification_permission.notification_count)); - permission.Set(site_settings::kNotificationInfoString, - notification_info_string); - result.Append(std::move(permission)); - } - - return result; -} - // Dictionary keys for an individual `FileSystemPermissionGrant`. // Schema (per grant): // { @@ -2710,8 +2591,9 @@ void SiteSettingsHandler::SendNotificationPermissionReviewList() { // an unchanged list may be sent. This is the case for // HandleResetCategoryPermissionForPattern and // HandleSetCategoryPermissionForPattern. - FireWebUIListener("notification-permission-review-list-maybe-changed", - PopulateNotificationPermissionReviewData()); + FireWebUIListener( + site_settings::kNotificationPermissionsReviewListMaybeChangedEvent, + site_settings::PopulateNotificationPermissionReviewData(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 b4edc1b2a06..5a22fb63250 100644 --- a/chromium/chrome/browser/ui/webui/settings/site_settings_handler.h +++ b/chromium/chrome/browser/ui/webui/settings/site_settings_handler.h @@ -9,6 +9,7 @@ #include <memory> #include <set> #include <string> +#include <vector> #include "base/gtest_prod_util.h" #include "base/memory/raw_ptr.h" @@ -50,6 +51,7 @@ class SiteSettingsHandler public: static GroupingKey Create(const url::Origin& origin); static GroupingKey CreateFromEtldPlus1(const std::string& etld_plus1); + static GroupingKey Deserialize(const std::string& serialized); GroupingKey(const GroupingKey& other); GroupingKey& operator=(const GroupingKey& other); @@ -171,7 +173,7 @@ class SiteSettingsHandler FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, SessionOnlyException); FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, ZoomLevels); FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, - HandleClearEtldPlus1DataAndCookies); + HandleClearSiteGroupDataAndCookies); FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, HandleClearUnpartitionedUsage); FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, ClearClientHints); @@ -190,24 +192,6 @@ class SiteSettingsHandler HandleGetFpsMembershipLabel); FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, NonTreeModelDeletion); FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, FirstPartySetsMembership); - FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, - HandleIgnoreOriginsForNotificationPermissionReview); - FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, - HandleBlockNotificationPermissionForOrigins); - FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, - HandleAllowNotificationPermissionForOrigins); - FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, - HandleResetNotificationPermissionForOrigins); - FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, - PopulateNotificationPermissionReviewData); - FRIEND_TEST_ALL_PREFIXES( - SiteSettingsHandlerTest, - HandleUndoIgnoreOriginsForNotificationPermissionReview); - FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, - SendNotificationPermissionReviewList_FeatureEnabled); - FRIEND_TEST_ALL_PREFIXES( - SiteSettingsHandlerTest, - SendNotificationPermissionReviewList_FeatureDisabled); FRIEND_TEST_ALL_PREFIXES( SiteSettingsHandlerInfobarTest, SettingPermissionsDoesNotTriggerInfobarOnDifferentProfile); @@ -215,6 +199,9 @@ class SiteSettingsHandler FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, HandleGetExtensionName); #endif FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, IsolatedWebAppUsageInfo); + FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerIsolatedWebAppTest, ZoomLevel); + FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerIsolatedWebAppTest, + ZoomLevelsSortedByAppName); // Rebuilds the BrowsingDataModel & CookiesTreeModel. Pending requests are // serviced when both models are built. @@ -296,9 +283,6 @@ class SiteSettingsHandler // Returns the list of chooser exceptions for a given chooser type. void HandleGetChooserExceptionList(const base::Value::List& args); - // Returns the list of notification permissions that needs to be reviewed. - void HandleGetNotificationPermissionReviewList(const base::Value::List& args); - // Returns the list of the allowed permission grants as defined by the // File System Access API. void HandleGetFileSystemGrants(const base::Value::List& args); @@ -326,28 +310,6 @@ class SiteSettingsHandler // Handles resetting a chooser exception for the given site. void HandleResetChooserExceptionForSite(const base::Value::List& args); - // Handles ignoring origins for the review notification permissions feature. - void HandleIgnoreOriginsForNotificationPermissionReview( - const base::Value::List& args); - - // Handles resetting a notification permission for given origins. - void HandleResetNotificationPermissionForOrigins( - const base::Value::List& args); - - // Handles blocking notification permissions for multiple origins. - void HandleBlockNotificationPermissionForOrigins( - const base::Value::List& args); - - // Handles allowing notification permissions for multiple origins. - void HandleAllowNotificationPermissionForOrigins( - const base::Value::List& args); - - // Handles reverting the action of ignoring origins for review notification - // permissions feature by removing them from the notification permission - // verification blocklist. - void HandleUndoIgnoreOriginsForNotificationPermissionReview( - const base::Value::List& args); - // Returns whether a given string is a valid origin. void HandleIsOriginValid(const base::Value::List& args); @@ -378,8 +340,8 @@ class SiteSettingsHandler // Updates the block autoplay enabled pref when the UI is toggled. void HandleSetBlockAutoplayEnabled(const base::Value::List& args); - // Clear web storage data and cookies from cookies tree model for an ETLD+1. - void HandleClearEtldPlus1DataAndCookies(const base::Value::List& args); + // Clear web storage data and cookies from CookiesTreeModel for a site group. + void HandleClearSiteGroupDataAndCookies(const base::Value::List& args); // Record metrics for actions on All Sites Page. void HandleRecordAction(const base::Value::List& args); @@ -403,11 +365,6 @@ class SiteSettingsHandler // provides the updated description label for display. void SendCookieSettingDescription(); - // Returns a list of domains to be shown on the 'Review Notification - // Permissions' module in site settings notification page. Those domains send - // a lot of notifications, but have low site engagement. - base::Value::List PopulateNotificationPermissionReviewData(); - // Returns a dictionary containing the lists of the allowed permission // grant objects granted via the File System Access API, per origin. base::Value::List PopulateFileSystemGrantData(); @@ -415,20 +372,17 @@ class SiteSettingsHandler // Sends the list of notification permissions to review to the WebUI. void SendNotificationPermissionReviewList(); - const raw_ptr<Profile> profile_; + const raw_ptr<Profile, DanglingUntriaged> profile_; base::ScopedMultiSourceObservation<Profile, ProfileObserver> observed_profiles_{this}; // Keeps track of events related to zooming. - base::CallbackListSubscription host_zoom_map_subscription_; + std::vector<base::CallbackListSubscription> host_zoom_map_subscriptions_; // The origin for which to fetch usage. std::string usage_origin_; - // The origin for which to clear usage. - std::string clearing_origin_; - // Change observer for content settings. base::ScopedMultiSourceObservation<HostContentSettingsMap, content_settings::Observer> 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 ad52d5eaa6d..9fd8fd8bf8f 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 @@ -42,19 +42,25 @@ #include "chrome/browser/extensions/test_extension_system.h" #include "chrome/browser/file_system_access/chrome_file_system_access_permission_context.h" #include "chrome/browser/file_system_access/file_system_access_permission_context_factory.h" +#include "chrome/browser/hid/hid_chooser_context.h" +#include "chrome/browser/hid/hid_chooser_context_factory.h" #include "chrome/browser/history/history_service_factory.h" -#include "chrome/browser/permissions/notification_permission_review_service_factory.h" -#include "chrome/browser/permissions/notifications_engagement_service_factory.h" #include "chrome/browser/permissions/permission_decision_auto_blocker_factory.h" #include "chrome/browser/prefs/browser_prefs.h" #include "chrome/browser/privacy_sandbox/mock_privacy_sandbox_service.h" #include "chrome/browser/privacy_sandbox/privacy_sandbox_service_factory.h" +#include "chrome/browser/serial/serial_chooser_context.h" +#include "chrome/browser/serial/serial_chooser_context_factory.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/web_applications/test/isolated_web_app_test_utils.h" #include "chrome/browser/ui/webui/settings/site_settings_helper.h" #include "chrome/browser/usb/usb_chooser_context.h" #include "chrome/browser/usb/usb_chooser_context_factory.h" +#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h" +#include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/web_app_helpers.h" +#include "chrome/browser/web_applications/web_app_id.h" #include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" @@ -69,6 +75,7 @@ #include "components/browsing_topics/browsing_topics_service.h" #include "components/browsing_topics/test_util.h" #include "components/client_hints/common/client_hints.h" +#include "components/content_settings/core/browser/content_settings_uma_util.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" @@ -93,6 +100,7 @@ #include "components/sync_preferences/testing_pref_service_syncable.h" #include "components/ukm/test_ukm_recorder.h" #include "content/public/browser/browsing_data_remover.h" +#include "content/public/browser/host_zoom_map.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/web_ui_data_source.h" @@ -106,7 +114,11 @@ #include "extensions/common/extension_builder.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "ppapi/buildflags/buildflags.h" +#include "services/device/public/cpp/test/fake_hid_manager.h" +#include "services/device/public/cpp/test/fake_serial_port_manager.h" #include "services/device/public/cpp/test/fake_usb_device_manager.h" +#include "services/device/public/mojom/hid.mojom.h" +#include "services/device/public/mojom/serial.mojom.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -127,20 +139,6 @@ #include "chrome/browser/plugins/chrome_plugin_service_filter.h" #endif -#if !BUILDFLAG(IS_ANDROID) -#include "chrome/browser/hid/hid_chooser_context.h" -#include "chrome/browser/hid/hid_chooser_context_factory.h" -#include "chrome/browser/serial/serial_chooser_context.h" -#include "chrome/browser/serial/serial_chooser_context_factory.h" -#include "chrome/browser/ui/web_applications/test/isolated_web_app_test_utils.h" -#include "chrome/browser/web_applications/test/web_app_install_test_utils.h" -#include "chrome/browser/web_applications/web_app_id.h" -#include "services/device/public/cpp/test/fake_hid_manager.h" -#include "services/device/public/cpp/test/fake_serial_port_manager.h" -#include "services/device/public/mojom/hid.mojom.h" -#include "services/device/public/mojom/serial.mojom.h" -#endif - namespace { using ::base::test::ParseJson; @@ -151,6 +149,8 @@ using ::testing::NiceMock; using ::testing::Return; using ::testing::UnorderedElementsAre; +using GroupingKey = settings::SiteSettingsHandler::GroupingKey; + constexpr char kCallbackId[] = "test-callback-id"; constexpr char kSetting[] = "setting"; constexpr char kSource[] = "source"; @@ -178,6 +178,15 @@ const struct PatternContentTypeTestCase { {{"http://127.0.0.1", "location"}, {true, ""}}, // Localhost is secure. {{"http://[::1]", "location"}, {true, ""}}}; +// Matchers to make verifying GroupingKey contents easier. +MATCHER_P(IsEtldPlus1, etld_plus1, "") { + return arg == std::string("etld:") + etld_plus1; +} + +MATCHER_P(IsOrigin, origin, "") { + return arg == std::string("origin:") + origin.spec(); +} + // Converts |etld_plus1| into an HTTPS SchemefulSite. net::SchemefulSite ConvertEtldToSchemefulSite(const std::string etld_plus1) { return net::SchemefulSite(GURL(std::string(url::kHttpsScheme) + @@ -192,7 +201,12 @@ void ValidateSitesWithFps( base::flat_map<net::SchemefulSite, net::SchemefulSite>& first_party_sets) { for (const base::Value& site_group_value : storage_and_cookie_list) { const base::Value::Dict& site_group = site_group_value.GetDict(); - std::string etld_plus1 = *site_group.FindString("etldPlus1"); + GroupingKey grouping_key = GroupingKey::Deserialize( + CHECK_DEREF(site_group.FindString("groupingKey"))); + if (!grouping_key.GetEtldPlusOne().has_value()) { + return; + } + std::string etld_plus1 = *grouping_key.GetEtldPlusOne(); auto schemeful_site = ConvertEtldToSchemefulSite(etld_plus1); if (first_party_sets.count(schemeful_site)) { @@ -361,20 +375,6 @@ class SiteSettingsHandlerBaseTest : public testing::Test { } #endif // BUILDFLAG(IS_CHROMEOS_ASH) - void RecordNotification(permissions::NotificationsEngagementService* service, - GURL url, - int daily_average_count) { - // This many notifications were recorded during the past week in total. - int total_count = daily_average_count * 7; - service->RecordNotificationDisplayed(url, total_count); - } - - base::Time GetReferenceTime() { - base::Time time; - EXPECT_TRUE(base::Time::FromString("Sat, 1 Sep 2018 11:00:00 GMT", &time)); - return time; - } - TestingProfile* profile() { return profile_.get(); } Profile* incognito_profile() { return incognito_profile_; } content::TestWebUI* web_ui() { return &web_ui_; } @@ -544,8 +544,13 @@ class SiteSettingsHandlerBaseTest : public testing::Test { EXPECT_EQ(expected_incognito, data.arg2()->GetBool()); } - void ValidateZoom(const std::string& expected_host, - const std::string& expected_zoom, + struct ZoomLevel { + std::string host_or_spec; + std::string display_name; + std::string zoom; + }; + + void ValidateZoom(const std::vector<ZoomLevel>& zoom_levels, size_t expected_total_calls) { EXPECT_EQ(expected_total_calls, web_ui()->call_data().size()); @@ -557,20 +562,22 @@ class SiteSettingsHandlerBaseTest : public testing::Test { ASSERT_TRUE(data.arg2()->is_list()); const base::Value::List& exceptions = data.arg2()->GetList(); - if (expected_host.empty()) { - EXPECT_EQ(0U, exceptions.size()); - } else { - EXPECT_EQ(1U, exceptions.size()); + ASSERT_EQ(zoom_levels.size(), exceptions.size()); + for (size_t i = 0; i < zoom_levels.size(); i++) { + const ZoomLevel& zoom_level = zoom_levels[i]; + const base::Value::Dict& exception = exceptions[i].GetDict(); - const base::Value::Dict& exception = exceptions[0].GetDict(); + const std::string* host_or_spec = exception.FindString("hostOrSpec"); + ASSERT_TRUE(host_or_spec); + ASSERT_EQ(zoom_level.host_or_spec, *host_or_spec); - const std::string* host = exception.FindString("origin"); - ASSERT_TRUE(host); - ASSERT_EQ(expected_host, *host); + const std::string* display_name = exception.FindString("displayName"); + ASSERT_TRUE(display_name); + ASSERT_EQ(zoom_level.display_name, *display_name); const std::string* zoom = exception.FindString("zoom"); ASSERT_TRUE(zoom); - ASSERT_EQ(expected_zoom, *zoom); + ASSERT_EQ(zoom_level.zoom, *zoom); } } @@ -584,7 +591,7 @@ class SiteSettingsHandlerBaseTest : public testing::Test { ASSERT_EQ(expected_string, data.arg2()->GetString()); } - void ValidateUsageInfo(const std::string& expected_usage_host, + void ValidateUsageInfo(const std::string& expected_usage_origin, const std::string& expected_usage_string, const std::string& expected_cookie_string, const std::string& expected_fps_member_count_string, @@ -596,7 +603,7 @@ class SiteSettingsHandlerBaseTest : public testing::Test { EXPECT_EQ("usage-total-changed", data.arg_nth(0)->GetString()); ASSERT_TRUE(data.arg_nth(1)->is_string()); - EXPECT_EQ(expected_usage_host, data.arg_nth(1)->GetString()); + EXPECT_EQ(expected_usage_origin, data.arg_nth(1)->GetString()); ASSERT_TRUE(data.arg_nth(2)->is_string()); EXPECT_EQ(expected_usage_string, data.arg_nth(2)->GetString()); @@ -611,17 +618,6 @@ class SiteSettingsHandlerBaseTest : public testing::Test { EXPECT_EQ(expected_fps_policy, data.arg_nth(5)->GetBool()); } - void ValidateNotificationPermissionUpdate() { - const content::TestWebUI::CallData& data = *web_ui()->call_data().back(); - EXPECT_EQ("cr.webUIListenerCallback", data.function_name()); - - ASSERT_TRUE(data.arg1()->is_string()); - EXPECT_EQ("notification-permission-review-list-maybe-changed", - data.arg1()->GetString()); - - ASSERT_TRUE(data.arg2()->is_list()); - } - void CreateIncognitoProfile() { incognito_profile_ = profile_->GetOffTheRecordProfile( Profile::OTRProfileID::PrimaryID(), /*create_if_needed=*/true); @@ -659,11 +655,13 @@ class SiteSettingsHandlerBaseTest : public testing::Test { auto mock_cookies_tree_model = std::make_unique<CookiesTreeModel>( std::move(container), profile()->GetExtensionSpecialStoragePolicy()); - auto fake_browsing_data_model = std::make_unique<FakeBrowsingDataModel>(); + auto fake_browsing_data_model = std::make_unique<FakeBrowsingDataModel>( + ChromeBrowsingDataModelDelegate::CreateForProfile(profile())); - std::move(setup).Run({mock_browsing_data_cookie_helper, - mock_browsing_data_local_storage_helper, - raw_ref(*fake_browsing_data_model)}); + std::move(setup).Run( + {mock_browsing_data_cookie_helper, + mock_browsing_data_local_storage_helper, + ToRawRef<ExperimentalAsh>(*fake_browsing_data_model)}); mock_browsing_data_local_storage_helper->Notify(); mock_browsing_data_cookie_helper->Notify(); @@ -738,8 +736,7 @@ class SiteSettingsHandlerBaseTest : public testing::Test { base::Value::List GetOnStorageFetchedSentList() { handler()->ClearAllSitesMapForTesting(); - base::Value::List get_all_sites_args; - get_all_sites_args.Append(kCallbackId); + auto get_all_sites_args = base::Value::List().Append(kCallbackId); handler()->HandleGetAllSites(get_all_sites_args); handler()->ServicePendingRequests(); @@ -786,22 +783,13 @@ class SiteSettingsHandlerBaseTest : public testing::Test { return first_party_sets; } - base::Value::List GetOriginList(int size) { - base::Value::List origins; - for (int i = 0; i < size; i++) { - origins.Append("https://example" + base::NumberToString(i) + ".org:443"); - } - return origins; - } - scoped_refptr<const extensions::Extension> LoadExtension( const std::string& extension_name) { auto extension = extensions::ExtensionBuilder() - .SetManifest(extensions::DictionaryBuilder() + .SetManifest(base::Value::Dict() .Set("name", kExtensionName) .Set("version", "1.0.0") - .Set("manifest_version", 3) - .Build()) + .Set("manifest_version", 3)) .Build(); extensions::TestExtensionSystem* extension_system = @@ -848,7 +836,7 @@ class SiteSettingsHandlerBaseTest : public testing::Test { content::BrowserTaskEnvironment task_environment_; std::unique_ptr<TestingProfileManager> testing_profile_manager_; raw_ptr<TestingProfile> profile_ = nullptr; - raw_ptr<Profile> incognito_profile_ = nullptr; + raw_ptr<Profile, DanglingUntriaged> incognito_profile_ = nullptr; content::TestWebUI web_ui_; std::unique_ptr<SiteSettingsHandler> handler_; #if BUILDFLAG(IS_CHROMEOS_ASH) @@ -931,11 +919,10 @@ TEST_F(SiteSettingsHandlerTest, GetAllSites) { EXPECT_EQ(1UL, site_groups.size()); for (const base::Value& site_group_val : site_groups) { const base::Value::Dict& site_group = site_group_val.GetDict(); - const std::string& etld_plus1_string = - CHECK_DEREF(site_group.FindString("etldPlus1")); const base::Value::List& origin_list = CHECK_DEREF(site_group.FindList("origins")); - EXPECT_EQ("example.com", etld_plus1_string); + EXPECT_THAT(CHECK_DEREF(site_group.FindString("groupingKey")), + IsEtldPlus1("example.com")); EXPECT_EQ(2UL, origin_list.size()); const base::Value::Dict& first_origin = origin_list[0].GetDict(); const base::Value::Dict& second_origin = origin_list[1].GetDict(); @@ -963,16 +950,17 @@ TEST_F(SiteSettingsHandlerTest, GetAllSites) { EXPECT_EQ(2UL, site_groups.size()); for (const base::Value& site_group_val : site_groups) { const base::Value::Dict& site_group = site_group_val.GetDict(); - const std::string& etld_plus1_string = - CHECK_DEREF(site_group.FindString("etldPlus1")); + const std::string& grouping_key_string = + CHECK_DEREF(site_group.FindString("groupingKey")); + auto grouping_key = GroupingKey::Deserialize(grouping_key_string); const base::Value::List& origin_list = CHECK_DEREF(site_group.FindList("origins")); - if (etld_plus1_string == "example2.net") { + if (grouping_key.GetEtldPlusOne() == "example2.net") { EXPECT_EQ(1UL, origin_list.size()); const base::Value::Dict& first_origin = origin_list[0].GetDict(); EXPECT_EQ(url3.spec(), CHECK_DEREF(first_origin.FindString("origin"))); } else { - EXPECT_EQ("example.com", etld_plus1_string); + EXPECT_THAT(grouping_key_string, IsEtldPlus1("example.com")); } } } @@ -1015,10 +1003,10 @@ TEST_F(SiteSettingsHandlerTest, GetAllSites) { const base::Value::List& site_groups = data.arg3()->GetList(); EXPECT_EQ(2UL, site_groups.size()); - EXPECT_EQ("example.com", - CHECK_DEREF(site_groups[0].GetDict().FindString("etldPlus1"))); - EXPECT_EQ("example2.net", - CHECK_DEREF(site_groups[1].GetDict().FindString("etldPlus1"))); + EXPECT_THAT(CHECK_DEREF(site_groups[0].GetDict().FindString("groupingKey")), + IsEtldPlus1("example.com")); + EXPECT_THAT(CHECK_DEREF(site_groups[1].GetDict().FindString("groupingKey")), + IsEtldPlus1("example2.net")); } // Add an expired embargo setting to an existing eTLD+1 group and make sure it @@ -1045,10 +1033,10 @@ TEST_F(SiteSettingsHandlerTest, GetAllSites) { const base::Value::List& site_groups = data.arg3()->GetList(); EXPECT_EQ(2UL, site_groups.size()); - EXPECT_EQ("example.com", - CHECK_DEREF(site_groups[0].GetDict().FindString("etldPlus1"))); - EXPECT_EQ("example2.net", - CHECK_DEREF(site_groups[1].GetDict().FindString("etldPlus1"))); + EXPECT_THAT(CHECK_DEREF(site_groups[0].GetDict().FindString("groupingKey")), + IsEtldPlus1("example.com")); + EXPECT_THAT(CHECK_DEREF(site_groups[1].GetDict().FindString("groupingKey")), + IsEtldPlus1("example2.net")); } // Add an expired embargo to a new eTLD+1 and make sure it doesn't appear. @@ -1075,10 +1063,10 @@ TEST_F(SiteSettingsHandlerTest, GetAllSites) { const base::Value::List& site_groups = data.arg3()->GetList(); EXPECT_EQ(2UL, site_groups.size()); - EXPECT_EQ("example.com", - CHECK_DEREF(site_groups[0].GetDict().FindString("etldPlus1"))); - EXPECT_EQ("example2.net", - CHECK_DEREF(site_groups[1].GetDict().FindString("etldPlus1"))); + EXPECT_THAT(CHECK_DEREF(site_groups[0].GetDict().FindString("groupingKey")), + IsEtldPlus1("example.com")); + EXPECT_THAT(CHECK_DEREF(site_groups[1].GetDict().FindString("groupingKey")), + IsEtldPlus1("example2.net")); } // Same extension url from different content setting types shows only one @@ -1099,13 +1087,18 @@ TEST_F(SiteSettingsHandlerTest, GetAllSites) { const base::Value::List& site_groups = data.arg3()->GetList(); EXPECT_EQ(3UL, site_groups.size()); - // Extension etldPlus1 string will be in the pattern of + // Extension groupingKey will be its origin with the pattern // "chrome-extension://<extension_id>" so it is before other site groups in // the list. - EXPECT_EQ(extension->url().spec(), - CHECK_DEREF(site_groups[0].GetDict().FindString("etldPlus1"))); + EXPECT_THAT(CHECK_DEREF(site_groups[0].GetDict().FindString("groupingKey")), + IsOrigin(extension->url())); + EXPECT_EQ(nullptr, site_groups[0].GetDict().FindString("etldPlus1")); + EXPECT_THAT(CHECK_DEREF(site_groups[1].GetDict().FindString("groupingKey")), + IsEtldPlus1("example.com")); EXPECT_EQ("example.com", CHECK_DEREF(site_groups[1].GetDict().FindString("etldPlus1"))); + EXPECT_THAT(CHECK_DEREF(site_groups[2].GetDict().FindString("groupingKey")), + IsEtldPlus1("example2.net")); EXPECT_EQ("example2.net", CHECK_DEREF(site_groups[2].GetDict().FindString("etldPlus1"))); } @@ -1133,7 +1126,8 @@ TEST_F(SiteSettingsHandlerTest, Cookies) { ASSERT_EQ(1UL, site_groups.size()); const base::Value::Dict& first_group = site_groups[0].GetDict(); - EXPECT_EQ("c1.com", CHECK_DEREF(first_group.FindString("etldPlus1"))); + EXPECT_THAT(CHECK_DEREF(first_group.FindString("groupingKey")), + IsEtldPlus1("c1.com")); EXPECT_EQ(1, *first_group.FindInt("numCookies")); const base::Value::List& first_group_origins = CHECK_DEREF(first_group.FindList("origins")); @@ -1157,7 +1151,8 @@ TEST_F(SiteSettingsHandlerTest, Cookies) { ASSERT_EQ(1UL, site_groups.size()); const base::Value::Dict& first_group = site_groups[0].GetDict(); - EXPECT_EQ("c2.com", CHECK_DEREF(first_group.FindString("etldPlus1"))); + EXPECT_THAT(CHECK_DEREF(first_group.FindString("groupingKey")), + IsEtldPlus1("c2.com")); EXPECT_EQ(2, *first_group.FindInt("numCookies")); const base::Value::List& first_group_origins = CHECK_DEREF(first_group.FindList("origins")); @@ -1183,7 +1178,8 @@ TEST_F(SiteSettingsHandlerTest, Cookies) { ASSERT_EQ(1UL, site_groups.size()); const base::Value::Dict& first_group = site_groups[0].GetDict(); - EXPECT_EQ("c3.com", CHECK_DEREF(first_group.FindString("etldPlus1"))); + EXPECT_THAT(CHECK_DEREF(first_group.FindString("groupingKey")), + IsEtldPlus1("c3.com")); EXPECT_EQ(1, *first_group.FindInt("numCookies")); const base::Value::List& first_group_origins = CHECK_DEREF(first_group.FindList("origins")); @@ -1206,7 +1202,8 @@ TEST_F(SiteSettingsHandlerTest, Cookies) { ASSERT_EQ(1UL, site_groups.size()); const base::Value::Dict& first_group = site_groups[0].GetDict(); - EXPECT_EQ("c4.com", CHECK_DEREF(first_group.FindString("etldPlus1"))); + EXPECT_THAT(CHECK_DEREF(first_group.FindString("groupingKey")), + IsEtldPlus1("c4.com")); EXPECT_EQ(2, *first_group.FindInt("numCookies")); const base::Value::List& first_group_origins = CHECK_DEREF(first_group.FindList("origins")); @@ -1347,8 +1344,8 @@ TEST_F(SiteSettingsHandlerTest, OnStorageFetched) { ASSERT_TRUE(site_group_val.is_dict()); const base::Value::Dict& site_group = site_group_val.GetDict(); - ASSERT_TRUE(site_group.FindString("etldPlus1")); - ASSERT_EQ("example.com", *site_group.FindString("etldPlus1")); + ASSERT_THAT(CHECK_DEREF(site_group.FindString("groupingKey")), + IsEtldPlus1("example.com")); EXPECT_EQ(3, site_group.FindDouble("numCookies")); @@ -1381,8 +1378,8 @@ TEST_F(SiteSettingsHandlerTest, OnStorageFetched) { { const base::Value::Dict& site_group = storage_and_cookie_list[1].GetDict(); - ASSERT_TRUE(site_group.FindString("etldPlus1")); - ASSERT_EQ("google.com", *site_group.FindString("etldPlus1")); + ASSERT_THAT(CHECK_DEREF(site_group.FindString("groupingKey")), + IsEtldPlus1("google.com")); EXPECT_EQ(3, site_group.FindDouble("numCookies")); @@ -1419,8 +1416,8 @@ TEST_F(SiteSettingsHandlerTest, OnStorageFetched) { ASSERT_TRUE(site_group_val.is_dict()); const base::Value::Dict& site_group = site_group_val.GetDict(); - ASSERT_TRUE(site_group.FindString("etldPlus1")); - ASSERT_EQ("google.com.au", *site_group.FindString("etldPlus1")); + ASSERT_THAT(CHECK_DEREF(site_group.FindString("groupingKey")), + IsEtldPlus1("google.com.au")); EXPECT_EQ(4, site_group.FindDouble("numCookies")); @@ -1472,8 +1469,8 @@ TEST_F(SiteSettingsHandlerTest, OnStorageFetched) { ASSERT_TRUE(site_group_val.is_dict()); const base::Value::Dict& site_group = site_group_val.GetDict(); - ASSERT_TRUE(site_group.FindString("etldPlus1")); - ASSERT_EQ("ungrouped.com", *site_group.FindString("etldPlus1")); + ASSERT_THAT(CHECK_DEREF(site_group.FindString("groupingKey")), + IsEtldPlus1("ungrouped.com")); EXPECT_EQ(1, site_group.FindDouble("numCookies")); @@ -1509,8 +1506,8 @@ TEST_F(SiteSettingsHandlerTest, InstalledApps) { ASSERT_TRUE(site_group_val.is_dict()); const base::Value::Dict& site_group = site_group_val.GetDict(); - ASSERT_TRUE(site_group.FindString("etldPlus1")); - ASSERT_EQ("example.com", *site_group.FindString("etldPlus1")); + ASSERT_THAT(CHECK_DEREF(site_group.FindString("groupingKey")), + IsEtldPlus1("example.com")); ASSERT_TRUE(site_group.FindBool("hasInstalledPWA").value_or(false)); @@ -1530,8 +1527,8 @@ TEST_F(SiteSettingsHandlerTest, InstalledApps) { ASSERT_TRUE(site_group_val.is_dict()); const base::Value::Dict& site_group = site_group_val.GetDict(); - ASSERT_TRUE(site_group.FindString("etldPlus1")); - ASSERT_EQ("google.com", *site_group.FindString("etldPlus1")); + ASSERT_THAT(CHECK_DEREF(site_group.FindString("groupingKey")), + IsEtldPlus1("google.com")); EXPECT_FALSE(site_group.FindBool("hasInstalledPWA").value_or(true)); const base::Value::List* origin_list = site_group.FindList("origins"); @@ -1545,50 +1542,6 @@ TEST_F(SiteSettingsHandlerTest, InstalledApps) { } } -#if !BUILDFLAG(IS_ANDROID) -TEST_F(SiteSettingsHandlerTest, AllSitesDisplaysIsolatedWebAppName) { - std::string iwa_hostname = - "aerugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic"; - GURL iwa_url("isolated-app://" + iwa_hostname); - GURL https_url("https://" + iwa_hostname); - - // Install an IWA at |iwa_url|. - web_app::test::AwaitStartWebAppProviderAndSubsystems(profile()); - web_app::AppId app_id = - web_app::AddDummyIsolatedAppToRegistry(profile(), iwa_url, "IWA Name"); - RegisterWebApp(profile(), - MakeApp(app_id, apps::AppType::kWeb, iwa_url.spec(), - apps::Readiness::kReady, apps::InstallReason::kUser)); - - SetupModels(base::DoNothing()); - HostContentSettingsMap* map = - HostContentSettingsMapFactory::GetForProfile(profile()); - map->SetContentSettingDefaultScope(iwa_url, iwa_url, - ContentSettingsType::NOTIFICATIONS, - CONTENT_SETTING_BLOCK); - map->SetContentSettingDefaultScope(https_url, https_url, - ContentSettingsType::NOTIFICATIONS, - CONTENT_SETTING_BLOCK); - - base::Value::List site_groups = GetOnStorageFetchedSentList(); - - ASSERT_EQ(site_groups.size(), 2u); - const base::Value::Dict& group1 = site_groups[0].GetDict(); - const base::Value::Dict& origin1 = - CHECK_DEREF(group1.FindList("origins"))[0].GetDict(); - EXPECT_EQ(CHECK_DEREF(group1.FindString("etldPlus1")), iwa_url); - EXPECT_EQ(CHECK_DEREF(group1.FindString("displayName")), "IWA Name"); - EXPECT_EQ(CHECK_DEREF(origin1.FindString("origin")), iwa_url); - - const base::Value::Dict& group2 = site_groups[1].GetDict(); - const base::Value::Dict& origin2 = - CHECK_DEREF(group2.FindList("origins"))[0].GetDict(); - EXPECT_EQ(CHECK_DEREF(group2.FindString("etldPlus1")), iwa_hostname); - EXPECT_EQ(CHECK_DEREF(group2.FindString("displayName")), iwa_hostname); - EXPECT_EQ(CHECK_DEREF(origin2.FindString("origin")), https_url); -} -#endif // !BUILDFLAG(IS_ANDROID) - TEST_F(SiteSettingsHandlerTest, IncognitoExceptions) { constexpr char kOriginToBlock[] = "https://www.blocked.com:443"; @@ -1863,10 +1816,10 @@ TEST_F(SiteSettingsHandlerTest, NotificationPermissionRevokeUkm) { EXPECT_EQ( *ukm_recorder.GetEntryMetric(entry, "Source"), static_cast<int64_t>(permissions::PermissionSourceUI::SITE_SETTINGS)); - size_t num_values = 0; + EXPECT_EQ(*ukm_recorder.GetEntryMetric(entry, "PermissionType"), - ContentSettingTypeToHistogramValue( - ContentSettingsType::NOTIFICATIONS, &num_values)); + content_settings_uma_util::ContentSettingTypeToHistogramValue( + ContentSettingsType::NOTIFICATIONS)); EXPECT_EQ(*ukm_recorder.GetEntryMetric(entry, "Action"), static_cast<int64_t>(permissions::PermissionAction::REVOKED)); } @@ -2062,11 +2015,10 @@ TEST_F(SiteSettingsHandlerTest, ExceptionHelpers) { scoped_refptr<const extensions::Extension> extension; extension = extensions::ExtensionBuilder() - .SetManifest(extensions::DictionaryBuilder() + .SetManifest(base::Value::Dict() .Set("name", kExtensionName) .Set("version", "1.0.0") - .Set("manifest_version", 2) - .Build()) + .Set("manifest_version", 2)) .SetID("ahfgeienlihckogmohjhadlkjgocpleb") .Build(); @@ -2088,8 +2040,7 @@ TEST_F(SiteSettingsHandlerTest, ExceptionHelpers) { } TEST_F(SiteSettingsHandlerTest, ExtensionDisplayName) { - // When the extension is loaded, the displayName is the extension's name, and - // there is extensionNameWithId field. + // When the extension is loaded, displayName is the extension's name and id. auto extension = LoadExtension(kExtensionName); auto extension_url = extension->url().spec(); { @@ -2102,28 +2053,14 @@ TEST_F(SiteSettingsHandlerTest, ExtensionDisplayName) { get_origin_permissions_args.Append(std::move(category_list)); } handler()->HandleGetOriginPermissions(get_origin_permissions_args); - ValidateOrigin(extension_url, extension_url, kExtensionName, + std::string expected_display_name = + base::StringPrintf("Test Extension (ID: %s)", extension->id().c_str()); + ValidateOrigin(extension_url, extension_url, expected_display_name, CONTENT_SETTING_ASK, site_settings::SiteSettingSource::kDefault, 1U); - // Validates the extensionNameWithId field. - { - const content::TestWebUI::CallData& data = *web_ui()->call_data().back(); - EXPECT_EQ("cr.webUIResponse", data.function_name()); - ASSERT_TRUE(data.arg3()->is_list()); - EXPECT_EQ(1U, data.arg3()->GetList().size()); - const base::Value& exception = data.arg3()->GetList()[0]; - ASSERT_TRUE(exception.is_dict()); - const std::string* extension_name_with_id = - exception.GetDict().FindString(site_settings::kExtensionNameWithId); - ASSERT_TRUE(extension_name_with_id); - ASSERT_EQ(base::StringPrintf("Test Extension (ID: %s)", - extension->id().c_str()), - *extension_name_with_id); - } } - // When the extension is unloaded, the displayName is the extension's origin, - // and there is no extensionNameWithId field. + // When the extension is unloaded, the displayName is the extension's origin. UnloadExtension(extension->id()); { base::Value::List get_origin_permissions_args; @@ -2139,17 +2076,6 @@ TEST_F(SiteSettingsHandlerTest, ExtensionDisplayName) { extension_url, extension_url, base::StringPrintf("chrome-extension://%s", extension->id().c_str()), CONTENT_SETTING_ASK, site_settings::SiteSettingSource::kDefault, 2U); - // Validates there is no extensionNameWithId field. - { - const content::TestWebUI::CallData& data = *web_ui()->call_data().back(); - EXPECT_EQ("cr.webUIResponse", data.function_name()); - ASSERT_TRUE(data.arg3()->is_list()); - EXPECT_EQ(1U, data.arg3()->GetList().size()); - const base::Value::Dict& exception = data.arg3()->GetList()[0].GetDict(); - const std::string* extension_name_with_id = - exception.FindString(site_settings::kExtensionNameWithId); - ASSERT_FALSE(extension_name_with_id); - } } } @@ -2180,27 +2106,165 @@ TEST_F(SiteSettingsHandlerTest, Incognito) { } TEST_F(SiteSettingsHandlerTest, ZoomLevels) { - std::string host("http://www.google.com"); + std::string http_host("www.google.com"); + std::string error_host("chromewebdata"); + std::string data_url("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ=="); double zoom_level = 1.1; content::HostZoomMap* host_zoom_map = content::HostZoomMap::GetDefaultForBrowserContext(profile()); - host_zoom_map->SetZoomLevelForHost(host, zoom_level); - ValidateZoom(host, "122%", 1U); + host_zoom_map->SetZoomLevelForHost(http_host, zoom_level); + host_zoom_map->SetZoomLevelForHost(error_host, zoom_level); + host_zoom_map->SetZoomLevelForHost(data_url, zoom_level); + ValidateZoom({{error_host, "(Chrome error pages)", "122%"}, + {data_url, data_url, "122%"}, + {http_host, http_host, "122%"}}, + 3U); base::Value::List args; handler()->HandleFetchZoomLevels(args); - ValidateZoom(host, "122%", 2U); + ValidateZoom({{error_host, "(Chrome error pages)", "122%"}, + {data_url, data_url, "122%"}, + {http_host, http_host, "122%"}}, + 4U); - args.Append("http://www.google.com"); + args.Append(http_host); + handler()->HandleRemoveZoomLevel(args); + args.front() = base::Value(error_host); + handler()->HandleRemoveZoomLevel(args); + args.front() = base::Value(data_url); handler()->HandleRemoveZoomLevel(args); - ValidateZoom("", "", 3U); + ValidateZoom({}, 7U); double default_level = host_zoom_map->GetDefaultZoomLevel(); - double level = host_zoom_map->GetZoomLevelForHostAndScheme("http", host); + double level = host_zoom_map->GetZoomLevelForHostAndScheme("http", http_host); + EXPECT_EQ(default_level, level); +} + +class SiteSettingsHandlerIsolatedWebAppTest : public SiteSettingsHandlerTest { + public: + void SetUp() override { + web_app::test::AwaitStartWebAppProviderAndSubsystems(profile()); + InstallIsolatedWebApp(iwa_url(), "IWA Name"); + + SiteSettingsHandlerTest::SetUp(); + } + + protected: + GURL iwa_url() { + return GURL( + "isolated-app://" + "aerugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic"); + } + + web_app::AppId InstallIsolatedWebApp(const GURL& iwa_url, + const std::string& name) { + web_app::AppId app_id = + web_app::AddDummyIsolatedAppToRegistry(profile(), iwa_url, name); + RegisterWebApp(profile(), MakeApp(app_id, apps::AppType::kWeb, + iwa_url.spec(), apps::Readiness::kReady, + apps::InstallReason::kUser)); + return app_id; + } + + content::HostZoomMap* GetIwaHostZoomMap(const GURL& url) { + auto url_info = *web_app::IsolatedWebAppUrlInfo::Create(url); + content::StoragePartition* iwa_partition = profile()->GetStoragePartition( + url_info.storage_partition_config(profile())); + return content::HostZoomMap::GetForStoragePartition(iwa_partition); + } +}; + +TEST_F(SiteSettingsHandlerIsolatedWebAppTest, AllSitesDisplaysAppName) { + GURL https_url("https://" + iwa_url().host()); + + SetupModelsWithIsolatedWebAppData(iwa_url().spec(), 50); + HostContentSettingsMap* map = + HostContentSettingsMapFactory::GetForProfile(profile()); + map->SetContentSettingDefaultScope(iwa_url(), iwa_url(), + ContentSettingsType::NOTIFICATIONS, + CONTENT_SETTING_BLOCK); + map->SetContentSettingDefaultScope(https_url, https_url, + ContentSettingsType::NOTIFICATIONS, + CONTENT_SETTING_BLOCK); + + base::Value::List site_groups = GetOnStorageFetchedSentList(); + + ASSERT_EQ(site_groups.size(), 2u); + const base::Value::Dict& group1 = site_groups[0].GetDict(); + const base::Value::Dict& origin1 = + CHECK_DEREF(group1.FindList("origins"))[0].GetDict(); + EXPECT_THAT(CHECK_DEREF(group1.FindString("groupingKey")), + IsOrigin(iwa_url())); + EXPECT_EQ(group1.FindString("etldPlus1"), nullptr); + EXPECT_EQ(CHECK_DEREF(group1.FindString("displayName")), "IWA Name"); + EXPECT_EQ(CHECK_DEREF(origin1.FindString("origin")), iwa_url()); + EXPECT_EQ(origin1.FindDouble("usage").value(), 50.0); + + const base::Value::Dict& group2 = site_groups[1].GetDict(); + const base::Value::Dict& origin2 = + CHECK_DEREF(group2.FindList("origins"))[0].GetDict(); + EXPECT_THAT(CHECK_DEREF(group2.FindString("groupingKey")), + IsEtldPlus1(iwa_url().host())); + EXPECT_EQ(CHECK_DEREF(group2.FindString("etldPlus1")), iwa_url().host()); + EXPECT_EQ(CHECK_DEREF(group2.FindString("displayName")), iwa_url().host()); + EXPECT_EQ(CHECK_DEREF(origin2.FindString("origin")), https_url); + EXPECT_EQ(origin2.FindDouble("usage").value(), 0.0); +} + +TEST_F(SiteSettingsHandlerIsolatedWebAppTest, ZoomLevel) { + content::HostZoomMap* iwa_host_zoom_map = GetIwaHostZoomMap(iwa_url()); + + std::string host_or_spec = url::Origin::Create(iwa_url()).Serialize(); + iwa_host_zoom_map->SetZoomLevelForHost(iwa_url().host(), 1.1); + ValidateZoom({{host_or_spec, "IWA Name", "122%"}}, 1U); + + base::Value::List args; + handler()->HandleFetchZoomLevels(args); + ValidateZoom({{host_or_spec, "IWA Name", "122%"}}, 2U); + + args.Append(host_or_spec); + handler()->HandleRemoveZoomLevel(args); + ValidateZoom({}, 3U); + + double default_level = iwa_host_zoom_map->GetDefaultZoomLevel(); + double level = iwa_host_zoom_map->GetZoomLevelForHostAndScheme( + "isolated-app", iwa_url().host()); EXPECT_EQ(default_level, level); } +TEST_F(SiteSettingsHandlerIsolatedWebAppTest, ZoomLevelsSortedByAppName) { + GetIwaHostZoomMap(iwa_url())->SetZoomLevelForHost(iwa_url().host(), 1.1); + + // Install 3 more IWAs. + GURL iwa3_url( + "isolated-app://" + "cerugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic"); + InstallIsolatedWebApp(iwa3_url, "IWA Name 3"); + GetIwaHostZoomMap(iwa3_url)->SetZoomLevelForHost(iwa3_url.host(), 1.1); + + GURL iwa2_url( + "isolated-app://" + "berugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic"); + InstallIsolatedWebApp(iwa2_url, "IWA Name 2"); + GetIwaHostZoomMap(iwa2_url)->SetZoomLevelForHost(iwa2_url.host(), 1.1); + + // Don't set a zoom for this app to make sure it's not in the list. + GURL iwa4_url( + "isolated-app://" + "derugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic"); + InstallIsolatedWebApp(iwa4_url, "IWA Name 4"); + + base::Value::List args; + handler()->HandleFetchZoomLevels(args); + + ValidateZoom( + {{url::Origin::Create(iwa_url()).Serialize(), "IWA Name", "122%"}, + {url::Origin::Create(iwa2_url).Serialize(), "IWA Name 2", "122%"}, + {url::Origin::Create(iwa3_url).Serialize(), "IWA Name 3", "122%"}}, + 2U); +} + class SiteSettingsHandlerInfobarTest : public BrowserWithTestWindowTest { public: SiteSettingsHandlerInfobarTest() @@ -2610,9 +2674,8 @@ TEST_F(SiteSettingsHandlerTest, ExcludeWebUISchemesInLists) { EXPECT_EQ(1UL, site_groups.size()); const base::Value::Dict& first_site_group = site_groups[0].GetDict(); - const std::string etld_plus1_string = - CHECK_DEREF(first_site_group.FindString("etldPlus1")); - EXPECT_EQ("example.com", etld_plus1_string); + EXPECT_THAT(CHECK_DEREF(first_site_group.FindString("groupingKey")), + IsEtldPlus1("example.com")); const base::Value::List& origin_list = CHECK_DEREF(first_site_group.FindList("origins")); EXPECT_EQ(1UL, origin_list.size()); @@ -3964,7 +4027,6 @@ TEST_F(SiteSettingsHandlerBluetoothTest, HandleSetOriginPermissionsPolicyOnly) { TestHandleSetOriginPermissionsPolicyOnly(); } -#if !BUILDFLAG(IS_ANDROID) class SiteSettingsHandlerHidTest : public SiteSettingsHandlerChooserExceptionTest { protected: @@ -4099,12 +4161,14 @@ class SiteSettingsHandlerHidTest base::Value GetPersistentDeviceValueForOrigin( const url::Origin& origin) override { - return HidChooserContext::DeviceInfoToValue(*persistent_device_); + return base::Value( + HidChooserContext::DeviceInfoToValue(*persistent_device_)); } base::Value GetUserGrantedDeviceValueForOrigin( const url::Origin& origin) override { - return HidChooserContext::DeviceInfoToValue(*user_granted_device_); + return base::Value( + HidChooserContext::DeviceInfoToValue(*user_granted_device_)); } std::string GetAllDevicesDisplayName() override { return "Any HID device"; } @@ -4343,12 +4407,14 @@ class SiteSettingsHandlerSerialTest base::Value GetPersistentDeviceValueForOrigin( const url::Origin& origin) override { - return SerialChooserContext::PortInfoToValue(*persistent_port_); + return base::Value( + SerialChooserContext::PortInfoToValue(*persistent_port_)); } base::Value GetUserGrantedDeviceValueForOrigin( const url::Origin& origin) override { - return SerialChooserContext::PortInfoToValue(*user_granted_port_); + return base::Value( + SerialChooserContext::PortInfoToValue(*user_granted_port_)); } std::string GetAllDevicesDisplayName() override { return "Any serial port"; } @@ -4405,7 +4471,6 @@ TEST_F(SiteSettingsHandlerSerialTest, HandleSetOriginPermissions) { TEST_F(SiteSettingsHandlerSerialTest, HandleSetOriginPermissionsPolicyOnly) { TestHandleSetOriginPermissionsPolicyOnly(); } -#endif // !BUILDFLAG(IS_ANDROID) class SiteSettingsHandlerUsbTest : public SiteSettingsHandlerChooserExceptionTest { @@ -4545,12 +4610,14 @@ class SiteSettingsHandlerUsbTest base::Value GetPersistentDeviceValueForOrigin( const url::Origin& origin) override { - return UsbChooserContext::DeviceInfoToValue(*persistent_device_); + return base::Value( + UsbChooserContext::DeviceInfoToValue(*persistent_device_)); } base::Value GetUserGrantedDeviceValueForOrigin( const url::Origin& origin) override { - return UsbChooserContext::DeviceInfoToValue(*user_granted_device_); + return base::Value( + UsbChooserContext::DeviceInfoToValue(*user_granted_device_)); } std::string GetAllDevicesDisplayName() override { @@ -4610,7 +4677,7 @@ TEST_F(SiteSettingsHandlerUsbTest, HandleSetOriginPermissionsPolicyOnly) { TestHandleSetOriginPermissionsPolicyOnly(); } -TEST_F(SiteSettingsHandlerTest, HandleClearEtldPlus1DataAndCookies) { +TEST_F(SiteSettingsHandlerTest, HandleClearSiteGroupDataAndCookies) { SetupModels(); EXPECT_EQ(28u, @@ -4619,10 +4686,8 @@ TEST_F(SiteSettingsHandlerTest, HandleClearEtldPlus1DataAndCookies) { auto verify_site_group = [](const base::Value& site_group, std::string expected_etld_plus1) { ASSERT_TRUE(site_group.is_dict()); - const std::string* etld_plus1 = - site_group.GetDict().FindString("etldPlus1"); - ASSERT_TRUE(etld_plus1); - ASSERT_EQ(expected_etld_plus1, *etld_plus1); + ASSERT_THAT(CHECK_DEREF(site_group.GetDict().FindString("groupingKey")), + IsEtldPlus1(expected_etld_plus1)); }; base::Value::List storage_and_cookie_list = GetOnStorageFetchedSentList(); @@ -4630,8 +4695,8 @@ TEST_F(SiteSettingsHandlerTest, HandleClearEtldPlus1DataAndCookies) { verify_site_group(storage_and_cookie_list[0], "example.com"); base::Value::List args; - args.Append("example.com"); - handler()->HandleClearEtldPlus1DataAndCookies(args); + args.Append(GroupingKey::CreateFromEtldPlus1("example.com").Serialize()); + handler()->HandleClearSiteGroupDataAndCookies(args); // All host nodes for non-secure example.com, and abc.example.com, which do // not have any unpartitioned storage, should have been removed. @@ -4664,9 +4729,9 @@ TEST_F(SiteSettingsHandlerTest, HandleClearEtldPlus1DataAndCookies) { verify_site_group(storage_and_cookie_list[0], "google.com"); args.clear(); - args.Append("google.com"); + args.Append(GroupingKey::CreateFromEtldPlus1("google.com").Serialize()); - handler()->HandleClearEtldPlus1DataAndCookies(args); + handler()->HandleClearSiteGroupDataAndCookies(args); EXPECT_EQ(14u, handler()->cookies_tree_model_->GetRoot()->GetTotalNodeCount()); @@ -4676,9 +4741,9 @@ TEST_F(SiteSettingsHandlerTest, HandleClearEtldPlus1DataAndCookies) { verify_site_group(storage_and_cookie_list[0], "google.com.au"); args.clear(); - args.Append("google.com.au"); + args.Append(GroupingKey::CreateFromEtldPlus1("google.com.au").Serialize()); - handler()->HandleClearEtldPlus1DataAndCookies(args); + handler()->HandleClearSiteGroupDataAndCookies(args); // No nodes representing storage partitioned on google.com.au should be // present. for (const auto& host_node : @@ -4703,9 +4768,9 @@ TEST_F(SiteSettingsHandlerTest, HandleClearEtldPlus1DataAndCookies) { verify_site_group(storage_and_cookie_list[0], "ungrouped.com"); args.clear(); - args.Append("ungrouped.com"); + args.Append(GroupingKey::CreateFromEtldPlus1("ungrouped.com").Serialize()); - handler()->HandleClearEtldPlus1DataAndCookies(args); + handler()->HandleClearSiteGroupDataAndCookies(args); storage_and_cookie_list = GetOnStorageFetchedSentList(); EXPECT_EQ(0U, storage_and_cookie_list.size()); @@ -4775,8 +4840,7 @@ TEST_P(SiteSettingsHandlerTest, HandleClearUnpartitionedUsage) { // In the beginning, there should be nothing stored in the origin data. ASSERT_EQ(0u, user_prefs->GetDict(prefs::kMediaCdmOriginData).size()); - base::Value::Dict entry_google; - entry_google.Set( + auto entry_google = base::Value::Dict().Set( "https://www.google.com/", base::UnguessableTokenToValue(base::UnguessableToken::Create())); @@ -4842,8 +4906,8 @@ TEST_F(SiteSettingsHandlerTest, ClearClientHints) { // Clear at the eTLD+1 level and ensure affected origins are cleared. base::Value::List args; - args.Append("example.com"); - handler()->HandleClearEtldPlus1DataAndCookies(args); + args.Append(GroupingKey::CreateFromEtldPlus1("example.com").Serialize()); + handler()->HandleClearSiteGroupDataAndCookies(args); host_content_settings_map->GetSettingsForOneType( ContentSettingsType::CLIENT_HINTS, &client_hints_settings); EXPECT_EQ(2U, client_hints_settings.size()); @@ -4917,8 +4981,8 @@ TEST_F(SiteSettingsHandlerTest, ClearReducedAcceptLanguage) { // Clear at the eTLD+1 level and ensure affected origins are cleared. base::Value::List args; - args.Append("example.com"); - handler()->HandleClearEtldPlus1DataAndCookies(args); + args.Append(GroupingKey::CreateFromEtldPlus1("example.com").Serialize()); + handler()->HandleClearSiteGroupDataAndCookies(args); host_content_settings_map->GetSettingsForOneType( ContentSettingsType::REDUCED_ACCEPT_LANGUAGE, &accept_language_settings); EXPECT_EQ(2U, accept_language_settings.size()); @@ -4980,7 +5044,7 @@ TEST_F(SiteSettingsHandlerTest, HandleClearPartitionedUsage) { base::Value::List args; args.Append("https://www.example.com/"); - args.Append("google.com"); + args.Append(GroupingKey::CreateFromEtldPlus1("google.com").Serialize()); handler()->HandleClearPartitionedUsage(args); // This should have only removed cookies for embedded.com partitioned on @@ -5180,11 +5244,20 @@ TEST_F(SiteSettingsHandlerTest, HandleGetUsageInfo) { handler()->ServicePendingRequests(); ValidateUsageInfo("http://google.com", "", "2 cookies", "2 sites in google.com's group", false); + args.clear(); args.Append("http://ungrouped.com"); handler()->HandleFetchUsageTotal(args); handler()->ServicePendingRequests(); ValidateUsageInfo("http://ungrouped.com", "", "1 cookie", "", false); + + // Test that the argument URL formatting is preserved in the response because + // the UI ignores responses with different URL strings. + args.clear(); + args.Append("http://ungrouped.com//"); + handler()->HandleFetchUsageTotal(args); + handler()->ServicePendingRequests(); + ValidateUsageInfo("http://ungrouped.com//", "", "1 cookie", "", false); } TEST_F(SiteSettingsHandlerTest, NonTreeModelDeletion) { @@ -5202,8 +5275,8 @@ TEST_F(SiteSettingsHandlerTest, NonTreeModelDeletion) { url::Origin::Create(GURL("https://google.com")))); base::Value::List args; - args.Append("google.com"); - handler()->HandleClearEtldPlus1DataAndCookies(args); + args.Append(GroupingKey::CreateFromEtldPlus1("google.com").Serialize()); + handler()->HandleClearSiteGroupDataAndCookies(args); auto* browsing_data_remover = profile()->GetBrowsingDataRemover(); EXPECT_EQ(content::BrowsingDataRemover::DATA_TYPE_PRIVACY_SANDBOX & @@ -5247,241 +5320,10 @@ TEST_F(SiteSettingsHandlerTest, FirstPartySetsMembership) { ValidateSitesWithFps(storage_and_cookie_list, first_party_sets); } -TEST_F(SiteSettingsHandlerTest, - HandleIgnoreOriginsForNotificationPermissionReview) { - base::test::ScopedFeatureList scoped_feature; - scoped_feature.InitAndEnableFeature( - ::features::kSafetyCheckNotificationPermissions); - - HostContentSettingsMap* content_settings = - HostContentSettingsMapFactory::GetForProfile(profile()); - ContentSettingsForOneType ignored_patterns; - content_settings->GetSettingsForOneType( - ContentSettingsType::NOTIFICATION_PERMISSION_REVIEW, &ignored_patterns); - ASSERT_EQ(0U, ignored_patterns.size()); - - base::Value::List args; - args.Append(GetOriginList(1)); - handler()->HandleIgnoreOriginsForNotificationPermissionReview(args); - - // Check there is 1 origin in ignore list. - content_settings->GetSettingsForOneType( - ContentSettingsType::NOTIFICATION_PERMISSION_REVIEW, &ignored_patterns); - ASSERT_EQ(1U, ignored_patterns.size()); - - ValidateNotificationPermissionUpdate(); -} - -TEST_F(SiteSettingsHandlerTest, HandleBlockNotificationPermissionForOrigins) { - base::test::ScopedFeatureList scoped_feature; - scoped_feature.InitAndEnableFeature( - ::features::kSafetyCheckNotificationPermissions); - - base::Value::List args; - base::Value::List origins = GetOriginList(2); - args.Append(origins.Clone()); - - handler()->HandleBlockNotificationPermissionForOrigins(args); - - // Check the permission for the two origins is block. - HostContentSettingsMap* content_settings = - HostContentSettingsMapFactory::GetForProfile(profile()); - ContentSettingsForOneType notification_permissions; - content_settings->GetSettingsForOneType(ContentSettingsType::NOTIFICATIONS, - ¬ification_permissions); - auto type = content_settings->GetContentSetting( - GURL(origins[0].GetString()), GURL(), ContentSettingsType::NOTIFICATIONS); - ASSERT_EQ(CONTENT_SETTING_BLOCK, type); - - type = content_settings->GetContentSetting( - GURL(origins[1].GetString()), GURL(), ContentSettingsType::NOTIFICATIONS); - ASSERT_EQ(CONTENT_SETTING_BLOCK, type); - - ValidateNotificationPermissionUpdate(); -} - -TEST_F(SiteSettingsHandlerTest, HandleAllowNotificationPermissionForOrigins) { - base::test::ScopedFeatureList scoped_feature; - scoped_feature.InitAndEnableFeature( - ::features::kSafetyCheckNotificationPermissions); - - base::Value::List args; - base::Value::List origins = GetOriginList(2); - args.Append(origins.Clone()); - handler()->HandleAllowNotificationPermissionForOrigins(args); - - // Check the permission for the two origins is allow. - HostContentSettingsMap* content_settings = - HostContentSettingsMapFactory::GetForProfile(profile()); - ContentSettingsForOneType notification_permissions; - content_settings->GetSettingsForOneType(ContentSettingsType::NOTIFICATIONS, - ¬ification_permissions); - auto type = content_settings->GetContentSetting( - GURL(origins[0].GetString()), GURL(), ContentSettingsType::NOTIFICATIONS); - ASSERT_EQ(CONTENT_SETTING_ALLOW, type); - - type = content_settings->GetContentSetting( - GURL(origins[1].GetString()), GURL(), ContentSettingsType::NOTIFICATIONS); - ASSERT_EQ(CONTENT_SETTING_ALLOW, type); - - ValidateNotificationPermissionUpdate(); -} - -TEST_F(SiteSettingsHandlerTest, HandleResetNotificationPermissionForOrigins) { - base::test::ScopedFeatureList scoped_feature; - scoped_feature.InitAndEnableFeature( - ::features::kSafetyCheckNotificationPermissions); - - HostContentSettingsMap* content_settings = - HostContentSettingsMapFactory::GetForProfile(profile()); - base::Value::List args; - base::Value::List origins = GetOriginList(1); - args.Append(origins.Clone()); - - content_settings->SetContentSettingCustomScope( - ContentSettingsPattern::FromString(origins[0].GetString()), - ContentSettingsPattern::Wildcard(), ContentSettingsType::NOTIFICATIONS, - CONTENT_SETTING_ALLOW); - - handler()->HandleResetNotificationPermissionForOrigins(args); - - // Check the permission for the origin is reset. - auto type = content_settings->GetContentSetting( - GURL(origins[0].GetString()), GURL(), ContentSettingsType::NOTIFICATIONS); - ASSERT_EQ(CONTENT_SETTING_ASK, type); - - ValidateNotificationPermissionUpdate(); -} - -TEST_F(SiteSettingsHandlerTest, PopulateNotificationPermissionReviewData) { - base::test::ScopedFeatureList scoped_feature; - scoped_feature.InitAndEnableFeature( - ::features::kSafetyCheckNotificationPermissions); - - // Add a couple of notification permission and check they appear in review - // list. - HostContentSettingsMap* map = - HostContentSettingsMapFactory::GetForProfile(profile()); - GURL urls[] = {GURL("https://google.com:443"), - GURL("https://www.youtube.com:443"), - GURL("https://www.example.com:443")}; - - map->SetContentSettingDefaultScope(urls[0], GURL(), - ContentSettingsType::NOTIFICATIONS, - CONTENT_SETTING_ALLOW); - map->SetContentSettingDefaultScope(urls[1], GURL(), - ContentSettingsType::NOTIFICATIONS, - CONTENT_SETTING_ALLOW); - map->SetContentSettingDefaultScope(urls[2], GURL(), - ContentSettingsType::NOTIFICATIONS, - CONTENT_SETTING_ALLOW); - - // Record initial display date to enable comparing dictionaries for - // NotificationEngagementService. - auto* notification_engagement_service = - NotificationsEngagementServiceFactory::GetForProfile(profile()); - std::string displayedDate = - notification_engagement_service->GetBucketLabel(base::Time::Now()); - - auto* site_engagement_service = - site_engagement::SiteEngagementServiceFactory::GetForProfile(profile()); - - // Set a host to have minimum engagement. This should be in review list. - RecordNotification(notification_engagement_service, urls[0], 1); - site_engagement::SiteEngagementScore score = - site_engagement_service->CreateEngagementScore(urls[0]); - score.Reset(0.5, GetReferenceTime()); - score.Commit(); - EXPECT_EQ(blink::mojom::EngagementLevel::MINIMAL, - site_engagement_service->GetEngagementLevel(urls[0])); - - // Set a host to have large number of notifications, but low engagement. This - // should be in review list. - RecordNotification(notification_engagement_service, urls[1], 5); - site_engagement_service->AddPointsForTesting(urls[1], 1.0); - EXPECT_EQ(blink::mojom::EngagementLevel::LOW, - site_engagement_service->GetEngagementLevel(urls[1])); - - // Set a host to have medium engagement and high notification count. This - // should not be in review list. - RecordNotification(notification_engagement_service, urls[2], 5); - site_engagement_service->AddPointsForTesting(urls[2], 50.0); - EXPECT_EQ(blink::mojom::EngagementLevel::MEDIUM, - site_engagement_service->GetEngagementLevel(urls[2])); - - const auto& notification_permissions = - handler()->PopulateNotificationPermissionReviewData(); - // Check if resulting list contains only the expected URLs. They should be in - // descending order of notification count. - EXPECT_EQ(2UL, notification_permissions.size()); - EXPECT_EQ("https://www.youtube.com:443", - *notification_permissions[0].GetDict().FindString( - site_settings::kOrigin)); - EXPECT_EQ("https://google.com:443", - *notification_permissions[1].GetDict().FindString( - site_settings::kOrigin)); - - // Increasing notification count also promotes host in the list. - RecordNotification(notification_engagement_service, - GURL("https://google.com:443"), 10); - const auto& updated_notification_permissions = - handler()->PopulateNotificationPermissionReviewData(); - EXPECT_EQ(2UL, updated_notification_permissions.size()); - EXPECT_EQ("https://google.com:443", - *updated_notification_permissions[0].GetDict().FindString( - site_settings::kOrigin)); - EXPECT_EQ("https://www.youtube.com:443", - *updated_notification_permissions[1].GetDict().FindString( - site_settings::kOrigin)); -} - -TEST_F(SiteSettingsHandlerTest, - HandleUndoIgnoreOriginsForNotificationPermissionReview) { - base::Value::List args; - args.Append(GetOriginList(1)); - handler()->HandleIgnoreOriginsForNotificationPermissionReview(args); - - // Check there is 1 origin in ignore list. - HostContentSettingsMap* content_settings = - HostContentSettingsMapFactory::GetForProfile(profile()); - ContentSettingsForOneType ignored_patterns; - ASSERT_EQ(0U, ignored_patterns.size()); - content_settings->GetSettingsForOneType( - ContentSettingsType::NOTIFICATION_PERMISSION_REVIEW, &ignored_patterns); - ASSERT_EQ(1U, ignored_patterns.size()); - - // Check there are no origins in ignore list. - handler()->HandleUndoIgnoreOriginsForNotificationPermissionReview(args); - content_settings->GetSettingsForOneType( - ContentSettingsType::NOTIFICATION_PERMISSION_REVIEW, &ignored_patterns); - ASSERT_EQ(0U, ignored_patterns.size()); -} - -TEST_F(SiteSettingsHandlerTest, - SendNotificationPermissionReviewList_FeatureEnabled) { - base::test::ScopedFeatureList scoped_feature; - scoped_feature.InitAndEnableFeature( - ::features::kSafetyCheckNotificationPermissions); - - handler()->SendNotificationPermissionReviewList(); - - ValidateNotificationPermissionUpdate(); -} - -TEST_F(SiteSettingsHandlerTest, - SendNotificationPermissionReviewList_FeatureDisabled) { - base::test::ScopedFeatureList scoped_feature; - scoped_feature.InitAndDisableFeature( - ::features::kSafetyCheckNotificationPermissions); - - handler()->SendNotificationPermissionReviewList(); - - ASSERT_EQ(0U, web_ui()->call_data().size()); -} - TEST_F(SiteSettingsHandlerTest, IsolatedWebAppUsageInfo) { std::string iwa_url = - "isolated-app://aerugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic"; + "isolated-app://" + "aerugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic/"; SetupModelsWithIsolatedWebAppData(iwa_url, 1000); base::Value::List args; diff --git a/chromium/chrome/browser/ui/webui/settings/site_settings_helper.cc b/chromium/chrome/browser/ui/webui/settings/site_settings_helper.cc index 60957ef4bd5..0bc74c27f99 100644 --- a/chromium/chrome/browser/ui/webui/settings/site_settings_helper.cc +++ b/chromium/chrome/browser/ui/webui/settings/site_settings_helper.cc @@ -27,6 +27,7 @@ #include "chrome/browser/file_system_access/file_system_access_permission_context_factory.h" #include "chrome/browser/hid/hid_chooser_context.h" #include "chrome/browser/hid/hid_chooser_context_factory.h" +#include "chrome/browser/permissions/notification_permission_review_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/serial/serial_chooser_context.h" #include "chrome/browser/serial/serial_chooser_context_factory.h" @@ -34,9 +35,14 @@ #include "chrome/browser/ui/url_identity.h" #include "chrome/browser/usb/usb_chooser_context.h" #include "chrome/browser/usb/usb_chooser_context_factory.h" +#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h" +#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/web_app_provider.h" +#include "chrome/browser/web_applications/web_app_registrar.h" #include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" +#include "chrome/grit/generated_resources.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_pattern.h" @@ -49,6 +55,7 @@ #include "components/permissions/permissions_client.h" #include "components/prefs/pref_service.h" #include "components/privacy_sandbox/privacy_sandbox_features.h" +#include "components/site_engagement/content/site_engagement_service.h" #include "components/subresource_filter/content/browser/subresource_filter_content_settings_manager.h" #include "components/subresource_filter/content/browser/subresource_filter_profile_context.h" #include "components/subresource_filter/core/browser/subresource_filter_features.h" @@ -60,8 +67,10 @@ #include "content/public/common/url_utils.h" #include "extensions/browser/extension_registry.h" #include "extensions/common/constants.h" +#include "services/network/public/cpp/features.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/permissions/permission_utils.h" +#include "ui/base/l10n/l10n_util.h" #include "url/origin.h" namespace site_settings { @@ -80,7 +89,7 @@ const char kBluetoothChooserDataGroupType[] = "bluetooth-devices-data"; const ContentSettingsTypeNameEntry kContentSettingsTypeGroupNames[] = { // The following ContentSettingsTypes have UI in Content Settings // and require a mapping from their Javascript string representation in - // chrome/browser/resources/settings/site_settings/constants.js to their C++ + // chrome/browser/resources/settings/site_settings/constants.ts to their C++ // ContentSettingsType provided here. These group names are only used by // desktop webui. {ContentSettingsType::COOKIES, "cookies"}, @@ -125,6 +134,7 @@ const ContentSettingsTypeNameEntry kContentSettingsTypeGroupNames[] = { {ContentSettingsType::PRIVATE_NETWORK_CHOOSER_DATA, "private-network-devices-data"}, {ContentSettingsType::ANTI_ABUSE, "anti-abuse"}, + {ContentSettingsType::STORAGE_ACCESS, "storage-access"}, // Add new content settings here if a corresponding Javascript string // representation for it is not required, for example if the content setting @@ -155,7 +165,6 @@ const ContentSettingsTypeNameEntry kContentSettingsTypeGroupNames[] = { {ContentSettingsType::NFC, nullptr}, {ContentSettingsType::SAFE_BROWSING_URL_CHECK_DATA, nullptr}, {ContentSettingsType::FILE_SYSTEM_READ_GUARD, nullptr}, - {ContentSettingsType::STORAGE_ACCESS, nullptr}, {ContentSettingsType::CAMERA_PAN_TILT_ZOOM, nullptr}, {ContentSettingsType::INSECURE_LOCAL_NETWORK, nullptr}, {ContentSettingsType::PERMISSION_AUTOREVOCATION_DATA, nullptr}, @@ -169,7 +178,6 @@ const ContentSettingsTypeNameEntry kContentSettingsTypeGroupNames[] = { {ContentSettingsType::FEDERATED_IDENTITY_ACTIVE_SESSION, nullptr}, {ContentSettingsType::AUTO_DARK_WEB_CONTENT, nullptr}, {ContentSettingsType::REQUEST_DESKTOP_SITE, nullptr}, - {ContentSettingsType::GET_DISPLAY_MEDIA_SET_SELECT_ALL_SCREENS, nullptr}, {ContentSettingsType::NOTIFICATION_INTERACTIONS, nullptr}, {ContentSettingsType::REDUCED_ACCEPT_LANGUAGE, nullptr}, {ContentSettingsType::NOTIFICATION_PERMISSION_REVIEW, nullptr}, @@ -186,6 +194,7 @@ const ContentSettingsTypeNameEntry kContentSettingsTypeGroupNames[] = { {ContentSettingsType::FEDERATED_IDENTITY_IDENTITY_PROVIDER_REGISTRATION, nullptr}, {ContentSettingsType::THIRD_PARTY_STORAGE_PARTITIONING, nullptr}, + {ContentSettingsType::ALL_SCREEN_CAPTURE, nullptr}, }; static_assert(std::size(kContentSettingsTypeGroupNames) == @@ -420,17 +429,49 @@ const ChooserTypeNameEntry kChooserTypeGroupNames[] = { {&GetHidChooserContext, kHidChooserDataGroupType}, {&GetBluetoothChooserContext, kBluetoothChooserDataGroupType}}; -// There are two FormatOptions to support both hostname-only and schemeful URL -// formatting, both of which are used in Site Settings. -constexpr UrlIdentity::FormatOptions kUrlIdentityOptionsWithScheme = { +// These variables represent different formatting options for default (i.e. not +// extension or IWA) URLs as well as fallbacks for when the IWA/extension is not +// found in the registry. +constexpr UrlIdentity::FormatOptions kUrlIdentityOptionsOmitHttps = { .default_options = { UrlIdentity::DefaultFormatOptions::kOmitCryptographicScheme}}; -constexpr UrlIdentity::FormatOptions kUrlIdentityOptionsHostnameOnly = { +constexpr UrlIdentity::FormatOptions kUrlIdentityOptionsHostOnly = { .default_options = {UrlIdentity::DefaultFormatOptions::kHostname}}; +constexpr UrlIdentity::FormatOptions kUrlIdentityOptionsRawSpec = { + .default_options = {UrlIdentity::DefaultFormatOptions::kRawSpec}}; + constexpr UrlIdentity::TypeSet kUrlIdentityAllowedTypes = { UrlIdentity::Type::kDefault, UrlIdentity::Type::kFile, UrlIdentity::Type::kIsolatedWebApp, UrlIdentity::Type::kChromeExtension}; +bool ShouldAddToNotificationPermissionReviewList( + site_engagement::SiteEngagementService* service, + GURL url, + int notification_count) { + // The notification permission should be added to the list if one of the + // criteria below holds: + // - Site engagement level is NONE OR MINIMAL and average daily notification + // count is more than 0. + // - Site engamment level is LOW and average daily notification count is + // more than 3. Otherwise, the notification permission should not be added + // to review list. + double score = service->GetScore(url); + int low_engagement_notification_limit = + features::kSafetyCheckNotificationPermissionsLowEnagementLimit.Get(); + bool is_low_engagement = + !site_engagement::SiteEngagementService::IsEngagementAtLeast( + score, blink::mojom::EngagementLevel::MEDIUM) && + notification_count > low_engagement_notification_limit; + int min_engagement_notification_limit = + features::kSafetyCheckNotificationPermissionsMinEnagementLimit.Get(); + bool is_minimal_engagement = + !site_engagement::SiteEngagementService::IsEngagementAtLeast( + score, blink::mojom::EngagementLevel::LOW) && + notification_count > min_engagement_notification_limit; + + return is_minimal_engagement || is_low_engagement; +} + } // namespace bool HasRegisteredGroupName(ContentSettingsType type) { @@ -458,12 +499,18 @@ ContentSettingsType ContentSettingsTypeFromGroupName(base::StringPiece name) { } base::StringPiece ContentSettingsTypeToGroupName(ContentSettingsType type) { - for (size_t i = 0; i < std::size(kContentSettingsTypeGroupNames); ++i) { - if (type == kContentSettingsTypeGroupNames[i].type) { - const char* name = kContentSettingsTypeGroupNames[i].name; - if (name) - return name; - break; + for (const auto& entry : kContentSettingsTypeGroupNames) { + if (type == entry.type) { + // Content setting types that aren't represented in the settings UI + // will have `nullptr` as their `name`. Although they are valid content + // settings types, they don't have a readable name. + // TODO(crbug.com/1459305): Replace LOG with CHECK. + if (!entry.name) { + LOG(ERROR) << static_cast<int32_t>(type) + << " does not have a readable name."; + } + + return entry.name ? entry.name : base::StringPiece(); } } @@ -531,7 +578,7 @@ const std::vector<ContentSettingsType>& GetVisiblePermissionCategories() { } if (base::FeatureList::IsEnabled( - blink::features::kPrivateNetworkAccessPermissionPrompt)) { + network::features::kPrivateNetworkAccessPermissionPrompt)) { base_types->push_back(ContentSettingsType::PRIVATE_NETWORK_GUARD); } @@ -626,19 +673,26 @@ base::Value::Dict GetExceptionForPage( return exception; } -std::string GetDisplayNameForGURL(Profile* profile, +UrlIdentity GetUrlIdentityForGURL(Profile* profile, const GURL& url, bool hostname_only) { auto origin = url::Origin::Create(url); if (origin.opaque()) { - return url.spec(); + return {.type = UrlIdentity::Type::kDefault, + .name = base::UTF8ToUTF16(url.spec())}; } - auto url_identity = UrlIdentity::CreateFromUrl( + return UrlIdentity::CreateFromUrl( profile, origin.GetURL(), kUrlIdentityAllowedTypes, - hostname_only ? kUrlIdentityOptionsHostnameOnly - : kUrlIdentityOptionsWithScheme); - return base::UTF16ToUTF8(url_identity.name); + hostname_only ? kUrlIdentityOptionsHostOnly + : kUrlIdentityOptionsOmitHttps); +} + +std::string GetDisplayNameForGURL(Profile* profile, + const GURL& url, + bool hostname_only) { + return base::UTF16ToUTF8( + GetUrlIdentityForGURL(profile, url, hostname_only).name); } void GetExceptionsForContentType(ContentSettingsType type, @@ -800,19 +854,17 @@ ContentSetting GetContentSettingForOrigin(Profile* profile, const HostContentSettingsMap* map, const GURL& origin, ContentSettingsType content_type, - std::string* source_string, - std::string* display_name) { + std::string* source_string) { // TODO(patricialor): In future, PermissionManager should know about all // content settings, not just the permissions, plus all the possible sources, // and the calls to HostContentSettingsMap should be removed. content_settings::SettingInfo info; - const base::Value value = - map->GetWebsiteSetting(origin, origin, content_type, &info); + ContentSetting setting = + map->GetContentSetting(origin, origin, content_type, &info); // Retrieve the content setting. permissions::PermissionResult result( - content_settings::ValueToContentSetting(value), - permissions::PermissionStatusSource::UNSPECIFIED); + setting, permissions::PermissionStatusSource::UNSPECIFIED); if (permissions::PermissionDecisionAutoBlocker::IsEnabledForContentSetting( content_type)) { if (permissions::PermissionUtil::IsPermission(content_type)) { @@ -838,10 +890,9 @@ ContentSetting GetContentSettingForOrigin(Profile* profile, // Retrieve the source of the content setting. *source_string = SiteSettingSourceToString( CalculateSiteSettingSource(profile, content_type, origin, info, result)); - *display_name = - GetDisplayNameForGURL(profile, origin, /*hostname_only=*/false); - if (info.metadata.session_model == content_settings::SessionModel::OneTime) { + if (info.metadata.session_model() == + content_settings::SessionModel::OneTime) { DCHECK( permissions::PermissionUtil::CanPermissionBeAllowedOnce(content_type)); DCHECK_EQ(result.content_setting, CONTENT_SETTING_ALLOW); @@ -874,7 +925,7 @@ void GetFileSystemGrantedEntries(std::vector<base::Value::Dict>* exceptions, for (const auto& grant : grants) { const std::string url = grant->origin.spec(); - auto* const optional_path = grant->value.GetDict().Find( + auto* const optional_path = grant->value.Find( ChromeFileSystemAccessPermissionContext::kPermissionPathKey); // Ensure that the file path is found for the given kPermissionPathKey. @@ -929,23 +980,10 @@ base::Value::Dict CreateChooserExceptionObject( const std::string& source = std::get<1>(details); const bool incognito = std::get<2>(details); - std::string site_display_name = origin.spec(); -#if BUILDFLAG(ENABLE_EXTENSIONS) - // Set the |site_display_name| to the extension's name which is more clear - // to the user if the |origin| is for an extension and the extension name - // can be found in the |profile|. - if (origin.SchemeIs(extensions::kExtensionScheme)) { - DCHECK(profile); - const auto* extension_registry = - extensions::ExtensionRegistry::Get(profile); - const extensions::Extension* extension = - extension_registry->GetExtensionById( - origin.host(), extensions::ExtensionRegistry::EVERYTHING); - if (extension) { - site_display_name = extension->name(); - } - } -#endif + std::string site_display_name = base::UTF16ToUTF8( + UrlIdentity::CreateFromUrl(profile, origin, kUrlIdentityAllowedTypes, + kUrlIdentityOptionsRawSpec) + .name); auto& this_provider_sites = all_provider_sites[HostContentSettingsMap::GetProviderTypeFromSource( @@ -1014,8 +1052,8 @@ base::Value::List GetChooserExceptionListFromProfile( continue; std::u16string name = chooser_context->GetObjectDisplayName(object->value); - auto& chooser_exception_details = - all_chooser_objects[std::make_pair(name, object->value.Clone())]; + auto& chooser_exception_details = all_chooser_objects[std::make_pair( + name, base::Value(object->value.Clone()))]; std::string source = GetSourceStringForChooserException( profile, content_type, object->source); @@ -1036,23 +1074,83 @@ base::Value::List GetChooserExceptionListFromProfile( return exceptions; } -absl::optional<std::string> GetExtensionDisplayName(Profile* profile, - GURL url) { - if (!url.SchemeIs(extensions::kExtensionScheme)) { +std::vector<web_app::IsolatedWebAppUrlInfo> GetInstalledIsolatedWebApps( + Profile* profile) { + auto* web_app_provider = web_app::WebAppProvider::GetForWebApps(profile); + if (!web_app_provider) { return {}; } - auto* extension_registry = extensions::ExtensionRegistry::Get(profile); - if (!extension_registry) { - return {}; + + std::vector<web_app::IsolatedWebAppUrlInfo> iwas; + web_app::WebAppRegistrar& registrar = web_app_provider->registrar_unsafe(); + for (const web_app::WebApp& web_app : registrar.GetApps()) { + if (!registrar.IsIsolated(web_app.app_id())) { + continue; + } + base::expected<web_app::IsolatedWebAppUrlInfo, std::string> url_info = + web_app::IsolatedWebAppUrlInfo::Create(web_app.scope()); + if (url_info.has_value()) { + iwas.push_back(*url_info); + } } - // For the extension scheme, the pattern must be a valid URL. - DCHECK(url.is_valid()); - const extensions::Extension* extension = extension_registry->GetExtensionById( - url.host(), extensions::ExtensionRegistry::EVERYTHING); - if (!extension) { - return {}; + return iwas; +} + +// TODO(crbug.com/1444024): Migrate to NotificationPermissionsReviewService. +base::Value::List PopulateNotificationPermissionReviewData(Profile* profile) { + base::Value::List result; + if (!base::FeatureList::IsEnabled( + features::kSafetyCheckNotificationPermissions)) { + return result; } - return extension->name(); + + auto* service = + NotificationPermissionsReviewServiceFactory::GetForProfile(profile); + if (!service) { + return result; + } + + auto notification_permissions = service->GetNotificationSiteListForReview(); + + site_engagement::SiteEngagementService* engagement_service = + site_engagement::SiteEngagementService::Get(profile); + + // Sort notification permissions by their priority for surfacing to the user. + auto notification_permission_ordering = + [](const permissions::NotificationPermissions& left, + const permissions::NotificationPermissions& right) { + return left.notification_count > right.notification_count; + }; + std::sort(notification_permissions.begin(), notification_permissions.end(), + notification_permission_ordering); + + for (const auto& notification_permission : notification_permissions) { + // Converting primary pattern to GURL should always be valid, since + // Notification Permission Review list only contains single origins. Those + // are filtered in + // NotificationPermissionsReviewService::GetNotificationSiteListForReview. + GURL url = GURL(notification_permission.primary_pattern.ToString()); + DCHECK(url.is_valid()); + if (!ShouldAddToNotificationPermissionReviewList( + engagement_service, url, + notification_permission.notification_count)) { + continue; + } + + base::Value::Dict permission; + permission.Set(site_settings::kOrigin, + notification_permission.primary_pattern.ToString()); + + std::string notification_info_string = + base::UTF16ToUTF8(l10n_util::GetPluralStringFUTF16( + IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_COUNT_LABEL, + notification_permission.notification_count)); + permission.Set(site_settings::kNotificationInfoString, + notification_info_string); + result.Append(std::move(permission)); + } + + return result; } } // namespace site_settings diff --git a/chromium/chrome/browser/ui/webui/settings/site_settings_helper.h b/chromium/chrome/browser/ui/webui/settings/site_settings_helper.h index 303d3926b77..d05b9dde71d 100644 --- a/chromium/chrome/browser/ui/webui/settings/site_settings_helper.h +++ b/chromium/chrome/browser/ui/webui/settings/site_settings_helper.h @@ -22,6 +22,7 @@ class HostContentSettingsMap; class Profile; +struct UrlIdentity; namespace content { class WebUI; @@ -31,6 +32,10 @@ namespace permissions { class ObjectPermissionContextBase; } +namespace web_app { +class IsolatedWebAppUrlInfo; +} // namespace web_app + namespace site_settings { // Maps from a secondary pattern to a setting. @@ -46,31 +51,32 @@ typedef std::map<std::pair<ContentSettingsPattern, std::string>, using ChooserExceptionDetails = std::set<std::tuple<GURL, std::string, bool>>; constexpr char kChooserType[] = "chooserType"; +constexpr char kDirectoryReadGrants[] = "directoryReadGrants"; +constexpr char kDirectoryWriteGrants[] = "directoryWriteGrants"; +constexpr char kDisabled[] = "disabled"; constexpr char kDisplayName[] = "displayName"; constexpr char kEmbeddingOrigin[] = "embeddingOrigin"; +constexpr char kFilePath[] = "filePath"; +constexpr char kFileReadGrants[] = "fileReadGrants"; +constexpr char kFileWriteGrants[] = "fileWriteGrants"; +constexpr char kHostOrSpec[] = "hostOrSpec"; constexpr char kIncognito[] = "incognito"; +constexpr char kIsDirectory[] = "isDirectory"; +constexpr char kIsEmbargoed[] = "isEmbargoed"; +constexpr char kIsWritable[] = "isWritable"; +constexpr char kNotificationInfoString[] = "notificationInfoString"; constexpr char kObject[] = "object"; -constexpr char kDisabled[] = "disabled"; -constexpr char kIsolatedWebAppName[] = "isolatedWebAppName"; constexpr char kOrigin[] = "origin"; constexpr char kOriginForFavicon[] = "originForFavicon"; +constexpr char kPermissions[] = "permissions"; +constexpr char kPolicyIndicator[] = "indicator"; constexpr char kRecentPermissions[] = "recentPermissions"; constexpr char kSetting[] = "setting"; constexpr char kSites[] = "sites"; -constexpr char kPolicyIndicator[] = "indicator"; constexpr char kSource[] = "source"; constexpr char kType[] = "type"; -constexpr char kIsDirectory[] = "isDirectory"; -constexpr char kIsEmbargoed[] = "isEmbargoed"; -constexpr char kIsWritable[] = "isWritable"; -constexpr char kDirectoryReadGrants[] = "directoryReadGrants"; -constexpr char kDirectoryWriteGrants[] = "directoryWriteGrants"; -constexpr char kFilePath[] = "filePath"; -constexpr char kFileReadGrants[] = "fileReadGrants"; -constexpr char kFileWriteGrants[] = "fileWriteGrants"; -constexpr char kNotificationInfoString[] = "notificationInfoString"; -constexpr char kPermissions[] = "permissions"; -constexpr char kExtensionNameWithId[] = "extensionNameWithId"; +constexpr char kNotificationPermissionsReviewListMaybeChangedEvent[] = + "notification-permission-review-list-maybe-changed"; enum class SiteSettingSource { kAllowlist, @@ -151,8 +157,7 @@ ContentSetting GetContentSettingForOrigin(Profile* profile, const HostContentSettingsMap* map, const GURL& origin, ContentSettingsType content_type, - std::string* source_string, - std::string* display_name); + std::string* source_string); // Returns URLs with granted entries from the File System Access API. void GetFileSystemGrantedEntries(std::vector<base::Value::Dict>* exceptions, @@ -199,20 +204,27 @@ base::Value::List GetChooserExceptionListFromProfile( Profile* profile, const ChooserTypeNameEntry& chooser_type); -// Returns the short name of a browser extension, or nullopt if `origin` is not -// an extension URL. -absl::optional<std::string> GetExtensionDisplayName(Profile* profile, - GURL origin); - // Takes |url| and converts it into an individual origin string or retrieves // name of the extension or Isolated Web App it belongs to. If |hostname_only| // is true, returns |url|'s hostname for HTTP/HTTPS pages or unknown // extension/IWA URLs, otherwise an origin string will be returned that // includes the scheme if it's non-cryptographic. +UrlIdentity GetUrlIdentityForGURL(Profile* profile, + const GURL& url, + bool hostname_only); std::string GetDisplayNameForGURL(Profile* profile, const GURL& url, bool hostname_only); +// Returns data about all currently installed Isolated Web Apps. +std::vector<web_app::IsolatedWebAppUrlInfo> GetInstalledIsolatedWebApps( + Profile* profile); + +// Returns a list of domains to be shown on the 'Review Notification +// Permissions' module in site settings notification page. Those domains send +// a lot of notifications, but have low site engagement. +base::Value::List PopulateNotificationPermissionReviewData(Profile* profile); + } // namespace site_settings #endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_SITE_SETTINGS_HELPER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/site_settings_helper_unittest.cc b/chromium/chrome/browser/ui/webui/settings/site_settings_helper_unittest.cc index 412c83f821f..1723406b7b3 100644 --- a/chromium/chrome/browser/ui/webui/settings/site_settings_helper_unittest.cc +++ b/chromium/chrome/browser/ui/webui/settings/site_settings_helper_unittest.cc @@ -13,11 +13,17 @@ #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" +#include "chrome/browser/engagement/site_engagement_service_factory.h" #include "chrome/browser/file_system_access/chrome_file_system_access_permission_context.h" #include "chrome/browser/file_system_access/file_system_access_permission_context_factory.h" +#include "chrome/browser/permissions/notifications_engagement_service_factory.h" #include "chrome/browser/permissions/permission_decision_auto_blocker_factory.h" +#include "chrome/browser/ui/web_applications/test/isolated_web_app_test_utils.h" #include "chrome/browser/usb/usb_chooser_context.h" #include "chrome/browser/usb/usb_chooser_context_factory.h" +#include "chrome/browser/web_applications/test/web_app_install_test_utils.h" +#include "chrome/browser/web_applications/test/web_app_test_utils.h" +#include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/testing_profile.h" #include "components/content_settings/core/browser/content_settings_utils.h" @@ -32,6 +38,7 @@ #include "components/permissions/test/permission_test_util.h" #include "components/prefs/pref_service.h" #include "components/privacy_sandbox/privacy_sandbox_features.h" +#include "components/site_engagement/content/site_engagement_score.h" #include "content/public/test/browser_task_environment.h" #include "extensions/browser/extension_registry.h" #include "mojo/public/cpp/bindings/pending_remote.h" @@ -46,7 +53,7 @@ #include "extensions/browser/extension_system.h" #include "extensions/browser/unloaded_extension_reason.h" #include "extensions/test/test_extension_dir.h" -#endif +#endif // BUILDFLAG(ENABLE_EXTENSIONS) namespace site_settings { @@ -90,6 +97,20 @@ class SiteSettingsHelperTest : public testing::Test { ContentSettingsPattern::Wildcard(), kContentType, setting); } + void RecordNotification(permissions::NotificationsEngagementService* service, + GURL url, + int daily_average_count) { + // This many notifications were recorded during the past week in total. + int total_count = daily_average_count * 7; + service->RecordNotificationDisplayed(url, total_count); + } + + base::Time GetReferenceTime() { + base::Time time; + EXPECT_TRUE(base::Time::FromString("Sat, 1 Sep 2018 11:00:00 GMT", &time)); + return time; + } + private: content::BrowserTaskEnvironment task_environment_; }; @@ -432,34 +453,33 @@ TEST_F(SiteSettingsHelperTest, ContentSettingSource) { GURL origin("https://www.example.com/"); std::string source; - std::string display_name; ContentSetting content_setting; // Built in Chrome default. - content_setting = GetContentSettingForOrigin( - &profile, map, origin, kContentType, &source, &display_name); + content_setting = + GetContentSettingForOrigin(&profile, map, origin, kContentType, &source); EXPECT_EQ(SiteSettingSourceToString(SiteSettingSource::kDefault), source); EXPECT_EQ(CONTENT_SETTING_ASK, content_setting); // User-set global default. map->SetDefaultContentSetting(kContentType, CONTENT_SETTING_ALLOW); - content_setting = GetContentSettingForOrigin( - &profile, map, origin, kContentType, &source, &display_name); + content_setting = + GetContentSettingForOrigin(&profile, map, origin, kContentType, &source); EXPECT_EQ(SiteSettingSourceToString(SiteSettingSource::kDefault), source); EXPECT_EQ(CONTENT_SETTING_ALLOW, content_setting); // User-set pattern. AddSetting(map, "https://*", CONTENT_SETTING_BLOCK); - content_setting = GetContentSettingForOrigin( - &profile, map, origin, kContentType, &source, &display_name); + content_setting = + GetContentSettingForOrigin(&profile, map, origin, kContentType, &source); EXPECT_EQ(SiteSettingSourceToString(SiteSettingSource::kPreference), source); EXPECT_EQ(CONTENT_SETTING_BLOCK, content_setting); // User-set origin setting. map->SetContentSettingDefaultScope(origin, origin, kContentType, CONTENT_SETTING_ALLOW); - content_setting = GetContentSettingForOrigin( - &profile, map, origin, kContentType, &source, &display_name); + content_setting = + GetContentSettingForOrigin(&profile, map, origin, kContentType, &source); EXPECT_EQ(SiteSettingSourceToString(SiteSettingSource::kPreference), source); EXPECT_EQ(CONTENT_SETTING_ALLOW, content_setting); @@ -473,8 +493,8 @@ TEST_F(SiteSettingsHelperTest, ContentSettingSource) { content_settings::TestUtils::OverrideProvider( map, std::move(extension_provider), HostContentSettingsMap::CUSTOM_EXTENSION_PROVIDER); - content_setting = GetContentSettingForOrigin( - &profile, map, origin, kContentType, &source, &display_name); + content_setting = + GetContentSettingForOrigin(&profile, map, origin, kContentType, &source); EXPECT_EQ(SiteSettingSourceToString(SiteSettingSource::kExtension), source); EXPECT_EQ(CONTENT_SETTING_BLOCK, content_setting); @@ -487,15 +507,15 @@ TEST_F(SiteSettingsHelperTest, ContentSettingSource) { policy_provider->set_read_only(true); content_settings::TestUtils::OverrideProvider( map, std::move(policy_provider), HostContentSettingsMap::POLICY_PROVIDER); - content_setting = GetContentSettingForOrigin( - &profile, map, origin, kContentType, &source, &display_name); + content_setting = + GetContentSettingForOrigin(&profile, map, origin, kContentType, &source); EXPECT_EQ(SiteSettingSourceToString(SiteSettingSource::kPolicy), source); EXPECT_EQ(CONTENT_SETTING_ALLOW, content_setting); // Insecure origins. content_setting = GetContentSettingForOrigin( &profile, map, GURL("http://www.insecure_http_site.com/"), kContentType, - &source, &display_name); + &source); EXPECT_EQ(SiteSettingSourceToString(SiteSettingSource::kInsecureOrigin), source); EXPECT_EQ(CONTENT_SETTING_BLOCK, content_setting); @@ -754,6 +774,89 @@ TEST_F(SiteSettingsHelperTest, CreateChooserExceptionObject) { } } +TEST_F(SiteSettingsHelperTest, PopulateNotificationPermissionReviewData) { + TestingProfile profile; + base::test::ScopedFeatureList scoped_feature; + scoped_feature.InitAndEnableFeature( + ::features::kSafetyCheckNotificationPermissions); + + // Add a couple of notification permission and check they appear in review + // list. + HostContentSettingsMap* map = + HostContentSettingsMapFactory::GetForProfile(&profile); + GURL urls[] = {GURL("https://google.com:443"), + GURL("https://www.youtube.com:443"), + GURL("https://www.example.com:443")}; + + map->SetContentSettingDefaultScope(urls[0], GURL(), + ContentSettingsType::NOTIFICATIONS, + CONTENT_SETTING_ALLOW); + map->SetContentSettingDefaultScope(urls[1], GURL(), + ContentSettingsType::NOTIFICATIONS, + CONTENT_SETTING_ALLOW); + map->SetContentSettingDefaultScope(urls[2], GURL(), + ContentSettingsType::NOTIFICATIONS, + CONTENT_SETTING_ALLOW); + + // Record initial display date to enable comparing dictionaries for + // NotificationEngagementService. + auto* notification_engagement_service = + NotificationsEngagementServiceFactory::GetForProfile(&profile); + std::string displayedDate = + notification_engagement_service->GetBucketLabel(base::Time::Now()); + + auto* site_engagement_service = + site_engagement::SiteEngagementServiceFactory::GetForProfile(&profile); + + // Set a host to have minimum engagement. This should be in review list. + RecordNotification(notification_engagement_service, urls[0], 1); + site_engagement::SiteEngagementScore score = + site_engagement_service->CreateEngagementScore(urls[0]); + score.Reset(0.5, GetReferenceTime()); + score.Commit(); + EXPECT_EQ(blink::mojom::EngagementLevel::MINIMAL, + site_engagement_service->GetEngagementLevel(urls[0])); + + // Set a host to have large number of notifications, but low engagement. This + // should be in review list. + RecordNotification(notification_engagement_service, urls[1], 5); + site_engagement_service->AddPointsForTesting(urls[1], 1.0); + EXPECT_EQ(blink::mojom::EngagementLevel::LOW, + site_engagement_service->GetEngagementLevel(urls[1])); + + // Set a host to have medium engagement and high notification count. This + // should not be in review list. + RecordNotification(notification_engagement_service, urls[2], 5); + site_engagement_service->AddPointsForTesting(urls[2], 50.0); + EXPECT_EQ(blink::mojom::EngagementLevel::MEDIUM, + site_engagement_service->GetEngagementLevel(urls[2])); + + const auto& notification_permissions = + PopulateNotificationPermissionReviewData(&profile); + // Check if resulting list contains only the expected URLs. They should be in + // descending order of notification count. + EXPECT_EQ(2UL, notification_permissions.size()); + EXPECT_EQ("https://www.youtube.com:443", + *notification_permissions[0].GetDict().FindString( + site_settings::kOrigin)); + EXPECT_EQ("https://google.com:443", + *notification_permissions[1].GetDict().FindString( + site_settings::kOrigin)); + + // Increasing notification count also promotes host in the list. + RecordNotification(notification_engagement_service, + GURL("https://google.com:443"), 10); + const auto& updated_notification_permissions = + PopulateNotificationPermissionReviewData(&profile); + EXPECT_EQ(2UL, updated_notification_permissions.size()); + EXPECT_EQ("https://google.com:443", + *updated_notification_permissions[0].GetDict().FindString( + site_settings::kOrigin)); + EXPECT_EQ("https://www.youtube.com:443", + *updated_notification_permissions[1].GetDict().FindString( + site_settings::kOrigin)); +} + namespace { constexpr char kUsbPolicySetting[] = R"( @@ -1140,4 +1243,68 @@ TEST_F(SiteSettingsHelperExtensionTest, } #endif // #if BUILDFLAG(ENABLE_EXTENSIONS) +class SiteSettingsHelperIsolatedWebAppTest : public testing::Test { + protected: + void InstallIsolatedWebApp(const GURL& url, const std::string& name) { + web_app::test::AwaitStartWebAppProviderAndSubsystems(&testing_profile_); + web_app::AddDummyIsolatedAppToRegistry(&testing_profile_, url, name); + } + + Profile* profile() { return &testing_profile_; } + + private: + content::BrowserTaskEnvironment task_environment_; + TestingProfile testing_profile_; + +#if BUILDFLAG(IS_CHROMEOS_LACROS) + web_app::test::ScopedSkipMainProfileCheck skip_main_profile_check_; +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) +}; + +TEST_F(SiteSettingsHelperIsolatedWebAppTest, + IsolatedWebAppsUseAppNameAsDisplayName) { + const GURL kAppUrl( + "isolated-app://" + "berugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic"); + const std::string kAppName("test IWA Name"); + + const std::string kUsbChooserGroupName( + ContentSettingsTypeToGroupName(ContentSettingsType::USB_CHOOSER_DATA)); + const std::string& kPolicySource = + SiteSettingSourceToString(SiteSettingSource::kPolicy); + const std::string& kPreferenceSource = + SiteSettingSourceToString(SiteSettingSource::kPreference); + const std::u16string& kObjectName = u"Gadget"; + + InstallIsolatedWebApp(kAppUrl, kAppName); + + // Create a chooser object for testing. + base::Value::Dict chooser_object; + chooser_object.Set("name", kObjectName); + + // Add a user permission for an origin of |kAppUrl|. + ChooserExceptionDetails exception_details; + exception_details.insert({kAppUrl.DeprecatedGetOriginAsURL(), + kPreferenceSource, /*incognito=*/false}); + { + auto exception = CreateChooserExceptionObject( + /*display_name=*/kObjectName, + /*object=*/base::Value(chooser_object.Clone()), + /*chooser_type=*/kUsbChooserGroupName, + /*chooser_exception_details=*/exception_details, + /*profile=*/profile()); + ExpectValidChooserExceptionObject( + exception, /*chooser_type=*/kUsbChooserGroupName, + /*display_name=*/kObjectName, chooser_object); + + const auto& sites_list = exception.Find(kSites)->GetList(); + ExpectValidSiteExceptionObject( + /*actual_site_object=*/sites_list[0], + /*display_name=*/kAppName, + /*origin=*/kAppUrl, + /*source=*/kPreferenceSource, + /*incognito=*/false); + } +} + } // namespace site_settings diff --git a/chromium/chrome/browser/ui/webui/settings/site_settings_permissions_handler.cc b/chromium/chrome/browser/ui/webui/settings/site_settings_permissions_handler.cc deleted file mode 100644 index b43272ed11b..00000000000 --- a/chromium/chrome/browser/ui/webui/settings/site_settings_permissions_handler.cc +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright 2022 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/webui/settings/site_settings_permissions_handler.h" - -#include "base/check.h" -#include "base/json/values_util.h" -#include "base/metrics/histogram_functions.h" -#include "base/threading/thread_checker.h" -#include "base/time/clock.h" -#include "base/time/default_clock.h" -#include "base/time/time.h" -#include "base/values.h" -#include "chrome/browser/content_settings/host_content_settings_map_factory.h" -#include "chrome/browser/permissions/unused_site_permissions_service_factory.h" -#include "chrome/browser/ui/webui/settings/site_settings_helper.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_pattern.h" -#include "components/content_settings/core/common/features.h" -#include "components/permissions/constants.h" -#include "components/permissions/unused_site_permissions_service.h" -#include "url/gurl.h" - -namespace { -// Reflects the maximum number of days between a permissions being revoked and -// the time when the user regrants the permission through the unused site -// permission module of Safete Check. The maximum number of days is determined -// by `content_settings::features:: -// kSafetyCheckUnusedSitePermissionsRevocationCleanUpThreshold`. -size_t kAllowAgainMetricsExclusiveMaxCount = 31; -// Using a single bucket per day, following the value of -// |kAllowAgainMetricsExclusiveMaxCount|. -size_t kAllowAgainMetricsBuckets = 31; -// Key of the expiration time in the |UnusedSitePermissions| object. Indicates -// the time after which the associated origin and permissions are no longer -// shown in the UI. -constexpr char kExpirationKey[] = "expiration"; -} // namespace - -SiteSettingsPermissionsHandler::SiteSettingsPermissionsHandler(Profile* profile) - : profile_(profile), clock_(base::DefaultClock::GetInstance()) {} -SiteSettingsPermissionsHandler::~SiteSettingsPermissionsHandler() = default; - -void SiteSettingsPermissionsHandler::HandleGetRevokedUnusedSitePermissionsList( - const base::Value::List& args) { - AllowJavascript(); - - CHECK_EQ(1U, args.size()); - const base::Value& callback_id = args[0]; - - base::Value::List result = PopulateUnusedSitePermissionsData(); - - ResolveJavascriptCallback(callback_id, base::Value(std::move(result))); -} - -void SiteSettingsPermissionsHandler::HandleAllowPermissionsAgainForUnusedSite( - const base::Value::List& args) { - CHECK_EQ(1U, args.size()); - CHECK(args[0].is_string()); - const std::string& origin_str = args[0].GetString(); - - permissions::UnusedSitePermissionsService* service = - UnusedSitePermissionsServiceFactory::GetForProfile(profile_); - - url::Origin origin = url::Origin::Create(GURL(origin_str)); - - HostContentSettingsMap* hcsm = - HostContentSettingsMapFactory::GetForProfile(profile_); - content_settings::SettingInfo info; - base::Value stored_value(hcsm->GetWebsiteSetting( - origin.GetURL(), origin.GetURL(), - ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS, &info)); - base::Time revoked_time = - info.metadata.expiration - - content_settings::features:: - kSafetyCheckUnusedSitePermissionsRevocationCleanUpThreshold.Get(); - base::UmaHistogramCustomCounts( - "Settings.SafetyCheck.UnusedSitePermissionsAllowAgainDays", - (clock_->Now() - revoked_time).InDays(), 0, - kAllowAgainMetricsExclusiveMaxCount, kAllowAgainMetricsBuckets); - - service->RegrantPermissionsForOrigin(origin); - SendUnusedSitePermissionsReviewList(); -} - -void SiteSettingsPermissionsHandler:: - HandleUndoAllowPermissionsAgainForUnusedSite( - const base::Value::List& args) { - CHECK_EQ(1U, args.size()); - CHECK(args[0].is_dict()); - - auto [origin, permissions, constraints] = - GetUnusedSitePermissionsFromDict(args[0].GetDict()); - permissions::UnusedSitePermissionsService* service = - UnusedSitePermissionsServiceFactory::GetForProfile(profile_); - - service->UndoRegrantPermissionsForOrigin(permissions, constraints, origin); - - SendUnusedSitePermissionsReviewList(); -} - -void SiteSettingsPermissionsHandler:: - HandleAcknowledgeRevokedUnusedSitePermissionsList( - const base::Value::List& args) { - permissions::UnusedSitePermissionsService* service = - UnusedSitePermissionsServiceFactory::GetForProfile(profile_); - service->ClearRevokedPermissionsList(); - - SendUnusedSitePermissionsReviewList(); -} - -void SiteSettingsPermissionsHandler:: - HandleUndoAcknowledgeRevokedUnusedSitePermissionsList( - const base::Value::List& args) { - CHECK_EQ(1U, args.size()); - CHECK(args[0].is_list()); - - const base::Value::List& unused_site_permissions_list = args[0].GetList(); - permissions::UnusedSitePermissionsService* service = - UnusedSitePermissionsServiceFactory::GetForProfile(profile_); - - for (const auto& unused_site_permissions_js : unused_site_permissions_list) { - CHECK(unused_site_permissions_js.is_dict()); - auto [origin, permissions, constraints] = - GetUnusedSitePermissionsFromDict(unused_site_permissions_js.GetDict()); - - service->StorePermissionInRevokedPermissionSetting(permissions, constraints, - origin); - } - - SendUnusedSitePermissionsReviewList(); -} - -base::Value::List -SiteSettingsPermissionsHandler::PopulateUnusedSitePermissionsData() { - base::Value::List result; - if (!base::FeatureList::IsEnabled( - content_settings::features::kSafetyCheckUnusedSitePermissions)) { - return result; - } - - HostContentSettingsMap* hcsm = - HostContentSettingsMapFactory::GetForProfile(profile_); - - ContentSettingsForOneType settings; - hcsm->GetSettingsForOneType( - ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS, &settings); - - for (const auto& revoked_permissions : settings) { - base::Value::Dict revoked_permission_value; - revoked_permission_value.Set( - site_settings::kOrigin, revoked_permissions.primary_pattern.ToString()); - const base::Value& stored_value = revoked_permissions.setting_value; - DCHECK(stored_value.is_dict()); - - // The revoked permissions list should be reachable by given key. - DCHECK(stored_value.GetDict().FindList(permissions::kRevokedKey)); - - auto type_list = - stored_value.GetDict().FindList(permissions::kRevokedKey)->Clone(); - base::Value::List permissions_value_list; - for (base::Value& type : type_list) { - permissions_value_list.Append( - site_settings::ContentSettingsTypeToGroupName( - static_cast<ContentSettingsType>(type.GetInt()))); - } - - revoked_permission_value.Set( - site_settings::kPermissions, - base::Value(std::move(permissions_value_list))); - - revoked_permission_value.Set( - kExpirationKey, - base::TimeToValue(revoked_permissions.metadata.expiration)); - - result.Append(std::move(revoked_permission_value)); - } - return result; -} - -std::tuple<url::Origin, - std::set<ContentSettingsType>, - content_settings::ContentSettingConstraints> -SiteSettingsPermissionsHandler::GetUnusedSitePermissionsFromDict( - const base::Value::Dict& unused_site_permissions) { - const std::string* origin_str = - unused_site_permissions.FindString(site_settings::kOrigin); - CHECK(origin_str); - const auto url = GURL(*origin_str); - CHECK(url.is_valid()); - const url::Origin origin = url::Origin::Create(url); - - const base::Value::List* permissions = - unused_site_permissions.FindList(site_settings::kPermissions); - CHECK(permissions); - std::set<ContentSettingsType> permission_types; - for (const auto& permission : *permissions) { - CHECK(permission.is_string()); - const std::string& type_string = permission.GetString(); - ContentSettingsType type = - site_settings::ContentSettingsTypeFromGroupName(type_string); - CHECK(type != ContentSettingsType::DEFAULT) - << type_string << " is not expected to have a UI representation."; - permission_types.insert(type); - } - - const base::Value* js_expiration = - unused_site_permissions.Find(kExpirationKey); - CHECK(js_expiration); - auto expiration = base::ValueToTime(js_expiration); - - const content_settings::ContentSettingConstraints constraints{ - .expiration = *expiration}; - - return std::make_tuple(origin, permission_types, constraints); -} - -void SiteSettingsPermissionsHandler::RegisterMessages() { - // Usage of base::Unretained(this) is safe, because web_ui() owns `this` and - // won't release ownership until destruction. - web_ui()->RegisterMessageCallback( - "getRevokedUnusedSitePermissionsList", - base::BindRepeating(&SiteSettingsPermissionsHandler:: - HandleGetRevokedUnusedSitePermissionsList, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "allowPermissionsAgainForUnusedSite", - base::BindRepeating(&SiteSettingsPermissionsHandler:: - HandleAllowPermissionsAgainForUnusedSite, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "undoAllowPermissionsAgainForUnusedSite", - base::BindRepeating(&SiteSettingsPermissionsHandler:: - HandleUndoAllowPermissionsAgainForUnusedSite, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "acknowledgeRevokedUnusedSitePermissionsList", - base::BindRepeating(&SiteSettingsPermissionsHandler:: - HandleAcknowledgeRevokedUnusedSitePermissionsList, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "undoAcknowledgeRevokedUnusedSitePermissionsList", - base::BindRepeating( - &SiteSettingsPermissionsHandler:: - HandleUndoAcknowledgeRevokedUnusedSitePermissionsList, - base::Unretained(this))); -} - -void SiteSettingsPermissionsHandler::SendUnusedSitePermissionsReviewList() { - // Notify observers that the unused site permission review list could have - // changed. Note that the list is not guaranteed to have changed. In places - // where determining whether the list has changed is cause for performance - // concerns, an unchanged list may be sent. - FireWebUIListener("unused-permission-review-list-maybe-changed", - PopulateUnusedSitePermissionsData()); -} - -void SiteSettingsPermissionsHandler::SetClockForTesting(base::Clock* clock) { - clock_ = clock; -} - -void SiteSettingsPermissionsHandler::OnJavascriptAllowed() {} - -void SiteSettingsPermissionsHandler::OnJavascriptDisallowed() {} diff --git a/chromium/chrome/browser/ui/webui/settings/site_settings_permissions_handler.h b/chromium/chrome/browser/ui/webui/settings/site_settings_permissions_handler.h deleted file mode 100644 index 414f949d423..00000000000 --- a/chromium/chrome/browser/ui/webui/settings/site_settings_permissions_handler.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2022 The Chromium Authors -// 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_SITE_SETTINGS_PERMISSIONS_HANDLER_H_ -#define CHROME_BROWSER_UI_WEBUI_SETTINGS_SITE_SETTINGS_PERMISSIONS_HANDLER_H_ - -#include "base/memory/raw_ptr.h" -#include "base/time/clock.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" -#include "components/content_settings/core/common/content_settings_constraints.h" -#include "components/content_settings/core/common/content_settings_types.h" -#include "url/origin.h" - -/** - * This handler deals with the permission-related operations on the site - * settings page. - */ - -class SiteSettingsPermissionsHandler : public settings::SettingsPageUIHandler { - public: - explicit SiteSettingsPermissionsHandler(Profile* profile); - - ~SiteSettingsPermissionsHandler() override; - - private: - friend class SiteSettingsPermissionsHandlerTest; - FRIEND_TEST_ALL_PREFIXES(SiteSettingsPermissionsHandlerTest, - PopulateUnusedSitePermissionsData); - FRIEND_TEST_ALL_PREFIXES(SiteSettingsPermissionsHandlerTest, - HandleAllowPermissionsAgainForUnusedSite); - FRIEND_TEST_ALL_PREFIXES(SiteSettingsPermissionsHandlerTest, - HandleAcknowledgeRevokedUnusedSitePermissionsList); - - // SettingsPageUIHandler implementation. - void OnJavascriptAllowed() override; - void OnJavascriptDisallowed() override; - - // WebUIMessageHandler implementation. - void RegisterMessages() override; - - // Returns the list of revoked permissions to be used in - // "Unused site permissions" module. - void HandleGetRevokedUnusedSitePermissionsList(const base::Value::List& args); - - // Re-grant the revoked permissions and remove the given origin from the - // revoked permissions list. - void HandleAllowPermissionsAgainForUnusedSite(const base::Value::List& args); - - // Reverse the changes made by |HandleAllowPermissionsAgainForUnusedSite| for - // the given |UnusedSitePermission| object. - void HandleUndoAllowPermissionsAgainForUnusedSite( - const base::Value::List& args); - - // Clear the list of revoked permissions so they are not shown again. - // Permission settings themselves are not affected by this. - void HandleAcknowledgeRevokedUnusedSitePermissionsList( - const base::Value::List& args); - - // Reverse the changes made by - // |HandleAcknowledgeRevokedUnusedSitePermissionsList| for the given list of - // |UnusedSitePermission| objects. List of revoked - // permissions is repopulated. Permission settings are not changed. - void HandleUndoAcknowledgeRevokedUnusedSitePermissionsList( - const base::Value::List& args); - - // Returns the list of revoked permissions that belongs to origins which - // haven't been visited recently. - base::Value::List PopulateUnusedSitePermissionsData(); - - // Sends the list of unused site permissions to review to the WebUI. - void SendUnusedSitePermissionsReviewList(); - - // Get values from |UnusedSitePermission| object in - // site_settings_permissions_browser_proxy.ts. - std::tuple<url::Origin, - std::set<ContentSettingsType>, - content_settings::ContentSettingConstraints> - GetUnusedSitePermissionsFromDict( - const base::Value::Dict& unused_site_permissions); - - const raw_ptr<Profile> profile_; - - raw_ptr<base::Clock> clock_; - - void SetClockForTesting(base::Clock* clock); -}; - -#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_SITE_SETTINGS_PERMISSIONS_HANDLER_H_ diff --git a/chromium/chrome/browser/ui/webui/settings/site_settings_permissions_handler_unittest.cc b/chromium/chrome/browser/ui/webui/settings/site_settings_permissions_handler_unittest.cc deleted file mode 100644 index 186208b69ce..00000000000 --- a/chromium/chrome/browser/ui/webui/settings/site_settings_permissions_handler_unittest.cc +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2022 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <ctime> -#include <memory> - -#include "base/memory/scoped_refptr.h" -#include "base/test/metrics/histogram_tester.h" -#include "base/test/simple_test_clock.h" -#include "base/time/clock.h" -#include "base/time/time.h" -#include "chrome/browser/content_settings/host_content_settings_map_factory.h" -#include "chrome/browser/history/history_service_factory.h" -#include "chrome/browser/ui/webui/settings/site_settings_helper.h" -#include "chrome/browser/ui/webui/settings/site_settings_permissions_handler.h" -#include "chrome/test/base/testing_profile.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_pattern.h" -#include "components/content_settings/core/common/content_settings_types.h" -#include "components/content_settings/core/common/features.h" -#include "components/permissions/constants.h" -#include "components/permissions/unused_site_permissions_service.h" -#include "content/public/browser/storage_partition.h" -#include "content/public/test/browser_task_environment.h" -#include "content/public/test/test_web_ui.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "url/gurl.h" - -constexpr char kUnusedTestSite[] = "https://example1.com"; -constexpr char kUsedTestSite[] = "https://example2.com"; -constexpr ContentSettingsType kUnusedPermission = - ContentSettingsType::GEOLOCATION; - -class SiteSettingsPermissionsHandlerTest : public testing::Test { - public: - SiteSettingsPermissionsHandlerTest() { - feature_list_.InitAndEnableFeature( - content_settings::features::kSafetyCheckUnusedSitePermissions); - } - - void SetUp() override { - // Fully initialize |profile_| in the constructor since some children - // classes need it right away for SetUp(). - TestingProfile::Builder profile_builder; - profile_builder.AddTestingFactory( - HistoryServiceFactory::GetInstance(), - HistoryServiceFactory::GetDefaultFactory()); - profile_ = profile_builder.Build(); - - // Set clock for HostContentSettingsMap. - base::Time time; - ASSERT_TRUE(base::Time::FromString("2022-09-07 13:00", &time)); - clock_.SetNow(time); - hcsm_ = HostContentSettingsMapFactory::GetForProfile(profile()); - hcsm_->SetClockForTesting(&clock_); - - handler_ = std::make_unique<SiteSettingsPermissionsHandler>(profile()); - handler()->set_web_ui(web_ui()); - handler()->AllowJavascript(); - - // Create a revoked permission. - base::Value::Dict dict = base::Value::Dict(); - base::Value::List permission_type_list = base::Value::List(); - permission_type_list.Append( - static_cast<int32_t>(ContentSettingsType::GEOLOCATION)); - dict.Set(permissions::kRevokedKey, - base::Value::List(std::move(permission_type_list))); - const content_settings::ContentSettingConstraints constraint{ - .expiration = - clock()->Now() + - content_settings::features:: - kSafetyCheckUnusedSitePermissionsRevocationCleanUpThreshold - .Get()}; - - hcsm()->SetWebsiteSettingDefaultScope( - GURL(kUnusedTestSite), GURL(kUnusedTestSite), - ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS, - base::Value(dict.Clone()), constraint); - - // There should be only an unused URL in the revoked permissions list. - const auto& revoked_permissions = - handler()->PopulateUnusedSitePermissionsData(); - EXPECT_EQ(revoked_permissions.size(), 1UL); - EXPECT_EQ(GURL(kUnusedTestSite), - GURL(*revoked_permissions[0].GetDict().FindString( - site_settings::kOrigin))); - handler()->SetClockForTesting(&clock_); - } - - void TearDown() override { - if (profile_) { - auto* partition = profile_->GetDefaultStoragePartition(); - if (partition) { - partition->WaitForDeletionTasksForTesting(); - } - } - } - - void ExpectRevokedPermission() { - ContentSettingsForOneType revoked_permissions_list; - hcsm()->GetSettingsForOneType( - ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS, - &revoked_permissions_list); - EXPECT_EQ(1U, revoked_permissions_list.size()); - EXPECT_EQ( - ContentSetting::CONTENT_SETTING_ASK, - hcsm()->GetContentSetting(GURL(kUnusedTestSite), GURL(kUnusedTestSite), - kUnusedPermission)); - } - - TestingProfile* profile() { return profile_.get(); } - content::TestWebUI* web_ui() { return &web_ui_; } - SiteSettingsPermissionsHandler* handler() { return handler_.get(); } - HostContentSettingsMap* hcsm() { return hcsm_.get(); } - base::SimpleTestClock* clock() { return &clock_; } - - private: - base::test::ScopedFeatureList feature_list_; - content::BrowserTaskEnvironment task_environment_; - std::unique_ptr<SiteSettingsPermissionsHandler> handler_; - std::unique_ptr<TestingProfile> profile_; - content::TestWebUI web_ui_; - scoped_refptr<HostContentSettingsMap> hcsm_; - base::SimpleTestClock clock_; -}; - -TEST_F(SiteSettingsPermissionsHandlerTest, PopulateUnusedSitePermissionsData) { - // Add GEOLOCATION setting for url but do not add to revoked list. - const content_settings::ContentSettingConstraints constraint{ - .expiration = - clock()->Now() + - content_settings::features:: - kSafetyCheckUnusedSitePermissionsRevocationCleanUpThreshold.Get(), - .track_last_visit_for_autoexpiration = true}; - hcsm()->SetContentSettingDefaultScope( - GURL(kUsedTestSite), GURL(kUsedTestSite), - ContentSettingsType::GEOLOCATION, ContentSetting::CONTENT_SETTING_ALLOW, - constraint); - - // Revoked permissions list should still only contain the initial unused site. - const auto& revoked_permissions = - handler()->PopulateUnusedSitePermissionsData(); - EXPECT_EQ(revoked_permissions.size(), 1UL); - EXPECT_EQ(GURL(kUnusedTestSite), - GURL(*revoked_permissions[0].GetDict().FindString( - site_settings::kOrigin))); -} - -TEST_F(SiteSettingsPermissionsHandlerTest, - HandleAllowPermissionsAgainForUnusedSite) { - // Advance 14 days; this will be the expected histogram sample. - clock()->Advance(base::Days(14)); - base::HistogramTester histogram_tester; - base::Value::List initial_unused_site_permissions = - handler()->PopulateUnusedSitePermissionsData(); - ExpectRevokedPermission(); - - // Allow the revoked permission for the unused site again. - base::Value::List args; - args.Append(base::Value(kUnusedTestSite)); - handler()->HandleAllowPermissionsAgainForUnusedSite(args); - - // Only a single entry should be recorded in the histogram. - const std::vector<base::Bucket> buckets = histogram_tester.GetAllSamples( - "Settings.SafetyCheck.UnusedSitePermissionsAllowAgainDays"); - EXPECT_EQ(1U, buckets.size()); - // The recorded metric should be the elapsed days since the revocation. - histogram_tester.ExpectUniqueSample( - "Settings.SafetyCheck.UnusedSitePermissionsAllowAgainDays", 14, 1); - - // Check there is no origin in revoked permissions list. - ContentSettingsForOneType revoked_permissions_list; - hcsm()->GetSettingsForOneType( - ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS, - &revoked_permissions_list); - EXPECT_EQ(0U, revoked_permissions_list.size()); - // Check if the permissions of url is regranted. - EXPECT_EQ( - ContentSetting::CONTENT_SETTING_ALLOW, - hcsm()->GetContentSetting(GURL(kUnusedTestSite), GURL(kUnusedTestSite), - kUnusedPermission)); - - // Undoing restores the initial state. - handler()->HandleUndoAllowPermissionsAgainForUnusedSite( - std::move(initial_unused_site_permissions)); - ExpectRevokedPermission(); -} - -TEST_F(SiteSettingsPermissionsHandlerTest, - HandleAcknowledgeRevokedUnusedSitePermissionsList) { - const auto& revoked_permissions_before = - handler()->PopulateUnusedSitePermissionsData(); - EXPECT_GT(revoked_permissions_before.size(), 0U); - // Acknowledging revoked permissions from unused sites clears the list. - base::Value::List args; - handler()->HandleAcknowledgeRevokedUnusedSitePermissionsList(args); - const auto& revoked_permissions_after = - handler()->PopulateUnusedSitePermissionsData(); - EXPECT_EQ(revoked_permissions_after.size(), 0U); - - // Undo reverts the list to its initial state. - base::Value::List undo_args; - undo_args.Append(revoked_permissions_before.Clone()); - handler()->HandleUndoAcknowledgeRevokedUnusedSitePermissionsList(undo_args); - EXPECT_EQ(revoked_permissions_before, - handler()->PopulateUnusedSitePermissionsData()); -} |