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