| // Copyright 2014 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/extensions/settings_api_bubble_helpers.h" |
| |
| #include <utility> |
| |
| #include "base/auto_reset.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" |
| #include "chrome/browser/ui/extensions/controlled_home_dialog_controller.h" |
| #include "chrome/browser/ui/extensions/extension_settings_overridden_dialog.h" |
| #include "chrome/browser/ui/extensions/extensions_dialogs.h" |
| #include "chrome/browser/ui/extensions/settings_overridden_params_providers.h" |
| #include "chrome/common/url_constants.h" |
| #include "components/prefs/pref_registry.h" |
| #include "components/prefs/pref_registry_simple.h" |
| #include "content/public/browser/browser_url_handler.h" |
| #include "content/public/browser/navigation_controller.h" |
| #include "content/public/browser/navigation_entry.h" |
| #include "content/public/browser/web_contents.h" |
| #include "extensions/browser/extension_prefs.h" |
| #include "extensions/common/constants.h" |
| #include "extensions/common/manifest_handlers/chrome_url_overrides_handler.h" |
| #include "ui/base/base_window.h" |
| |
| namespace extensions { |
| |
| namespace { |
| |
| // Whether the NTP post-install UI is enabled. By default, this is limited to |
| // Windows, Mac, ChromeOS, and Desktop Android but can be overridden for |
| // testing. |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS) || \ |
| BUILDFLAG(IS_ANDROID) |
| bool g_ntp_post_install_ui_enabled = true; |
| #else |
| bool g_ntp_post_install_ui_enabled = false; |
| #endif |
| |
| // Whether to acknowledge existing extensions overriding the NTP for the active |
| // profile. Active on MacOS to rollout the NTP bubble without prompting for |
| // previously-installed extensions. |
| // TODO(devlin): This has been rolled out on Mac for awhile; we can flip this to |
| // false (and keep the logic around for when/if we decide to expand the warning |
| // treatment to Linux). |
| bool g_acknowledge_existing_ntp_extensions = |
| #if BUILDFLAG(IS_MAC) |
| true; |
| #else |
| false; |
| #endif |
| |
| // The name of the preference indicating whether existing NTP extensions have |
| // been automatically acknowledged. |
| const char kDidAcknowledgeExistingNtpExtensions[] = |
| "ack_existing_ntp_extensions"; |
| |
| } // namespace |
| |
| // Whether a given ntp-overriding extension has been acknowledged by the user. |
| // The terse key value is because the pref has migrated between code layers. |
| const char kNtpOverridingExtensionAcknowledged[] = "ack_ntp_bubble"; |
| |
| void SetNtpPostInstallUiEnabledForTesting(bool enabled) { |
| g_ntp_post_install_ui_enabled = enabled; |
| } |
| |
| base::AutoReset<bool> SetAcknowledgeExistingNtpExtensionsForTesting( |
| bool should_acknowledge) { |
| return base::AutoReset<bool>(&g_acknowledge_existing_ntp_extensions, |
| should_acknowledge); |
| } |
| |
| void AcknowledgePreExistingNtpExtensions(Profile* profile) { |
| DCHECK(g_acknowledge_existing_ntp_extensions); |
| |
| ExtensionRegistry* registry = ExtensionRegistry::Get(profile); |
| PrefService* profile_prefs = profile->GetPrefs(); |
| // Only acknowledge existing extensions once per profile. |
| if (profile_prefs->GetBoolean(kDidAcknowledgeExistingNtpExtensions)) { |
| return; |
| } |
| |
| profile_prefs->SetBoolean(kDidAcknowledgeExistingNtpExtensions, true); |
| ExtensionPrefs* prefs = ExtensionPrefs::Get(profile); |
| for (const auto& extension : registry->enabled_extensions()) { |
| const URLOverrides::URLOverrideMap& overrides = |
| URLOverrides::GetChromeURLOverrides(extension.get()); |
| if (overrides.find(chrome::kChromeUINewTabHost) != overrides.end()) { |
| prefs->UpdateExtensionPref(extension->id(), |
| kNtpOverridingExtensionAcknowledged, |
| base::Value(true)); |
| } |
| } |
| } |
| |
| void RegisterSettingsOverriddenUiPrefs(PrefRegistrySimple* registry) { |
| registry->RegisterBooleanPref(kDidAcknowledgeExistingNtpExtensions, false, |
| PrefRegistry::NO_REGISTRATION_FLAGS); |
| } |
| |
| void MaybeShowExtensionControlledHomeNotification( |
| BrowserWindowInterface* browser, |
| content::WebContents* web_contents) { |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) |
| auto* profile = browser->GetProfile(); |
| auto bubble_delegate = |
| std::make_unique<ControlledHomeDialogController>(profile, web_contents); |
| if (!bubble_delegate->ShouldShow()) { |
| return; |
| } |
| |
| bubble_delegate->PendingShow(); |
| ShowControlledHomeDialog(profile, browser->GetWindow()->GetNativeWindow(), |
| std::move(bubble_delegate)); |
| #endif |
| } |
| |
| void MaybeShowExtensionControlledSearchNotification( |
| content::WebContents* web_contents, |
| AutocompleteMatch::Type match_type) { |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) |
| if (!AutocompleteMatch::IsSearchType(match_type) || |
| match_type == AutocompleteMatchType::SEARCH_OTHER_ENGINE) { |
| return; |
| } |
| |
| Profile* profile = |
| Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
| if (!profile) { |
| return; |
| } |
| |
| std::optional<ExtensionSettingsOverriddenDialog::Params> params = |
| settings_overridden_params::GetSearchOverriddenParams(profile); |
| if (!params) { |
| return; |
| } |
| |
| auto dialog = std::make_unique<ExtensionSettingsOverriddenDialog>( |
| std::move(*params), profile); |
| if (!dialog->ShouldShow()) { |
| return; |
| } |
| |
| gfx::NativeWindow parent_window = web_contents->GetTopLevelNativeWindow(); |
| ShowSettingsOverriddenDialog(std::move(dialog), parent_window); |
| #endif |
| } |
| |
| void MaybeShowExtensionControlledNewTabPage( |
| BrowserWindowInterface* browser, |
| content::WebContents* web_contents) { |
| if (!g_ntp_post_install_ui_enabled) { |
| return; |
| } |
| |
| // Acknowledge existing extensions if necessary. |
| if (g_acknowledge_existing_ntp_extensions) { |
| AcknowledgePreExistingNtpExtensions(browser->GetProfile()); |
| } |
| |
| // Jump through a series of hoops to see if the web contents is pointing to |
| // an extension-controlled NTP. |
| // TODO(devlin): Some of this is redundant with the checks in the bubble/ |
| // dialog. We should consolidate, but that'll be simpler once we only have |
| // one UI option. In the meantime, extra checks don't hurt. |
| content::NavigationEntry* entry = |
| web_contents->GetController().GetVisibleEntry(); |
| if (!entry) { |
| return; |
| } |
| GURL active_url = entry->GetURL(); |
| if (!active_url.SchemeIs(extensions::kExtensionScheme)) { |
| return; // Not a URL that we care about. |
| } |
| |
| // See if the current active URL matches a transformed NewTab URL. |
| GURL ntp_url(chrome::kChromeUINewTabURL); |
| content::BrowserURLHandler::GetInstance()->RewriteURLIfNecessary( |
| &ntp_url, web_contents->GetBrowserContext()); |
| if (ntp_url != active_url) { |
| return; // Not being overridden by an extension. |
| } |
| |
| Profile* const profile = browser->GetProfile(); |
| |
| std::optional<ExtensionSettingsOverriddenDialog::Params> params = |
| settings_overridden_params::GetNtpOverriddenParams(profile); |
| if (!params) { |
| return; |
| } |
| |
| auto dialog = std::make_unique<ExtensionSettingsOverriddenDialog>( |
| std::move(*params), profile); |
| if (!dialog->ShouldShow()) { |
| return; |
| } |
| |
| ShowSettingsOverriddenDialog(std::move(dialog), |
| browser->GetWindow()->GetNativeWindow()); |
| } |
| |
| } // namespace extensions |