| // Copyright 2015 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/chrome/browser/ui/webui/flags_ui.h" |
| |
| #import <memory> |
| #import <string> |
| #import <utility> |
| |
| #import "base/functional/bind.h" |
| #import "base/functional/callback_helpers.h" |
| #import "base/memory/ptr_util.h" |
| #import "base/strings/utf_string_conversions.h" |
| #import "base/values.h" |
| #import "build/branding_buildflags.h" |
| #import "components/flags_ui/flags_ui_constants.h" |
| #import "components/flags_ui/flags_ui_pref_names.h" |
| #import "components/flags_ui/pref_service_flags_storage.h" |
| #import "components/grit/flags_ui_resources.h" |
| #import "components/prefs/pref_registry_simple.h" |
| #import "components/prefs/pref_service.h" |
| #import "components/strings/grit/components_chromium_strings.h" |
| #import "components/strings/grit/components_strings.h" |
| #import "components/version_info/version_info.h" |
| #import "ios/chrome/browser/flags/about_flags.h" |
| #import "ios/chrome/browser/shared/model/application_context/application_context.h" |
| #import "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h" |
| #import "ios/chrome/browser/shared/model/url/chrome_url_constants.h" |
| #import "ios/web/public/webui/web_ui_ios.h" |
| #import "ios/web/public/webui/web_ui_ios_data_source.h" |
| #import "ios/web/public/webui/web_ui_ios_message_handler.h" |
| #import "ui/base/l10n/l10n_util.h" |
| #import "ui/base/resource/resource_bundle.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| namespace { |
| |
| web::WebUIIOSDataSource* CreateFlagsUIHTMLSource() { |
| web::WebUIIOSDataSource* source = |
| web::WebUIIOSDataSource::Create(kChromeUIFlagsHost); |
| source->AddString(flags_ui::kVersion, |
| std::string(version_info::GetVersionNumber())); |
| |
| source->UseStringsJs(); |
| FlagsUI::AddFlagsIOSStrings(source); |
| source->AddResourcePath(flags_ui::kFlagsJS, IDR_FLAGS_UI_FLAGS_JS); |
| source->AddResourcePath(flags_ui::kFlagsCSS, IDR_FLAGS_UI_FLAGS_CSS); |
| source->SetDefaultResource(IDR_FLAGS_UI_FLAGS_HTML); |
| source->UseStringsJs(); |
| return source; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // FlagsDOMHandler |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| // The handler for Javascript messages for the about:flags page. |
| class FlagsDOMHandler : public web::WebUIIOSMessageHandler { |
| public: |
| FlagsDOMHandler() : access_(flags_ui::kGeneralAccessFlagsOnly) {} |
| |
| FlagsDOMHandler(const FlagsDOMHandler&) = delete; |
| FlagsDOMHandler& operator=(const FlagsDOMHandler&) = delete; |
| |
| ~FlagsDOMHandler() override {} |
| |
| // Initializes the DOM handler with the provided flags storage and flags |
| // access. If there were flags experiments requested from javascript before |
| // this was called, it calls `HandleRequestExperimentalFeatures` again. |
| void Init(std::unique_ptr<flags_ui::FlagsStorage> flags_storage, |
| flags_ui::FlagAccess access); |
| |
| // WebUIMessageHandler implementation. |
| void RegisterMessages() override; |
| |
| // Callback for the "requestExperimentFeatures" message. |
| void HandleRequestExperimentalFeatures(const base::Value::List& args); |
| |
| // Callback for the "enableExperimentalFeature" message. |
| void HandleEnableExperimentalFeatureMessage(const base::Value::List& args); |
| |
| // Callback for the "restartBrowser" message. Restores all tabs on restart. |
| void HandleRestartBrowser(const base::Value::List& args); |
| |
| // Callback for the "resetAllFlags" message. |
| void HandleResetAllFlags(const base::Value::List& args); |
| |
| private: |
| std::unique_ptr<flags_ui::FlagsStorage> flags_storage_; |
| flags_ui::FlagAccess access_; |
| }; |
| |
| void FlagsDOMHandler::RegisterMessages() { |
| web_ui()->RegisterMessageCallback( |
| flags_ui::kRequestExperimentalFeatures, |
| base::BindRepeating(&FlagsDOMHandler::HandleRequestExperimentalFeatures, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| flags_ui::kEnableExperimentalFeature, |
| base::BindRepeating( |
| &FlagsDOMHandler::HandleEnableExperimentalFeatureMessage, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| flags_ui::kRestartBrowser, |
| base::BindRepeating(&FlagsDOMHandler::HandleRestartBrowser, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| flags_ui::kResetAllFlags, |
| base::BindRepeating(&FlagsDOMHandler::HandleResetAllFlags, |
| base::Unretained(this))); |
| } |
| |
| void FlagsDOMHandler::Init( |
| std::unique_ptr<flags_ui::FlagsStorage> flags_storage, |
| flags_ui::FlagAccess access) { |
| flags_storage_ = std::move(flags_storage); |
| access_ = access; |
| } |
| |
| void FlagsDOMHandler::HandleRequestExperimentalFeatures( |
| const base::Value::List& args) { |
| DCHECK(flags_storage_); |
| DCHECK(!args.empty()); |
| const base::Value& callback_id = args[0]; |
| |
| base::Value::List supported_features; |
| base::Value::List unsupported_features; |
| GetFlagFeatureEntries(flags_storage_.get(), access_, supported_features, |
| unsupported_features); |
| |
| base::Value::Dict results; |
| results.Set(flags_ui::kSupportedFeatures, std::move(supported_features)); |
| results.Set(flags_ui::kUnsupportedFeatures, std::move(unsupported_features)); |
| |
| results.Set(flags_ui::kNeedsRestart, IsRestartNeededToCommitChanges()); |
| results.Set(flags_ui::kShowOwnerWarning, |
| access_ == flags_ui::kGeneralAccessFlagsOnly); |
| |
| results.Set(flags_ui::kShowBetaChannelPromotion, false); |
| results.Set(flags_ui::kShowDevChannelPromotion, false); |
| |
| web_ui()->ResolveJavascriptCallback(callback_id, results); |
| } |
| |
| void FlagsDOMHandler::HandleEnableExperimentalFeatureMessage( |
| const base::Value::List& args) { |
| DCHECK(flags_storage_); |
| DCHECK_EQ(2u, args.size()); |
| if (args.size() != 2) |
| return; |
| |
| const std::string* entry_internal_name = args[0].GetIfString(); |
| const std::string* enable_str = args[1].GetIfString(); |
| if (!entry_internal_name || !enable_str) |
| return; |
| |
| SetFeatureEntryEnabled(flags_storage_.get(), *entry_internal_name, |
| *enable_str == "true"); |
| flags_storage_->CommitPendingWrites(); |
| } |
| |
| void FlagsDOMHandler::HandleRestartBrowser(const base::Value::List& args) { |
| #if BUILDFLAG(CHROMIUM_BRANDING) |
| CHECK(false); |
| #endif // BUILDFLAG(CHROMIUM_BRANDING) |
| } |
| |
| void FlagsDOMHandler::HandleResetAllFlags(const base::Value::List& args) { |
| DCHECK(flags_storage_); |
| ResetAllFlags(flags_storage_.get()); |
| flags_storage_->CommitPendingWrites(); |
| } |
| |
| } // namespace |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // FlagsUI |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| FlagsUI::FlagsUI(web::WebUIIOS* web_ui, const std::string& host) |
| : web::WebUIIOSController(web_ui, host), weak_factory_(this) { |
| FlagsDOMHandler* handler = new FlagsDOMHandler(); |
| web_ui->AddMessageHandler(base::WrapUnique(handler)); |
| |
| flags_ui::FlagAccess flag_access = flags_ui::kOwnerAccessToFlags; |
| handler->Init(std::make_unique<flags_ui::PrefServiceFlagsStorage>( |
| GetApplicationContext()->GetLocalState()), |
| flag_access); |
| |
| // Set up the about:flags source. |
| web::WebUIIOSDataSource::Add(ChromeBrowserState::FromWebUIIOS(web_ui), |
| CreateFlagsUIHTMLSource()); |
| } |
| |
| FlagsUI::~FlagsUI() {} |
| |
| // static |
| void FlagsUI::AddFlagsIOSStrings(web::WebUIIOSDataSource* source) { |
| // Strings added here are all marked a non-translatable, so they are not |
| // actually localized. |
| source->AddLocalizedString(flags_ui::kFlagsRestartNotice, |
| IDS_FLAGS_UI_RELAUNCH_NOTICE); |
| source->AddLocalizedString("available", IDS_FLAGS_UI_AVAILABLE_FEATURE); |
| source->AddLocalizedString("clear-search", IDS_FLAGS_UI_CLEAR_SEARCH); |
| source->AddLocalizedString("disabled", IDS_FLAGS_UI_DISABLED_FEATURE); |
| source->AddLocalizedString("enabled", IDS_FLAGS_UI_ENABLED_FEATURE); |
| source->AddLocalizedString("experiment-enabled", |
| IDS_FLAGS_UI_EXPERIMENT_ENABLED); |
| source->AddLocalizedString("heading", IDS_FLAGS_UI_TITLE); |
| source->AddLocalizedString("no-results", IDS_FLAGS_UI_NO_RESULTS); |
| source->AddLocalizedString("not-available-platform", |
| IDS_FLAGS_UI_NOT_AVAILABLE_ON_PLATFORM); |
| source->AddLocalizedString("page-warning", IDS_FLAGS_UI_PAGE_WARNING); |
| source->AddLocalizedString("page-warning-explanation", |
| IDS_FLAGS_UI_PAGE_WARNING_EXPLANATION); |
| source->AddLocalizedString("relaunch", IDS_FLAGS_UI_RELAUNCH); |
| source->AddLocalizedString("reset", IDS_FLAGS_UI_PAGE_RESET); |
| source->AddLocalizedString("reset-acknowledged", |
| IDS_FLAGS_UI_RESET_ACKNOWLEDGED); |
| source->AddLocalizedString("search-label", IDS_FLAGS_UI_SEARCH_LABEL); |
| source->AddLocalizedString("search-placeholder", |
| IDS_FLAGS_UI_SEARCH_PLACEHOLDER); |
| source->AddLocalizedString("title", IDS_FLAGS_UI_TITLE); |
| source->AddLocalizedString("unavailable", IDS_FLAGS_UI_UNAVAILABLE_FEATURE); |
| source->AddLocalizedString("searchResultsSingular", |
| IDS_FLAGS_UI_SEARCH_RESULTS_SINGULAR); |
| source->AddLocalizedString("searchResultsPlural", |
| IDS_FLAGS_UI_SEARCH_RESULTS_PLURAL); |
| } |