1 // Copyright (c) 2012 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_EXTENSIONS_API_COMMANDS_COMMAND_SERVICE_H_ 6 #define CHROME_BROWSER_EXTENSIONS_API_COMMANDS_COMMAND_SERVICE_H_ 7 8 #include <string> 9 10 #include "base/basictypes.h" 11 #include "base/scoped_observer.h" 12 #include "chrome/common/extensions/command.h" 13 #include "extensions/browser/browser_context_keyed_api_factory.h" 14 #include "extensions/browser/extension_registry_observer.h" 15 #include "extensions/common/extension.h" 16 17 class Profile; 18 19 namespace base { 20 class DictionaryValue; 21 } 22 23 namespace content { 24 class BrowserContext; 25 } 26 27 namespace ui { 28 class Accelerator; 29 } 30 31 namespace user_prefs { 32 class PrefRegistrySyncable; 33 } 34 35 namespace extensions { 36 class ExtensionRegistry; 37 38 // This service keeps track of preferences related to extension commands 39 // (assigning initial keybindings on install and removing them on deletion 40 // and answers questions related to which commands are active. 41 class CommandService : public BrowserContextKeyedAPI, 42 public ExtensionRegistryObserver { 43 public: 44 // An enum specifying whether to fetch all extension commands or only active 45 // ones. 46 enum QueryType { 47 ALL, 48 ACTIVE_ONLY, 49 }; 50 51 // An enum specifying whether the command is global in scope or not. Global 52 // commands -- unlike regular commands -- have a global keyboard hook 53 // associated with them (and therefore work when Chrome doesn't have focus). 54 enum CommandScope { 55 REGULAR, // Regular (non-globally scoped) command. 56 GLOBAL, // Global command (works when Chrome doesn't have focus) 57 ANY_SCOPE, // All commands, regardless of scope (used when querying). 58 }; 59 60 // An enum specifying the types of commands that can be used by an extension. 61 enum ExtensionCommandType { 62 NAMED, 63 BROWSER_ACTION, 64 PAGE_ACTION 65 }; 66 67 // Register prefs for keybinding. 68 static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); 69 70 // Constructs a CommandService object for the given profile. 71 explicit CommandService(content::BrowserContext* context); 72 virtual ~CommandService(); 73 74 // BrowserContextKeyedAPI implementation. 75 static BrowserContextKeyedAPIFactory<CommandService>* GetFactoryInstance(); 76 77 // Convenience method to get the CommandService for a profile. 78 static CommandService* Get(content::BrowserContext* context); 79 80 // Returns true if |extension| is permitted to and does remove the bookmark 81 // shortcut key. 82 static bool RemovesBookmarkShortcut(const Extension* extension); 83 84 // Returns true if |extension| is permitted to and does remove the bookmark 85 // open pages shortcut key. 86 static bool RemovesBookmarkOpenPagesShortcut(const Extension* extension); 87 88 // Gets the command (if any) for the browser action of an extension given 89 // its |extension_id|. The function consults the master list to see if 90 // the command is active. Returns false if the extension has no browser 91 // action. Returns false if the command is not active and |type| requested 92 // is ACTIVE_ONLY. |command| contains the command found and |active| (if not 93 // NULL) contains whether |command| is active. 94 bool GetBrowserActionCommand(const std::string& extension_id, 95 QueryType type, 96 Command* command, 97 bool* active) const; 98 99 // Gets the command (if any) for the page action of an extension given 100 // its |extension_id|. The function consults the master list to see if 101 // the command is active. Returns false if the extension has no page 102 // action. Returns false if the command is not active and |type| requested 103 // is ACTIVE_ONLY. |command| contains the command found and |active| (if not 104 // NULL) contains whether |command| is active. 105 bool GetPageActionCommand(const std::string& extension_id, 106 QueryType type, 107 Command* command, 108 bool* active) const; 109 110 // Gets the active named commands (if any) for the extension with 111 // |extension_id|. The function consults the master list to see if the 112 // commands are active. Returns an empty map if the extension has no named 113 // commands of the right |scope| or no such active named commands when |type| 114 // requested is ACTIVE_ONLY. 115 bool GetNamedCommands(const std::string& extension_id, 116 QueryType type, 117 CommandScope scope, 118 CommandMap* command_map) const; 119 120 // Records a keybinding |accelerator| as active for an extension with id 121 // |extension_id| and command with the name |command_name|. If 122 // |allow_overrides| is false, the keybinding must be free for the change to 123 // be recorded (as determined by the master list in |user_prefs|). If 124 // |allow_overwrites| is true, any previously recorded keybinding for this 125 // |accelerator| will be overwritten. If |global| is true, the command will 126 // be registered as a global command (be active even when Chrome does not have 127 // focus. Returns true if the change was successfully recorded. 128 bool AddKeybindingPref(const ui::Accelerator& accelerator, 129 std::string extension_id, 130 std::string command_name, 131 bool allow_overrides, 132 bool global); 133 134 // Removes all keybindings for a given extension by its |extension_id|. 135 // |command_name| is optional and if specified, causes only the command with 136 // the name |command_name| to be removed. 137 void RemoveKeybindingPrefs(const std::string& extension_id, 138 const std::string& command_name); 139 140 // Update the keybinding prefs (for a command with a matching |extension_id| 141 // and |command_name|) to |keystroke|. If the command had another key assigned 142 // that key assignment will be removed. 143 void UpdateKeybindingPrefs(const std::string& extension_id, 144 const std::string& command_name, 145 const std::string& keystroke); 146 147 // Set the scope of the keybinding. If |global| is true, the keybinding works 148 // even when Chrome does not have focus. If the scope requested is already 149 // set, the function returns false, otherwise true. 150 bool SetScope(const std::string& extension_id, 151 const std::string& command_name, 152 bool global); 153 154 // Finds the command with the name |command_name| within an extension with id 155 // |extension_id| . Returns an empty Command object (with keycode 156 // VKEY_UNKNOWN) if the command is not found. 157 Command FindCommandByName(const std::string& extension_id, 158 const std::string& command) const; 159 160 // If the extension with |extension_id| binds a command to |accelerator|, 161 // returns true and assigns *|command| and *|command_type| to the command and 162 // its type if non-NULL. 163 bool GetBoundExtensionCommand(const std::string& extension_id, 164 const ui::Accelerator& accelerator, 165 Command* command, 166 ExtensionCommandType* command_type) const; 167 168 // Returns true if |extension| is permitted to and does override the bookmark 169 // shortcut key. 170 bool OverridesBookmarkShortcut(const Extension* extension) const; 171 172 private: 173 friend class BrowserContextKeyedAPIFactory<CommandService>; 174 175 // BrowserContextKeyedAPI implementation. 176 static const char* service_name() { 177 return "CommandService"; 178 } 179 static const bool kServiceRedirectedInIncognito = true; 180 181 // ExtensionRegistryObserver. 182 virtual void OnExtensionWillBeInstalled( 183 content::BrowserContext* browser_context, 184 const Extension* extension, 185 bool is_update, 186 bool from_ephemeral, 187 const std::string& old_name) OVERRIDE; 188 virtual void OnExtensionUninstalled(content::BrowserContext* browser_context, 189 const Extension* extension) OVERRIDE; 190 191 // Updates keybindings for a given |extension|'s page action, browser action 192 // and named commands. Assigns new keybindings and removes relinquished 193 // keybindings if not changed by the user. In the case of adding keybindings, 194 // if the suggested keybinding is free, it will be taken by this extension. If 195 // not, the keybinding request is ignored. 196 void UpdateKeybindings(const Extension* extension); 197 198 // On update, removes keybindings that the extension previously suggested but 199 // now no longer does, as long as the user has not modified them. 200 void RemoveRelinquishedKeybindings(const Extension* extension); 201 202 // Assigns keybindings that the extension suggests, as long as they are not 203 // already assigned. 204 void AssignKeybindings(const Extension* extension); 205 206 // Checks if |extension| is permitted to automatically assign the 207 // |accelerator| key. 208 bool CanAutoAssign(const Command &command, 209 const Extension* extension); 210 211 // Updates the record of |extension|'s most recent suggested command shortcut 212 // keys in the preferences. 213 void UpdateExtensionSuggestedCommandPrefs(const Extension* extension); 214 215 // Remove suggested key command prefs that apply to commands that have been 216 // removed. 217 void RemoveDefunctExtensionSuggestedCommandPrefs(const Extension* extension); 218 219 // Returns true if the user modified a command's shortcut key from the 220 // |extension|-suggested value. 221 bool IsCommandShortcutUserModified(const Extension* extension, 222 const std::string& command_name); 223 224 // Returns true if the extension is changing the binding of |command_name| on 225 // install. 226 bool IsKeybindingChanging(const Extension* extension, 227 const std::string& command_name); 228 229 // Returns |extension|'s previous suggested key for |command_name| in the 230 // preferences, or the empty string if none. 231 std::string GetSuggestedKeyPref(const Extension* extension, 232 const std::string& command_name); 233 234 bool GetExtensionActionCommand(const std::string& extension_id, 235 QueryType query_type, 236 Command* command, 237 bool* active, 238 ExtensionCommandType action_type) const; 239 240 // A weak pointer to the profile we are associated with. Not owned by us. 241 Profile* profile_; 242 243 ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> 244 extension_registry_observer_; 245 246 DISALLOW_COPY_AND_ASSIGN(CommandService); 247 }; 248 249 template <> 250 void 251 BrowserContextKeyedAPIFactory<CommandService>::DeclareFactoryDependencies(); 252 253 } // namespace extensions 254 255 #endif // CHROME_BROWSER_EXTENSIONS_API_COMMANDS_COMMAND_SERVICE_H_ 256