blob: 53a5f7b7d9295f0f5eadd5e8f736fa9bfc3ce9f8 [file] [log] [blame]
rdevlin.cronin09530742014-11-03 19:23:281// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_UI_EXTENSIONS_EXTENSION_ACTION_VIEW_CONTROLLER_H_
6#define CHROME_BROWSER_UI_EXTENSIONS_EXTENSION_ACTION_VIEW_CONTROLLER_H_
7
avi655876a2015-12-25 07:18:158#include "base/macros.h"
rdevlin.croninfb6edb42015-04-28 18:23:179#include "base/memory/weak_ptr.h"
Sigurdur Asgeirsson70fd5db2021-04-28 19:10:3510#include "base/scoped_observation.h"
rdevlin.cronin09530742014-11-03 19:23:2811#include "chrome/browser/extensions/extension_action_icon_factory.h"
12#include "chrome/browser/extensions/extension_context_menu_model.h"
13#include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
Evan Stade75872a62019-09-06 21:17:3814#include "extensions/browser/extension_host.h"
rdevlin.cronin42efb7dd2015-02-11 17:50:5215#include "extensions/browser/extension_host_observer.h"
Devlin Cronina208ee12021-04-28 20:43:3116#include "extensions/common/extension.h"
17#include "extensions/common/extension_id.h"
rdevlin.cronin09530742014-11-03 19:23:2818#include "ui/gfx/image/image.h"
19
20class Browser;
rdevlin.cronin09530742014-11-03 19:23:2821class ExtensionActionPlatformDelegate;
22class GURL;
rdevlin.croninfbfcca32015-07-09 00:28:3523class IconWithBadgeImageSource;
Peter Boström91a80e82019-05-06 16:02:5324class ExtensionsContainer;
rdevlin.cronin09530742014-11-03 19:23:2825
26namespace extensions {
27class Command;
28class Extension;
Devlin Cronin720a0fb2020-07-22 01:31:3829class ExtensionAction;
rdevlin.cronin651153652014-11-15 00:34:4830class ExtensionRegistry;
rdevlin.croninb43d48e2015-01-29 17:51:4131class ExtensionViewHost;
rdevlin.cronin09530742014-11-03 19:23:2832}
33
34// The platform-independent controller for an ExtensionAction that is shown on
35// the toolbar (such as a page or browser action).
rdevlin.cronin651153652014-11-15 00:34:4836// Since this class doesn't own the extension or extension action in question,
37// be sure to check for validity using ExtensionIsValid() before using those
38// members (see also comments above ExtensionIsValid()).
rdevlin.cronin09530742014-11-03 19:23:2839class ExtensionActionViewController
40 : public ToolbarActionViewController,
41 public ExtensionActionIconFactory::Observer,
rdevlin.cronin2b74ad82015-09-17 22:15:5442 public extensions::ExtensionContextMenuModel::PopupDelegate,
rdevlin.cronin42efb7dd2015-02-11 17:50:5243 public extensions::ExtensionHostObserver {
rdevlin.cronin09530742014-11-03 19:23:2844 public:
45 // The different options for showing a popup.
46 enum PopupShowAction { SHOW_POPUP, SHOW_POPUP_AND_INSPECT };
47
Devlin Cronina208ee12021-04-28 20:43:3148 static std::unique_ptr<ExtensionActionViewController> Create(
49 const extensions::ExtensionId& extension_id,
50 Browser* browser,
Devlin Cronin1c1b6ef62021-05-04 20:57:3051 ExtensionsContainer* extensions_container);
Devlin Cronina208ee12021-04-28 20:43:3152
Peter Boström53c6c5952021-09-17 09:41:2653 ExtensionActionViewController(const ExtensionActionViewController&) = delete;
54 ExtensionActionViewController& operator=(
55 const ExtensionActionViewController&) = delete;
56
rdevlin.cronin09530742014-11-03 19:23:2857 ~ExtensionActionViewController() override;
58
59 // ToolbarActionViewController:
apacible3f73e9b32015-08-21 21:21:0860 std::string GetId() const override;
rdevlin.cronin09530742014-11-03 19:23:2861 void SetDelegate(ToolbarActionViewDelegate* delegate) override;
rdevlin.cronin3a57a7f2015-07-06 21:22:4362 gfx::Image GetIcon(content::WebContents* web_contents,
Karan Bhatiafaee83d2018-07-19 06:20:5963 const gfx::Size& size) override;
Jan Wilken Dörrie3f97e292021-03-11 18:07:1464 std::u16string GetActionName() const override;
65 std::u16string GetAccessibleName(
66 content::WebContents* web_contents) const override;
67 std::u16string GetTooltip(content::WebContents* web_contents) const override;
Peter Boström251aebee2019-04-25 18:52:5768 PageInteractionStatus GetPageInteractionStatus(
69 content::WebContents* web_contents) const override;
rdevlin.cronin09530742014-11-03 19:23:2870 bool IsEnabled(content::WebContents* web_contents) const override;
Peter Kasting16ad82b82018-12-26 20:11:4771 bool IsShowingPopup() const override;
rdevlin.cronin09530742014-11-03 19:23:2872 void HidePopup() override;
73 gfx::NativeView GetPopupNativeView() override;
rdevlin.croninc10ac9e2015-01-16 21:10:0874 ui::MenuModel* GetContextMenu() override;
Caroline Rising9999a612020-02-24 23:41:5075 void OnContextMenuShown() override;
rdevlin.cronina81394e2015-04-30 20:16:5676 void OnContextMenuClosed() override;
Devlin Cronin49550fe32020-04-22 19:58:5877 bool ExecuteAction(bool by_user, InvocationSource source) override;
rdevlin.cronin1b9a3a12014-11-13 17:15:1178 void UpdateState() override;
rdevlin.cronin09530742014-11-03 19:23:2879 void RegisterCommand() override;
Peter Kasting8ac405b2020-05-25 10:54:1880 void UnregisterCommand() override;
rdevlin.cronin09530742014-11-03 19:23:2881
82 // ExtensionContextMenuModel::PopupDelegate:
83 void InspectPopup() override;
84
rdevlin.cronin09530742014-11-03 19:23:2885 // Populates |command| with the command associated with |extension|, if one
86 // exists. Returns true if |command| was populated.
Devlin Cronin722a1782019-12-27 19:24:4687 bool GetExtensionCommand(extensions::Command* command) const;
88
89 // Returns true if this controller can handle accelerators (i.e., keyboard
90 // commands) on the currently-active WebContents.
91 // This must only be called if the extension has an associated command.
92 // TODO(devlin): Move accelerator logic out of the platform delegate and into
93 // this class.
94 bool CanHandleAccelerators() const;
rdevlin.cronin09530742014-11-03 19:23:2895
rdevlin.cronin75c546722015-05-06 00:26:0496 const extensions::Extension* extension() const { return extension_.get(); }
rdevlin.cronin09530742014-11-03 19:23:2897 Browser* browser() { return browser_; }
Devlin Cronin720a0fb2020-07-22 01:31:3898 extensions::ExtensionAction* extension_action() { return extension_action_; }
99 const extensions::ExtensionAction* extension_action() const {
100 return extension_action_;
101 }
rdevlin.cronin09530742014-11-03 19:23:28102 ToolbarActionViewDelegate* view_delegate() { return view_delegate_; }
rdevlin.cronin09530742014-11-03 19:23:28103
dcheng9603ab92016-04-08 04:17:32104 std::unique_ptr<IconWithBadgeImageSource> GetIconImageSourceForTesting(
rdevlin.croninfbfcca32015-07-09 00:28:35105 content::WebContents* web_contents,
106 const gfx::Size& size);
Devlin Croninac822052020-04-17 18:43:10107 bool HasBeenBlockedForTesting(content::WebContents* web_contents) const;
rdevlin.croninfbfcca32015-07-09 00:28:35108
rdevlin.cronin09530742014-11-03 19:23:28109 private:
Devlin Cronina208ee12021-04-28 20:43:31110 // New instances should be instantiated with Create().
111 ExtensionActionViewController(
112 scoped_refptr<const extensions::Extension> extension,
113 Browser* browser,
114 extensions::ExtensionAction* extension_action,
115 extensions::ExtensionRegistry* extension_registry,
Devlin Cronin1c1b6ef62021-05-04 20:57:30116 ExtensionsContainer* extensions_container);
Devlin Cronina208ee12021-04-28 20:43:31117
rdevlin.cronin09530742014-11-03 19:23:28118 // ExtensionActionIconFactory::Observer:
119 void OnIconUpdated() override;
120
rdevlin.cronin42efb7dd2015-02-11 17:50:52121 // ExtensionHostObserver:
Fabian Sommerfc5b6f052020-06-04 19:39:01122 void OnExtensionHostDestroyed(extensions::ExtensionHost* host) override;
rdevlin.croninb43d48e2015-01-29 17:51:41123
rdevlin.cronin651153652014-11-15 00:34:48124 // Checks if the associated |extension| is still valid by checking its
125 // status in the registry. Since the OnExtensionUnloaded() notifications are
126 // not in a deterministic order, it's possible that the view tries to refresh
127 // itself before we're notified to remove it.
128 bool ExtensionIsValid() const;
129
rdevlin.cronin5eb91b22015-04-23 19:39:05130 // In some cases (such as when an action is shown in a menu), a substitute
131 // ToolbarActionViewController should be used for showing popups. This
132 // returns the preferred controller.
133 ExtensionActionViewController* GetPreferredPopupViewController();
134
rdevlin.cronin09530742014-11-03 19:23:28135 // Executes the extension action with |show_action|. If
136 // |grant_tab_permissions| is true, this will grant the extension active tab
137 // permissions. Only do this if this was done through a user action (and not
138 // e.g. an API). Returns true if a popup is shown.
139 bool ExecuteAction(PopupShowAction show_action, bool grant_tab_permissions);
140
rdevlin.croninfb6edb42015-04-28 18:23:17141 // Begins the process of showing the popup for the extension action, given the
142 // associated |popup_url|. |grant_tab_permissions| is true if active tab
143 // permissions should be given to the extension; this is only true if the
144 // popup is opened through a user action.
145 // The popup may not be shown synchronously if the extension is hidden and
146 // first needs to slide itself out.
147 // Returns true if a popup will be shown.
148 bool TriggerPopupWithUrl(PopupShowAction show_action,
149 const GURL& popup_url,
150 bool grant_tab_permissions);
151
152 // Shows the popup with the given |host|.
dcheng9603ab92016-04-08 04:17:32153 void ShowPopup(std::unique_ptr<extensions::ExtensionViewHost> host,
rdevlin.croninfb6edb42015-04-28 18:23:17154 bool grant_tab_permissions,
155 PopupShowAction show_action);
rdevlin.cronin09530742014-11-03 19:23:28156
rdevlin.croninb43d48e2015-01-29 17:51:41157 // Handles cleanup after the popup closes.
158 void OnPopupClosed();
159
rdevlin.croninfbfcca32015-07-09 00:28:35160 // Returns the image source for the icon.
dcheng9603ab92016-04-08 04:17:32161 std::unique_ptr<IconWithBadgeImageSource> GetIconImageSource(
rdevlin.croninfbfcca32015-07-09 00:28:35162 content::WebContents* web_contents,
Karan Bhatiafaee83d2018-07-19 06:20:59163 const gfx::Size& size);
rdevlin.croninfbfcca32015-07-09 00:28:35164
Tim Judkinsa45686b2020-06-12 00:21:45165 // Returns true if this extension uses the activeTab permission and would
166 // probably be able to to access the given |url|. The actual checks when an
167 // activeTab extension tries to run are a little more complicated and can be
168 // seen in ExtensionActionRunner and ActiveTabPermissionGranter.
169 // Note: The rare cases where this gets it wrong should only be for false
170 // positives, where it reports that the extension wants access but it can't
171 // actually be given access when it tries to run.
172 bool HasActiveTabAndCanAccess(const GURL& url) const;
173
rdevlin.cronin343fd102016-03-17 00:24:54174 // Returns true if this extension has been blocked on the given
175 // |web_contents|.
176 bool HasBeenBlocked(content::WebContents* web_contents) const;
177
rdevlin.cronin09530742014-11-03 19:23:28178 // The extension associated with the action we're displaying.
rdevlin.cronin75c546722015-05-06 00:26:04179 scoped_refptr<const extensions::Extension> extension_;
rdevlin.cronin09530742014-11-03 19:23:28180
181 // The corresponding browser.
Peter Boström4d71c392019-04-10 00:21:04182 Browser* const browser_;
183
rdevlin.cronin09530742014-11-03 19:23:28184 // The browser action this view represents. The ExtensionAction is not owned
185 // by this class.
Devlin Cronin720a0fb2020-07-22 01:31:38186 extensions::ExtensionAction* const extension_action_;
rdevlin.cronin09530742014-11-03 19:23:28187
Peter Boström91a80e82019-05-06 16:02:53188 // The corresponding ExtensionsContainer on the toolbar.
189 ExtensionsContainer* const extensions_container_;
rdevlin.cronin5eb91b22015-04-23 19:39:05190
rdevlin.croninb43d48e2015-01-29 17:51:41191 // The extension popup's host if the popup is visible; null otherwise.
192 extensions::ExtensionViewHost* popup_host_;
193
rdevlin.croninc10ac9e2015-01-16 21:10:08194 // The context menu model for the extension.
dcheng9603ab92016-04-08 04:17:32195 std::unique_ptr<extensions::ExtensionContextMenuModel> context_menu_model_;
rdevlin.croninc10ac9e2015-01-16 21:10:08196
rdevlin.cronin09530742014-11-03 19:23:28197 // Our view delegate.
198 ToolbarActionViewDelegate* view_delegate_;
199
200 // The delegate to handle platform-specific implementations.
dcheng9603ab92016-04-08 04:17:32201 std::unique_ptr<ExtensionActionPlatformDelegate> platform_delegate_;
rdevlin.cronin09530742014-11-03 19:23:28202
203 // The object that will be used to get the browser action icon for us.
204 // It may load the icon asynchronously (in which case the initial icon
205 // returned by the factory will be transparent), so we have to observe it for
206 // updates to the icon.
207 ExtensionActionIconFactory icon_factory_;
208
rdevlin.cronin651153652014-11-15 00:34:48209 // The associated ExtensionRegistry; cached for quick checking.
210 extensions::ExtensionRegistry* extension_registry_;
211
Sigurdur Asgeirsson70fd5db2021-04-28 19:10:35212 base::ScopedObservation<extensions::ExtensionHost,
213 extensions::ExtensionHostObserver>
214 popup_host_observation_{this};
rdevlin.croninb43d48e2015-01-29 17:51:41215
Jeremy Roman495db682019-07-12 16:03:24216 base::WeakPtrFactory<ExtensionActionViewController> weak_factory_{this};
rdevlin.cronin09530742014-11-03 19:23:28217};
218
219#endif // CHROME_BROWSER_UI_EXTENSIONS_EXTENSION_ACTION_VIEW_CONTROLLER_H_