| Index: chrome/browser/ui/views/extensions/extension_message_bubble_view.cc
|
| diff --git a/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc b/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc
|
| index a2b70d479088a19c95ada0f5f36d95aad2d49982..578d693c599f3c1b9db7b2fdcbd6200f058d8c29 100644
|
| --- a/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc
|
| +++ b/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc
|
| @@ -7,9 +7,24 @@
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/string_util.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| +#include "chrome/browser/extensions/dev_mode_bubble_controller.h"
|
| +#include "chrome/browser/extensions/extension_action_manager.h"
|
| #include "chrome/browser/extensions/extension_message_bubble_controller.h"
|
| +#include "chrome/browser/extensions/extension_service.h"
|
| +#include "chrome/browser/extensions/extension_toolbar_model.h"
|
| +#include "chrome/browser/extensions/proxy_overridden_bubble_controller.h"
|
| +#include "chrome/browser/extensions/settings_api_bubble_controller.h"
|
| +#include "chrome/browser/extensions/settings_api_helpers.h"
|
| +#include "chrome/browser/extensions/suspicious_extension_bubble_controller.h"
|
| +#include "chrome/browser/profiles/profile.h"
|
| #include "chrome/browser/ui/view_ids.h"
|
| +#include "chrome/browser/ui/views/frame/browser_view.h"
|
| +#include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
|
| +#include "chrome/browser/ui/views/toolbar/browser_actions_container_observer.h"
|
| +#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
|
| #include "chrome/grit/locale_settings.h"
|
| +#include "extensions/browser/extension_prefs.h"
|
| +#include "extensions/browser/extension_system.h"
|
| #include "ui/accessibility/ax_view_state.h"
|
| #include "ui/base/resource/resource_bundle.h"
|
| #include "ui/views/controls/button/label_button.h"
|
| @@ -20,6 +35,9 @@
|
| #include "ui/views/widget/widget.h"
|
|
|
| namespace {
|
| +
|
| +base::LazyInstance<std::set<Profile*> > g_profiles_evaluated =
|
| + LAZY_INSTANCE_INITIALIZER;
|
|
|
| // Layout constants.
|
| const int kExtensionListPadding = 10;
|
| @@ -61,6 +79,21 @@
|
| set_anchor_view_insets(gfx::Insets(5, 0, 5, 0));
|
| }
|
|
|
| +void ExtensionMessageBubbleView::OnActionButtonClicked(
|
| + const base::Closure& callback) {
|
| + action_callback_ = callback;
|
| +}
|
| +
|
| +void ExtensionMessageBubbleView::OnDismissButtonClicked(
|
| + const base::Closure& callback) {
|
| + dismiss_callback_ = callback;
|
| +}
|
| +
|
| +void ExtensionMessageBubbleView::OnLinkClicked(
|
| + const base::Closure& callback) {
|
| + link_callback_ = callback;
|
| +}
|
| +
|
| void ExtensionMessageBubbleView::Show() {
|
| // Not showing the bubble right away (during startup) has a few benefits:
|
| // We don't have to worry about focus being lost due to the Omnibox (or to
|
| @@ -81,7 +114,7 @@
|
| // To catch Esc, we monitor destroy message. Unless the link has been clicked,
|
| // we assume Dismiss was the action taken.
|
| if (!link_clicked_ && !action_taken_)
|
| - controller_->OnBubbleDismiss();
|
| + dismiss_callback_.Run();
|
| }
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
| @@ -208,7 +241,7 @@
|
| const ui::Event& event) {
|
| if (sender == action_button_) {
|
| action_taken_ = true;
|
| - controller_->OnBubbleAction();
|
| + action_callback_.Run();
|
| } else {
|
| DCHECK_EQ(dismiss_button_, sender);
|
| }
|
| @@ -219,7 +252,7 @@
|
| int event_flags) {
|
| DCHECK_EQ(learn_more_, source);
|
| link_clicked_ = true;
|
| - controller_->OnLinkClicked();
|
| + link_callback_.Run();
|
| GetWidget()->Close();
|
| }
|
|
|
| @@ -234,4 +267,243 @@
|
| NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true);
|
| }
|
|
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +// ExtensionMessageBubbleFactory
|
| +
|
| +ExtensionMessageBubbleFactory::ExtensionMessageBubbleFactory(
|
| + Profile* profile,
|
| + ToolbarView* toolbar_view)
|
| + : profile_(profile),
|
| + toolbar_view_(toolbar_view),
|
| + shown_suspicious_extensions_bubble_(false),
|
| + shown_startup_override_extensions_bubble_(false),
|
| + shown_proxy_override_extensions_bubble_(false),
|
| + shown_dev_mode_extensions_bubble_(false),
|
| + is_observing_(false),
|
| + stage_(STAGE_START),
|
| + container_(NULL),
|
| + anchor_view_(NULL) {}
|
| +
|
| +ExtensionMessageBubbleFactory::~ExtensionMessageBubbleFactory() {
|
| + MaybeStopObserving();
|
| +}
|
| +
|
| +void ExtensionMessageBubbleFactory::MaybeShow(views::View* anchor_view) {
|
| +#if defined(OS_WIN)
|
| + bool is_initial_check = IsInitialProfileCheck(profile_->GetOriginalProfile());
|
| + RecordProfileCheck(profile_->GetOriginalProfile());
|
| +
|
| + // 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 (!shown_suspicious_extensions_bubble_ &&
|
| + MaybeShowSuspiciousExtensionsBubble(anchor_view))
|
| + return;
|
| +
|
| + if (!shown_startup_override_extensions_bubble_ &&
|
| + is_initial_check &&
|
| + MaybeShowStartupOverrideExtensionsBubble(anchor_view))
|
| + return;
|
| +
|
| + if (!shown_proxy_override_extensions_bubble_ &&
|
| + MaybeShowProxyOverrideExtensionsBubble(anchor_view))
|
| + return;
|
| +
|
| + if (!shown_dev_mode_extensions_bubble_)
|
| + MaybeShowDevModeExtensionsBubble(anchor_view);
|
| +#endif // OS_WIN
|
| +}
|
| +
|
| +bool ExtensionMessageBubbleFactory::MaybeShowSuspiciousExtensionsBubble(
|
| + views::View* anchor_view) {
|
| + DCHECK(!shown_suspicious_extensions_bubble_);
|
| +
|
| + scoped_ptr<SuspiciousExtensionBubbleController> suspicious_extensions(
|
| + new SuspiciousExtensionBubbleController(profile_));
|
| + if (!suspicious_extensions->ShouldShow())
|
| + return false;
|
| +
|
| + shown_suspicious_extensions_bubble_ = true;
|
| + SuspiciousExtensionBubbleController* weak_controller =
|
| + suspicious_extensions.get();
|
| + ExtensionMessageBubbleView* bubble_delegate =
|
| + new ExtensionMessageBubbleView(anchor_view,
|
| + views::BubbleBorder::TOP_RIGHT,
|
| + suspicious_extensions.Pass());
|
| +
|
| + views::BubbleDelegateView::CreateBubble(bubble_delegate);
|
| + weak_controller->Show(bubble_delegate);
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool ExtensionMessageBubbleFactory::MaybeShowStartupOverrideExtensionsBubble(
|
| + views::View* anchor_view) {
|
| +#if !defined(OS_WIN)
|
| + return false;
|
| +#else
|
| + DCHECK(!shown_startup_override_extensions_bubble_);
|
| +
|
| + const Extension* extension = GetExtensionOverridingStartupPages(profile_);
|
| + if (!extension)
|
| + return false;
|
| +
|
| + scoped_ptr<SettingsApiBubbleController> settings_api_bubble(
|
| + new SettingsApiBubbleController(profile_,
|
| + BUBBLE_TYPE_STARTUP_PAGES));
|
| + if (!settings_api_bubble->ShouldShow(extension->id()))
|
| + return false;
|
| +
|
| + shown_startup_override_extensions_bubble_ = true;
|
| + PrepareToHighlightExtensions(settings_api_bubble.Pass(), anchor_view);
|
| + return true;
|
| +#endif
|
| +}
|
| +
|
| +bool ExtensionMessageBubbleFactory::MaybeShowProxyOverrideExtensionsBubble(
|
| + views::View* anchor_view) {
|
| +#if !defined(OS_WIN)
|
| + return false;
|
| +#else
|
| + DCHECK(!shown_proxy_override_extensions_bubble_);
|
| +
|
| + const Extension* extension = GetExtensionOverridingProxy(profile_);
|
| + if (!extension)
|
| + return false;
|
| +
|
| + scoped_ptr<ProxyOverriddenBubbleController> proxy_bubble(
|
| + new ProxyOverriddenBubbleController(profile_));
|
| + if (!proxy_bubble->ShouldShow(extension->id()))
|
| + return false;
|
| +
|
| + shown_proxy_override_extensions_bubble_ = true;
|
| + PrepareToHighlightExtensions(proxy_bubble.Pass(), anchor_view);
|
| + return true;
|
| +#endif
|
| +}
|
| +
|
| +bool ExtensionMessageBubbleFactory::MaybeShowDevModeExtensionsBubble(
|
| + views::View* anchor_view) {
|
| + DCHECK(!shown_dev_mode_extensions_bubble_);
|
| +
|
| + // Check the Developer Mode extensions.
|
| + scoped_ptr<DevModeBubbleController> dev_mode_extensions(
|
| + new DevModeBubbleController(profile_));
|
| +
|
| + // Return early if we have none to show.
|
| + if (!dev_mode_extensions->ShouldShow())
|
| + return false;
|
| +
|
| + shown_dev_mode_extensions_bubble_ = true;
|
| + PrepareToHighlightExtensions(dev_mode_extensions.Pass(), anchor_view);
|
| + return true;
|
| +}
|
| +
|
| +void ExtensionMessageBubbleFactory::MaybeObserve() {
|
| + if (!is_observing_) {
|
| + is_observing_ = true;
|
| + container_->AddObserver(this);
|
| + }
|
| +}
|
| +
|
| +void ExtensionMessageBubbleFactory::MaybeStopObserving() {
|
| + if (is_observing_) {
|
| + is_observing_ = false;
|
| + container_->RemoveObserver(this);
|
| + }
|
| +}
|
| +
|
| +void ExtensionMessageBubbleFactory::RecordProfileCheck(Profile* profile) {
|
| + g_profiles_evaluated.Get().insert(profile);
|
| +}
|
| +
|
| +bool ExtensionMessageBubbleFactory::IsInitialProfileCheck(Profile* profile) {
|
| + return g_profiles_evaluated.Get().count(profile) == 0;
|
| +}
|
| +
|
| +void ExtensionMessageBubbleFactory::OnBrowserActionsContainerAnimationEnded() {
|
| + MaybeStopObserving();
|
| + if (stage_ == STAGE_START) {
|
| + HighlightExtensions();
|
| + } else if (stage_ == STAGE_HIGHLIGHTED) {
|
| + ShowHighlightingBubble();
|
| + } else { // We shouldn't be observing if we've completed the process.
|
| + NOTREACHED();
|
| + Finish();
|
| + }
|
| +}
|
| +
|
| +void ExtensionMessageBubbleFactory::OnBrowserActionsContainerDestroyed() {
|
| + // If the container associated with the bubble is destroyed, abandon the
|
| + // process.
|
| + Finish();
|
| +}
|
| +
|
| +void ExtensionMessageBubbleFactory::PrepareToHighlightExtensions(
|
| + scoped_ptr<ExtensionMessageBubbleController> controller,
|
| + views::View* anchor_view) {
|
| + // We should be in the start stage (i.e., should not have a pending attempt to
|
| + // show a bubble).
|
| + DCHECK_EQ(stage_, STAGE_START);
|
| +
|
| + // Prepare to display and highlight the extensions before showing the bubble.
|
| + // Since this is an asynchronous process, set member variables for later use.
|
| + controller_ = controller.Pass();
|
| + anchor_view_ = anchor_view;
|
| + container_ = toolbar_view_->browser_actions();
|
| +
|
| + if (container_->animating())
|
| + MaybeObserve();
|
| + else
|
| + HighlightExtensions();
|
| +}
|
| +
|
| +void ExtensionMessageBubbleFactory::HighlightExtensions() {
|
| + DCHECK_EQ(STAGE_START, stage_);
|
| + stage_ = STAGE_HIGHLIGHTED;
|
| +
|
| + const ExtensionIdList extension_list = controller_->GetExtensionIdList();
|
| + DCHECK(!extension_list.empty());
|
| + ExtensionToolbarModel::Get(profile_)->HighlightExtensions(extension_list);
|
| + if (container_->animating())
|
| + MaybeObserve();
|
| + else
|
| + ShowHighlightingBubble();
|
| +}
|
| +
|
| +void ExtensionMessageBubbleFactory::ShowHighlightingBubble() {
|
| + DCHECK_EQ(stage_, STAGE_HIGHLIGHTED);
|
| + stage_ = STAGE_COMPLETE;
|
| +
|
| + views::View* reference_view = NULL;
|
| + if (container_->num_toolbar_actions() > 0u)
|
| + reference_view = container_->GetToolbarActionViewAt(0);
|
| + if (reference_view && reference_view->visible())
|
| + anchor_view_ = reference_view;
|
| +
|
| + ExtensionMessageBubbleController* weak_controller = controller_.get();
|
| + ExtensionMessageBubbleView* bubble_delegate =
|
| + new ExtensionMessageBubbleView(
|
| + anchor_view_,
|
| + views::BubbleBorder::TOP_RIGHT,
|
| + scoped_ptr<ExtensionMessageBubbleController>(
|
| + controller_.release()));
|
| + views::BubbleDelegateView::CreateBubble(bubble_delegate);
|
| + weak_controller->Show(bubble_delegate);
|
| +
|
| + Finish();
|
| +}
|
| +
|
| +void ExtensionMessageBubbleFactory::Finish() {
|
| + MaybeStopObserving();
|
| + controller_.reset();
|
| + anchor_view_ = NULL;
|
| + container_ = NULL;
|
| +}
|
| +
|
| } // namespace extensions
|
|
|