Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(800)

Side by Side Diff: chrome/browser/extensions/api/commands/command_service_new.cc

Issue 23445013: Parse media keys for named command in the manifest. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: nit fix. Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/api/commands/command_service.h"
6
7 #include "base/lazy_instance.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/extensions/api/commands/commands.h"
12 #include "chrome/browser/extensions/extension_function_registry.h"
13 #include "chrome/browser/extensions/extension_keybinding_registry.h"
14 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/extensions/extension_system.h"
16 #include "chrome/browser/prefs/scoped_user_pref_update.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/common/pref_names.h"
19 #include "components/user_prefs/pref_registry_syncable.h"
20 #include "content/public/browser/notification_details.h"
21 #include "content/public/browser/notification_service.h"
22
23 using extensions::Extension;
24
25 namespace {
26
27 const char kExtension[] = "extension";
28 const char kCommandName[] = "command_name";
29
30 std::string GetPlatformKeybindingKeyForAccelerator(
31 const ui::Accelerator& accelerator) {
32 return extensions::Command::CommandPlatform() + ":" +
33 UTF16ToUTF8(accelerator.GetShortcutText());
34 }
35
36 } // namespace
37
38 namespace extensions {
39
40 // static
41 void CommandService::RegisterProfilePrefs(
42 user_prefs::PrefRegistrySyncable* registry) {
43 registry->RegisterDictionaryPref(
44 prefs::kExtensionCommands,
45 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
46 }
47
48 CommandService::CommandService(Profile* profile)
49 : profile_(profile) {
50 ExtensionFunctionRegistry::GetInstance()->
51 RegisterFunction<GetAllCommandsFunction>();
52
53 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
54 content::Source<Profile>(profile));
55 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
56 content::Source<Profile>(profile));
57 }
58
59 CommandService::~CommandService() {
60 }
61
62 static base::LazyInstance<ProfileKeyedAPIFactory<CommandService> >
63 g_factory = LAZY_INSTANCE_INITIALIZER;
64
65 // static
66 ProfileKeyedAPIFactory<CommandService>* CommandService::GetFactoryInstance() {
67 return &g_factory.Get();
68 }
69
70 // static
71 CommandService* CommandService::Get(Profile* profile) {
72 return ProfileKeyedAPIFactory<CommandService>::GetForProfile(profile);
73 }
74
75 bool CommandService::GetBrowserActionCommand(
76 const std::string& extension_id,
77 QueryType type,
78 extensions::Command* command,
79 bool* active) {
80 return GetExtensionActionCommand(
81 extension_id, type, command, active, BROWSER_ACTION);
82 }
83
84 bool CommandService::GetPageActionCommand(
85 const std::string& extension_id,
86 QueryType type,
87 extensions::Command* command,
88 bool* active) {
89 return GetExtensionActionCommand(
90 extension_id, type, command, active, PAGE_ACTION);
91 }
92
93 bool CommandService::GetScriptBadgeCommand(
94 const std::string& extension_id,
95 QueryType type,
96 extensions::Command* command,
97 bool* active) {
98 return GetExtensionActionCommand(
99 extension_id, type, command, active, SCRIPT_BADGE);
100 }
101
102 bool CommandService::GetNamedCommands(const std::string& extension_id,
103 QueryType type,
104 extensions::CommandMap* command_map) {
105 const ExtensionSet* extensions =
106 ExtensionSystem::Get(profile_)->extension_service()->extensions();
107 const Extension* extension = extensions->GetByID(extension_id);
108 CHECK(extension);
109
110 command_map->clear();
111 const extensions::CommandMap* commands =
112 CommandsInfo::GetNamedCommands(extension);
113 if (!commands)
114 return false;
115
116 extensions::CommandMap::const_iterator iter = commands->begin();
117 for (; iter != commands->end(); ++iter) {
118 ui::Accelerator shortcut_assigned =
119 FindShortcutForCommand(extension_id, iter->second.command_name());
120
121 if (type == ACTIVE_ONLY && shortcut_assigned.key_code() == ui::VKEY_UNKNOWN)
122 continue;
123
124 extensions::Command command = iter->second;
125 if (shortcut_assigned.key_code() != ui::VKEY_UNKNOWN)
126 command.set_accelerator(shortcut_assigned);
127
128 (*command_map)[iter->second.command_name()] = command;
129 }
130
131 return true;
132 }
133
134 bool CommandService::AddKeybindingPref(
135 const ui::Accelerator& accelerator,
136 std::string extension_id,
137 std::string command_name,
138 bool allow_overrides) {
139 if (accelerator.key_code() == ui::VKEY_UNKNOWN)
140 return false;
141
142 DictionaryPrefUpdate updater(profile_->GetPrefs(),
143 prefs::kExtensionCommands);
144 base::DictionaryValue* bindings = updater.Get();
145
146 std::string key = GetPlatformKeybindingKeyForAccelerator(accelerator);
147
148 if (!allow_overrides && bindings->HasKey(key))
149 return false; // Already taken.
150
151 base::DictionaryValue* keybinding = new base::DictionaryValue();
152 keybinding->SetString(kExtension, extension_id);
153 keybinding->SetString(kCommandName, command_name);
154
155 bindings->Set(key, keybinding);
156
157 std::pair<const std::string, const std::string> details =
158 std::make_pair(extension_id, command_name);
159 content::NotificationService::current()->Notify(
160 chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED,
161 content::Source<Profile>(profile_),
162 content::Details<
163 std::pair<const std::string, const std::string> >(&details));
164
165 return true;
166 }
167
168 void CommandService::Observe(
169 int type,
170 const content::NotificationSource& source,
171 const content::NotificationDetails& details) {
172 switch (type) {
173 case chrome::NOTIFICATION_EXTENSION_INSTALLED:
174 AssignInitialKeybindings(
175 content::Details<const InstalledExtensionInfo>(details)->extension);
176 break;
177 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
178 RemoveKeybindingPrefs(
179 content::Details<const Extension>(details)->id(),
180 std::string());
181 break;
182 default:
183 NOTREACHED();
184 break;
185 }
186 }
187
188 void CommandService::UpdateKeybindingPrefs(const std::string& extension_id,
189 const std::string& command_name,
190 const std::string& keystroke) {
191 // The extension command might be assigned another shortcut. Remove that
192 // shortcut before proceeding.
193 RemoveKeybindingPrefs(extension_id, command_name);
194
195 ui::Accelerator accelerator = Command::StringToAccelerator(keystroke);
196 AddKeybindingPref(accelerator, extension_id, command_name, true);
197 }
198
199 ui::Accelerator CommandService::FindShortcutForCommand(
200 const std::string& extension_id, const std::string& command) {
201 const base::DictionaryValue* bindings =
202 profile_->GetPrefs()->GetDictionary(prefs::kExtensionCommands);
203 for (base::DictionaryValue::Iterator it(*bindings); !it.IsAtEnd();
204 it.Advance()) {
205 const base::DictionaryValue* item = NULL;
206 it.value().GetAsDictionary(&item);
207
208 std::string extension;
209 item->GetString(kExtension, &extension);
210 if (extension != extension_id)
211 continue;
212 std::string command_name;
213 item->GetString(kCommandName, &command_name);
214 if (command != command_name)
215 continue;
216
217 std::string shortcut = it.key();
218 if (StartsWithASCII(shortcut, Command::CommandPlatform() + ":", true))
219 shortcut = shortcut.substr(Command::CommandPlatform().length() + 1);
220
221 return Command::StringToAccelerator(shortcut);
222 }
223
224 return ui::Accelerator();
225 }
226
227 void CommandService::AssignInitialKeybindings(const Extension* extension) {
228 const extensions::CommandMap* commands =
229 CommandsInfo::GetNamedCommands(extension);
230 if (!commands)
231 return;
232
233 extensions::CommandMap::const_iterator iter = commands->begin();
234 for (; iter != commands->end(); ++iter) {
235 AddKeybindingPref(iter->second.accelerator(),
236 extension->id(),
237 iter->second.command_name(),
238 false); // Overwriting not allowed.
239 }
240
241 const extensions::Command* browser_action_command =
242 CommandsInfo::GetBrowserActionCommand(extension);
243 if (browser_action_command) {
244 AddKeybindingPref(browser_action_command->accelerator(),
245 extension->id(),
246 browser_action_command->command_name(),
247 false); // Overwriting not allowed.
248 }
249
250 const extensions::Command* page_action_command =
251 CommandsInfo::GetPageActionCommand(extension);
252 if (page_action_command) {
253 AddKeybindingPref(page_action_command->accelerator(),
254 extension->id(),
255 page_action_command->command_name(),
256 false); // Overwriting not allowed.
257 }
258
259 const extensions::Command* script_badge_command =
260 CommandsInfo::GetScriptBadgeCommand(extension);
261 if (script_badge_command) {
262 AddKeybindingPref(script_badge_command->accelerator(),
263 extension->id(),
264 script_badge_command->command_name(),
265 false); // Overwriting not allowed.
266 }
267 }
268
269 void CommandService::RemoveKeybindingPrefs(const std::string& extension_id,
270 const std::string& command_name) {
271 DictionaryPrefUpdate updater(profile_->GetPrefs(),
272 prefs::kExtensionCommands);
273 base::DictionaryValue* bindings = updater.Get();
274
275 typedef std::vector<std::string> KeysToRemove;
276 KeysToRemove keys_to_remove;
277 for (base::DictionaryValue::Iterator it(*bindings); !it.IsAtEnd();
278 it.Advance()) {
279 const base::DictionaryValue* item = NULL;
280 it.value().GetAsDictionary(&item);
281
282 std::string extension;
283 item->GetString(kExtension, &extension);
284
285 if (extension == extension_id) {
286 // If |command_name| is specified, delete only that command. Otherwise,
287 // delete all commands.
288 if (!command_name.empty()) {
289 std::string command;
290 item->GetString(kCommandName, &command);
291 if (command_name != command)
292 continue;
293 }
294
295 keys_to_remove.push_back(it.key());
296 }
297 }
298
299 for (KeysToRemove::const_iterator it = keys_to_remove.begin();
300 it != keys_to_remove.end(); ++it) {
301 std::string key = *it;
302 bindings->Remove(key, NULL);
303
304 std::pair<const std::string, const std::string> details =
305 std::make_pair(extension_id, command_name);
306 content::NotificationService::current()->Notify(
307 chrome::NOTIFICATION_EXTENSION_COMMAND_REMOVED,
308 content::Source<Profile>(profile_),
309 content::Details<
310 std::pair<const std::string, const std::string> >(&details));
311 }
312 }
313
314 bool CommandService::GetExtensionActionCommand(
315 const std::string& extension_id,
316 QueryType query_type,
317 extensions::Command* command,
318 bool* active,
319 ExtensionActionType action_type) {
320 ExtensionService* service =
321 ExtensionSystem::Get(profile_)->extension_service();
322 if (!service)
323 return false; // Can happen in tests.
324 const ExtensionSet* extensions = service->extensions();
325 const Extension* extension = extensions->GetByID(extension_id);
326 CHECK(extension);
327
328 if (active)
329 *active = false;
330
331 const extensions::Command* requested_command = NULL;
332 switch (action_type) {
333 case BROWSER_ACTION:
334 requested_command = CommandsInfo::GetBrowserActionCommand(extension);
335 break;
336 case PAGE_ACTION:
337 requested_command = CommandsInfo::GetPageActionCommand(extension);
338 break;
339 case SCRIPT_BADGE:
340 requested_command = CommandsInfo::GetScriptBadgeCommand(extension);
341 break;
342 }
343 if (!requested_command)
344 return false;
345
346 ui::Accelerator shortcut_assigned =
347 FindShortcutForCommand(extension_id, requested_command->command_name());
348
349 if (active)
350 *active = (shortcut_assigned.key_code() != ui::VKEY_UNKNOWN);
351
352 if (query_type == ACTIVE_ONLY &&
353 shortcut_assigned.key_code() == ui::VKEY_UNKNOWN)
354 return false;
355
356 *command = *requested_command;
357 if (shortcut_assigned.key_code() != ui::VKEY_UNKNOWN)
358 command->set_accelerator(shortcut_assigned);
359
360 return true;
361 }
362
363 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698