blob: 6833b35fbf7bb27ef1770d43ceeea9f20e2a2d4a [file] [log] [blame]
// 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