1 // 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 8 #include "base/macros.h" 9 #include "base/memory/weak_ptr.h" 10 #include "base/scoped_observer.h" 11 #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" 14 #include "extensions/browser/extension_host.h" 15 #include "extensions/browser/extension_host_observer.h" 16 #include "ui/gfx/image/image.h" 17 18 class Browser; 19 class ExtensionActionPlatformDelegate; 20 class GURL; 21 class IconWithBadgeImageSource; 22 class ExtensionsContainer; 23 24 namespace extensions { 25 class Command; 26 class Extension; 27 class ExtensionAction; 28 class ExtensionRegistry; 29 class ExtensionViewHost; 30 } 31 32 // The platform-independent controller for an ExtensionAction that is shown on 33 // the toolbar (such as a page or browser action). 34 // Since this class doesn't own the extension or extension action in question, 35 // be sure to check for validity using ExtensionIsValid() before using those 36 // members (see also comments above ExtensionIsValid()). 37 class ExtensionActionViewController 38 : public ToolbarActionViewController, 39 public ExtensionActionIconFactory::Observer, 40 public extensions::ExtensionContextMenuModel::PopupDelegate, 41 public extensions::ExtensionHostObserver { 42 public: 43 // The different options for showing a popup. 44 enum PopupShowAction { SHOW_POPUP, SHOW_POPUP_AND_INSPECT }; 45 46 ExtensionActionViewController(const extensions::Extension* extension, 47 Browser* browser, 48 extensions::ExtensionAction* extension_action, 49 ExtensionsContainer* extensions_container, 50 bool in_overflow_mode); 51 ~ExtensionActionViewController() override; 52 53 // ToolbarActionViewController: 54 std::string GetId() const override; 55 void SetDelegate(ToolbarActionViewDelegate* delegate) override; 56 gfx::Image GetIcon(content::WebContents* web_contents, 57 const gfx::Size& size) override; 58 base::string16 GetActionName() const override; 59 base::string16 GetAccessibleName(content::WebContents* web_contents) const 60 override; 61 base::string16 GetTooltip(content::WebContents* web_contents) const override; 62 PageInteractionStatus GetPageInteractionStatus( 63 content::WebContents* web_contents) const override; 64 bool IsEnabled(content::WebContents* web_contents) const override; 65 bool HasPopup(content::WebContents* web_contents) const override; 66 bool IsShowingPopup() const override; 67 void HidePopup() override; 68 gfx::NativeView GetPopupNativeView() override; 69 ui::MenuModel* GetContextMenu() override; 70 void OnContextMenuShown() override; 71 void OnContextMenuClosed() override; 72 bool ExecuteAction(bool by_user, InvocationSource source) override; 73 void UpdateState() override; 74 void RegisterCommand() override; 75 void UnregisterCommand() override; 76 bool DisabledClickOpensMenu() const override; 77 78 // ExtensionContextMenuModel::PopupDelegate: 79 void InspectPopup() override; 80 81 // Populates |command| with the command associated with |extension|, if one 82 // exists. Returns true if |command| was populated. 83 bool GetExtensionCommand(extensions::Command* command) const; 84 85 // Returns true if this controller can handle accelerators (i.e., keyboard 86 // commands) on the currently-active WebContents. 87 // This must only be called if the extension has an associated command. 88 // TODO(devlin): Move accelerator logic out of the platform delegate and into 89 // this class. 90 bool CanHandleAccelerators() const; 91 extension()92 const extensions::Extension* extension() const { return extension_.get(); } browser()93 Browser* browser() { return browser_; } extension_action()94 extensions::ExtensionAction* extension_action() { return extension_action_; } extension_action()95 const extensions::ExtensionAction* extension_action() const { 96 return extension_action_; 97 } view_delegate()98 ToolbarActionViewDelegate* view_delegate() { return view_delegate_; } 99 100 std::unique_ptr<IconWithBadgeImageSource> GetIconImageSourceForTesting( 101 content::WebContents* web_contents, 102 const gfx::Size& size); 103 bool HasBeenBlockedForTesting(content::WebContents* web_contents) const; 104 105 private: 106 // ExtensionActionIconFactory::Observer: 107 void OnIconUpdated() override; 108 109 // ExtensionHostObserver: 110 void OnExtensionHostDestroyed(extensions::ExtensionHost* host) override; 111 112 // Checks if the associated |extension| is still valid by checking its 113 // status in the registry. Since the OnExtensionUnloaded() notifications are 114 // not in a deterministic order, it's possible that the view tries to refresh 115 // itself before we're notified to remove it. 116 bool ExtensionIsValid() const; 117 118 // In some cases (such as when an action is shown in a menu), a substitute 119 // ToolbarActionViewController should be used for showing popups. This 120 // returns the preferred controller. 121 ExtensionActionViewController* GetPreferredPopupViewController(); 122 123 // Executes the extension action with |show_action|. If 124 // |grant_tab_permissions| is true, this will grant the extension active tab 125 // permissions. Only do this if this was done through a user action (and not 126 // e.g. an API). Returns true if a popup is shown. 127 bool ExecuteAction(PopupShowAction show_action, bool grant_tab_permissions); 128 129 // Begins the process of showing the popup for the extension action, given the 130 // associated |popup_url|. |grant_tab_permissions| is true if active tab 131 // permissions should be given to the extension; this is only true if the 132 // popup is opened through a user action. 133 // The popup may not be shown synchronously if the extension is hidden and 134 // first needs to slide itself out. 135 // Returns true if a popup will be shown. 136 bool TriggerPopupWithUrl(PopupShowAction show_action, 137 const GURL& popup_url, 138 bool grant_tab_permissions); 139 140 // Shows the popup with the given |host|. 141 void ShowPopup(std::unique_ptr<extensions::ExtensionViewHost> host, 142 bool grant_tab_permissions, 143 PopupShowAction show_action); 144 145 // Handles cleanup after the popup closes. 146 void OnPopupClosed(); 147 148 // Returns the image source for the icon. 149 std::unique_ptr<IconWithBadgeImageSource> GetIconImageSource( 150 content::WebContents* web_contents, 151 const gfx::Size& size); 152 153 // Returns true if this extension has a page action and that page action wants 154 // to run on the given |web_contents|. 155 bool PageActionWantsToRun(content::WebContents* web_contents) const; 156 157 // Returns true if this extension uses the activeTab permission and would 158 // probably be able to to access the given |url|. The actual checks when an 159 // activeTab extension tries to run are a little more complicated and can be 160 // seen in ExtensionActionRunner and ActiveTabPermissionGranter. 161 // Note: The rare cases where this gets it wrong should only be for false 162 // positives, where it reports that the extension wants access but it can't 163 // actually be given access when it tries to run. 164 bool HasActiveTabAndCanAccess(const GURL& url) const; 165 166 // Returns true if this extension has been blocked on the given 167 // |web_contents|. 168 bool HasBeenBlocked(content::WebContents* web_contents) const; 169 170 // The extension associated with the action we're displaying. 171 scoped_refptr<const extensions::Extension> extension_; 172 173 // The corresponding browser. 174 Browser* const browser_; 175 176 // Whether we are displayed in the 3-dot menu or not. 177 // TODO(pbos): Remove when 3-dot menu no longer contains extensions. 178 const bool in_overflow_mode_; 179 180 // The browser action this view represents. The ExtensionAction is not owned 181 // by this class. 182 extensions::ExtensionAction* const extension_action_; 183 184 // The corresponding ExtensionsContainer on the toolbar. 185 ExtensionsContainer* const extensions_container_; 186 187 // The extension popup's host if the popup is visible; null otherwise. 188 extensions::ExtensionViewHost* popup_host_; 189 190 // The context menu model for the extension. 191 std::unique_ptr<extensions::ExtensionContextMenuModel> context_menu_model_; 192 193 // Our view delegate. 194 ToolbarActionViewDelegate* view_delegate_; 195 196 // The delegate to handle platform-specific implementations. 197 std::unique_ptr<ExtensionActionPlatformDelegate> platform_delegate_; 198 199 // The object that will be used to get the browser action icon for us. 200 // It may load the icon asynchronously (in which case the initial icon 201 // returned by the factory will be transparent), so we have to observe it for 202 // updates to the icon. 203 ExtensionActionIconFactory icon_factory_; 204 205 // The associated ExtensionRegistry; cached for quick checking. 206 extensions::ExtensionRegistry* extension_registry_; 207 208 ScopedObserver<extensions::ExtensionHost, extensions::ExtensionHostObserver> 209 popup_host_observer_{this}; 210 211 base::WeakPtrFactory<ExtensionActionViewController> weak_factory_{this}; 212 213 DISALLOW_COPY_AND_ASSIGN(ExtensionActionViewController); 214 }; 215 216 #endif // CHROME_BROWSER_UI_EXTENSIONS_EXTENSION_ACTION_VIEW_CONTROLLER_H_ 217