Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / extension_action_manager.cc
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/profiles/profile.h"
10 #include "components/keyed_service/content/browser_context_dependency_manager.h"
11 #include "extensions/browser/extension_registry.h"
12 #include "extensions/browser/extension_system.h"
13 #include "extensions/browser/extensions_browser_client.h"
14 #include "extensions/common/constants.h"
15 #include "extensions/common/manifest_handlers/icons_handler.h"
16
17 namespace extensions {
18
19 namespace {
20
21 // BrowserContextKeyedServiceFactory for ExtensionActionManager.
22 class ExtensionActionManagerFactory : public BrowserContextKeyedServiceFactory {
23  public:
24   // BrowserContextKeyedServiceFactory implementation:
25   static ExtensionActionManager* GetForBrowserContext(
26       content::BrowserContext* context) {
27     return static_cast<ExtensionActionManager*>(
28         GetInstance()->GetServiceForBrowserContext(context, true));
29   }
30
31   static ExtensionActionManagerFactory* GetInstance();
32
33  private:
34   friend struct DefaultSingletonTraits<ExtensionActionManagerFactory>;
35
36   ExtensionActionManagerFactory()
37       : BrowserContextKeyedServiceFactory(
38           "ExtensionActionManager",
39           BrowserContextDependencyManager::GetInstance()) {
40   }
41
42   KeyedService* BuildServiceInstanceFor(
43       content::BrowserContext* profile) const override {
44     return new ExtensionActionManager(static_cast<Profile*>(profile));
45   }
46
47   content::BrowserContext* GetBrowserContextToUse(
48       content::BrowserContext* context) const override {
49     return ExtensionsBrowserClient::Get()->GetOriginalContext(context);
50   }
51 };
52
53 ExtensionActionManagerFactory*
54 ExtensionActionManagerFactory::GetInstance() {
55   return Singleton<ExtensionActionManagerFactory>::get();
56 }
57
58 }  // namespace
59
60 ExtensionActionManager::ExtensionActionManager(Profile* profile)
61     : profile_(profile), extension_registry_observer_(this) {
62   CHECK_EQ(profile, profile->GetOriginalProfile())
63       << "Don't instantiate this with an incognito profile.";
64   extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
65 }
66
67 ExtensionActionManager::~ExtensionActionManager() {
68   // Don't assert that the ExtensionAction maps are empty because Extensions are
69   // sometimes (only in tests?) not unloaded before the Profile is destroyed.
70 }
71
72 ExtensionActionManager* ExtensionActionManager::Get(
73     content::BrowserContext* context) {
74   return ExtensionActionManagerFactory::GetForBrowserContext(context);
75 }
76
77 void ExtensionActionManager::OnExtensionUnloaded(
78     content::BrowserContext* browser_context,
79     const Extension* extension,
80     UnloadedExtensionInfo::Reason reason) {
81   page_actions_.erase(extension->id());
82   browser_actions_.erase(extension->id());
83   system_indicators_.erase(extension->id());
84 }
85
86 namespace {
87
88 // Loads resources missing from |action| (i.e. title, icons) from the "icons"
89 // key of |extension|'s manifest.
90 void PopulateMissingValues(const Extension& extension,
91                            ExtensionAction* action) {
92   // If the title is missing from |action|, set it to |extension|'s name.
93   if (action->GetTitle(ExtensionAction::kDefaultTabId).empty())
94     action->SetTitle(ExtensionAction::kDefaultTabId, extension.name());
95
96   scoped_ptr<ExtensionIconSet> default_icon(new ExtensionIconSet());
97   if (action->default_icon())
98     *default_icon = *action->default_icon();
99
100   const ExtensionIconSet& extension_icons = IconsInfo::GetIcons(&extension);
101   std::string largest_icon = extension_icons.Get(
102       extension_misc::EXTENSION_ICON_GIGANTOR,
103       ExtensionIconSet::MATCH_SMALLER);
104
105   if (!largest_icon.empty()) {
106     int largest_icon_size = extension_icons.GetIconSizeFromPath(largest_icon);
107     // Replace any missing extension action icons with the largest icon
108     // retrieved from |extension|'s manifest so long as the largest icon is
109     // larger than the current key.
110     for (int i = extension_misc::kNumExtensionActionIconSizes - 1;
111          i >= 0; --i) {
112       int size = extension_misc::kExtensionActionIconSizes[i].size;
113       if (default_icon->Get(size, ExtensionIconSet::MATCH_BIGGER).empty()
114           && largest_icon_size > size) {
115         default_icon->Add(size, largest_icon);
116         break;
117       }
118     }
119     action->set_default_icon(default_icon.Pass());
120   }
121 }
122
123 // Returns map[extension_id] if that entry exists. Otherwise, if
124 // action_info!=NULL, creates an ExtensionAction from it, fills in the map, and
125 // returns that.  Otherwise (action_info==NULL), returns NULL.
126 ExtensionAction* GetOrCreateOrNull(
127     std::map<std::string, linked_ptr<ExtensionAction> >* map,
128     const Extension& extension,
129     ActionInfo::Type action_type,
130     const ActionInfo* action_info,
131     Profile* profile) {
132   std::map<std::string, linked_ptr<ExtensionAction> >::const_iterator it =
133       map->find(extension.id());
134   if (it != map->end())
135     return it->second.get();
136   if (!action_info)
137     return NULL;
138
139   // Only create action info for enabled extensions.
140   // This avoids bugs where actions are recreated just after being removed
141   // in response to OnExtensionUnloaded().
142   if (!ExtensionRegistry::Get(profile)
143       ->enabled_extensions().Contains(extension.id())) {
144     return NULL;
145   }
146
147   linked_ptr<ExtensionAction> action(new ExtensionAction(
148       extension.id(), action_type, *action_info));
149   (*map)[extension.id()] = action;
150   PopulateMissingValues(extension, action.get());
151   return action.get();
152 }
153
154 }  // namespace
155
156 ExtensionAction* ExtensionActionManager::GetPageAction(
157     const Extension& extension) const {
158   return GetOrCreateOrNull(&page_actions_, extension,
159                            ActionInfo::TYPE_PAGE,
160                            ActionInfo::GetPageActionInfo(&extension),
161                            profile_);
162 }
163
164 ExtensionAction* ExtensionActionManager::GetBrowserAction(
165     const Extension& extension) const {
166   return GetOrCreateOrNull(&browser_actions_, extension,
167                            ActionInfo::TYPE_BROWSER,
168                            ActionInfo::GetBrowserActionInfo(&extension),
169                            profile_);
170 }
171
172 scoped_ptr<ExtensionAction> ExtensionActionManager::GetBestFitAction(
173     const Extension& extension,
174     ActionInfo::Type type) const {
175   const ActionInfo* info = ActionInfo::GetBrowserActionInfo(&extension);
176   if (!info)
177     info = ActionInfo::GetPageActionInfo(&extension);
178
179   // Create a new ExtensionAction of |type| with |extension|'s ActionInfo.
180   // If no ActionInfo exists for |extension|, create and return a new action
181   // with a blank ActionInfo.
182   // Populate any missing values from |extension|'s manifest.
183   scoped_ptr<ExtensionAction> new_action(new ExtensionAction(
184       extension.id(), type, info ? *info : ActionInfo()));
185   PopulateMissingValues(extension, new_action.get());
186   return new_action.Pass();
187 }
188
189 ExtensionAction* ExtensionActionManager::GetSystemIndicator(
190     const Extension& extension) const {
191   // If it does not already exist, create the SystemIndicatorManager for the
192   // given profile.  This could return NULL if the system indicator area is
193   // unavailable on the current system.  If so, return NULL to signal that
194   // the system indicator area is unusable.
195   if (!SystemIndicatorManagerFactory::GetForProfile(profile_))
196     return NULL;
197
198   return GetOrCreateOrNull(&system_indicators_, extension,
199                            ActionInfo::TYPE_SYSTEM_INDICATOR,
200                            ActionInfo::GetSystemIndicatorInfo(&extension),
201                            profile_);
202 }
203
204 ExtensionAction* ExtensionActionManager::GetExtensionAction(
205     const Extension& extension) const {
206   ExtensionAction* action = GetBrowserAction(extension);
207   return action ? action : GetPageAction(extension);
208 }
209
210 }  // namespace extensions