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/api/system_indicator/system_indicator_manager.h" 6 7#include "base/memory/linked_ptr.h" 8#include "base/strings/utf_string_conversions.h" 9#include "chrome/browser/extensions/extension_action.h" 10#include "chrome/browser/profiles/profile.h" 11#include "chrome/browser/status_icons/status_icon.h" 12#include "chrome/browser/status_icons/status_icon_observer.h" 13#include "chrome/browser/status_icons/status_tray.h" 14#include "chrome/common/extensions/api/system_indicator.h" 15#include "content/public/browser/web_contents.h" 16#include "extensions/browser/event_router.h" 17#include "extensions/browser/extension_registry.h" 18#include "extensions/common/extension.h" 19#include "ui/gfx/image/image.h" 20 21namespace extensions { 22 23namespace system_indicator = api::system_indicator; 24 25// Observes clicks on a given status icon and forwards the event to the 26// appropriate extension. Handles icon updates, and responsible for creating 27// and removing the icon from the notification area during construction and 28// destruction. 29class ExtensionIndicatorIcon : public StatusIconObserver, 30 public ExtensionActionIconFactory::Observer { 31 public: 32 static ExtensionIndicatorIcon* Create(const Extension* extension, 33 const ExtensionAction* action, 34 Profile* profile, 35 StatusTray* status_tray); 36 virtual ~ExtensionIndicatorIcon(); 37 38 // StatusIconObserver implementation. 39 virtual void OnStatusIconClicked() OVERRIDE; 40 41 // ExtensionActionIconFactory::Observer implementation. 42 virtual void OnIconUpdated() OVERRIDE; 43 44 private: 45 ExtensionIndicatorIcon(const Extension* extension, 46 const ExtensionAction* action, 47 Profile* profile, 48 StatusTray* status_tray); 49 50 const extensions::Extension* extension_; 51 StatusTray* status_tray_; 52 StatusIcon* icon_; 53 Profile* profile_; 54 ExtensionActionIconFactory icon_factory_; 55}; 56 57ExtensionIndicatorIcon* ExtensionIndicatorIcon::Create( 58 const Extension* extension, 59 const ExtensionAction* action, 60 Profile* profile, 61 StatusTray* status_tray) { 62 scoped_ptr<ExtensionIndicatorIcon> extension_icon( 63 new ExtensionIndicatorIcon(extension, action, profile, status_tray)); 64 65 // Check if a status icon was successfully created. 66 if (extension_icon->icon_) 67 return extension_icon.release(); 68 69 // We could not create a status icon. 70 return NULL; 71} 72 73ExtensionIndicatorIcon::~ExtensionIndicatorIcon() { 74 if (icon_) { 75 icon_->RemoveObserver(this); 76 status_tray_->RemoveStatusIcon(icon_); 77 } 78} 79 80void ExtensionIndicatorIcon::OnStatusIconClicked() { 81 scoped_ptr<base::ListValue> params( 82 api::system_indicator::OnClicked::Create()); 83 84 EventRouter* event_router = EventRouter::Get(profile_); 85 scoped_ptr<Event> event(new Event( 86 system_indicator::OnClicked::kEventName, 87 params.Pass(), 88 profile_)); 89 event_router->DispatchEventToExtension( 90 extension_->id(), event.Pass()); 91} 92 93void ExtensionIndicatorIcon::OnIconUpdated() { 94 icon_->SetImage( 95 icon_factory_.GetIcon(ExtensionAction::kDefaultTabId).AsImageSkia()); 96} 97 98ExtensionIndicatorIcon::ExtensionIndicatorIcon(const Extension* extension, 99 const ExtensionAction* action, 100 Profile* profile, 101 StatusTray* status_tray) 102 : extension_(extension), 103 status_tray_(status_tray), 104 icon_(NULL), 105 profile_(profile), 106 icon_factory_(profile, extension, action, this) { 107 // Get the icon image and tool tip for the status icon. The extension name is 108 // used as the tool tip. 109 gfx::ImageSkia icon_image = 110 icon_factory_.GetIcon(ExtensionAction::kDefaultTabId).AsImageSkia(); 111 base::string16 tool_tip = base::UTF8ToUTF16(extension_->name()); 112 113 icon_ = status_tray_->CreateStatusIcon( 114 StatusTray::OTHER_ICON, icon_image, tool_tip); 115 if (icon_) 116 icon_->AddObserver(this); 117} 118 119SystemIndicatorManager::SystemIndicatorManager(Profile* profile, 120 StatusTray* status_tray) 121 : profile_(profile), 122 status_tray_(status_tray), 123 extension_action_observer_(this), 124 extension_registry_observer_(this) { 125 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); 126 extension_action_observer_.Add(ExtensionActionAPI::Get(profile_)); 127} 128 129SystemIndicatorManager::~SystemIndicatorManager() { 130 DCHECK(thread_checker_.CalledOnValidThread()); 131} 132 133void SystemIndicatorManager::Shutdown() { 134 DCHECK(thread_checker_.CalledOnValidThread()); 135} 136 137void SystemIndicatorManager::OnExtensionUnloaded( 138 content::BrowserContext* browser_context, 139 const Extension* extension, 140 UnloadedExtensionInfo::Reason reason) { 141 RemoveIndicator(extension->id()); 142} 143 144void SystemIndicatorManager::OnExtensionActionUpdated( 145 ExtensionAction* extension_action, 146 content::WebContents* web_contents, 147 content::BrowserContext* browser_context) { 148 DCHECK(thread_checker_.CalledOnValidThread()); 149 if (profile_->GetOriginalProfile() != browser_context || 150 extension_action->action_type() != ActionInfo::TYPE_SYSTEM_INDICATOR) 151 return; 152 153 std::string extension_id = extension_action->extension_id(); 154 if (extension_action->GetIsVisible(ExtensionAction::kDefaultTabId)) { 155 CreateOrUpdateIndicator( 156 ExtensionRegistry::Get(profile_)->enabled_extensions().GetByID( 157 extension_id), 158 extension_action); 159 } else { 160 RemoveIndicator(extension_id); 161 } 162} 163 164bool SystemIndicatorManager::SendClickEventToExtensionForTest( 165 const std::string extension_id) { 166 167 extensions::SystemIndicatorManager::SystemIndicatorMap::iterator it = 168 system_indicators_.find(extension_id); 169 170 if (it == system_indicators_.end()) 171 return false; 172 173 it->second->OnStatusIconClicked(); 174 return true; 175} 176 177void SystemIndicatorManager::CreateOrUpdateIndicator( 178 const Extension* extension, 179 const ExtensionAction* extension_action) { 180 DCHECK(thread_checker_.CalledOnValidThread()); 181 SystemIndicatorMap::iterator it = system_indicators_.find(extension->id()); 182 if (it != system_indicators_.end()) { 183 it->second->OnIconUpdated(); 184 return; 185 } 186 187 ExtensionIndicatorIcon* extension_icon = ExtensionIndicatorIcon::Create( 188 extension, extension_action, profile_, status_tray_); 189 if (extension_icon) 190 system_indicators_[extension->id()] = make_linked_ptr(extension_icon); 191} 192 193void SystemIndicatorManager::RemoveIndicator(const std::string& extension_id) { 194 DCHECK(thread_checker_.CalledOnValidThread()); 195 system_indicators_.erase(extension_id); 196} 197 198} // namespace extensions 199