| // 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 |