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/extensions/api/system_indicator/system_indicator_manager_factory.h" 8 #include "chrome/browser/extensions/extension_action.h" 9 #include "chrome/browser/extensions/extension_service.h" 10 #include "chrome/browser/profiles/profile.h" 11 #include "components/keyed_service/content/browser_context_dependency_manager.h" 12 #include "extensions/browser/extension_registry.h" 13 #include "extensions/browser/extension_system.h" 14 #include "extensions/browser/extensions_browser_client.h" 15 16 namespace extensions { 17 18 namespace { 19 20 // BrowserContextKeyedServiceFactory for ExtensionActionManager. 21 class ExtensionActionManagerFactory : public BrowserContextKeyedServiceFactory { 22 public: 23 // BrowserContextKeyedServiceFactory implementation: 24 static ExtensionActionManager* GetForProfile(Profile* profile) { 25 return static_cast<ExtensionActionManager*>( 26 GetInstance()->GetServiceForBrowserContext(profile, true)); 27 } 28 29 static ExtensionActionManagerFactory* GetInstance(); 30 31 private: 32 friend struct DefaultSingletonTraits<ExtensionActionManagerFactory>; 33 34 ExtensionActionManagerFactory() 35 : BrowserContextKeyedServiceFactory( 36 "ExtensionActionManager", 37 BrowserContextDependencyManager::GetInstance()) { 38 } 39 40 virtual KeyedService* BuildServiceInstanceFor( 41 content::BrowserContext* profile) const OVERRIDE { 42 return new ExtensionActionManager(static_cast<Profile*>(profile)); 43 } 44 45 virtual content::BrowserContext* GetBrowserContextToUse( 46 content::BrowserContext* context) const OVERRIDE { 47 return ExtensionsBrowserClient::Get()->GetOriginalContext(context); 48 } 49 }; 50 51 ExtensionActionManagerFactory* 52 ExtensionActionManagerFactory::GetInstance() { 53 return Singleton<ExtensionActionManagerFactory>::get(); 54 } 55 56 } // namespace 57 58 ExtensionActionManager::ExtensionActionManager(Profile* profile) 59 : profile_(profile), extension_registry_observer_(this) { 60 CHECK_EQ(profile, profile->GetOriginalProfile()) 61 << "Don't instantiate this with an incognito profile."; 62 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); 63 } 64 65 ExtensionActionManager::~ExtensionActionManager() { 66 // Don't assert that the ExtensionAction maps are empty because Extensions are 67 // sometimes (only in tests?) not unloaded before the Profile is destroyed. 68 } 69 70 ExtensionActionManager* ExtensionActionManager::Get(Profile* profile) { 71 return ExtensionActionManagerFactory::GetForProfile(profile); 72 } 73 74 void ExtensionActionManager::OnExtensionUnloaded( 75 content::BrowserContext* browser_context, 76 const Extension* extension, 77 UnloadedExtensionInfo::Reason reason) { 78 page_actions_.erase(extension->id()); 79 browser_actions_.erase(extension->id()); 80 system_indicators_.erase(extension->id()); 81 } 82 83 namespace { 84 85 // Returns map[extension_id] if that entry exists. Otherwise, if 86 // action_info!=NULL, creates an ExtensionAction from it, fills in the map, and 87 // returns that. Otherwise (action_info==NULL), returns NULL. 88 ExtensionAction* GetOrCreateOrNull( 89 std::map<std::string, linked_ptr<ExtensionAction> >* map, 90 const std::string& extension_id, 91 ActionInfo::Type action_type, 92 const ActionInfo* action_info, 93 Profile* profile) { 94 std::map<std::string, linked_ptr<ExtensionAction> >::const_iterator it = 95 map->find(extension_id); 96 if (it != map->end()) 97 return it->second.get(); 98 if (!action_info) 99 return NULL; 100 101 // Only create action info for enabled extensions. 102 // This avoids bugs where actions are recreated just after being removed 103 // in response to OnExtensionUnloaded(). 104 ExtensionService* service = 105 ExtensionSystem::Get(profile)->extension_service(); 106 if (!service->GetExtensionById(extension_id, false)) 107 return NULL; 108 109 linked_ptr<ExtensionAction> action(new ExtensionAction( 110 extension_id, action_type, *action_info)); 111 (*map)[extension_id] = action; 112 return action.get(); 113 } 114 115 } // namespace 116 117 ExtensionAction* ExtensionActionManager::GetPageAction( 118 const extensions::Extension& extension) const { 119 return GetOrCreateOrNull(&page_actions_, extension.id(), 120 ActionInfo::TYPE_PAGE, 121 ActionInfo::GetPageActionInfo(&extension), 122 profile_); 123 } 124 125 ExtensionAction* ExtensionActionManager::GetBrowserAction( 126 const extensions::Extension& extension) const { 127 return GetOrCreateOrNull(&browser_actions_, extension.id(), 128 ActionInfo::TYPE_BROWSER, 129 ActionInfo::GetBrowserActionInfo(&extension), 130 profile_); 131 } 132 133 ExtensionAction* ExtensionActionManager::GetSystemIndicator( 134 const extensions::Extension& extension) const { 135 // If it does not already exist, create the SystemIndicatorManager for the 136 // given profile. This could return NULL if the system indicator area is 137 // unavailable on the current system. If so, return NULL to signal that 138 // the system indicator area is unusable. 139 if (!extensions::SystemIndicatorManagerFactory::GetForProfile(profile_)) 140 return NULL; 141 142 return GetOrCreateOrNull(&system_indicators_, extension.id(), 143 ActionInfo::TYPE_SYSTEM_INDICATOR, 144 ActionInfo::GetSystemIndicatorInfo(&extension), 145 profile_); 146 } 147 148 } // namespace extensions 149