Home | History | Annotate | Download | only in extensions
      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/event_router.h"
     11 #include "chrome/browser/extensions/extension_service.h"
     12 #include "chrome/browser/extensions/extension_system.h"
     13 #include "chrome/browser/profiles/profile.h"
     14 #include "chrome/common/extensions/extension_manifest_constants.h"
     15 #include "chrome/common/extensions/extension_set.h"
     16 
     17 namespace extensions {
     18 
     19 ExtensionKeybindingRegistry::ExtensionKeybindingRegistry(
     20     Profile* profile, ExtensionFilter extension_filter, Delegate* delegate)
     21     : profile_(profile),
     22       extension_filter_(extension_filter),
     23       delegate_(delegate) {
     24   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
     25                  content::Source<Profile>(profile->GetOriginalProfile()));
     26   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
     27                  content::Source<Profile>(profile->GetOriginalProfile()));
     28   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED,
     29                  content::Source<Profile>(profile->GetOriginalProfile()));
     30   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_COMMAND_REMOVED,
     31                  content::Source<Profile>(profile->GetOriginalProfile()));
     32 }
     33 
     34 ExtensionKeybindingRegistry::~ExtensionKeybindingRegistry() {
     35 }
     36 
     37 void ExtensionKeybindingRegistry::Init() {
     38   ExtensionService* service =
     39       extensions::ExtensionSystem::Get(profile_)->extension_service();
     40   if (!service)
     41     return;  // ExtensionService can be null during testing.
     42 
     43   const ExtensionSet* extensions = service->extensions();
     44   ExtensionSet::const_iterator iter = extensions->begin();
     45   for (; iter != extensions->end(); ++iter)
     46     if (ExtensionMatchesFilter(iter->get()))
     47       AddExtensionKeybinding(iter->get(), std::string());
     48 }
     49 
     50 bool ExtensionKeybindingRegistry::ShouldIgnoreCommand(
     51     const std::string& command) const {
     52   return command == extension_manifest_values::kPageActionCommandEvent ||
     53          command == extension_manifest_values::kBrowserActionCommandEvent ||
     54          command == extension_manifest_values::kScriptBadgeCommandEvent;
     55 }
     56 
     57 void ExtensionKeybindingRegistry::CommandExecuted(
     58     const std::string& extension_id, const std::string& command) {
     59   ExtensionService* service =
     60       ExtensionSystem::Get(profile_)->extension_service();
     61 
     62   const Extension* extension = service->extensions()->GetByID(extension_id);
     63   if (!extension)
     64     return;
     65 
     66   // Grant before sending the event so that the permission is granted before
     67   // the extension acts on the command.
     68   ActiveTabPermissionGranter* granter =
     69       delegate_->GetActiveTabPermissionGranter();
     70   if (granter)
     71     granter->GrantIfRequested(extension);
     72 
     73   scoped_ptr<base::ListValue> args(new base::ListValue());
     74   args->Append(Value::CreateStringValue(command));
     75 
     76   scoped_ptr<Event> event(new Event("commands.onCommand", args.Pass()));
     77   event->restrict_to_profile = profile_;
     78   event->user_gesture = EventRouter::USER_GESTURE_ENABLED;
     79   ExtensionSystem::Get(profile_)->event_router()->
     80       DispatchEventToExtension(extension_id, event.Pass());
     81 }
     82 
     83 void ExtensionKeybindingRegistry::Observe(
     84     int type,
     85     const content::NotificationSource& source,
     86     const content::NotificationDetails& details) {
     87   switch (type) {
     88     case chrome::NOTIFICATION_EXTENSION_LOADED: {
     89       const extensions::Extension* extension =
     90           content::Details<const extensions::Extension>(details).ptr();
     91       if (ExtensionMatchesFilter(extension))
     92         AddExtensionKeybinding(extension, std::string());
     93       break;
     94     }
     95     case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
     96       const extensions::Extension* extension =
     97           content::Details<UnloadedExtensionInfo>(details)->extension;
     98       if (ExtensionMatchesFilter(extension))
     99         RemoveExtensionKeybinding(extension, std::string());
    100       break;
    101     }
    102     case chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED:
    103     case chrome::NOTIFICATION_EXTENSION_COMMAND_REMOVED: {
    104       std::pair<const std::string, const std::string>* payload =
    105           content::Details<std::pair<const std::string, const std::string> >(
    106               details).ptr();
    107 
    108       const extensions::Extension* extension =
    109           ExtensionSystem::Get(profile_)->extension_service()->
    110               extensions()->GetByID(payload->first);
    111       // During install and uninstall the extension won't be found. We'll catch
    112       // those events above, with the LOADED/UNLOADED, so we ignore this event.
    113       if (!extension)
    114         return;
    115 
    116       if (ExtensionMatchesFilter(extension)) {
    117         if (type == chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED)
    118           AddExtensionKeybinding(extension, payload->second);
    119         else
    120           RemoveExtensionKeybinding(extension, payload->second);
    121       }
    122       break;
    123     }
    124     default:
    125       NOTREACHED();
    126       break;
    127   }
    128 }
    129 
    130 bool ExtensionKeybindingRegistry::ExtensionMatchesFilter(
    131     const extensions::Extension* extension)
    132 {
    133   switch (extension_filter_) {
    134     case ALL_EXTENSIONS:
    135       return true;
    136     case PLATFORM_APPS_ONLY:
    137       return extension->is_platform_app();
    138     default:
    139       NOTREACHED();
    140   }
    141   return false;
    142 }
    143 
    144 }  // namespace extensions
    145