blob: f1a603dc6636066771db488a2a0cf4b076a9e03f [file] [log] [blame]
// Copyright 2015 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/ui/extensions/extension_message_bubble_factory.h"
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/no_destructor.h"
#include "base/stl_util.h"
#include "build/build_config.h"
#include "chrome/browser/extensions/dev_mode_bubble_delegate.h"
#include "chrome/browser/extensions/extension_message_bubble_controller.h"
#include "chrome/browser/extensions/install_verifier.h"
#include "chrome/browser/extensions/proxy_overridden_bubble_delegate.h"
#include "chrome/browser/extensions/settings_api_bubble_delegate.h"
#include "chrome/browser/extensions/settings_api_helpers.h"
#include "chrome/browser/extensions/suspicious_extension_bubble_delegate.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/startup/startup_browser_creator.h"
#include "chrome/common/channel_info.h"
#include "components/version_info/version_info.h"
#include "content/public/common/content_switches.h"
#include "extensions/common/feature_switch.h"
namespace {
// This is used to turn on override whether bubbles are enabled or disabled for
// testing.
ExtensionMessageBubbleFactory::OverrideForTesting g_override_for_testing =
ExtensionMessageBubbleFactory::NO_OVERRIDE;
// A set of all profiles evaluated, so we can tell if it's the initial check.
// TODO(devlin): It would be nice to coalesce all the "profiles evaluated" maps
// that are in the different bubble controllers.
std::set<Profile*>& GetEvaluatedProfiles() {
static base::NoDestructor<std::set<Profile*>> s;
return *s;
}
bool EnableSuspiciousExtensionsBubble() {
return g_override_for_testing ==
ExtensionMessageBubbleFactory::OVERRIDE_ENABLED ||
extensions::InstallVerifier::ShouldEnforce();
}
bool EnableSettingsApiBubble() {
#if defined(OS_WIN) || defined(OS_MACOSX)
return true;
#else
return g_override_for_testing ==
ExtensionMessageBubbleFactory::OVERRIDE_ENABLED;
#endif
}
bool EnableProxyOverrideBubble() {
#if defined(OS_WIN) || defined(OS_MACOSX)
return true;
#else
return g_override_for_testing ==
ExtensionMessageBubbleFactory::OVERRIDE_ENABLED;
#endif
}
bool EnableDevModeBubble() {
if (extensions::FeatureSwitch::force_dev_mode_highlighting()->IsEnabled())
return true;
// If an automated test is controlling the browser, we don't show the dev mode
// bubble because it interferes with focus. This isn't a security concern
// because we'll instead show an (even scarier) infobar. See also
// AutomationInfoBarDelegate.
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kEnableAutomation))
return false;
#if defined(OS_WIN)
if (chrome::GetChannel() >= version_info::Channel::BETA)
return true;
#endif
return g_override_for_testing ==
ExtensionMessageBubbleFactory::OVERRIDE_ENABLED;
}
} // namespace
ExtensionMessageBubbleFactory::ExtensionMessageBubbleFactory(Browser* browser)
: browser_(browser) {
}
ExtensionMessageBubbleFactory::~ExtensionMessageBubbleFactory() {
}
std::unique_ptr<extensions::ExtensionMessageBubbleController>
ExtensionMessageBubbleFactory::GetController() {
Profile* original_profile = browser_->profile()->GetOriginalProfile();
std::set<Profile*>& profiles_evaluated = GetEvaluatedProfiles();
bool is_initial_check = profiles_evaluated.insert(original_profile).second;
std::unique_ptr<extensions::ExtensionMessageBubbleController> controller;
if (g_override_for_testing == OVERRIDE_DISABLED)
return controller;
// The list of suspicious extensions takes priority over the dev mode bubble
// and the settings API bubble, since that needs to be shown as soon as we
// disable something. The settings API bubble is shown on first startup after
// an extension has changed the startup pages and it is acceptable if that
// waits until the next startup because of the suspicious extension bubble.
// The dev mode bubble is not time sensitive like the other two so we'll catch
// the dev mode extensions on the next startup/next window that opens. That
// way, we're not too spammy with the bubbles.
if (EnableSuspiciousExtensionsBubble()) {
controller.reset(
new extensions::ExtensionMessageBubbleController(
new extensions::SuspiciousExtensionBubbleDelegate(
browser_->profile()),
browser_));
if (controller->ShouldShow())
return controller;
}
if (EnableSettingsApiBubble()) {
// No use showing this if it's not the startup of the profile, and if the
// browser was restarted, then we always do a session restore (rather than
// showing normal startup pages).
if (is_initial_check && !StartupBrowserCreator::WasRestarted()) {
controller =
std::make_unique<extensions::ExtensionMessageBubbleController>(
new extensions::SettingsApiBubbleDelegate(
browser_->profile(), extensions::BUBBLE_TYPE_STARTUP_PAGES),
browser_);
if (controller->ShouldShow())
return controller;
}
}
if (EnableProxyOverrideBubble()) {
controller.reset(
new extensions::ExtensionMessageBubbleController(
new extensions::ProxyOverriddenBubbleDelegate(
browser_->profile()),
browser_));
if (controller->ShouldShow())
return controller;
}
if (EnableDevModeBubble()) {
controller.reset(
new extensions::ExtensionMessageBubbleController(
new extensions::DevModeBubbleDelegate(
browser_->profile()),
browser_));
if (controller->ShouldShow())
return controller;
}
controller.reset();
return controller;
}
// static
void ExtensionMessageBubbleFactory::set_override_for_tests(
OverrideForTesting override) {
g_override_for_testing = override;
}