15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_action_manager.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 77dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/system_indicator/system_indicator_manager.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_action.h" 11a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_system.h" 13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/profiles/incognito_helpers.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/api/extension_action/action_info.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/api/extension_action/page_action_handler.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/api/extension_action/script_badge_handler.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/feature_switch.h" 2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "components/browser_context_keyed_service/browser_context_dependency_manager.h" 2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// BrowserContextKeyedServiceFactory for ExtensionActionManager. 3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class ExtensionActionManagerFactory : public BrowserContextKeyedServiceFactory { 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // BrowserContextKeyedServiceFactory implementation: 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static ExtensionActionManager* GetForProfile(Profile* profile) { 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return static_cast<ExtensionActionManager*>( 3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) GetInstance()->GetServiceForBrowserContext(profile, true)); 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static ExtensionActionManagerFactory* GetInstance(); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend struct DefaultSingletonTraits<ExtensionActionManagerFactory>; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensionActionManagerFactory() 4490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) : BrowserContextKeyedServiceFactory( 4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "ExtensionActionManager", 4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) BrowserContextDependencyManager::GetInstance()) { 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) virtual BrowserContextKeyedService* BuildServiceInstanceFor( 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::BrowserContext* profile) const OVERRIDE { 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return new ExtensionActionManager(static_cast<Profile*>(profile)); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual content::BrowserContext* GetBrowserContextToUse( 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::BrowserContext* context) const OVERRIDE { 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return chrome::GetBrowserContextRedirectedInIncognito(context); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionActionManagerFactory* 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionActionManagerFactory::GetInstance() { 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Singleton<ExtensionActionManagerFactory>::get(); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ExtensionActionManager::ExtensionActionManager(Profile* profile) 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : profile_(profile) { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(profile, profile->GetOriginalProfile()) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Don't instantiate this with an incognito profile."; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Source<Profile>(profile)); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionActionManager::~ExtensionActionManager() { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Don't assert that the ExtensionAction maps are empty because Extensions are 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // sometimes (only in tests?) not unloaded before the Profile is destroyed. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionActionManager* ExtensionActionManager::Get(Profile* profile) { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ExtensionActionManagerFactory::GetForProfile(profile); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionActionManager::Observe( 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int type, 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NotificationSource& source, 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NotificationDetails& details) { 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (type) { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case chrome::NOTIFICATION_EXTENSION_UNLOADED: { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Extension* extension = 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Details<UnloadedExtensionInfo>(details)->extension; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) page_actions_.erase(extension->id()); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) browser_actions_.erase(extension->id()); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) script_badges_.erase(extension->id()); 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) system_indicators_.erase(extension->id()); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns map[extension_id] if that entry exists. Otherwise, if 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// action_info!=NULL, creates an ExtensionAction from it, fills in the map, and 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// returns that. Otherwise (action_info==NULL), returns NULL. 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionAction* GetOrCreateOrNull( 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::map<std::string, linked_ptr<ExtensionAction> >* map, 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& extension_id, 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ActionInfo::Type action_type, 110a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) const ActionInfo* action_info, 111a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) Profile* profile) { 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::map<std::string, linked_ptr<ExtensionAction> >::const_iterator it = 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) map->find(extension_id); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it != map->end()) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return it->second.get(); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!action_info) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 118a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 119a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Only create action info for enabled extensions. 120a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // This avoids bugs where actions are recreated just after being removed 121a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // in response to NOTIFICATION_EXTENSION_UNLOADED in 122a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // ExtensionActionManager::Observe() 123a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ExtensionService* service = 124a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ExtensionSystem::Get(profile)->extension_service(); 125a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!service->GetExtensionById(extension_id, false)) 126a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return NULL; 127a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) linked_ptr<ExtensionAction> action(new ExtensionAction( 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_id, action_type, *action_info)); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*map)[extension_id] = action; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return action.get(); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionAction* ExtensionActionManager::GetPageAction( 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const extensions::Extension& extension) const { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The action box changes the meaning of the page action area, so we 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // need to convert page actions into browser actions. 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FeatureSwitch::script_badges()->IsEnabled()) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetOrCreateOrNull(&page_actions_, extension.id(), 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ActionInfo::TYPE_PAGE, 144a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ActionInfo::GetPageActionInfo(&extension), 145a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) profile_); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionAction* ExtensionActionManager::GetBrowserAction( 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const extensions::Extension& extension) const { 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ActionInfo* action_info = ActionInfo::GetBrowserActionInfo(&extension); 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ActionInfo::Type action_type = ActionInfo::TYPE_BROWSER; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FeatureSwitch::script_badges()->IsEnabled() && 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ActionInfo::GetPageActionInfo(&extension)) { 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The action box changes the meaning of the page action area, so we 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // need to convert page actions into browser actions. 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) action_info = ActionInfo::GetPageActionInfo(&extension); 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) action_type = ActionInfo::TYPE_PAGE; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetOrCreateOrNull(&browser_actions_, extension.id(), 160a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) action_type, action_info, profile_); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ExtensionAction* ExtensionActionManager::GetSystemIndicator( 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const extensions::Extension& extension) const { 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If it does not already exist, create the SystemIndicatorManager for the 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // given profile. This could return NULL if the system indicator area is 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // unavailable on the current system. If so, return NULL to signal that 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the system indicator area is unusable. 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!extensions::SystemIndicatorManagerFactory::GetForProfile(profile_)) 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return NULL; 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return GetOrCreateOrNull(&system_indicators_, extension.id(), 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ActionInfo::TYPE_SYSTEM_INDICATOR, 174a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ActionInfo::GetSystemIndicatorInfo(&extension), 175a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) profile_); 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionAction* ExtensionActionManager::GetScriptBadge( 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const extensions::Extension& extension) const { 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetOrCreateOrNull(&script_badges_, extension.id(), 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ActionInfo::TYPE_SCRIPT_BADGE, 182a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ActionInfo::GetScriptBadgeInfo(&extension), 183a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) profile_); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace extensions 187