Chromium Code Reviews| Index: ash/system/chromeos/network/network_icon.cc |
| diff --git a/ash/system/chromeos/network/network_icon.cc b/ash/system/chromeos/network/network_icon.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..bf10d2995217fac7f88c668da2a9391a0a5ce728 |
| --- /dev/null |
| +++ b/ash/system/chromeos/network/network_icon.cc |
| @@ -0,0 +1,553 @@ |
| +// 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 "ash/system/chromeos/network/network_icon.h" |
| + |
| +#include "ash/shell.h" |
| +#include "base/observer_list.h" |
| +#include "chromeos/network/device_state.h" |
| +#include "chromeos/network/network_state.h" |
| +#include "chromeos/network/network_state_handler.h" |
| +#include "grit/ash_resources.h" |
| +#include "third_party/cros_system_api/dbus/service_constants.h" |
| +#include "ui/base/animation/animation_delegate.h" |
| +#include "ui/base/animation/throb_animation.h" |
| +#include "ui/base/resource/resource_bundle.h" |
| +#include "ui/gfx/canvas.h" |
| +#include "ui/gfx/rect.h" |
| +#include "ui/gfx/image/image_skia_operations.h" |
| +#include "ui/gfx/image/image_skia_source.h" |
| +#include "ui/gfx/size_conversions.h" |
| + |
| +using chromeos::DeviceState; |
| +using chromeos::NetworkStateHandler; |
| +using chromeos::NetworkState; |
| + |
| +namespace ash { |
| + |
| +namespace { |
| + |
| +//============================================================================== |
|
Greg Spencer (Chromium)
2012/11/21 18:01:51
nit: Can you use "-" for all of the separators if
stevenjb
2012/11/27 00:58:18
Done.
|
| +// Utilities for generating icon images. |
| + |
| +enum ImageType { |
| + ARCS = 0, |
| + BARS |
| +}; |
| + |
| +struct Badges { |
| + Badges() |
| + : top_left(NULL), |
| + top_right(NULL), |
| + bottom_left(NULL), |
| + bottom_right(NULL) { |
| + } |
| + const gfx::ImageSkia* top_left; |
| + const gfx::ImageSkia* top_right; |
| + const gfx::ImageSkia* bottom_left; |
| + const gfx::ImageSkia* bottom_right; |
| +}; |
| + |
| +// Animation cycle length. |
| +const int kThrobDurationMs = 750; |
| + |
| +// Amount to fade icons while connecting. |
| +const double kConnectingImageAlpha = 0.5; |
| + |
| +// Images for strength bars for wired networks. |
| +const int kNumBarsImages = 5; |
| +gfx::ImageSkia* kBarsImagesAnimatingDark[kNumBarsImages - 1]; |
| +gfx::ImageSkia* kBarsImagesAnimatingLight[kNumBarsImages - 1]; |
| + |
| +// Imagaes for strength arcs for wireless networks. |
| +const int kNumArcsImages = 5; |
| +gfx::ImageSkia* kArcsImagesAnimatingDark[kNumArcsImages - 1]; |
| +gfx::ImageSkia* kArcsImagesAnimatingLight[kNumArcsImages - 1]; |
| + |
| +//------------------------------------------------------------------------------ |
| +// Classes for generating scaled images. |
| + |
| +const SkBitmap GetEmptyBitmap(const gfx::Size pixel_size) { |
| + typedef std::pair<int, int> SizeKey; |
| + typedef std::map<SizeKey, SkBitmap> SizeBitmapMap; |
| + static SizeBitmapMap* empty_bitmaps_ = new SizeBitmapMap; |
|
Greg Spencer (Chromium)
2012/11/21 18:01:51
I think this should be named with g_empty_bitmaps
stevenjb
2012/11/27 00:58:18
Done.
|
| + |
| + SizeKey key(pixel_size.width(), pixel_size.height()); |
| + |
| + SizeBitmapMap::iterator iter = empty_bitmaps_->find(key); |
| + if (iter != empty_bitmaps_->end()) |
| + return iter->second; |
| + |
| + SkBitmap empty; |
| + empty.setConfig(SkBitmap::kARGB_8888_Config, key.first, key.second); |
| + empty.allocPixels(); |
| + empty.eraseARGB(0, 0, 0, 0); |
| + (*empty_bitmaps_)[key] = empty; |
| + return empty; |
| +} |
| + |
| +class EmptyImageSource: public gfx::ImageSkiaSource { |
| + public: |
| + explicit EmptyImageSource(const gfx::Size& size) |
| + : size_(size) { |
| + } |
| + |
| + virtual gfx::ImageSkiaRep GetImageForScale( |
| + ui::ScaleFactor scale_factor) OVERRIDE { |
| + gfx::Size pixel_size = gfx::ToFlooredSize( |
| + gfx::ScaleSize(size_, ui::GetScaleFactorScale(scale_factor))); |
| + SkBitmap empty_bitmap = GetEmptyBitmap(pixel_size); |
| + return gfx::ImageSkiaRep(empty_bitmap, scale_factor); |
| + } |
| + private: |
| + const gfx::Size size_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(EmptyImageSource); |
| +}; |
| + |
| +// This defines how we assemble a network icon. |
| +class NetworkIconImageSource : public gfx::ImageSkiaSource { |
| + public: |
| + NetworkIconImageSource(const gfx::ImageSkia& icon, const Badges& badges) |
| + : icon_(icon), |
| + badges_(badges) { |
| + } |
| + virtual ~NetworkIconImageSource() {} |
| + |
| + // TODO(pkotwicz): Figure out what to do when a new image resolution becomes |
| + // available. |
| + virtual gfx::ImageSkiaRep GetImageForScale( |
| + ui::ScaleFactor scale_factor) OVERRIDE { |
| + gfx::ImageSkiaRep icon_rep = icon_.GetRepresentation(scale_factor); |
| + if (icon_rep.is_null()) |
| + return gfx::ImageSkiaRep(); |
| + gfx::Canvas canvas(icon_rep, false); |
| + if (badges_.top_left) |
| + canvas.DrawImageInt(*badges_.top_left, 0, 0); |
| + if (badges_.top_right) |
| + canvas.DrawImageInt(*badges_.top_right, |
| + icon_.width() - badges_.top_right->width(), 0); |
| + if (badges_.bottom_left) { |
| + canvas.DrawImageInt(*badges_.bottom_left, |
| + 0, icon_.height() - badges_.bottom_left->height()); |
| + } |
| + if (badges_.bottom_right) { |
| + canvas.DrawImageInt(*badges_.bottom_right, |
| + icon_.width() - badges_.bottom_right->width(), |
| + icon_.height() - badges_.bottom_right->height()); |
| + } |
| + return canvas.ExtractImageRep(); |
| + } |
| + |
| + private: |
| + const gfx::ImageSkia icon_; |
| + const Badges badges_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(NetworkIconImageSource); |
| +}; |
| + |
| +//------------------------------------------------------------------------------ |
| +// Utilities for extracting icon images. |
| + |
| +int NumImagesForType(ImageType type) { |
| + return (type == ARCS) ? kNumArcsImages : kNumBarsImages; |
| +} |
| + |
| +gfx::ImageSkia** ImageListForType(ImageType type, |
| + NetworkIcon::ResourceColorTheme color) { |
| + gfx::ImageSkia** images; |
| + if (type == ARCS) { |
| + images = (color == NetworkIcon::COLOR_DARK) ? |
| + kArcsImagesAnimatingDark : kArcsImagesAnimatingLight; |
| + } else { |
| + images = (color == NetworkIcon::COLOR_DARK) ? |
| + kBarsImagesAnimatingDark : kBarsImagesAnimatingLight; |
| + } |
| + return images; |
| +} |
| + |
| +gfx::ImageSkia* BaseImageForType(ImageType type, |
| + NetworkIcon::ResourceColorTheme color) { |
| + gfx::ImageSkia* image; |
| + if (type == ARCS) { |
| + image = ResourceBundle::GetSharedInstance().GetImageSkiaNamed( |
| + color == NetworkIcon::COLOR_DARK ? |
| + IDR_AURA_UBER_TRAY_NETWORK_ARCS_DARK : |
| + IDR_AURA_UBER_TRAY_NETWORK_ARCS_LIGHT); |
| + } else { |
| + image = ResourceBundle::GetSharedInstance().GetImageSkiaNamed( |
| + color == NetworkIcon::COLOR_DARK ? |
| + IDR_AURA_UBER_TRAY_NETWORK_BARS_DARK : |
| + IDR_AURA_UBER_TRAY_NETWORK_BARS_LIGHT); |
| + } |
| + return image; |
| +} |
| + |
| +gfx::ImageSkia GetImageForIndex(ImageType type, |
| + NetworkIcon::ResourceColorTheme color, |
| + int index) { |
| + int num_images = NumImagesForType(type); |
| + if (index < 0 || index >= num_images) |
| + return gfx::ImageSkia(); |
| + gfx::ImageSkia* images = BaseImageForType(type, color); |
| + int width = images->width(); |
| + int height = images->height() / num_images; |
| + return gfx::ImageSkiaOperations::ExtractSubset(*images, |
| + gfx::Rect(0, index * height, width, height)); |
| +} |
| + |
| +const gfx::ImageSkia GetDisconnectedImage( |
| + NetworkIcon::ResourceColorTheme color) { |
| + return GetImageForIndex(ARCS, color, 0); |
| +} |
| + |
| +int StrengthIndex(int strength, int count) { |
| + // Return an index in the range [1, count-1]. |
| + const float findex = (static_cast<float>(strength) / 100.0f) * |
| + nextafter(static_cast<float>(count - 1), 0); |
| + int index = 1 + static_cast<int>(findex); |
| + index = std::max(std::min(index, count - 1), 1); |
| + return index; |
| +} |
| + |
| +int GetStrengthIndex(const NetworkState* network) { |
| + if (network->type() == flimflam::kTypeWifi) { |
| + return StrengthIndex(network->signal_strength(), kNumArcsImages); |
| + } else if (network->type() == flimflam::kTypeWimax) { |
| + return StrengthIndex(network->signal_strength(), kNumBarsImages); |
| + } else if (network->type() == flimflam::kTypeCellular) { // && |
| + // TODO: network->data_left() != NetworkState::DATA_NONE) { |
| + return StrengthIndex(network->signal_strength(), kNumBarsImages); |
| + } |
| + return 0; |
| +} |
| + |
| +const gfx::ImageSkia* BadgeForNetworkTechnology( |
| + const NetworkState* network, |
| + NetworkIcon::ResourceColorTheme color) { |
| + const int kUnknownBadgeType = -1; |
| + int id = kUnknownBadgeType; |
| + // TODO(stevenjb): Implement NetworkState::data_left() |
| + if (network->technology() == flimflam::kNetworkTechnologyEvdo) { |
|
Greg Spencer (Chromium)
2012/11/21 18:01:51
Shouldn't you just leave this entire if/else out?
stevenjb
2012/11/27 00:58:18
Actually, I didn't want to leave this as a TODO th
|
| + // TODO: |
| + // switch (network->data_left()) { |
| + // case NetworkState::DATA_NONE: |
| + // id = IDR_AURA_UBER_TRAY_NETWORK_3G_ERROR; |
| + // break; |
| + // case NetworkState::DATA_VERY_LOW: |
| + // case NetworkState::DATA_LOW: |
| + // case NetworkState::DATA_NORMAL: |
| + id = (color == NetworkIcon::COLOR_DARK) ? |
| + IDR_AURA_UBER_TRAY_NETWORK_3G_DARK : |
| + IDR_AURA_UBER_TRAY_NETWORK_3G_LIGHT; |
| + // break; |
| + // case NetworkState::DATA_UNKNOWN: |
| + // id = IDR_AURA_UBER_TRAY_NETWORK_3G_UNKNOWN; |
| + // break; |
| + // } |
| + } else if (network->technology() == flimflam::kNetworkTechnology1Xrtt) { |
| + // TODO: |
| + // switch (network->data_left()) { |
| + // case NetworkState::DATA_NONE: |
| + // id = IDR_AURA_UBER_TRAY_NETWORK_1X_ERROR; |
| + // break; |
| + // case NetworkState::DATA_VERY_LOW: |
| + // case NetworkState::DATA_LOW: |
| + // case NetworkState::DATA_NORMAL: |
| + id = IDR_AURA_UBER_TRAY_NETWORK_1X; |
| + // break; |
| + // case NetworkState::DATA_UNKNOWN: |
| + // id = IDR_AURA_UBER_TRAY_NETWORK_1X_UNKNOWN; |
| + // break; |
| + // } |
| + } |
| + // Note: we may not be able to obtain data usage info from GSM carriers, |
| + // so there may not be a reason to create _ERROR or _UNKNOWN versions |
| + // of the following icons. |
| + else if (network->technology() == flimflam::kNetworkTechnologyGprs) { |
| + id = IDR_AURA_UBER_TRAY_NETWORK_GPRS; |
| + } else if (network->technology() == flimflam::kNetworkTechnologyEdge) { |
| + id = (color == NetworkIcon::COLOR_DARK) ? |
| + IDR_AURA_UBER_TRAY_NETWORK_EDGE_DARK : |
| + IDR_AURA_UBER_TRAY_NETWORK_EDGE_LIGHT; |
| + } else if (network->technology() == flimflam::kNetworkTechnologyUmts) { |
| + id = (color == NetworkIcon::COLOR_DARK) ? |
| + IDR_AURA_UBER_TRAY_NETWORK_3G_DARK : |
| + IDR_AURA_UBER_TRAY_NETWORK_3G_LIGHT; |
| + } else if (network->technology() == flimflam::kNetworkTechnologyHspa) { |
| + id = IDR_AURA_UBER_TRAY_NETWORK_HSPA; |
| + } else if (network->technology() == flimflam::kNetworkTechnologyHspaPlus) { |
| + id = IDR_AURA_UBER_TRAY_NETWORK_HSPA_PLUS; |
| + } else if (network->technology() == flimflam::kNetworkTechnologyLte) { |
| + id = IDR_AURA_UBER_TRAY_NETWORK_LTE; |
| + } else if (network->technology() == flimflam::kNetworkTechnologyLteAdvanced) { |
| + id = IDR_AURA_UBER_TRAY_NETWORK_LTE_ADVANCED; |
| + } else if (network->technology() == flimflam::kNetworkTechnologyGsm) { |
| + id = IDR_AURA_UBER_TRAY_NETWORK_GPRS; |
| + } |
| + if (id == kUnknownBadgeType) |
| + return NULL; |
| + else |
| + return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(id); |
| +} |
| + |
| +gfx::ImageSkia GetIcon(const NetworkState* network, |
| + NetworkIcon::ResourceColorTheme color, |
| + int strength_index) { |
| + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| + const std::string& type = network->type(); |
| + if (type == flimflam::kTypeEthernet) { |
| + return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED); |
| + } else if (type == flimflam::kTypeWifi) { |
| + DCHECK(strength_index > 0); |
| + return GetImageForIndex(ARCS, color, strength_index); |
| + } else if (type == flimflam::kTypeWimax) { |
| + DCHECK(strength_index > 0); |
| + return GetImageForIndex(BARS, color, strength_index); |
| + } else if (type == flimflam::kTypeCellular) { |
| + DCHECK(strength_index > 0); |
| + return GetImageForIndex(BARS, color, strength_index); |
| + } else if (type == flimflam::kTypeVPN) { |
| + return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN); |
| + } else { |
| + LOG(WARNING) << "Request for icon for unsupported type: " << type; |
| + return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED); |
| + } |
| +} |
| + |
| +void GetBadges(const NetworkState* network, |
| + NetworkIcon::ResourceColorTheme color, |
| + Badges* badges) { |
| + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| + chromeos::NetworkStateHandler* handler = |
| + Shell::GetInstance()->network_state_handler(); |
| + |
| + bool use_dark_icons = color == NetworkIcon::COLOR_DARK; |
| + const std::string& type = network->type(); |
| + if (type == flimflam::kTypeWifi) { |
| + if (network->security() != flimflam::kSecurityNone && use_dark_icons) { |
| + badges->bottom_right = rb.GetImageSkiaNamed( |
| + IDR_AURA_UBER_TRAY_NETWORK_SECURE_DARK); |
| + } |
| + } else if (type == flimflam::kTypeWimax) { |
| + badges->top_left = rb.GetImageSkiaNamed( |
| + use_dark_icons ? |
| + IDR_AURA_UBER_TRAY_NETWORK_4G_DARK : |
| + IDR_AURA_UBER_TRAY_NETWORK_4G_LIGHT); |
| + } else if (type == flimflam::kTypeCellular) { |
| + if (network->roaming() == flimflam::kRoamingStateRoaming) { |
| + // For networks that always in roaming don't show roaming badge. |
|
Greg Spencer (Chromium)
2012/11/21 18:01:51
nit: always in => are always
stevenjb
2012/11/27 00:58:18
Done.
|
| + const DeviceState* device = |
| + handler->GetDeviceState(network->device_path()); |
| + if (!device->provider_requires_roaming()) { |
| + badges->bottom_right = rb.GetImageSkiaNamed( |
| + use_dark_icons ? |
| + IDR_AURA_UBER_TRAY_NETWORK_ROAMING_DARK : |
| + IDR_AURA_UBER_TRAY_NETWORK_ROAMING_LIGHT); |
| + } |
| + } |
| + if (!network->IsConnectingState()) { |
| + badges->top_left = BadgeForNetworkTechnology(network, color); |
| + } |
| + } |
| +} |
| + |
| +//------------------------------------------------------------------------------ |
| +// Handle connecting images |
| + |
| +class ConnectingAnimation : public ui::AnimationDelegate { |
| + public: |
| + ConnectingAnimation() |
| + : ALLOW_THIS_IN_INITIALIZER_LIST(animation_(this)) { |
| + // Set up the animation throbber. |
| + animation_.SetThrobDuration(kThrobDurationMs); |
| + animation_.SetTweenType(ui::Tween::LINEAR); |
| + } |
| + |
| + virtual ~ConnectingAnimation() {} |
| + |
| + // ui::AnimationDelegate implementation. |
| + virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE { |
| + if (animation == &animation_) { |
| + FOR_EACH_OBSERVER( |
| + NetworkIcon::AnimationObserver, observers_, NetworkIconChanged()); |
| + } |
| + } |
| + |
| + double GetAnimation() { |
| + if (!animation_.is_animating()) { |
| + animation_.Reset(); |
| + animation_.StartThrobbing(-1 /*throb indefinitely*/); |
| + return 0; |
| + } |
| + return animation_.GetCurrentValue(); |
| + } |
| + |
| + void AddObserver(NetworkIcon::AnimationObserver* observer) { |
| + observers_.AddObserver(observer); |
| + } |
| + |
| + void RemoveObserver(NetworkIcon::AnimationObserver* observer) { |
| + observers_.RemoveObserver(observer); |
| + if (observers_.size() == 0) |
| + animation_.Stop(); |
| + } |
| + |
| + private: |
| + ui::ThrobAnimation animation_; |
| + ObserverList<NetworkIcon::AnimationObserver> observers_; |
| +}; |
| + |
| +ConnectingAnimation* GetConnectingAnimation() { |
| + static ConnectingAnimation* connecting_animation = new ConnectingAnimation(); |
| + return connecting_animation; |
| +} |
| + |
| +gfx::ImageSkia GetConnectingImage(const std::string& type, |
| + NetworkIcon::ResourceColorTheme color) { |
| + ImageType image_type = (type == flimflam::kTypeWifi) ? ARCS : BARS; |
| + int image_count = NumImagesForType(image_type) - 1; |
| + gfx::ImageSkia** images = ImageListForType(image_type, color); |
| + double animation = GetConnectingAnimation()->GetAnimation(); |
| + int index = animation * nextafter(static_cast<float>(image_count), 0); |
| + index = std::max(std::min(index, image_count - 1), 0); |
| + |
| + // Lazily cache images. |
| + if (!images[index]) { |
| + gfx::ImageSkia source = GetImageForIndex(image_type, color, index + 1); |
| + images[index] = new gfx::ImageSkia( |
| + gfx::ImageSkiaOperations::CreateBlendedImage( |
| + gfx::ImageSkia(new EmptyImageSource(source.size()), source.size()), |
| + source, |
| + kConnectingImageAlpha)); |
| + } |
| + gfx::ImageSkia& icon = *images[index]; |
| + return gfx::ImageSkia( |
| + new NetworkIconImageSource(icon, Badges()), icon.size()); |
| +} |
| + |
| + |
| +//------------------------------------------------------------------------------ |
| +// Maintain a static (global) icon map. Note: Icons are never destroyed; |
| +// it is assumed that a finite and reasonable number of network icons will be |
| +// created during a session. |
| + |
| +typedef std::map<std::string, NetworkIcon*> NetworkIconMap; |
| + |
| +NetworkIconMap* GetIconMap(NetworkIcon::ResourceColorTheme color) { |
| + if (color == NetworkIcon::COLOR_DARK) { |
| + static NetworkIconMap* icon_map_dark = NULL; |
|
Greg Spencer (Chromium)
2012/11/21 18:01:51
g_icon_map_dark? I'm not sure what the naming con
stevenjb
2012/11/27 00:58:18
I don't like g_ in function scope, but I've seen s
|
| + if (icon_map_dark == NULL) |
| + icon_map_dark = new NetworkIconMap; |
| + return icon_map_dark; |
| + } else { |
| + static NetworkIconMap* icon_map_light = NULL; |
|
Greg Spencer (Chromium)
2012/11/21 18:01:51
g_icon_map_light?
stevenjb
2012/11/27 00:58:18
Ditto
|
| + if (icon_map_light == NULL) |
| + icon_map_light = new NetworkIconMap; |
| + return icon_map_light; |
| + } |
| +} |
| + |
| +} // namespace |
| + |
| +//============================================================================== |
| +// NetworkIcon |
| + |
| +NetworkIcon::NetworkIcon(const std::string& service_path, |
| + ResourceColorTheme color) |
| + : service_path_(service_path), |
| + color_(color), |
| + strength_index_(-1), |
| + technology_badge_(NULL) { |
| + // Default image |
| + image_ = GetDisconnectedImage(color); |
| +} |
| + |
| +void NetworkIcon::Update(const NetworkState* network) { |
| + // Determine whether or not we need to update the icon. |
| + bool dirty = image_.isNull(); |
| + |
| + // If the network state has changed, the icon needs updating. |
| + if (state_ != network->state()) { |
| + state_ = network->state(); |
| + dirty = true; |
| + } |
| + |
| + const std::string& type = network->type(); |
| + if (type != flimflam::kTypeEthernet) |
| + dirty |= UpdateWirelessStrengthIndex(network); |
| + |
| + if (type == flimflam::kTypeCellular) |
| + dirty |= UpdateCellularState(network); |
| + |
| + if (dirty) { |
| + // Set the icon and badges based on the network and generate the image. |
| + GenerateImage(network); |
| + } |
| +} |
| + |
| +bool NetworkIcon::UpdateWirelessStrengthIndex(const NetworkState* network) { |
| + int index = GetStrengthIndex(network); |
| + if (index != strength_index_) { |
| + strength_index_ = index; |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +bool NetworkIcon::UpdateCellularState(const NetworkState* network) { |
| + bool dirty = false; |
| + const gfx::ImageSkia* technology_badge = |
| + BadgeForNetworkTechnology(network, color_); |
| + if (technology_badge != technology_badge_) { |
| + technology_badge_ = technology_badge; |
| + dirty = true; |
| + } |
| + std::string roaming_state = network->roaming(); |
| + if (roaming_state != roaming_state_) { |
| + roaming_state_ = roaming_state; |
| + dirty = true; |
| + } |
| + return dirty; |
| +} |
| + |
| +void NetworkIcon::GenerateImage(const NetworkState* network) { |
| + gfx::ImageSkia icon = GetIcon(network, color_, strength_index_); |
| + Badges badges; |
| + GetBadges(network, color_, &badges); |
| + image_ = gfx::ImageSkia( |
| + new NetworkIconImageSource(icon, badges), icon.size()); |
| +} |
| + |
| +// static |
| +gfx::ImageSkia NetworkIcon::GetImageForNetwork(const NetworkState* network, |
| + ResourceColorTheme color, |
| + AnimationObserver* observer) { |
| + if (network->IsConnectingState()) { |
| + if (observer) |
| + GetConnectingAnimation()->AddObserver(observer); |
| + return GetConnectingImage(network->type(), color); |
| + } |
| + // Not connecting, remove observer. |
| + if (observer) |
| + GetConnectingAnimation()->RemoveObserver(observer); |
| + |
| + NetworkIconMap* icon_map = GetIconMap(color); |
| + |
| + // Find or add the icon. |
| + NetworkIcon* icon; |
| + NetworkIconMap::iterator iter = icon_map->find(network->path()); |
| + if (iter == icon_map->end()) { |
| + icon = new NetworkIcon(network->path(), color); |
| + icon_map->insert(std::make_pair(network->path(), icon)); |
| + } else { |
| + icon = iter->second; |
| + } |
| + |
| + // Update and return the icon's image. |
| + icon->Update(network); |
| + return icon->image(); |
| +} |
| + |
| +} // namespace ash |