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.
5 #include "chrome/browser/extensions/extension_action_manager.h"
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_service.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/common/extensions/api/extension_action/action_info.h"
14 #include "chrome/common/extensions/api/extension_action/page_action_handler.h"
15 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
16 #include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
17 #include "content/public/browser/notification_service.h"
18 #include "content/public/browser/notification_source.h"
19 #include "extensions/browser/extension_system.h"
20 #include "extensions/browser/extensions_browser_client.h"
21 #include "extensions/common/extension.h"
22 #include "extensions/common/feature_switch.h"
24 namespace extensions
{
28 // BrowserContextKeyedServiceFactory for ExtensionActionManager.
29 class ExtensionActionManagerFactory
: public BrowserContextKeyedServiceFactory
{
31 // BrowserContextKeyedServiceFactory implementation:
32 static ExtensionActionManager
* GetForProfile(Profile
* profile
) {
33 return static_cast<ExtensionActionManager
*>(
34 GetInstance()->GetServiceForBrowserContext(profile
, true));
37 static ExtensionActionManagerFactory
* GetInstance();
40 friend struct DefaultSingletonTraits
<ExtensionActionManagerFactory
>;
42 ExtensionActionManagerFactory()
43 : BrowserContextKeyedServiceFactory(
44 "ExtensionActionManager",
45 BrowserContextDependencyManager::GetInstance()) {
48 virtual BrowserContextKeyedService
* BuildServiceInstanceFor(
49 content::BrowserContext
* profile
) const OVERRIDE
{
50 return new ExtensionActionManager(static_cast<Profile
*>(profile
));
53 virtual content::BrowserContext
* GetBrowserContextToUse(
54 content::BrowserContext
* context
) const OVERRIDE
{
55 return ExtensionsBrowserClient::Get()->GetOriginalContext(context
);
59 ExtensionActionManagerFactory
*
60 ExtensionActionManagerFactory::GetInstance() {
61 return Singleton
<ExtensionActionManagerFactory
>::get();
66 ExtensionActionManager::ExtensionActionManager(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
));
74 ExtensionActionManager::~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.
79 ExtensionActionManager
* ExtensionActionManager::Get(Profile
* profile
) {
80 return ExtensionActionManagerFactory::GetForProfile(profile
);
83 void ExtensionActionManager::Observe(
85 const content::NotificationSource
& source
,
86 const content::NotificationDetails
& details
) {
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 system_indicators_
.erase(extension
->id());
101 // Returns map[extension_id] if that entry exists. Otherwise, if
102 // action_info!=NULL, creates an ExtensionAction from it, fills in the map, and
103 // returns that. Otherwise (action_info==NULL), returns NULL.
104 ExtensionAction
* GetOrCreateOrNull(
105 std::map
<std::string
, linked_ptr
<ExtensionAction
> >* map
,
106 const std::string
& extension_id
,
107 ActionInfo::Type action_type
,
108 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();
117 // Only create action info for enabled extensions.
118 // This avoids bugs where actions are recreated just after being removed
119 // in response to NOTIFICATION_EXTENSION_UNLOADED in
120 // ExtensionActionManager::Observe()
121 ExtensionService
* service
=
122 ExtensionSystem::Get(profile
)->extension_service();
123 if (!service
->GetExtensionById(extension_id
, false))
126 linked_ptr
<ExtensionAction
> action(new ExtensionAction(
127 extension_id
, action_type
, *action_info
));
128 (*map
)[extension_id
] = action
;
134 ExtensionAction
* ExtensionActionManager::GetPageAction(
135 const extensions::Extension
& extension
) const {
136 return GetOrCreateOrNull(&page_actions_
, extension
.id(),
137 ActionInfo::TYPE_PAGE
,
138 ActionInfo::GetPageActionInfo(&extension
),
142 ExtensionAction
* ExtensionActionManager::GetBrowserAction(
143 const extensions::Extension
& extension
) const {
144 return GetOrCreateOrNull(&browser_actions_
, extension
.id(),
145 ActionInfo::TYPE_BROWSER
,
146 ActionInfo::GetBrowserActionInfo(&extension
),
150 ExtensionAction
* 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_
))
159 return GetOrCreateOrNull(&system_indicators_
, extension
.id(),
160 ActionInfo::TYPE_SYSTEM_INDICATOR
,
161 ActionInfo::GetSystemIndicatorInfo(&extension
),
165 } // namespace extensions