diff options
Diffstat (limited to 'chromium/ash/system/chromeos/network/network_icon.cc')
-rw-r--r-- | chromium/ash/system/chromeos/network/network_icon.cc | 849 |
1 files changed, 849 insertions, 0 deletions
diff --git a/chromium/ash/system/chromeos/network/network_icon.cc b/chromium/ash/system/chromeos/network/network_icon.cc new file mode 100644 index 00000000000..efe7e07afc4 --- /dev/null +++ b/chromium/ash/system/chromeos/network/network_icon.cc @@ -0,0 +1,849 @@ +// 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 "ash/system/chromeos/network/network_icon_animation.h" +#include "ash/system/chromeos/network/network_icon_animation_observer.h" +#include "base/strings/utf_string_conversions.h" +#include "chromeos/network/device_state.h" +#include "chromeos/network/network_connection_handler.h" +#include "chromeos/network/network_state.h" +#include "chromeos/network/network_state_handler.h" +#include "grit/ash_resources.h" +#include "grit/ash_strings.h" +#include "third_party/cros_system_api/dbus/service_constants.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/image/image_skia_operations.h" +#include "ui/gfx/image/image_skia_source.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/size_conversions.h" + +using chromeos::DeviceState; +using chromeos::NetworkConnectionHandler; +using chromeos::NetworkHandler; +using chromeos::NetworkState; +using chromeos::NetworkStateHandler; + +namespace ash { +namespace network_icon { + +namespace { + +//------------------------------------------------------------------------------ +// Struct to pass icon badges to NetworkIconImageSource. +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; +}; + +//------------------------------------------------------------------------------ +// class used for maintaining a map of network state and images. +class NetworkIconImpl { + public: + explicit NetworkIconImpl(IconType icon_type); + + // Determines whether or not the associated network might be dirty and if so + // updates and generates the icon. Does nothing if network no longer exists. + void Update(const chromeos::NetworkState* network); + + const gfx::ImageSkia& image() const { return image_; } + + private: + // Updates |strength_index_| for wireless networks. Returns true if changed. + bool UpdateWirelessStrengthIndex(const chromeos::NetworkState* network); + + // Updates the local state for cellular networks. Returns true if changed. + bool UpdateCellularState(const chromeos::NetworkState* network); + + // Updates the VPN badge. Returns true if changed. + bool UpdateVPNBadge(); + + // Gets |badges| based on |network| and the current state. + void GetBadges(const NetworkState* network, Badges* badges); + + // Gets the appropriate icon and badges and composites the image. + void GenerateImage(const chromeos::NetworkState* network); + + // Defines color theme and VPN badging + const IconType icon_type_; + + // Cached state of the network when the icon was last generated. + std::string state_; + + // Cached strength index of the network when the icon was last generated. + int strength_index_; + + // Cached technology badge for the network when the icon was last generated. + const gfx::ImageSkia* technology_badge_; + + // Cached vpn badge for the network when the icon was last generated. + const gfx::ImageSkia* vpn_badge_; + + // Cached roaming state of the network when the icon was last generated. + std::string roaming_state_; + + // Generated icon image. + gfx::ImageSkia image_; + + DISALLOW_COPY_AND_ASSIGN(NetworkIconImpl); +}; + +//------------------------------------------------------------------------------ +// 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, NetworkIconImpl*> NetworkIconMap; + +NetworkIconMap* GetIconMapInstance(IconType icon_type, bool create) { + typedef std::map<IconType, NetworkIconMap*> IconTypeMap; + static IconTypeMap* s_icon_map = NULL; + if (s_icon_map == NULL) { + if (!create) + return NULL; + s_icon_map = new IconTypeMap; + } + if (s_icon_map->count(icon_type) == 0) { + if (!create) + return NULL; + (*s_icon_map)[icon_type] = new NetworkIconMap; + } + return (*s_icon_map)[icon_type]; +} + +NetworkIconMap* GetIconMap(IconType icon_type) { + return GetIconMapInstance(icon_type, true); +} + +void PurgeIconMap(IconType icon_type, + const std::set<std::string>& network_paths) { + NetworkIconMap* icon_map = GetIconMapInstance(icon_type, false); + if (!icon_map) + return; + for (NetworkIconMap::iterator loop_iter = icon_map->begin(); + loop_iter != icon_map->end(); ) { + NetworkIconMap::iterator cur_iter = loop_iter++; + if (network_paths.count(cur_iter->first) == 0) { + delete cur_iter->second; + icon_map->erase(cur_iter); + } + } +} + +//------------------------------------------------------------------------------ +// Utilities for generating icon images. + +// 'NONE' will default to ARCS behavior where appropriate (e.g. no network or +// if a new type gets added). +enum ImageType { + ARCS, + BARS, + NONE +}; + +// Amount to fade icons while connecting. +const double kConnectingImageAlpha = 0.5; + +// Images for strength bars for wired networks. +const int kNumBarsImages = 5; + +// Imagaes for strength arcs for wireless networks. +const int kNumArcsImages = 5; + +// Number of discrete images to use for alpha fade animation +const int kNumFadeImages = 10; + +//------------------------------------------------------------------------------ +// 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* s_empty_bitmaps = new SizeBitmapMap; + + SizeKey key(pixel_size.width(), pixel_size.height()); + + SizeBitmapMap::iterator iter = s_empty_bitmaps->find(key); + if (iter != s_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); + (*s_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. + +bool IconTypeIsDark(IconType icon_type) { + return (icon_type != ICON_TYPE_TRAY); +} + +bool IconTypeHasVPNBadge(IconType icon_type) { + return (icon_type != ICON_TYPE_LIST); +} + +int NumImagesForType(ImageType type) { + return (type == BARS) ? kNumBarsImages : kNumArcsImages; +} + +gfx::ImageSkia* BaseImageForType(ImageType image_type, IconType icon_type) { + gfx::ImageSkia* image; + if (image_type == BARS) { + image = ResourceBundle::GetSharedInstance().GetImageSkiaNamed( + IconTypeIsDark(icon_type) ? + IDR_AURA_UBER_TRAY_NETWORK_BARS_DARK : + IDR_AURA_UBER_TRAY_NETWORK_BARS_LIGHT); + } else { + image = ResourceBundle::GetSharedInstance().GetImageSkiaNamed( + IconTypeIsDark(icon_type) ? + IDR_AURA_UBER_TRAY_NETWORK_ARCS_DARK : + IDR_AURA_UBER_TRAY_NETWORK_ARCS_LIGHT); + } + return image; +} + +ImageType ImageTypeForNetworkType(const std::string& type) { + if (type == flimflam::kTypeWifi) + return ARCS; + else if (type == flimflam::kTypeCellular || type == flimflam::kTypeWimax) + return BARS; + return NONE; +} + +gfx::ImageSkia GetImageForIndex(ImageType image_type, + IconType icon_type, + int index) { + int num_images = NumImagesForType(image_type); + if (index < 0 || index >= num_images) + return gfx::ImageSkia(); + gfx::ImageSkia* images = BaseImageForType(image_type, icon_type); + 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 GetConnectedImage(const std::string& type, + IconType icon_type) { + if (type == flimflam::kTypeVPN) { + return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( + IDR_AURA_UBER_TRAY_NETWORK_VPN); + } + ImageType image_type = ImageTypeForNetworkType(type); + const int connected_index = NumImagesForType(image_type) - 1; + return GetImageForIndex(image_type, icon_type, connected_index); +} + +const gfx::ImageSkia GetDisconnectedImage(const std::string& type, + IconType icon_type) { + if (type == flimflam::kTypeVPN) { + // Note: same as connected image, shouldn't normally be seen. + return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( + IDR_AURA_UBER_TRAY_NETWORK_VPN); + } + ImageType image_type = ImageTypeForNetworkType(type); + const int disconnected_index = 0; + return GetImageForIndex(image_type, icon_type, disconnected_index); +} + +gfx::ImageSkia* ConnectingWirelessImage(ImageType image_type, + IconType icon_type, + double animation) { + static gfx::ImageSkia* s_bars_images_dark[kNumBarsImages - 1]; + static gfx::ImageSkia* s_bars_images_light[kNumBarsImages - 1]; + static gfx::ImageSkia* s_arcs_images_dark[kNumArcsImages - 1]; + static gfx::ImageSkia* s_arcs_images_light[kNumArcsImages - 1]; + int image_count = NumImagesForType(image_type) - 1; + int index = animation * nextafter(static_cast<float>(image_count), 0); + index = std::max(std::min(index, image_count - 1), 0); + gfx::ImageSkia** images; + bool dark = IconTypeIsDark(icon_type); + if (image_type == BARS) + images = dark ? s_bars_images_dark : s_bars_images_light; + else + images = dark ? s_arcs_images_dark : s_arcs_images_light; + if (!images[index]) { + // Lazily cache images. + gfx::ImageSkia source = GetImageForIndex(image_type, icon_type, index + 1); + images[index] = new gfx::ImageSkia( + gfx::ImageSkiaOperations::CreateBlendedImage( + gfx::ImageSkia(new EmptyImageSource(source.size()), source.size()), + source, + kConnectingImageAlpha)); + } + return images[index]; +} + +gfx::ImageSkia* ConnectingVpnImage(double animation) { + int index = animation * nextafter(static_cast<float>(kNumFadeImages), 0); + static gfx::ImageSkia* s_vpn_images[kNumFadeImages]; + if (!s_vpn_images[index]) { + // Lazily cache images. + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + gfx::ImageSkia* icon = rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN); + s_vpn_images[index] = new gfx::ImageSkia( + gfx::ImageSkiaOperations::CreateBlendedImage( + gfx::ImageSkia(new EmptyImageSource(icon->size()), icon->size()), + *icon, + animation)); + } + return s_vpn_images[index]; +} + +gfx::ImageSkia* ConnectingVpnBadge(double animation) { + int index = animation * nextafter(static_cast<float>(kNumFadeImages), 0); + static gfx::ImageSkia* s_vpn_badges[kNumFadeImages]; + if (!s_vpn_badges[index]) { + // Lazily cache images. + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + gfx::ImageSkia* icon = + rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED); // For size + gfx::ImageSkia* badge = + rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN_BADGE); + s_vpn_badges[index] = new gfx::ImageSkia( + gfx::ImageSkiaOperations::CreateBlendedImage( + gfx::ImageSkia(new EmptyImageSource(icon->size()), icon->size()), + *badge, + animation)); + } + return s_vpn_badges[index]; +} + +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) { + ImageType image_type = ImageTypeForNetworkType(network->type()); + if (image_type == ARCS) + return StrengthIndex(network->signal_strength(), kNumArcsImages); + else if (image_type == BARS) + return StrengthIndex(network->signal_strength(), kNumBarsImages); + return 0; +} + +const gfx::ImageSkia* BadgeForNetworkTechnology(const NetworkState* network, + IconType icon_type) { + const int kUnknownBadgeType = -1; + int id = kUnknownBadgeType; + const std::string& technology = network->network_technology(); + if (technology == flimflam::kNetworkTechnologyEvdo) { + id = IconTypeIsDark(icon_type) ? + IDR_AURA_UBER_TRAY_NETWORK_EVDO_DARK : + IDR_AURA_UBER_TRAY_NETWORK_EVDO_LIGHT; + } else if (technology == flimflam::kNetworkTechnology1Xrtt) { + id = IDR_AURA_UBER_TRAY_NETWORK_1X; + } else if (technology == flimflam::kNetworkTechnologyGprs) { + id = IconTypeIsDark(icon_type) ? + IDR_AURA_UBER_TRAY_NETWORK_GPRS_DARK : + IDR_AURA_UBER_TRAY_NETWORK_GPRS_LIGHT; + } else if (technology == flimflam::kNetworkTechnologyEdge) { + id = IconTypeIsDark(icon_type) ? + IDR_AURA_UBER_TRAY_NETWORK_EDGE_DARK : + IDR_AURA_UBER_TRAY_NETWORK_EDGE_LIGHT; + } else if (technology == flimflam::kNetworkTechnologyUmts) { + id = IconTypeIsDark(icon_type) ? + IDR_AURA_UBER_TRAY_NETWORK_3G_DARK : + IDR_AURA_UBER_TRAY_NETWORK_3G_LIGHT; + } else if (technology == flimflam::kNetworkTechnologyHspa) { + id = IconTypeIsDark(icon_type) ? + IDR_AURA_UBER_TRAY_NETWORK_HSPA_DARK : + IDR_AURA_UBER_TRAY_NETWORK_HSPA_LIGHT; + } else if (technology == flimflam::kNetworkTechnologyHspaPlus) { + id = IconTypeIsDark(icon_type) ? + IDR_AURA_UBER_TRAY_NETWORK_HSPA_PLUS_DARK : + IDR_AURA_UBER_TRAY_NETWORK_HSPA_PLUS_LIGHT; + } else if (technology == flimflam::kNetworkTechnologyLte) { + id = IconTypeIsDark(icon_type) ? + IDR_AURA_UBER_TRAY_NETWORK_LTE_DARK : + IDR_AURA_UBER_TRAY_NETWORK_LTE_LIGHT; + } else if (technology == flimflam::kNetworkTechnologyLteAdvanced) { + id = IconTypeIsDark(icon_type) ? + IDR_AURA_UBER_TRAY_NETWORK_LTE_ADVANCED_DARK : + IDR_AURA_UBER_TRAY_NETWORK_LTE_ADVANCED_LIGHT; + } else if (technology == flimflam::kNetworkTechnologyGsm) { + id = IconTypeIsDark(icon_type) ? + IDR_AURA_UBER_TRAY_NETWORK_GPRS_DARK : + IDR_AURA_UBER_TRAY_NETWORK_GPRS_LIGHT; + } + if (id == kUnknownBadgeType) + return NULL; + else + return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(id); +} + +const gfx::ImageSkia* BadgeForVPN(IconType icon_type) { + return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( + IDR_AURA_UBER_TRAY_NETWORK_VPN_BADGE); +} + +gfx::ImageSkia GetIcon(const NetworkState* network, + IconType icon_type, + 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 || + type == flimflam::kTypeWimax || + type == flimflam::kTypeCellular) { + DCHECK(strength_index > 0); + return GetImageForIndex( + ImageTypeForNetworkType(type), icon_type, 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); + } +} + +//------------------------------------------------------------------------------ +// Get connecting images + +gfx::ImageSkia GetConnectingVpnImage(IconType icon_type) { + NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); + const NetworkState* connected_network = NULL; + if (icon_type == ICON_TYPE_TRAY) { + connected_network = handler->ConnectedNetworkByType( + NetworkStateHandler::kMatchTypeNonVirtual); + } + double animation = NetworkIconAnimation::GetInstance()->GetAnimation(); + + if (connected_network) { + gfx::ImageSkia icon = GetImageForNetwork(connected_network, icon_type); + Badges badges; + badges.bottom_left = ConnectingVpnBadge(animation); + return gfx::ImageSkia( + new NetworkIconImageSource(icon, badges), icon.size()); + } else { + gfx::ImageSkia* icon = ConnectingVpnImage(animation); + return gfx::ImageSkia( + new NetworkIconImageSource(*icon, Badges()), icon->size()); + } +} + +gfx::ImageSkia GetConnectingImage(const std::string& network_type, + IconType icon_type) { + if (network_type == flimflam::kTypeVPN) + return GetConnectingVpnImage(icon_type); + + ImageType image_type = ImageTypeForNetworkType(network_type); + double animation = NetworkIconAnimation::GetInstance()->GetAnimation(); + + gfx::ImageSkia* icon = ConnectingWirelessImage( + image_type, icon_type, animation); + return gfx::ImageSkia( + new NetworkIconImageSource(*icon, Badges()), icon->size()); +} + +} // namespace + +//------------------------------------------------------------------------------ +// NetworkIconImpl + +NetworkIconImpl::NetworkIconImpl(IconType icon_type) + : icon_type_(icon_type), + strength_index_(-1), + technology_badge_(NULL), + vpn_badge_(NULL) { + // Default image + image_ = GetDisconnectedImage(flimflam::kTypeWifi, icon_type); +} + +void NetworkIconImpl::Update(const NetworkState* network) { + DCHECK(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->connection_state()) { + state_ = network->connection_state(); + dirty = true; + } + + const std::string& type = network->type(); + if (type != flimflam::kTypeEthernet) + dirty |= UpdateWirelessStrengthIndex(network); + + if (type == flimflam::kTypeCellular) + dirty |= UpdateCellularState(network); + + if (IconTypeHasVPNBadge(icon_type_) && type != flimflam::kTypeVPN) + dirty |= UpdateVPNBadge(); + + if (dirty) { + // Set the icon and badges based on the network and generate the image. + GenerateImage(network); + } +} + +bool NetworkIconImpl::UpdateWirelessStrengthIndex(const NetworkState* network) { + int index = GetStrengthIndex(network); + if (index != strength_index_) { + strength_index_ = index; + return true; + } + return false; +} + +bool NetworkIconImpl::UpdateCellularState(const NetworkState* network) { + bool dirty = false; + const gfx::ImageSkia* technology_badge = + BadgeForNetworkTechnology(network, icon_type_); + 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; +} + +bool NetworkIconImpl::UpdateVPNBadge() { + const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()-> + ConnectedNetworkByType(flimflam::kTypeVPN); + if (vpn && vpn_badge_ == NULL) { + vpn_badge_ = BadgeForVPN(icon_type_); + return true; + } else if (!vpn && vpn_badge_ != NULL) { + vpn_badge_ = NULL; + return true; + } + return false; +} + +void NetworkIconImpl::GetBadges(const NetworkState* network, Badges* badges) { + DCHECK(network); + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); + + const std::string& type = network->type(); + if (type == flimflam::kTypeWifi) { + if (network->security() != flimflam::kSecurityNone && + IconTypeIsDark(icon_type_)) { + badges->bottom_right = rb.GetImageSkiaNamed( + IDR_AURA_UBER_TRAY_NETWORK_SECURE_DARK); + } + } else if (type == flimflam::kTypeWimax) { + technology_badge_ = rb.GetImageSkiaNamed( + IconTypeIsDark(icon_type_) ? + 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 are always in roaming don't show roaming badge. + const DeviceState* device = + handler->GetDeviceState(network->device_path()); + DCHECK(device); + if (!device->provider_requires_roaming()) { + badges->bottom_right = rb.GetImageSkiaNamed( + IconTypeIsDark(icon_type_) ? + IDR_AURA_UBER_TRAY_NETWORK_ROAMING_DARK : + IDR_AURA_UBER_TRAY_NETWORK_ROAMING_LIGHT); + } + } + } + if (!network->IsConnectingState()) { + badges->top_left = technology_badge_; + badges->bottom_left = vpn_badge_; + } +} + +void NetworkIconImpl::GenerateImage(const NetworkState* network) { + DCHECK(network); + gfx::ImageSkia icon = GetIcon(network, icon_type_, strength_index_); + Badges badges; + GetBadges(network, &badges); + image_ = gfx::ImageSkia( + new NetworkIconImageSource(icon, badges), icon.size()); +} + +//------------------------------------------------------------------------------ +// Public interface + +gfx::ImageSkia GetImageForNetwork(const NetworkState* network, + IconType icon_type) { + DCHECK(network); + // Handle connecting icons. + if (network->IsConnectingState()) + return GetConnectingImage(network->type(), icon_type); + + // Find or add the icon. + NetworkIconMap* icon_map = GetIconMap(icon_type); + NetworkIconImpl* icon; + NetworkIconMap::iterator iter = icon_map->find(network->path()); + if (iter == icon_map->end()) { + icon = new NetworkIconImpl(icon_type); + 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(); +} + +gfx::ImageSkia GetImageForConnectedNetwork(IconType icon_type, + const std::string& network_type) { + return GetConnectedImage(network_type, icon_type); +} + +gfx::ImageSkia GetImageForConnectingNetwork(IconType icon_type, + const std::string& network_type) { + return GetConnectingImage(network_type, icon_type); +} + +gfx::ImageSkia GetImageForDisconnectedNetwork(IconType icon_type, + const std::string& network_type) { + return GetDisconnectedImage(network_type, icon_type); +} + +base::string16 GetLabelForNetwork(const chromeos::NetworkState* network, + IconType icon_type) { + DCHECK(network); + std::string activation_state = network->activation_state(); + if (icon_type == ICON_TYPE_LIST) { + // Show "<network>: [Connecting|Activating]..." + if (network->IsConnectingState()) { + return l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_NETWORK_LIST_CONNECTING, + UTF8ToUTF16(network->name())); + } + if (activation_state == flimflam::kActivationStateActivating) { + return l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_NETWORK_LIST_ACTIVATING, + UTF8ToUTF16(network->name())); + } + // Show "Activate <network>" in list view only. + if (activation_state == flimflam::kActivationStateNotActivated || + activation_state == flimflam::kActivationStatePartiallyActivated) { + return l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_NETWORK_LIST_ACTIVATE, + UTF8ToUTF16(network->name())); + } + } else { + // Show "[Connected to|Connecting to|Activating] <network>" (non-list view). + if (network->IsConnectedState()) { + return l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED, UTF8ToUTF16(network->name())); + } + if (network->IsConnectingState()) { + return l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_NETWORK_CONNECTING, UTF8ToUTF16(network->name())); + } + if (activation_state == flimflam::kActivationStateActivating) { + return l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_NETWORK_ACTIVATING, UTF8ToUTF16(network->name())); + } + } + + // Otherwise just show the network name or 'Ethernet'. + if (network->type() == flimflam::kTypeEthernet) { + return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ETHERNET); + } else { + return UTF8ToUTF16(network->name()); + } +} + +int GetCellularUninitializedMsg() { + static base::Time s_uninitialized_state_time; + static int s_uninitialized_msg(0); + + NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); + if (handler->GetTechnologyState(NetworkStateHandler::kMatchTypeMobile) + == NetworkStateHandler::TECHNOLOGY_UNINITIALIZED) { + s_uninitialized_msg = IDS_ASH_STATUS_TRAY_INITIALIZING_CELLULAR; + s_uninitialized_state_time = base::Time::Now(); + return s_uninitialized_msg; + } else if (handler->GetScanningByType( + NetworkStateHandler::kMatchTypeMobile)) { + s_uninitialized_msg = IDS_ASH_STATUS_TRAY_CELLULAR_SCANNING; + s_uninitialized_state_time = base::Time::Now(); + return s_uninitialized_msg; + } + // There can be a delay between leaving the Initializing state and when + // a Cellular device shows up, so keep showing the initializing + // animation for a bit to avoid flashing the disconnect icon. + const int kInitializingDelaySeconds = 1; + base::TimeDelta dtime = base::Time::Now() - s_uninitialized_state_time; + if (dtime.InSeconds() < kInitializingDelaySeconds) + return s_uninitialized_msg; + return 0; +} + +void GetDefaultNetworkImageAndLabel(IconType icon_type, + gfx::ImageSkia* image, + base::string16* label, + bool* animating) { + NetworkStateHandler* state_handler = + NetworkHandler::Get()->network_state_handler(); + NetworkConnectionHandler* connect_handler = + NetworkHandler::Get()->network_connection_handler(); + const NetworkState* connected_network = + state_handler->ConnectedNetworkByType( + NetworkStateHandler::kMatchTypeNonVirtual); + const NetworkState* connecting_network = + state_handler->ConnectingNetworkByType( + NetworkStateHandler::kMatchTypeWireless); + if (!connecting_network && icon_type == ICON_TYPE_TRAY) { + connecting_network = + state_handler->ConnectingNetworkByType(flimflam::kTypeVPN); + } + + const NetworkState* network; + // If we are connecting to a network, and there is either no connected + // network, or the connection was user requested, use the connecting + // network. + if (connecting_network && + (!connected_network || + connect_handler->HasConnectingNetwork(connecting_network->path()))) { + network = connecting_network; + } else { + network = connected_network; + } + + // Don't show ethernet in the tray + if (icon_type == ICON_TYPE_TRAY && + network && network->type() == flimflam::kTypeEthernet) { + *image = gfx::ImageSkia(); + *animating = false; + return; + } + + if (!network) { + // If no connecting network, check if we are activating a network. + const NetworkState* mobile_network = state_handler->FirstNetworkByType( + NetworkStateHandler::kMatchTypeMobile); + if (mobile_network && (mobile_network->activation_state() == + flimflam::kActivationStateActivating)) { + network = mobile_network; + } + } + if (!network) { + // If no connecting network, check for cellular initializing. + int uninitialized_msg = GetCellularUninitializedMsg(); + if (uninitialized_msg != 0) { + *image = GetImageForConnectingNetwork(icon_type, flimflam::kTypeCellular); + if (label) + *label = l10n_util::GetStringUTF16(uninitialized_msg); + *animating = true; + } else { + // Otherwise show the disconnected wifi icon. + *image = GetImageForDisconnectedNetwork(icon_type, flimflam::kTypeWifi); + if (label) { + *label = l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_NETWORK_NOT_CONNECTED); + } + *animating = false; + } + return; + } + *animating = network->IsConnectingState(); + // Get icon and label for connected or connecting network. + *image = GetImageForNetwork(network, icon_type); + if (label) + *label = GetLabelForNetwork(network, icon_type); +} + +void PurgeNetworkIconCache() { + NetworkStateHandler::NetworkStateList networks; + NetworkHandler::Get()->network_state_handler()->GetNetworkList(&networks); + std::set<std::string> network_paths; + for (NetworkStateHandler::NetworkStateList::iterator iter = networks.begin(); + iter != networks.end(); ++iter) { + network_paths.insert((*iter)->path()); + } + PurgeIconMap(ICON_TYPE_TRAY, network_paths); + PurgeIconMap(ICON_TYPE_DEFAULT_VIEW, network_paths); + PurgeIconMap(ICON_TYPE_LIST, network_paths); +} + +} // namespace network_icon +} // namespace ash |