blob: 034c89a5ad5d3f72fab7b2a088cede87218e2ff5 [file] [log] [blame]
// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/ntp_overridden_bubble_delegate.h"
#include <memory>
#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_web_ui.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/generated_resources.h"
#include "components/prefs/pref_registry.h"
#include "components/prefs/pref_registry_simple.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
#include "ui/base/l10n/l10n_util.h"
namespace {
// Whether the user has been notified about extension overriding the new tab
// page.
const char kNtpBubbleAcknowledged[] = "ack_ntp_bubble";
// Whether existing NTP extensions have been automatically acknowledged.
const char kDidAcknowledgeExistingNtpExtensions[] =
"ack_existing_ntp_extensions";
// Whether to acknowledge existing extensions overriding the NTP for the active
// profile. Active on ChromeOS to rollout the NTP bubble without prompting for
// previously-installed extensions.
bool g_acknowledge_existing_extensions =
#if defined(OS_CHROMEOS)
true;
#else
false;
#endif
base::LazyInstance<std::set<std::pair<Profile*, std::string>>>::Leaky g_shown =
LAZY_INSTANCE_INITIALIZER;
} // namespace
namespace extensions {
NtpOverriddenBubbleDelegate::NtpOverriddenBubbleDelegate(Profile* profile)
: extensions::ExtensionMessageBubbleController::Delegate(profile),
profile_(profile) {
set_acknowledged_flag_pref_name(kNtpBubbleAcknowledged);
}
NtpOverriddenBubbleDelegate::~NtpOverriddenBubbleDelegate() {}
// static
void NtpOverriddenBubbleDelegate::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(kDidAcknowledgeExistingNtpExtensions, false,
PrefRegistry::NO_REGISTRATION_FLAGS);
}
// static
void NtpOverriddenBubbleDelegate::MaybeAcknowledgeExistingNtpExtensions(
Profile* profile) {
if (!g_acknowledge_existing_extensions)
return;
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(), kNtpBubbleAcknowledged,
std::make_unique<base::Value>(true));
}
}
}
bool NtpOverriddenBubbleDelegate::ShouldIncludeExtension(
const extensions::Extension* extension) {
if (!extension_id_.empty() && extension_id_ != extension->id())
return false;
GURL url(chrome::kChromeUINewTabURL);
if (!ExtensionWebUI::HandleChromeURLOverride(&url, profile()))
return false; // No override for newtab found.
if (extension->id() != url.host_piece())
return false;
if (HasBubbleInfoBeenAcknowledged(extension->id()))
return false;
extension_id_ = extension->id();
return true;
}
void NtpOverriddenBubbleDelegate::AcknowledgeExtension(
const std::string& extension_id,
ExtensionMessageBubbleController::BubbleAction user_action) {
if (user_action != ExtensionMessageBubbleController::ACTION_EXECUTE)
SetBubbleInfoBeenAcknowledged(extension_id, true);
}
void NtpOverriddenBubbleDelegate::PerformAction(
const extensions::ExtensionIdList& list) {
for (size_t i = 0; i < list.size(); ++i) {
service()->DisableExtension(
list[i], extensions::disable_reason::DISABLE_USER_ACTION);
}
}
base::string16 NtpOverriddenBubbleDelegate::GetTitle() const {
return l10n_util::GetStringUTF16(
IDS_EXTENSIONS_NTP_CONTROLLED_TITLE_HOME_PAGE_BUBBLE);
}
base::string16 NtpOverriddenBubbleDelegate::GetMessageBody(
bool anchored_to_browser_action,
int extension_count) const {
base::string16 body =
l10n_util::GetStringUTF16(IDS_EXTENSIONS_NTP_CONTROLLED_FIRST_LINE);
body += l10n_util::GetStringUTF16(
IDS_EXTENSIONS_SETTINGS_API_THIRD_LINE_CONFIRMATION);
return body;
}
base::string16 NtpOverriddenBubbleDelegate::GetOverflowText(
const base::string16& overflow_count) const {
// Does not have more than one extension in the list at a time.
NOTREACHED();
return base::string16();
}
GURL NtpOverriddenBubbleDelegate::GetLearnMoreUrl() const {
return GURL(chrome::kExtensionControlledSettingLearnMoreURL);
}
base::string16 NtpOverriddenBubbleDelegate::GetActionButtonLabel() const {
return l10n_util::GetStringUTF16(IDS_EXTENSION_CONTROLLED_RESTORE_SETTINGS);
}
base::string16 NtpOverriddenBubbleDelegate::GetDismissButtonLabel() const {
return l10n_util::GetStringUTF16(IDS_EXTENSION_CONTROLLED_KEEP_CHANGES);
}
bool NtpOverriddenBubbleDelegate::ShouldCloseOnDeactivate() const {
return true;
}
bool NtpOverriddenBubbleDelegate::ShouldAcknowledgeOnDeactivate() const {
return base::FeatureList::IsEnabled(
features::kAcknowledgeNtpOverrideOnDeactivate);
}
bool NtpOverriddenBubbleDelegate::ShouldShowExtensionList() const {
return false;
}
bool NtpOverriddenBubbleDelegate::ShouldHighlightExtensions() const {
return false;
}
bool NtpOverriddenBubbleDelegate::ShouldLimitToEnabledExtensions() const {
return true;
}
bool NtpOverriddenBubbleDelegate::ShouldShow(
const ExtensionIdList& extensions) const {
DCHECK_EQ(1u, extensions.size());
return !g_shown.Get().count(std::make_pair(profile_, extensions[0]));
}
void NtpOverriddenBubbleDelegate::OnShown(const ExtensionIdList& extensions) {
DCHECK_EQ(1u, extensions.size());
DCHECK(!g_shown.Get().count(std::make_pair(profile_, extensions[0])));
g_shown.Get().insert(std::make_pair(profile_, extensions[0]));
}
void NtpOverriddenBubbleDelegate::OnAction() {
// We clear the profile set because the user chooses to remove or disable the
// extension. Thus if that extension or another takes effect, it is worth
// mentioning to the user (ShouldShow() would return true) because it is
// contrary to the user's choice.
g_shown.Get().clear();
}
void NtpOverriddenBubbleDelegate::ClearProfileSetForTesting() {
g_shown.Get().clear();
}
void NtpOverriddenBubbleDelegate::LogExtensionCount(size_t count) {
}
void NtpOverriddenBubbleDelegate::LogAction(
ExtensionMessageBubbleController::BubbleAction action) {
UMA_HISTOGRAM_ENUMERATION(
"ExtensionOverrideBubble.NtpOverriddenUserSelection",
action,
ExtensionMessageBubbleController::ACTION_BOUNDARY);
}
bool NtpOverriddenBubbleDelegate::SupportsPolicyIndicator() {
return true;
}
void NtpOverriddenBubbleDelegate::
set_acknowledge_existing_extensions_for_testing(
bool acknowledge_existing_extensions) {
g_acknowledge_existing_extensions = acknowledge_existing_extensions;
}
} // namespace extensions