blob: 3bbd2fd8c303df238f4ce537166addb18673f6cf [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_MESSAGE_BUBBLE_CONTROLLER_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_MESSAGE_BUBBLE_CONTROLLER_H_
#include <stddef.h>
#include <string>
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_registry_observer.h"
#include "extensions/common/extension_id.h"
class Browser;
class ToolbarActionsModel;
class Profile;
namespace extensions {
class Extension;
class ExtensionService;
class ExtensionMessageBubbleController : public BrowserListObserver,
public ExtensionRegistryObserver {
public:
// UMA histogram constants.
enum BubbleAction {
ACTION_LEARN_MORE = 0,
ACTION_EXECUTE,
ACTION_DISMISS_USER_ACTION,
ACTION_DISMISS_DEACTIVATION,
ACTION_BOUNDARY, // Must be the last value.
};
class Delegate {
public:
explicit Delegate(Profile* profile);
Delegate(const Delegate&) = delete;
Delegate& operator=(const Delegate&) = delete;
virtual ~Delegate();
virtual bool ShouldIncludeExtension(const Extension* extension) = 0;
virtual void AcknowledgeExtension(
const std::string& extension_id,
BubbleAction action) = 0;
virtual void PerformAction(const ExtensionIdList& list) = 0;
// Text for various UI labels shown in the bubble.
virtual std::u16string GetTitle() const = 0;
// Fetches the message to show in the body. |anchored_to_browser_action|
// will be true if the bubble is anchored against a specific extension
// icon, allowing the bubble to show a different message than when it is
// anchored against something else (e.g. show "This extension has..."
// instead of "An extension has...").
// |extension_count| is the number of extensions being referenced.
virtual std::u16string GetMessageBody(bool anchored_to_browser_action,
int extension_count) const = 0;
virtual std::u16string GetOverflowText(
const std::u16string& overflow_count) const = 0;
virtual std::u16string GetLearnMoreLabel() const;
virtual GURL GetLearnMoreUrl() const = 0;
virtual std::u16string GetActionButtonLabel() const = 0;
virtual std::u16string GetDismissButtonLabel() const = 0;
// Returns true if the bubble should close when the widget deactivates.
virtual bool ShouldCloseOnDeactivate() const = 0;
// Returns true if the bubble should be shown. Called if and only if there
// is at least one extension in |extensions|.
virtual bool ShouldShow(const ExtensionIdList& extensions) const = 0;
// Called when the bubble is actually shown. Because some bubbles are
// delayed (in order to weather the "focus storm"), they are not shown
// immediately.
virtual void OnShown(const ExtensionIdList& extensions) = 0;
// Called when the user takes an acknowledging action (e.g. Accept or
// Cancel) on the displayed bubble, so that the bubble can do any additional
// cleanup. The action, if any, will be handled separately (through e.g.
// AcknowledgeExtension()).
virtual void OnAction();
// Clears the delegate's internal set of profiles that the bubble has been
// shown.
virtual void ClearProfileSetForTesting() = 0;
// Whether to show a list of extensions in the bubble.
virtual bool ShouldShowExtensionList() const = 0;
// Returns true if only enabled extensions should be considered.
virtual bool ShouldLimitToEnabledExtensions() const = 0;
// Returns true if the bubble is informing about a single extension that can
// be policy-installed.
// E.g. A proxy-type extension can be policy installed, but a developer-type
// extension cannot.
virtual bool SupportsPolicyIndicator() = 0;
// Has the user acknowledged info about the extension the bubble reports.
bool HasBubbleInfoBeenAcknowledged(const std::string& extension_id);
void SetBubbleInfoBeenAcknowledged(const std::string& extension_id,
bool value);
protected:
Profile* profile() { return profile_; }
ExtensionService* service() { return service_; }
const ExtensionRegistry* registry() const { return registry_; }
std::string get_acknowledged_flag_pref_name() const;
void set_acknowledged_flag_pref_name(const std::string& pref_name);
private:
// A weak pointer to the profile we are associated with. Not owned by us.
raw_ptr<Profile> profile_;
// The extension service associated with the profile.
raw_ptr<ExtensionService> service_;
// The extension registry associated with the profile.
raw_ptr<ExtensionRegistry> registry_;
// Name for corresponding pref that keeps if the info the bubble contains
// was acknowledged by user.
std::string acknowledged_pref_name_;
};
ExtensionMessageBubbleController(Delegate* delegate, Browser* browser);
ExtensionMessageBubbleController(const ExtensionMessageBubbleController&) =
delete;
ExtensionMessageBubbleController& operator=(
const ExtensionMessageBubbleController&) = delete;
~ExtensionMessageBubbleController() override;
Delegate* delegate() const { return delegate_.get(); }
Profile* profile();
// Returns true if the bubble should be displayed.
bool ShouldShow();
// Obtains a list of all extensions (by name) the controller knows about.
std::vector<std::u16string> GetExtensionList();
// Returns the list of all extensions to display in the bubble, including
// bullets and newlines. If the extension list should not be displayed,
// returns an empty string.
std::u16string GetExtensionListForDisplay();
// Obtains a list of all extensions (by id) the controller knows about.
const ExtensionIdList& GetExtensionIdList();
// Checks if each extension entry is installed, and if not, removes it from
// the list.
void UpdateExtensionIdList();
// Whether to close the bubble when it loses focus.
bool CloseOnDeactivate();
// Called when the bubble is actually shown. Because some bubbles are delayed
// (in order to weather the "focus storm"), they are not shown immediately.
// Accepts a callback from platform-specifc ui code to close the bubble.
void OnShown(base::OnceClosure close_bubble_callback);
// Callbacks from bubble. Declared virtual for testing purposes.
virtual void OnBubbleAction();
virtual void OnBubbleDismiss(bool dismissed_by_deactivation);
virtual void OnLinkClicked();
// Sets this bubble as the active bubble being shown.
void SetIsActiveBubble();
static void set_should_ignore_learn_more_for_testing(
bool should_ignore_learn_more);
private:
void HandleExtensionUnloadOrUninstall();
// ExtensionRegistryObserver:
void OnExtensionUnloaded(content::BrowserContext* browser_context,
const Extension* extension,
UnloadedExtensionReason reason) override;
void OnExtensionUninstalled(content::BrowserContext* browser_context,
const Extension* extension,
UninstallReason reason) override;
void OnShutdown(ExtensionRegistry* registry) override;
// BrowserListObserver:
void OnBrowserRemoved(Browser* browser) override;
// Iterate over the known extensions and acknowledge each one.
void AcknowledgeExtensions();
// Get the data this class needs.
ExtensionIdList* GetOrCreateExtensionList();
// Performs cleanup after the bubble closes.
void OnClose();
// A weak pointer to the Browser we are associated with. Not owned by us.
const raw_ptr<Browser> browser_;
// The associated ToolbarActionsModel. Not owned.
raw_ptr<ToolbarActionsModel> model_;
// The list of extensions found.
ExtensionIdList extension_list_;
// The action the user took in the bubble.
BubbleAction user_action_;
// Our delegate supplying information about what to show in the dialog.
std::unique_ptr<Delegate> delegate_;
// Whether this class has initialized.
bool initialized_;
// Whether or not this bubble is the active bubble being shown.
bool is_active_bubble_;
// Platform-specific implementation of closing the bubble.
base::OnceClosure close_bubble_callback_;
base::ScopedObservation<ExtensionRegistry, ExtensionRegistryObserver>
extension_registry_observation_{this};
};
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_MESSAGE_BUBBLE_CONTROLLER_H_