app_list: Re-enable people search.
[chromium-blink-merge.git] / chrome / browser / extensions / extension_keybinding_registry.cc
blob22837a82a1b36a0831e0030efa77d2e29a56bb8c
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.
5 #include "chrome/browser/extensions/extension_keybinding_registry.h"
7 #include "base/values.h"
8 #include "chrome/browser/extensions/active_tab_permission_granter.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/common/extensions/command.h"
11 #include "content/public/browser/browser_context.h"
12 #include "extensions/browser/event_router.h"
13 #include "extensions/browser/extension_registry.h"
14 #include "extensions/browser/notification_types.h"
15 #include "extensions/common/extension_set.h"
16 #include "extensions/common/manifest_constants.h"
18 namespace {
19 const char kOnCommandEventName[] = "commands.onCommand";
20 } // namespace
22 namespace extensions {
24 ExtensionKeybindingRegistry::ExtensionKeybindingRegistry(
25 content::BrowserContext* context,
26 ExtensionFilter extension_filter,
27 Delegate* delegate)
28 : browser_context_(context),
29 extension_filter_(extension_filter),
30 delegate_(delegate),
31 extension_registry_observer_(this) {
32 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
34 Profile* profile = Profile::FromBrowserContext(browser_context_);
35 registrar_.Add(this,
36 extensions::NOTIFICATION_EXTENSION_COMMAND_ADDED,
37 content::Source<Profile>(profile->GetOriginalProfile()));
38 registrar_.Add(this,
39 extensions::NOTIFICATION_EXTENSION_COMMAND_REMOVED,
40 content::Source<Profile>(profile->GetOriginalProfile()));
43 ExtensionKeybindingRegistry::~ExtensionKeybindingRegistry() {
46 void ExtensionKeybindingRegistry::RemoveExtensionKeybinding(
47 const Extension* extension,
48 const std::string& command_name) {
49 EventTargets::iterator it = event_targets_.begin();
50 while (it != event_targets_.end()) {
51 TargetList& target_list = it->second;
52 TargetList::iterator target = target_list.begin();
53 while (target != target_list.end()) {
54 if (target->first == extension->id() &&
55 (command_name.empty() || command_name == target->second))
56 target = target_list.erase(target);
57 else
58 target++;
61 EventTargets::iterator old = it++;
62 if (target_list.empty()) {
63 // Let each platform-specific implementation get a chance to clean up.
64 RemoveExtensionKeybindingImpl(old->first, command_name);
65 event_targets_.erase(old);
67 // If a specific command_name was requested, it has now been deleted so no
68 // further work is required.
69 if (!command_name.empty())
70 break;
75 void ExtensionKeybindingRegistry::Init() {
76 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
77 if (!registry)
78 return; // ExtensionRegistry can be null during testing.
80 for (const scoped_refptr<const extensions::Extension>& extension :
81 registry->enabled_extensions())
82 if (ExtensionMatchesFilter(extension.get()))
83 AddExtensionKeybindings(extension.get(), std::string());
86 bool ExtensionKeybindingRegistry::ShouldIgnoreCommand(
87 const std::string& command) const {
88 return command == manifest_values::kPageActionCommandEvent ||
89 command == manifest_values::kBrowserActionCommandEvent;
92 bool ExtensionKeybindingRegistry::NotifyEventTargets(
93 const ui::Accelerator& accelerator) {
94 return ExecuteCommands(accelerator, std::string());
97 void ExtensionKeybindingRegistry::CommandExecuted(
98 const std::string& extension_id, const std::string& command) {
99 const Extension* extension = ExtensionRegistry::Get(browser_context_)
100 ->enabled_extensions()
101 .GetByID(extension_id);
102 if (!extension)
103 return;
105 // Grant before sending the event so that the permission is granted before
106 // the extension acts on the command. NOTE: The Global Commands handler does
107 // not set the delegate as it deals only with named commands (not page/browser
108 // actions that are associated with the current page directly).
109 ActiveTabPermissionGranter* granter =
110 delegate_ ? delegate_->GetActiveTabPermissionGranter() : NULL;
111 if (granter)
112 granter->GrantIfRequested(extension);
114 scoped_ptr<base::ListValue> args(new base::ListValue());
115 args->Append(new base::StringValue(command));
117 scoped_ptr<Event> event(new Event(kOnCommandEventName, args.Pass()));
118 event->restrict_to_browser_context = browser_context_;
119 event->user_gesture = EventRouter::USER_GESTURE_ENABLED;
120 EventRouter::Get(browser_context_)
121 ->DispatchEventToExtension(extension_id, event.Pass());
124 bool ExtensionKeybindingRegistry::IsAcceleratorRegistered(
125 const ui::Accelerator& accelerator) const {
126 return event_targets_.find(accelerator) != event_targets_.end();
129 void ExtensionKeybindingRegistry::AddEventTarget(
130 const ui::Accelerator& accelerator,
131 const std::string& extension_id,
132 const std::string& command_name) {
133 event_targets_[accelerator].push_back(
134 std::make_pair(extension_id, command_name));
135 // Shortcuts except media keys have only one target in the list. See comment
136 // about |event_targets_|.
137 if (!extensions::Command::IsMediaKey(accelerator))
138 DCHECK_EQ(1u, event_targets_[accelerator].size());
141 bool ExtensionKeybindingRegistry::GetFirstTarget(
142 const ui::Accelerator& accelerator,
143 std::string* extension_id,
144 std::string* command_name) const {
145 EventTargets::const_iterator targets = event_targets_.find(accelerator);
146 if (targets == event_targets_.end())
147 return false;
149 DCHECK(!targets->second.empty());
150 TargetList::const_iterator first_target = targets->second.begin();
151 *extension_id = first_target->first;
152 *command_name = first_target->second;
153 return true;
156 bool ExtensionKeybindingRegistry::IsEventTargetsEmpty() const {
157 return event_targets_.empty();
160 void ExtensionKeybindingRegistry::ExecuteCommand(
161 const std::string& extension_id,
162 const ui::Accelerator& accelerator) {
163 ExecuteCommands(accelerator, extension_id);
166 void ExtensionKeybindingRegistry::OnExtensionLoaded(
167 content::BrowserContext* browser_context,
168 const Extension* extension) {
169 if (ExtensionMatchesFilter(extension))
170 AddExtensionKeybindings(extension, std::string());
173 void ExtensionKeybindingRegistry::OnExtensionUnloaded(
174 content::BrowserContext* browser_context,
175 const Extension* extension,
176 UnloadedExtensionInfo::Reason reason) {
177 if (ExtensionMatchesFilter(extension))
178 RemoveExtensionKeybinding(extension, std::string());
181 void ExtensionKeybindingRegistry::Observe(
182 int type,
183 const content::NotificationSource& source,
184 const content::NotificationDetails& details) {
185 switch (type) {
186 case extensions::NOTIFICATION_EXTENSION_COMMAND_ADDED:
187 case extensions::NOTIFICATION_EXTENSION_COMMAND_REMOVED: {
188 ExtensionCommandRemovedDetails* payload =
189 content::Details<ExtensionCommandRemovedDetails>(details).ptr();
191 const Extension* extension = ExtensionRegistry::Get(browser_context_)
192 ->enabled_extensions()
193 .GetByID(payload->extension_id);
194 // During install and uninstall the extension won't be found. We'll catch
195 // those events above, with the LOADED/UNLOADED, so we ignore this event.
196 if (!extension)
197 return;
199 if (ExtensionMatchesFilter(extension)) {
200 if (type == extensions::NOTIFICATION_EXTENSION_COMMAND_ADDED) {
201 // Component extensions triggers OnExtensionLoaded for extension
202 // installs as well as loads. This can cause adding of multiple key
203 // targets.
204 if (extension->location() == Manifest::COMPONENT)
205 return;
207 AddExtensionKeybindings(extension, payload->command_name);
208 } else {
209 RemoveExtensionKeybinding(extension, payload->command_name);
212 break;
214 default:
215 NOTREACHED();
216 break;
220 bool ExtensionKeybindingRegistry::ExtensionMatchesFilter(
221 const extensions::Extension* extension)
223 switch (extension_filter_) {
224 case ALL_EXTENSIONS:
225 return true;
226 case PLATFORM_APPS_ONLY:
227 return extension->is_platform_app();
228 default:
229 NOTREACHED();
231 return false;
234 bool ExtensionKeybindingRegistry::ExecuteCommands(
235 const ui::Accelerator& accelerator,
236 const std::string& extension_id) {
237 EventTargets::iterator targets = event_targets_.find(accelerator);
238 if (targets == event_targets_.end() || targets->second.empty())
239 return false;
241 bool executed = false;
242 for (TargetList::const_iterator it = targets->second.begin();
243 it != targets->second.end(); it++) {
244 if (!extensions::EventRouter::Get(browser_context_)
245 ->ExtensionHasEventListener(it->first, kOnCommandEventName))
246 continue;
248 if (extension_id.empty() || it->first == extension_id) {
249 CommandExecuted(it->first, it->second);
250 executed = true;
254 return executed;
257 } // namespace extensions