extension_action_manager.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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_action_manager.h" 6 7#include "chrome/browser/chrome_notification_types.h" 8#include "chrome/browser/extensions/api/system_indicator/system_indicator_manager.h" 9#include "chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.h" 10#include "chrome/browser/extensions/extension_action.h" 11#include "chrome/browser/extensions/extension_system.h" 12#include "chrome/browser/profiles/incognito_helpers.h" 13#include "chrome/browser/profiles/profile.h" 14#include "chrome/common/extensions/api/extension_action/action_info.h" 15#include "chrome/common/extensions/api/extension_action/page_action_handler.h" 16#include "chrome/common/extensions/api/extension_action/script_badge_handler.h" 17#include "chrome/common/extensions/extension.h" 18#include "chrome/common/extensions/feature_switch.h" 19#include "components/browser_context_keyed_service/browser_context_dependency_manager.h" 20#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h" 21#include "content/public/browser/notification_service.h" 22#include "content/public/browser/notification_source.h" 23 24namespace extensions { 25 26namespace { 27 28// BrowserContextKeyedServiceFactory for ExtensionActionManager. 29class ExtensionActionManagerFactory : public BrowserContextKeyedServiceFactory { 30 public: 31 // BrowserContextKeyedServiceFactory implementation: 32 static ExtensionActionManager* GetForProfile(Profile* profile) { 33 return static_cast<ExtensionActionManager*>( 34 GetInstance()->GetServiceForBrowserContext(profile, true)); 35 } 36 37 static ExtensionActionManagerFactory* GetInstance(); 38 39 private: 40 friend struct DefaultSingletonTraits<ExtensionActionManagerFactory>; 41 42 ExtensionActionManagerFactory() 43 : BrowserContextKeyedServiceFactory( 44 "ExtensionActionManager", 45 BrowserContextDependencyManager::GetInstance()) { 46 } 47 48 virtual BrowserContextKeyedService* BuildServiceInstanceFor( 49 content::BrowserContext* profile) const OVERRIDE { 50 return new ExtensionActionManager(static_cast<Profile*>(profile)); 51 } 52 53 virtual content::BrowserContext* GetBrowserContextToUse( 54 content::BrowserContext* context) const OVERRIDE { 55 return chrome::GetBrowserContextRedirectedInIncognito(context); 56 } 57}; 58 59ExtensionActionManagerFactory* 60ExtensionActionManagerFactory::GetInstance() { 61 return Singleton<ExtensionActionManagerFactory>::get(); 62} 63 64} // namespace 65 66ExtensionActionManager::ExtensionActionManager(Profile* profile) 67 : profile_(profile) { 68 CHECK_EQ(profile, profile->GetOriginalProfile()) 69 << "Don't instantiate this with an incognito profile."; 70 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, 71 content::Source<Profile>(profile)); 72} 73 74ExtensionActionManager::~ExtensionActionManager() { 75 // Don't assert that the ExtensionAction maps are empty because Extensions are 76 // sometimes (only in tests?) not unloaded before the Profile is destroyed. 77} 78 79ExtensionActionManager* ExtensionActionManager::Get(Profile* profile) { 80 return ExtensionActionManagerFactory::GetForProfile(profile); 81} 82 83void ExtensionActionManager::Observe( 84 int type, 85 const content::NotificationSource& source, 86 const content::NotificationDetails& details) { 87 switch (type) { 88 case chrome::NOTIFICATION_EXTENSION_UNLOADED: { 89 const Extension* extension = 90 content::Details<UnloadedExtensionInfo>(details)->extension; 91 page_actions_.erase(extension->id()); 92 browser_actions_.erase(extension->id()); 93 script_badges_.erase(extension->id()); 94 system_indicators_.erase(extension->id()); 95 break; 96 } 97 } 98} 99 100namespace { 101 102// Returns map[extension_id] if that entry exists. Otherwise, if 103// action_info!=NULL, creates an ExtensionAction from it, fills in the map, and 104// returns that. Otherwise (action_info==NULL), returns NULL. 105ExtensionAction* GetOrCreateOrNull( 106 std::map<std::string, linked_ptr<ExtensionAction> >* map, 107 const std::string& extension_id, 108 ActionInfo::Type action_type, 109 const ActionInfo* action_info) { 110 std::map<std::string, linked_ptr<ExtensionAction> >::const_iterator it = 111 map->find(extension_id); 112 if (it != map->end()) 113 return it->second.get(); 114 if (!action_info) 115 return NULL; 116 linked_ptr<ExtensionAction> action(new ExtensionAction( 117 extension_id, action_type, *action_info)); 118 (*map)[extension_id] = action; 119 return action.get(); 120} 121 122} // namespace 123 124ExtensionAction* ExtensionActionManager::GetPageAction( 125 const extensions::Extension& extension) const { 126 // The action box changes the meaning of the page action area, so we 127 // need to convert page actions into browser actions. 128 if (FeatureSwitch::script_badges()->IsEnabled()) 129 return NULL; 130 return GetOrCreateOrNull(&page_actions_, extension.id(), 131 ActionInfo::TYPE_PAGE, 132 ActionInfo::GetPageActionInfo(&extension)); 133} 134 135ExtensionAction* ExtensionActionManager::GetBrowserAction( 136 const extensions::Extension& extension) const { 137 const ActionInfo* action_info = ActionInfo::GetBrowserActionInfo(&extension); 138 ActionInfo::Type action_type = ActionInfo::TYPE_BROWSER; 139 if (FeatureSwitch::script_badges()->IsEnabled() && 140 ActionInfo::GetPageActionInfo(&extension)) { 141 // The action box changes the meaning of the page action area, so we 142 // need to convert page actions into browser actions. 143 action_info = ActionInfo::GetPageActionInfo(&extension); 144 action_type = ActionInfo::TYPE_PAGE; 145 } 146 return GetOrCreateOrNull(&browser_actions_, extension.id(), 147 action_type, action_info); 148} 149 150ExtensionAction* ExtensionActionManager::GetSystemIndicator( 151 const extensions::Extension& extension) const { 152 // If it does not already exist, create the SystemIndicatorManager for the 153 // given profile. This could return NULL if the system indicator area is 154 // unavailable on the current system. If so, return NULL to signal that 155 // the system indicator area is unusable. 156 if (!extensions::SystemIndicatorManagerFactory::GetForProfile(profile_)) 157 return NULL; 158 159 return GetOrCreateOrNull(&system_indicators_, extension.id(), 160 ActionInfo::TYPE_SYSTEM_INDICATOR, 161 ActionInfo::GetSystemIndicatorInfo(&extension)); 162} 163 164ExtensionAction* ExtensionActionManager::GetScriptBadge( 165 const extensions::Extension& extension) const { 166 return GetOrCreateOrNull(&script_badges_, extension.id(), 167 ActionInfo::TYPE_SCRIPT_BADGE, 168 ActionInfo::GetScriptBadgeInfo(&extension)); 169} 170 171} // namespace extensions 172