| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_EXTENSIONS_API_COMMANDS_COMMAND_SERVICE_H_ |
| #define CHROME_BROWSER_EXTENSIONS_API_COMMANDS_COMMAND_SERVICE_H_ |
| |
| #include <string> |
| |
| #include "base/macros.h" |
| #include "base/observer_list.h" |
| #include "base/scoped_observer.h" |
| #include "chrome/common/extensions/command.h" |
| #include "extensions/browser/browser_context_keyed_api_factory.h" |
| #include "extensions/browser/extension_registry_observer.h" |
| #include "extensions/common/extension.h" |
| |
| class Profile; |
| |
| namespace content { |
| class BrowserContext; |
| } |
| |
| namespace ui { |
| class Accelerator; |
| } |
| |
| namespace user_prefs { |
| class PrefRegistrySyncable; |
| } |
| |
| namespace extensions { |
| class ExtensionRegistry; |
| |
| // This service keeps track of preferences related to extension commands |
| // (assigning initial keybindings on install and removing them on deletion |
| // and answers questions related to which commands are active. |
| class CommandService : public BrowserContextKeyedAPI, |
| public ExtensionRegistryObserver { |
| public: |
| // An enum specifying which extension commands to fetch. There are effectively |
| // four options: all, active, suggested, and inactive. Only the first three |
| // appear in the enum since there hasn't been a need for 'inactive' yet. |
| // |
| // 'Inactive' means no key is bound. It might be because 1) a key wasn't |
| // specified (suggested) or 2) it was not granted (key already taken). |
| // |
| // SUGGESTED covers developer-assigned keys that may or may not have been |
| // granted. Reasons for not granting include permission denied/key already |
| // taken. |
| // |
| // ACTIVE means developer-assigned keys that were granted or user-assigned |
| // keys. |
| // |
| // ALL is all of the above. |
| enum QueryType { |
| ALL, |
| ACTIVE, |
| SUGGESTED, |
| }; |
| |
| // An enum specifying whether the command is global in scope or not. Global |
| // commands -- unlike regular commands -- have a global keyboard hook |
| // associated with them (and therefore work when Chrome doesn't have focus). |
| enum CommandScope { |
| REGULAR, // Regular (non-globally scoped) command. |
| GLOBAL, // Global command (works when Chrome doesn't have focus) |
| ANY_SCOPE, // All commands, regardless of scope (used when querying). |
| }; |
| |
| class Observer { |
| public: |
| // Called when an extension command is added. |
| virtual void OnExtensionCommandAdded(const std::string& extension_id, |
| const Command& command) {} |
| |
| // Called when an extension command is removed. |
| virtual void OnExtensionCommandRemoved(const std::string& extension_id, |
| const Command& command) {} |
| protected: |
| virtual ~Observer() {} |
| }; |
| |
| // Register prefs for keybinding. |
| static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); |
| |
| // Constructs a CommandService object for the given profile. |
| explicit CommandService(content::BrowserContext* context); |
| ~CommandService() override; |
| |
| // BrowserContextKeyedAPI implementation. |
| static BrowserContextKeyedAPIFactory<CommandService>* GetFactoryInstance(); |
| |
| // Convenience method to get the CommandService for a profile. |
| static CommandService* Get(content::BrowserContext* context); |
| |
| // Returns true if |extension| is permitted to and does remove the bookmark |
| // shortcut key. |
| static bool RemovesBookmarkShortcut(const Extension* extension); |
| |
| // Returns true if |extension| is permitted to and does remove the bookmark |
| // open pages shortcut key. |
| static bool RemovesBookmarkOpenPagesShortcut(const Extension* extension); |
| |
| // Gets the command (if any) for the browser action of an extension given |
| // its |extension_id|. The function consults the master list to see if |
| // the command is active. Returns false if the extension has no browser |
| // action. Returns false if the command is not active and |type| requested |
| // is ACTIVE. |command| contains the command found and |active| (if not |
| // NULL) contains whether |command| is active. |
| bool GetBrowserActionCommand(const std::string& extension_id, |
| QueryType type, |
| Command* command, |
| bool* active) const; |
| |
| // Gets the command (if any) for the page action of an extension given |
| // its |extension_id|. The function consults the master list to see if |
| // the command is active. Returns false if the extension has no page |
| // action. Returns false if the command is not active and |type| requested |
| // is ACTIVE. |command| contains the command found and |active| (if not |
| // NULL) contains whether |command| is active. |
| bool GetPageActionCommand(const std::string& extension_id, |
| QueryType type, |
| Command* command, |
| bool* active) const; |
| |
| // Gets the active named commands (if any) for the extension with |
| // |extension_id|. The function consults the master list to see if the |
| // commands are active. Returns an empty map if the extension has no named |
| // commands of the right |scope| or no such active named commands when |type| |
| // requested is ACTIVE. |
| bool GetNamedCommands(const std::string& extension_id, |
| QueryType type, |
| CommandScope scope, |
| CommandMap* command_map) const; |
| |
| // Records a keybinding |accelerator| as active for an extension with id |
| // |extension_id| and command with the name |command_name|. If |
| // |allow_overrides| is false, the keybinding must be free for the change to |
| // be recorded (as determined by the master list in |user_prefs|). If |
| // |allow_overwrites| is true, any previously recorded keybinding for this |
| // |accelerator| will be overwritten. If |global| is true, the command will |
| // be registered as a global command (be active even when Chrome does not have |
| // focus. Returns true if the change was successfully recorded. |
| bool AddKeybindingPref(const ui::Accelerator& accelerator, |
| const std::string& extension_id, |
| const std::string& command_name, |
| bool allow_overrides, |
| bool global); |
| |
| // Removes all keybindings for a given extension by its |extension_id|. |
| // |command_name| is optional and if specified, causes only the command with |
| // the name |command_name| to be removed. |
| void RemoveKeybindingPrefs(const std::string& extension_id, |
| const std::string& command_name); |
| |
| // Update the keybinding prefs (for a command with a matching |extension_id| |
| // and |command_name|) to |keystroke|. If the command had another key assigned |
| // that key assignment will be removed. |
| void UpdateKeybindingPrefs(const std::string& extension_id, |
| const std::string& command_name, |
| const std::string& keystroke); |
| |
| // Set the scope of the keybinding. If |global| is true, the keybinding works |
| // even when Chrome does not have focus. If the scope requested is already |
| // set, the function returns false, otherwise true. |
| bool SetScope(const std::string& extension_id, |
| const std::string& command_name, |
| bool global); |
| |
| // Finds the command with the name |command_name| within an extension with id |
| // |extension_id| . Returns an empty Command object (with keycode |
| // VKEY_UNKNOWN) if the command is not found. |
| Command FindCommandByName(const std::string& extension_id, |
| const std::string& command) const; |
| |
| // If the extension with |extension_id| suggests the assignment of a command |
| // to |accelerator|, returns true and assigns the command to *|command|. Also |
| // assigns the type to *|command_type| if non-null. |
| bool GetSuggestedExtensionCommand(const std::string& extension_id, |
| const ui::Accelerator& accelerator, |
| Command* command) const; |
| |
| // Returns true if |extension| requests to override the bookmark shortcut key |
| // and should be allowed to do so. |
| bool RequestsBookmarkShortcutOverride(const Extension* extension) const; |
| |
| void AddObserver(Observer* observer); |
| void RemoveObserver(Observer* observer); |
| |
| void UpdateKeybindingsForTest(const Extension* extension) { |
| UpdateKeybindings(extension); |
| } |
| |
| private: |
| friend class BrowserContextKeyedAPIFactory<CommandService>; |
| |
| // BrowserContextKeyedAPI implementation. |
| static const char* service_name() { |
| return "CommandService"; |
| } |
| static const bool kServiceRedirectedInIncognito = true; |
| |
| // ExtensionRegistryObserver. |
| void OnExtensionWillBeInstalled(content::BrowserContext* browser_context, |
| const Extension* extension, |
| bool is_update, |
| const std::string& old_name) override; |
| void OnExtensionUninstalled(content::BrowserContext* browser_context, |
| const Extension* extension, |
| extensions::UninstallReason reason) override; |
| |
| // Updates keybindings for a given |extension|'s page action, browser action |
| // and named commands. Assigns new keybindings and removes relinquished |
| // keybindings if not changed by the user. In the case of adding keybindings, |
| // if the suggested keybinding is free, it will be taken by this extension. If |
| // not, the keybinding request is ignored. |
| void UpdateKeybindings(const Extension* extension); |
| |
| // On update, removes keybindings that the extension previously suggested but |
| // now no longer does, as long as the user has not modified them. |
| void RemoveRelinquishedKeybindings(const Extension* extension); |
| |
| // Assigns keybindings that the extension suggests, as long as they are not |
| // already assigned. |
| void AssignKeybindings(const Extension* extension); |
| |
| // Checks if |extension| is permitted to automatically assign the |
| // |accelerator| key. |
| bool CanAutoAssign(const Command &command, |
| const Extension* extension); |
| |
| // Updates the record of |extension|'s most recent suggested command shortcut |
| // keys in the preferences. |
| void UpdateExtensionSuggestedCommandPrefs(const Extension* extension); |
| |
| // Remove suggested key command prefs that apply to commands that have been |
| // removed. |
| void RemoveDefunctExtensionSuggestedCommandPrefs(const Extension* extension); |
| |
| // Returns true if the user modified a command's shortcut key from the |
| // |extension|-suggested value. |
| bool IsCommandShortcutUserModified(const Extension* extension, |
| const std::string& command_name); |
| |
| // Returns true if the extension is changing the binding of |command_name| on |
| // install. |
| bool IsKeybindingChanging(const Extension* extension, |
| const std::string& command_name); |
| |
| // Returns |extension|'s previous suggested key for |command_name| in the |
| // preferences, or the empty string if none. |
| std::string GetSuggestedKeyPref(const Extension* extension, |
| const std::string& command_name); |
| |
| bool GetExtensionActionCommand(const std::string& extension_id, |
| QueryType query_type, |
| Command* command, |
| bool* active, |
| Command::Type type) const; |
| |
| // A weak pointer to the profile we are associated with. Not owned by us. |
| Profile* profile_; |
| |
| ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> |
| extension_registry_observer_; |
| |
| base::ObserverList<Observer>::Unchecked observers_; |
| |
| DISALLOW_COPY_AND_ASSIGN(CommandService); |
| }; |
| |
| template <> |
| void |
| BrowserContextKeyedAPIFactory<CommandService>::DeclareFactoryDependencies(); |
| |
| } // namespace extensions |
| |
| #endif // CHROME_BROWSER_EXTENSIONS_API_COMMANDS_COMMAND_SERVICE_H_ |