blob: a8b344d6dd1b9692f9c06005d999775ffbf2f53e [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 "base/memory/linked_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/event_router.h"
#include "chrome/browser/extensions/extension_action.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.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 "chrome/common/extensions/extension.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.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,
const ExtensionAction* action,
Profile* profile,
StatusTray* status_tray);
virtual ~ExtensionIndicatorIcon();
// StatusIconObserver implementation.
virtual void OnStatusIconClicked() OVERRIDE;
// ExtensionActionIconFactory::Observer implementation.
virtual void OnIconUpdated() OVERRIDE;
private:
ExtensionIndicatorIcon(const Extension* extension,
const 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,
const ExtensionAction* action,
Profile* profile,
StatusTray* status_tray) {
scoped_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.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<base::ListValue> params(
api::system_indicator::OnClicked::Create());
EventRouter* event_router =
ExtensionSystem::Get(profile_)->event_router();
scoped_ptr<Event> event(new Event(
system_indicator::OnClicked::kEventName,
params.Pass(),
profile_));
event_router->DispatchEventToExtension(
extension_->id(), event.Pass());
}
void ExtensionIndicatorIcon::OnIconUpdated() {
icon_->SetImage(
icon_factory_.GetIcon(ExtensionAction::kDefaultTabId).AsImageSkia());
}
ExtensionIndicatorIcon::ExtensionIndicatorIcon(const Extension* extension,
const 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();
string16 tool_tip = 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) {
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
content::Source<Profile>(profile_->GetOriginalProfile()));
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_SYSTEM_INDICATOR_UPDATED,
content::Source<Profile>(profile_->GetOriginalProfile()));
}
SystemIndicatorManager::~SystemIndicatorManager() {
DCHECK(thread_checker_.CalledOnValidThread());
}
void SystemIndicatorManager::Shutdown() {
DCHECK(thread_checker_.CalledOnValidThread());
}
void SystemIndicatorManager::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK(thread_checker_.CalledOnValidThread());
switch (type) {
case chrome::NOTIFICATION_EXTENSION_UNLOADED:
RemoveIndicator(
content::Details<UnloadedExtensionInfo>(details)->extension->id());
break;
case chrome::NOTIFICATION_EXTENSION_SYSTEM_INDICATOR_UPDATED:
OnSystemIndicatorChanged(
content::Details<ExtensionAction>(details).ptr());
break;
default:
NOTREACHED();
break;
}
}
void SystemIndicatorManager::OnSystemIndicatorChanged(
const ExtensionAction* extension_action) {
DCHECK(thread_checker_.CalledOnValidThread());
std::string extension_id = extension_action->extension_id();
ExtensionService* service =
ExtensionSystem::Get(profile_)->extension_service();
if (extension_action->GetIsVisible(ExtensionAction::kDefaultTabId)) {
const Extension* extension =
service->GetExtensionById(extension_id, false);
CreateOrUpdateIndicator(extension, 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,
const 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