// Copyright 2020 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/ash/settings/pages/main/main_section.h"
#include <string>
#include "ash/constants/ash_features.h"
#include "ash/constants/personalization_entry_point.h"
#include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h"
#include "ash/webui/personalization_app/personalization_app_url_constants.h"
#include "base/feature_list.h"
#include "base/i18n/message_formatter.h"
#include "base/i18n/number_formatting.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
#include "chrome/browser/ash/policy/handlers/minimum_version_policy_handler.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_process_platform_part.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/ash/settings/os_settings_features_util.h"
#include "chrome/browser/ui/webui/ash/settings/pages/main/os_settings_hats_handler.h"
#include "chrome/browser/ui/webui/ash/settings/pages/main/send_search_feedback_handler.h"
#include "chrome/browser/ui/webui/ash/settings/search/search_tag_registry.h"
#include "chrome/browser/ui/webui/metrics_handler.h"
#include "chrome/browser/ui/webui/plural_string_handler.h"
#include "chrome/browser/ui/webui/policy_indicator_localized_strings_provider.h"
#include "chrome/browser/ui/webui/settings/browser_lifetime_handler.h"
#include "chrome/browser/ui/webui/webui_util.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/webui_url_constants.h"
#include "chrome/grit/branded_strings.h"
#include "chrome/grit/browser_resources.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/grit/os_settings_resources.h"
#include "components/strings/grit/components_strings.h"
#include "components/user_manager/user_manager.h"
#include "content/public/browser/web_ui_data_source.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/webui/web_ui_util.h"
#include "ui/chromeos/devicetype_utils.h"
namespace ash::settings {
namespace mojom {
using ::chromeos::settings::mojom::Section;
using ::chromeos::settings::mojom::Setting;
} // namespace mojom
namespace {
void AddSearchInSettingsStrings(content::WebUIDataSource* html_source) {
static constexpr webui::LocalizedString kLocalizedStrings[] = {
{"searchPrompt", IDS_SETTINGS_SEARCH_PROMPT},
{"searchNoResults", IDS_SEARCH_NO_RESULTS},
{"searchResults", IDS_SEARCH_RESULTS},
{"searchResultSelected", IDS_OS_SEARCH_RESULT_ROW_A11Y_RESULT_SELECTED},
{"clearSearch", IDS_CLEAR_SEARCH},
{"searchFeedbackButton", IDS_OS_SETTINGS_SEARCH_FEEDBACK_BUTTON},
{"searchFeedbackDescriptionTemplate",
IDS_OS_SETTINGS_SEARCH_FEEDBACK_DESCRIPTION_TEMPLATE},
};
html_source->AddLocalizedStrings(kLocalizedStrings);
// Used to link to personalization app search results.
html_source->AddString("personalizationAppUrl",
personalization_app::kChromeUIPersonalizationAppURL);
html_source->AddString("ambientSubpageRelativeUrl",
personalization_app::kAmbientSubpageRelativeUrl);
}
void AddUpdateRequiredEolStrings(content::WebUIDataSource* html_source) {
policy::BrowserPolicyConnectorAsh* connector =
g_browser_process->platform_part()->browser_policy_connector_ash();
policy::MinimumVersionPolicyHandler* handler =
connector->GetMinimumVersionPolicyHandler();
bool device_managed = connector->IsDeviceEnterpriseManaged();
// |eol_return_banner_text| contains the update required end of life banner
// text which is left empty when the banner should not be shown.
std::u16string eol_return_banner_text;
if (device_managed && handler->ShouldShowUpdateRequiredEolBanner()) {
std::optional<int> days = handler->GetTimeRemainingInDays();
// We only need to show the banner if less than equal to one week remains to
// reach the update required deadline.
if (days && days.value() <= 7) {
// |days| could have value equal to zero if we are very close to the
// deadline.
int days_remaining = days.value() ? days.value() : 1;
std::u16string domain_name =
base::UTF8ToUTF16(connector->GetEnterpriseDomainManager());
std::u16string link_url = chrome::kChromeUIManagementURL16;
if (days_remaining == 7) {
eol_return_banner_text = l10n_util::GetStringFUTF16(
IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_ONE_WEEK, domain_name,
ui::GetChromeOSDeviceName(), link_url);
} else {
eol_return_banner_text =
base::i18n::MessageFormatter::FormatWithNumberedArgs(
l10n_util::GetStringUTF16(
IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_DAYS),
days_remaining,
base::UTF8ToUTF16(connector->GetEnterpriseDomainManager()),
ui::GetChromeOSDeviceName(),
std::u16string(chrome::kChromeUIManagementURL16));
}
}
}
html_source->AddString("updateRequiredEolBannerText", eol_return_banner_text);
}
} // namespace
MainSection::MainSection(Profile* profile,
SearchTagRegistry* search_tag_registry)
: OsSettingsSection(profile, search_tag_registry) {}
MainSection::~MainSection() = default;
void MainSection::AddLoadTimeData(content::WebUIDataSource* html_source) {
static constexpr webui::LocalizedString kLocalizedStrings[] = {
{"add", IDS_ADD},
{"advancedPageTitle", IDS_SETTINGS_ADVANCED},
{"back", IDS_ACCNAME_BACK},
{"basicPageTitle", IDS_SETTINGS_BASIC},
{"cancel", IDS_CANCEL},
{"clear", IDS_SETTINGS_CLEAR},
{"close", IDS_CLOSE},
{"confirm", IDS_CONFIRM},
{"continue", IDS_SETTINGS_CONTINUE},
{"controlledByExtension", IDS_SETTINGS_CONTROLLED_BY_EXTENSION},
{"custom", IDS_SETTINGS_CUSTOM},
{"delete", IDS_SETTINGS_DELETE},
{"deviceOff", IDS_SETTINGS_DEVICE_OFF},
{"deviceOn", IDS_SETTINGS_DEVICE_ON},
{"disable", IDS_DISABLE},
{"dismiss", IDS_SETTINGS_DISMISS},
{"done", IDS_DONE},
{"edit", IDS_SETTINGS_EDIT},
{"endTime", IDS_SETTINGS_END_TIME},
{"extensionsLinkTooltip", IDS_SETTINGS_MENU_EXTENSIONS_LINK_TOOLTIP},
{"learnMore", IDS_LEARN_MORE},
{"listSeparator", IDS_OS_SETTINGS_LIST_SEPARATOR},
{"shortcutBannerDismissed", IDS_SETTINGS_SHORTCUT_BANNER_DISMISSED},
{"manage", IDS_SETTINGS_MANAGE},
{"menu", IDS_MENU},
{"menuButtonLabel", IDS_SETTINGS_MENU_BUTTON_LABEL},
{"moreActions", IDS_SETTINGS_MORE_ACTIONS},
{"ok", IDS_OK},
{"opensInNewTab", IDS_OS_SETTINGS_OPENS_IN_NEW_TAB_A11Y_LABEL},
{"restart", IDS_SETTINGS_RESTART},
{"save", IDS_SAVE},
{"searchResultBubbleText", IDS_SEARCH_RESULT_BUBBLE_TEXT},
{"searchResultsBubbleText", IDS_SEARCH_RESULTS_BUBBLE_TEXT},
{"settings", IDS_SETTINGS_SETTINGS},
{"settingsAltPageTitle", IDS_SETTINGS_ALT_PAGE_TITLE},
{"startTime", IDS_SETTINGS_START_TIME},
{"subpageArrowRoleDescription", IDS_SETTINGS_SUBPAGE_BUTTON},
{"subpageBackButtonAriaLabel",
IDS_SETTINGS_SUBPAGE_BACK_BUTTON_ARIA_LABEL},
{"subpageBackButtonAriaRoleDescription",
IDS_SETTINGS_SUBPAGE_BACK_BUTTON_ARIA_ROLE_DESCRIPTION},
{"subpageLearnMoreAriaLabel", IDS_SETTINGS_SUBPAGE_LEARN_MORE_ARIA_LABEL},
{"notValidWebAddress", IDS_SETTINGS_NOT_VALID_WEB_ADDRESS},
{"notValidWebAddressForContentType",
IDS_SETTINGS_NOT_VALID_WEB_ADDRESS_FOR_CONTENT_TYPE},
// Common font related strings shown in a11y and appearance sections.
{"quickBrownFox", IDS_SETTINGS_QUICK_BROWN_FOX},
{"verySmall", IDS_SETTINGS_VERY_SMALL_FONT},
{"small", IDS_SETTINGS_SMALL_FONT},
{"medium", IDS_SETTINGS_MEDIUM_FONT},
{"large", IDS_SETTINGS_LARGE_FONT},
{"veryLarge", IDS_SETTINGS_VERY_LARGE_FONT},
};
html_source->AddLocalizedStrings(kLocalizedStrings);
// This handler is for chrome://os-settings.
html_source->AddBoolean("isOSSettings", true);
// Add app-wide feature flags
const bool kIsRevampEnabled =
ash::features::IsOsSettingsRevampWayfindingEnabled();
html_source->AddBoolean("isRevampWayfindingEnabled", kIsRevampEnabled);
html_source->AddString("chromeRefresh2023Attribute",
kIsRevampEnabled ? "chrome-refresh-2023" : "");
html_source->AddBoolean("isGuest", IsGuestModeActive());
html_source->AddBoolean(
"isKioskModeActive",
user_manager::UserManager::Get()->IsLoggedInAsAnyKioskApp());
html_source->AddBoolean("isChild", IsChildUser());
// Add the System Web App resources for Settings.
html_source->AddResourcePath("icon-192.png", IDR_SETTINGS_LOGO_192);
// Add Entry Point resources used for recording entry point metric
// to Personalization Hub though Settings search.
html_source->AddInteger(
"settingsSearchEntryPoint",
static_cast<int>(PersonalizationEntryPoint::kSettingsSearch));
html_source->AddInteger(
"entryPointEnumSize",
static_cast<int>(PersonalizationEntryPoint::kMaxValue) + 1);
AddSearchInSettingsStrings(html_source);
AddChromeOSUserStrings(html_source);
AddUpdateRequiredEolStrings(html_source);
policy_indicator::AddLocalizedStrings(html_source);
}
void MainSection::AddHandlers(content::WebUI* web_ui) {
// Add the metrics handler to write uma stats.
web_ui->AddMessageHandler(std::make_unique<MetricsHandler>());
web_ui->AddMessageHandler(
std::make_unique<::settings::BrowserLifetimeHandler>());
web_ui->AddMessageHandler(CreatePluralStringHandler());
web_ui->AddMessageHandler(std::make_unique<SendSearchFeedbackHandler>());
web_ui->AddMessageHandler(std::make_unique<OsSettingsHatsHandler>(profile()));
}
int MainSection::GetSectionNameMessageId() const {
NOTIMPLEMENTED();
return 0;
}
mojom::Section MainSection::GetSection() const {
NOTIMPLEMENTED();
return mojom::Section::kMinValue;
}
mojom::SearchResultIcon MainSection::GetSectionIcon() const {
NOTIMPLEMENTED();
return mojom::SearchResultIcon::kMinValue;
}
const char* MainSection::GetSectionPath() const {
NOTIMPLEMENTED();
return "";
}
bool MainSection::LogMetric(mojom::Setting setting, base::Value& value) const {
NOTIMPLEMENTED();
return false;
}
void MainSection::RegisterHierarchy(HierarchyGenerator* generator) const {
// MainSection is a container for common resources/functionality shared
// between sections and does not have its own subpages/settings.
NOTIMPLEMENTED();
}
void MainSection::AddChromeOSUserStrings(
content::WebUIDataSource* html_source) {
const user_manager::User* user =
ProfileHelper::Get()->GetUserByProfile(profile());
const user_manager::User* primary_user =
user_manager::UserManager::Get()->GetPrimaryUser();
std::string primary_user_email = primary_user->GetDisplayEmail();
html_source->AddString("primaryUserEmail", primary_user_email);
html_source->AddBoolean(
"isSecondaryUser",
user && user->GetAccountId() != primary_user->GetAccountId());
html_source->AddString(
"secondaryUserBannerText",
l10n_util::GetStringFUTF16(IDS_SETTINGS_SECONDARY_USER_BANNER,
base::ASCIIToUTF16(primary_user_email)));
html_source->AddString(
"sublabelWithEmail",
l10n_util::GetStringFUTF16(IDS_BLUETOOTH_SAVED_DEVICES_SUBTITLE,
base::ASCIIToUTF16(primary_user_email)));
html_source->AddString(
"noDevicesWithEmail",
l10n_util::GetStringFUTF16(IDS_BLUETOOTH_NO_SAVED_DEVICES_LABEL,
base::ASCIIToUTF16(primary_user_email)));
html_source->AddString(
"loadingDevicesWithEmail",
l10n_util::GetStringFUTF16(IDS_BLUETOOTH_SAVED_DEVICES_LOADING_LABEL,
base::ASCIIToUTF16(primary_user_email)));
html_source->AddString(
"savedDevicesErrorWithEmail",
l10n_util::GetStringFUTF16(IDS_BLUETOOTH_SAVED_DEVICES_ERROR_LABEL,
base::ASCIIToUTF16(primary_user_email)));
}
std::unique_ptr<PluralStringHandler> MainSection::CreatePluralStringHandler() {
auto plural_string_handler = std::make_unique<PluralStringHandler>();
plural_string_handler->AddLocalizedString("profileLabel",
IDS_OS_SETTINGS_PROFILE_LABEL_V2);
plural_string_handler->AddLocalizedString(
"nearbyShareContactVisibilityNumUnreachable",
IDS_NEARBY_CONTACT_VISIBILITY_NUM_UNREACHABLE_PH);
plural_string_handler->AddLocalizedString(
"lockScreenNumberFingerprints",
IDS_SETTINGS_PEOPLE_LOCK_SCREEN_NUM_FINGERPRINTS);
plural_string_handler->AddLocalizedString(
"remapKeyboardKeysRowSubLabel",
IDS_SETTINGS_KEYBOARD_REMAP_KEYS_ROW_SUB_LABEL);
return plural_string_handler;
}
} // namespace ash::settings