blob: 1f445043c1d017f2cee99081d32adaadcb14c116 [file] [log] [blame]
// 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 <utility>
#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 std::unique_ptr<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_;
};
std::unique_ptr<ExtensionIndicatorIcon> ExtensionIndicatorIcon::Create(
const Extension* extension,
ExtensionAction* action,
Profile* profile,
StatusTray* status_tray) {
std::unique_ptr<ExtensionIndicatorIcon> extension_icon(
new ExtensionIndicatorIcon(extension, action, profile, status_tray));
// Check if a status icon was successfully created.
if (extension_icon->icon_)
return extension_icon;
// We could not create a status icon.
return std::unique_ptr<ExtensionIndicatorIcon>();
}
ExtensionIndicatorIcon::~ExtensionIndicatorIcon() {
if (icon_) {
icon_->RemoveObserver(this);
status_tray_->RemoveStatusIcon(icon_);
}
}
void ExtensionIndicatorIcon::OnStatusIconClicked() {
std::unique_ptr<base::ListValue> params(
api::system_indicator::OnClicked::Create());
EventRouter* event_router = EventRouter::Get(profile_);
std::unique_ptr<Event> 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;
}
std::unique_ptr<ExtensionIndicatorIcon> extension_icon =
ExtensionIndicatorIcon::Create(extension, extension_action, profile_,
status_tray_);
if (extension_icon)
system_indicators_[extension->id()] = std::move(extension_icon);
}
void SystemIndicatorManager::RemoveIndicator(const std::string& extension_id) {
DCHECK(thread_checker_.CalledOnValidThread());
system_indicators_.erase(extension_id);
}
} // namespace extensions