15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/api/commands/command_service.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/lazy_instance.h" 85e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h" 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/commands/commands.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_function_registry.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_keybinding_registry.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_system.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/prefs/scoped_user_pref_update.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/accelerator_utils.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/api/commands/commands_handler.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "components/user_prefs/pref_registry_syncable.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_details.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::Extension; 26b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)using extensions::ExtensionPrefs; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kExtension[] = "extension"; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kCommandName[] = "command_name"; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 33b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// A preference that indicates that the initial keybindings for the given 34b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// extension have been set. 35b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)const char kInitialBindingsHaveBeenAssigned[] = "initial_keybindings_set"; 36b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetPlatformKeybindingKeyForAccelerator( 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ui::Accelerator& accelerator) { 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return extensions::Command::CommandPlatform() + ":" + 40a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) extensions::Command::AcceleratorToString(accelerator); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 43b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void SetInitialBindingsHaveBeenAssigned( 44b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ExtensionPrefs* prefs, const std::string& extension_id) { 45b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) prefs->UpdateExtensionPref(extension_id, kInitialBindingsHaveBeenAssigned, 46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Value::CreateBooleanValue(true)); 47b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} 48b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 49b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool InitialBindingsHaveBeenAssigned( 50b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const ExtensionPrefs* prefs, const std::string& extension_id) { 51b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) bool assigned = false; 52b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (!prefs || !prefs->ReadPrefAsBoolean(extension_id, 53b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) kInitialBindingsHaveBeenAssigned, 54b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) &assigned)) 55b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return false; 56b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 57b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return assigned; 58b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} 59b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid CommandService::RegisterProfilePrefs( 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) user_prefs::PrefRegistrySyncable* registry) { 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) registry->RegisterDictionaryPref( 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) prefs::kExtensionCommands, 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CommandService::CommandService(Profile* profile) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : profile_(profile) { 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ExtensionFunctionRegistry::GetInstance()-> 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RegisterFunction<GetAllCommandsFunction>(); 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Source<Profile>(profile)); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED, 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Source<Profile>(profile)); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CommandService::~CommandService() { 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static base::LazyInstance<ProfileKeyedAPIFactory<CommandService> > 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)g_factory = LAZY_INSTANCE_INITIALIZER; 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ProfileKeyedAPIFactory<CommandService>* CommandService::GetFactoryInstance() { 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return &g_factory.Get(); 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)CommandService* CommandService::Get(Profile* profile) { 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ProfileKeyedAPIFactory<CommandService>::GetForProfile(profile); 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CommandService::GetBrowserActionCommand( 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& extension_id, 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) QueryType type, 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extensions::Command* command, 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* active) { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetExtensionActionCommand( 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_id, type, command, active, BROWSER_ACTION); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CommandService::GetPageActionCommand( 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& extension_id, 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) QueryType type, 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extensions::Command* command, 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* active) { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetExtensionActionCommand( 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_id, type, command, active, PAGE_ACTION); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CommandService::GetScriptBadgeCommand( 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& extension_id, 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) QueryType type, 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extensions::Command* command, 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* active) { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetExtensionActionCommand( 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_id, type, command, active, SCRIPT_BADGE); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CommandService::GetNamedCommands(const std::string& extension_id, 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) QueryType type, 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extensions::CommandMap* command_map) { 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ExtensionSet* extensions = 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensionSystem::Get(profile_)->extension_service()->extensions(); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Extension* extension = extensions->GetByID(extension_id); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(extension); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_map->clear(); 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const extensions::CommandMap* commands = 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CommandsInfo::GetNamedCommands(extension); 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!commands) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extensions::CommandMap::const_iterator iter = commands->begin(); 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (; iter != commands->end(); ++iter) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::Accelerator shortcut_assigned = 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FindShortcutForCommand(extension_id, iter->second.command_name()); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type == ACTIVE_ONLY && shortcut_assigned.key_code() == ui::VKEY_UNKNOWN) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extensions::Command command = iter->second; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (shortcut_assigned.key_code() != ui::VKEY_UNKNOWN) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command.set_accelerator(shortcut_assigned); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*command_map)[iter->second.command_name()] = command; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CommandService::AddKeybindingPref( 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ui::Accelerator& accelerator, 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string extension_id, 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command_name, 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool allow_overrides) { 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (accelerator.key_code() == ui::VKEY_UNKNOWN) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DictionaryPrefUpdate updater(profile_->GetPrefs(), 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefs::kExtensionCommands); 168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::DictionaryValue* bindings = updater.Get(); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string key = GetPlatformKeybindingKeyForAccelerator(accelerator); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!allow_overrides && bindings->HasKey(key)) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; // Already taken. 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::DictionaryValue* keybinding = new base::DictionaryValue(); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keybinding->SetString(kExtension, extension_id); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keybinding->SetString(kCommandName, command_name); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bindings->Set(key, keybinding); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::pair<const std::string, const std::string> details = 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::make_pair(extension_id, command_name); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NotificationService::current()->Notify( 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED, 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Source<Profile>(profile_), 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Details< 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::pair<const std::string, const std::string> >(&details)); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CommandService::Observe( 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int type, 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NotificationSource& source, 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NotificationDetails& details) { 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (type) { 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case chrome::NOTIFICATION_EXTENSION_INSTALLED: 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AssignInitialKeybindings( 199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::Details<const InstalledExtensionInfo>(details)->extension); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RemoveKeybindingPrefs( 203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::Details<const Extension>(details)->id(), 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string()); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CommandService::UpdateKeybindingPrefs(const std::string& extension_id, 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& command_name, 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& keystroke) { 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The extension command might be assigned another shortcut. Remove that 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // shortcut before proceeding. 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RemoveKeybindingPrefs(extension_id, command_name); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::Accelerator accelerator = Command::StringToAccelerator(keystroke); 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddKeybindingPref(accelerator, extension_id, command_name, true); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ui::Accelerator CommandService::FindShortcutForCommand( 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& extension_id, const std::string& command) { 225eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const base::DictionaryValue* bindings = 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_->GetPrefs()->GetDictionary(prefs::kExtensionCommands); 227eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (base::DictionaryValue::Iterator it(*bindings); !it.IsAtEnd(); 228eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch it.Advance()) { 229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const base::DictionaryValue* item = NULL; 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it.value().GetAsDictionary(&item); 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string extension; 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item->GetString(kExtension, &extension); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (extension != extension_id) 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command_name; 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item->GetString(kCommandName, &command_name); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command != command_name) 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string shortcut = it.key(); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (StartsWithASCII(shortcut, Command::CommandPlatform() + ":", true)) 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) shortcut = shortcut.substr(Command::CommandPlatform().length() + 1); 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Command::StringToAccelerator(shortcut); 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CommandService::AssignInitialKeybindings(const Extension* extension) { 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const extensions::CommandMap* commands = 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CommandsInfo::GetNamedCommands(extension); 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!commands) 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 257b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ExtensionService* extension_service = 258b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ExtensionSystem::Get(profile_)->extension_service(); 259b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ExtensionPrefs* extension_prefs = extension_service->extension_prefs(); 260b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (InitialBindingsHaveBeenAssigned(extension_prefs, extension->id())) 261b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return; 262b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) SetInitialBindingsHaveBeenAssigned(extension_prefs, extension->id()); 263b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extensions::CommandMap::const_iterator iter = commands->begin(); 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (; iter != commands->end(); ++iter) { 266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!chrome::IsChromeAccelerator( 267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) iter->second.accelerator(), profile_)) { 268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) AddKeybindingPref(iter->second.accelerator(), 269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) extension->id(), 270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) iter->second.command_name(), 271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) false); // Overwriting not allowed. 272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const extensions::Command* browser_action_command = 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CommandsInfo::GetBrowserActionCommand(extension); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (browser_action_command) { 278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!chrome::IsChromeAccelerator( 279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) browser_action_command->accelerator(), profile_)) { 280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) AddKeybindingPref(browser_action_command->accelerator(), 281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) extension->id(), 282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) browser_action_command->command_name(), 283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) false); // Overwriting not allowed. 284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const extensions::Command* page_action_command = 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CommandsInfo::GetPageActionCommand(extension); 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (page_action_command) { 290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!chrome::IsChromeAccelerator( 291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) page_action_command->accelerator(), profile_)) { 292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) AddKeybindingPref(page_action_command->accelerator(), 293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) extension->id(), 294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) page_action_command->command_name(), 295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) false); // Overwriting not allowed. 296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const extensions::Command* script_badge_command = 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CommandsInfo::GetScriptBadgeCommand(extension); 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (script_badge_command) { 302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!chrome::IsChromeAccelerator( 303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) script_badge_command->accelerator(), profile_)) { 304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) AddKeybindingPref(script_badge_command->accelerator(), 305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) extension->id(), 306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) script_badge_command->command_name(), 307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) false); // Overwriting not allowed. 308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CommandService::RemoveKeybindingPrefs(const std::string& extension_id, 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& command_name) { 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DictionaryPrefUpdate updater(profile_->GetPrefs(), 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefs::kExtensionCommands); 316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::DictionaryValue* bindings = updater.Get(); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef std::vector<std::string> KeysToRemove; 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) KeysToRemove keys_to_remove; 320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (base::DictionaryValue::Iterator it(*bindings); !it.IsAtEnd(); 321eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch it.Advance()) { 322eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const base::DictionaryValue* item = NULL; 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it.value().GetAsDictionary(&item); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string extension; 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item->GetString(kExtension, &extension); 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (extension == extension_id) { 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If |command_name| is specified, delete only that command. Otherwise, 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // delete all commands. 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!command_name.empty()) { 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command; 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item->GetString(kCommandName, &command); 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command_name != command) 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) keys_to_remove.push_back(it.key()); 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (KeysToRemove::const_iterator it = keys_to_remove.begin(); 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != keys_to_remove.end(); ++it) { 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string key = *it; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bindings->Remove(key, NULL); 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::pair<const std::string, const std::string> details = 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::make_pair(extension_id, command_name); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NotificationService::current()->Notify( 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::NOTIFICATION_EXTENSION_COMMAND_REMOVED, 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Source<Profile>(profile_), 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Details< 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::pair<const std::string, const std::string> >(&details)); 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CommandService::GetExtensionActionCommand( 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& extension_id, 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) QueryType query_type, 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extensions::Command* command, 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* active, 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensionActionType action_type) { 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensionService* service = 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensionSystem::Get(profile_)->extension_service(); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!service) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; // Can happen in tests. 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ExtensionSet* extensions = service->extensions(); 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Extension* extension = extensions->GetByID(extension_id); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(extension); 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (active) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *active = false; 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const extensions::Command* requested_command = NULL; 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (action_type) { 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BROWSER_ACTION: 3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) requested_command = CommandsInfo::GetBrowserActionCommand(extension); 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case PAGE_ACTION: 3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) requested_command = CommandsInfo::GetPageActionCommand(extension); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SCRIPT_BADGE: 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) requested_command = CommandsInfo::GetScriptBadgeCommand(extension); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!requested_command) 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::Accelerator shortcut_assigned = 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FindShortcutForCommand(extension_id, requested_command->command_name()); 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (active) 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *active = (shortcut_assigned.key_code() != ui::VKEY_UNKNOWN); 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (query_type == ACTIVE_ONLY && 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) shortcut_assigned.key_code() == ui::VKEY_UNKNOWN) 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *command = *requested_command; 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (shortcut_assigned.key_code() != ui::VKEY_UNKNOWN) 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command->set_accelerator(shortcut_assigned); 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace extensions 407