Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / extension_keybinding_registry.cc
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 #include "chrome/browser/extensions/extension_keybinding_registry.h"
6
7 #include "base/values.h"
8 #include "chrome/browser/chrome_notification_types.h"
9 #include "chrome/browser/extensions/active_tab_permission_granter.h"
10 #include "chrome/browser/extensions/api/commands/command_service.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "extensions/browser/event_router.h"
14 #include "extensions/browser/extension_system.h"
15 #include "extensions/common/extension_set.h"
16 #include "extensions/common/manifest_constants.h"
17
18 namespace extensions {
19
20 ExtensionKeybindingRegistry::ExtensionKeybindingRegistry(
21     Profile* profile, ExtensionFilter extension_filter, Delegate* delegate)
22     : profile_(profile),
23       extension_filter_(extension_filter),
24       delegate_(delegate) {
25   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
26                  content::Source<Profile>(profile->GetOriginalProfile()));
27   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
28                  content::Source<Profile>(profile->GetOriginalProfile()));
29   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED,
30                  content::Source<Profile>(profile->GetOriginalProfile()));
31   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_COMMAND_REMOVED,
32                  content::Source<Profile>(profile->GetOriginalProfile()));
33 }
34
35 ExtensionKeybindingRegistry::~ExtensionKeybindingRegistry() {
36 }
37
38 void ExtensionKeybindingRegistry::RemoveExtensionKeybinding(
39     const Extension* extension,
40     const std::string& command_name) {
41   EventTargets::iterator it = event_targets_.begin();
42   while (it != event_targets_.end()) {
43     TargetList& target_list = it->second;
44     TargetList::iterator target = target_list.begin();
45     while (target != target_list.end()) {
46       if (target->first == extension->id() &&
47           (command_name.empty() || command_name == target->second))
48         target = target_list.erase(target);
49       else
50         target++;
51     }
52
53     EventTargets::iterator old = it++;
54     if (target_list.empty()) {
55       // Let each platform-specific implementation get a chance to clean up.
56       RemoveExtensionKeybindingImpl(old->first, command_name);
57       event_targets_.erase(old);
58
59       // If a specific command_name was requested, it has now been deleted so no
60       // further work is required.
61       if (!command_name.empty())
62         break;
63     }
64   }
65 }
66
67 void ExtensionKeybindingRegistry::Init() {
68   ExtensionService* service =
69       extensions::ExtensionSystem::Get(profile_)->extension_service();
70   if (!service)
71     return;  // ExtensionService can be null during testing.
72
73   const ExtensionSet* extensions = service->extensions();
74   ExtensionSet::const_iterator iter = extensions->begin();
75   for (; iter != extensions->end(); ++iter)
76     if (ExtensionMatchesFilter(iter->get()))
77       AddExtensionKeybinding(iter->get(), std::string());
78 }
79
80 bool ExtensionKeybindingRegistry::ShouldIgnoreCommand(
81     const std::string& command) const {
82   return command == manifest_values::kPageActionCommandEvent ||
83          command == manifest_values::kBrowserActionCommandEvent;
84 }
85
86 bool ExtensionKeybindingRegistry::NotifyEventTargets(
87     const ui::Accelerator& accelerator) {
88   EventTargets::iterator targets = event_targets_.find(accelerator);
89   if (targets == event_targets_.end() || targets->second.empty())
90     return false;
91
92   for (TargetList::const_iterator it = targets->second.begin();
93        it != targets->second.end(); it++)
94     CommandExecuted(it->first, it->second);
95
96   return true;
97 }
98
99 void ExtensionKeybindingRegistry::CommandExecuted(
100     const std::string& extension_id, const std::string& command) {
101   ExtensionService* service =
102       ExtensionSystem::Get(profile_)->extension_service();
103
104   const Extension* extension = service->extensions()->GetByID(extension_id);
105   if (!extension)
106     return;
107
108   // Grant before sending the event so that the permission is granted before
109   // the extension acts on the command. NOTE: The Global Commands handler does
110   // not set the delegate as it deals only with named commands (not page/browser
111   // actions that are associated with the current page directly).
112   ActiveTabPermissionGranter* granter =
113       delegate_ ? delegate_->GetActiveTabPermissionGranter() : NULL;
114   if (granter)
115     granter->GrantIfRequested(extension);
116
117   scoped_ptr<base::ListValue> args(new base::ListValue());
118   args->Append(new base::StringValue(command));
119
120   scoped_ptr<Event> event(new Event("commands.onCommand", args.Pass()));
121   event->restrict_to_browser_context = profile_;
122   event->user_gesture = EventRouter::USER_GESTURE_ENABLED;
123   ExtensionSystem::Get(profile_)->event_router()->
124       DispatchEventToExtension(extension_id, event.Pass());
125 }
126
127 void ExtensionKeybindingRegistry::Observe(
128     int type,
129     const content::NotificationSource& source,
130     const content::NotificationDetails& details) {
131   switch (type) {
132     case chrome::NOTIFICATION_EXTENSION_LOADED: {
133       const extensions::Extension* extension =
134           content::Details<const extensions::Extension>(details).ptr();
135       if (ExtensionMatchesFilter(extension))
136         AddExtensionKeybinding(extension, std::string());
137       break;
138     }
139     case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
140       const extensions::Extension* extension =
141           content::Details<UnloadedExtensionInfo>(details)->extension;
142       if (ExtensionMatchesFilter(extension))
143         RemoveExtensionKeybinding(extension, std::string());
144       break;
145     }
146     case chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED:
147     case chrome::NOTIFICATION_EXTENSION_COMMAND_REMOVED: {
148       std::pair<const std::string, const std::string>* payload =
149           content::Details<std::pair<const std::string, const std::string> >(
150               details).ptr();
151
152       const extensions::Extension* extension =
153           ExtensionSystem::Get(profile_)->extension_service()->
154               extensions()->GetByID(payload->first);
155       // During install and uninstall the extension won't be found. We'll catch
156       // those events above, with the LOADED/UNLOADED, so we ignore this event.
157       if (!extension)
158         return;
159
160       if (ExtensionMatchesFilter(extension)) {
161         if (type == chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED)
162           AddExtensionKeybinding(extension, payload->second);
163         else
164           RemoveExtensionKeybinding(extension, payload->second);
165       }
166       break;
167     }
168     default:
169       NOTREACHED();
170       break;
171   }
172 }
173
174 bool ExtensionKeybindingRegistry::ExtensionMatchesFilter(
175     const extensions::Extension* extension)
176 {
177   switch (extension_filter_) {
178     case ALL_EXTENSIONS:
179       return true;
180     case PLATFORM_APPS_ONLY:
181       return extension->is_platform_app();
182     default:
183       NOTREACHED();
184   }
185   return false;
186 }
187
188 }  // namespace extensions