// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/extensions/api/system_indicator/system_indicator_manager.h" #include #include "base/memory/linked_ptr.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/extensions/extension_action.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/status_icons/status_icon.h" #include "chrome/browser/status_icons/status_icon_observer.h" #include "chrome/browser/status_icons/status_tray.h" #include "chrome/common/extensions/api/system_indicator.h" #include "content/public/browser/web_contents.h" #include "extensions/browser/event_router.h" #include "extensions/browser/extension_registry.h" #include "extensions/common/extension.h" #include "ui/gfx/image/image.h" namespace extensions { namespace system_indicator = api::system_indicator; // Observes clicks on a given status icon and forwards the event to the // appropriate extension. Handles icon updates, and responsible for creating // and removing the icon from the notification area during construction and // destruction. class ExtensionIndicatorIcon : public StatusIconObserver, public ExtensionActionIconFactory::Observer { public: static ExtensionIndicatorIcon* Create(const Extension* extension, ExtensionAction* action, Profile* profile, StatusTray* status_tray); ~ExtensionIndicatorIcon() override; // StatusIconObserver implementation. void OnStatusIconClicked() override; // ExtensionActionIconFactory::Observer implementation. void OnIconUpdated() override; private: ExtensionIndicatorIcon(const Extension* extension, ExtensionAction* action, Profile* profile, StatusTray* status_tray); const extensions::Extension* extension_; StatusTray* status_tray_; StatusIcon* icon_; Profile* profile_; ExtensionActionIconFactory icon_factory_; }; ExtensionIndicatorIcon* ExtensionIndicatorIcon::Create( const Extension* extension, ExtensionAction* action, Profile* profile, StatusTray* status_tray) { scoped_ptr extension_icon( new ExtensionIndicatorIcon(extension, action, profile, status_tray)); // Check if a status icon was successfully created. if (extension_icon->icon_) return extension_icon.release(); // We could not create a status icon. return NULL; } ExtensionIndicatorIcon::~ExtensionIndicatorIcon() { if (icon_) { icon_->RemoveObserver(this); status_tray_->RemoveStatusIcon(icon_); } } void ExtensionIndicatorIcon::OnStatusIconClicked() { scoped_ptr params( api::system_indicator::OnClicked::Create()); EventRouter* event_router = EventRouter::Get(profile_); scoped_ptr event(new Event(events::SYSTEM_INDICATOR_ON_CLICKED, system_indicator::OnClicked::kEventName, std::move(params), profile_)); event_router->DispatchEventToExtension(extension_->id(), std::move(event)); } void ExtensionIndicatorIcon::OnIconUpdated() { icon_->SetImage( icon_factory_.GetIcon(ExtensionAction::kDefaultTabId).AsImageSkia()); } ExtensionIndicatorIcon::ExtensionIndicatorIcon(const Extension* extension, ExtensionAction* action, Profile* profile, StatusTray* status_tray) : extension_(extension), status_tray_(status_tray), icon_(NULL), profile_(profile), icon_factory_(profile, extension, action, this) { // Get the icon image and tool tip for the status icon. The extension name is // used as the tool tip. gfx::ImageSkia icon_image = icon_factory_.GetIcon(ExtensionAction::kDefaultTabId).AsImageSkia(); base::string16 tool_tip = base::UTF8ToUTF16(extension_->name()); icon_ = status_tray_->CreateStatusIcon( StatusTray::OTHER_ICON, icon_image, tool_tip); if (icon_) icon_->AddObserver(this); } SystemIndicatorManager::SystemIndicatorManager(Profile* profile, StatusTray* status_tray) : profile_(profile), status_tray_(status_tray), extension_action_observer_(this), extension_registry_observer_(this) { extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); extension_action_observer_.Add(ExtensionActionAPI::Get(profile_)); } SystemIndicatorManager::~SystemIndicatorManager() { DCHECK(thread_checker_.CalledOnValidThread()); } void SystemIndicatorManager::Shutdown() { DCHECK(thread_checker_.CalledOnValidThread()); } void SystemIndicatorManager::OnExtensionUnloaded( content::BrowserContext* browser_context, const Extension* extension, UnloadedExtensionInfo::Reason reason) { RemoveIndicator(extension->id()); } void SystemIndicatorManager::OnExtensionActionUpdated( ExtensionAction* extension_action, content::WebContents* web_contents, content::BrowserContext* browser_context) { DCHECK(thread_checker_.CalledOnValidThread()); if (profile_->GetOriginalProfile() != browser_context || extension_action->action_type() != ActionInfo::TYPE_SYSTEM_INDICATOR) return; std::string extension_id = extension_action->extension_id(); if (extension_action->GetIsVisible(ExtensionAction::kDefaultTabId)) { CreateOrUpdateIndicator( ExtensionRegistry::Get(profile_)->enabled_extensions().GetByID( extension_id), extension_action); } else { RemoveIndicator(extension_id); } } bool SystemIndicatorManager::SendClickEventToExtensionForTest( const std::string& extension_id) { extensions::SystemIndicatorManager::SystemIndicatorMap::iterator it = system_indicators_.find(extension_id); if (it == system_indicators_.end()) return false; it->second->OnStatusIconClicked(); return true; } void SystemIndicatorManager::CreateOrUpdateIndicator( const Extension* extension, ExtensionAction* extension_action) { DCHECK(thread_checker_.CalledOnValidThread()); SystemIndicatorMap::iterator it = system_indicators_.find(extension->id()); if (it != system_indicators_.end()) { it->second->OnIconUpdated(); return; } ExtensionIndicatorIcon* extension_icon = ExtensionIndicatorIcon::Create( extension, extension_action, profile_, status_tray_); if (extension_icon) system_indicators_[extension->id()] = make_linked_ptr(extension_icon); } void SystemIndicatorManager::RemoveIndicator(const std::string& extension_id) { DCHECK(thread_checker_.CalledOnValidThread()); system_indicators_.erase(extension_id); } } // namespace extensions