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