// 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 "ui/chromeos/network/network_icon.h" #include "base/macros.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 "chromeos/network/portal_detector/network_portal_detector.h" #include "grit/ui_chromeos_resources.h" #include "grit/ui_chromeos_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/base/webui/web_ui_util.h" #include "ui/chromeos/network/network_icon_animation.h" #include "ui/chromeos/network/network_icon_animation_observer.h" #include "ui/gfx/canvas.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size_conversions.h" #include "ui/gfx/image/image_skia_operations.h" #include "ui/gfx/image/image_skia_source.h" using chromeos::DeviceState; using chromeos::NetworkConnectionHandler; using chromeos::NetworkHandler; using chromeos::NetworkPortalDetector; using chromeos::NetworkState; using chromeos::NetworkStateHandler; using chromeos::NetworkTypePattern; namespace ui { 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: NetworkIconImpl(const std::string& path, 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 portal state for wireless networks. Returns true if changed. bool UpdatePortalState(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); // Network path, used for debugging. std::string network_path_; // 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_; // Cached portal state of the network when the icon was last generated. bool behind_captive_portal_; // 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 NetworkIconMap; NetworkIconMap* GetIconMapInstance(IconType icon_type, bool create) { typedef std::map 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& 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 SizeKey; typedef std::map 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.allocN32Pixels(key.first, key.second); 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) { } gfx::ImageSkiaRep GetImageForScale(float scale) override { gfx::Size pixel_size = gfx::ScaleToFlooredSize(size_, scale); SkBitmap empty_bitmap = GetEmptyBitmap(pixel_size); return gfx::ImageSkiaRep(empty_bitmap, scale); } 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) { } ~NetworkIconImageSource() override {} // TODO(pkotwicz): Figure out what to do when a new image resolution becomes // available. gfx::ImageSkiaRep GetImageForScale(float scale) override { gfx::ImageSkiaRep icon_rep = icon_.GetRepresentation(scale); 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 == shill::kTypeWifi) return ARCS; else if (type == shill::kTypeCellular || type == shill::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(IconType icon_type, const std::string& network_type) { if (network_type == shill::kTypeVPN) { return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( IDR_AURA_UBER_TRAY_NETWORK_VPN); } ImageType image_type = ImageTypeForNetworkType(network_type); const int connected_index = NumImagesForType(image_type) - 1; return GetImageForIndex(image_type, icon_type, connected_index); } const gfx::ImageSkia GetDisconnectedImage(IconType icon_type, const std::string& network_type) { if (network_type == shill::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(network_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(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(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(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(strength) / 100.0f) * nextafter(static_cast(count - 1), 0); int index = 1 + static_cast(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 == shill::kNetworkTechnologyEvdo) { id = IconTypeIsDark(icon_type) ? IDR_AURA_UBER_TRAY_NETWORK_EVDO_DARK : IDR_AURA_UBER_TRAY_NETWORK_EVDO_LIGHT; } else if (technology == shill::kNetworkTechnology1Xrtt) { id = IDR_AURA_UBER_TRAY_NETWORK_1X; } else if (technology == shill::kNetworkTechnologyGprs) { id = IconTypeIsDark(icon_type) ? IDR_AURA_UBER_TRAY_NETWORK_GPRS_DARK : IDR_AURA_UBER_TRAY_NETWORK_GPRS_LIGHT; } else if (technology == shill::kNetworkTechnologyEdge) { id = IconTypeIsDark(icon_type) ? IDR_AURA_UBER_TRAY_NETWORK_EDGE_DARK : IDR_AURA_UBER_TRAY_NETWORK_EDGE_LIGHT; } else if (technology == shill::kNetworkTechnologyUmts) { id = IconTypeIsDark(icon_type) ? IDR_AURA_UBER_TRAY_NETWORK_3G_DARK : IDR_AURA_UBER_TRAY_NETWORK_3G_LIGHT; } else if (technology == shill::kNetworkTechnologyHspa) { id = IconTypeIsDark(icon_type) ? IDR_AURA_UBER_TRAY_NETWORK_HSPA_DARK : IDR_AURA_UBER_TRAY_NETWORK_HSPA_LIGHT; } else if (technology == shill::kNetworkTechnologyHspaPlus) { id = IconTypeIsDark(icon_type) ? IDR_AURA_UBER_TRAY_NETWORK_HSPA_PLUS_DARK : IDR_AURA_UBER_TRAY_NETWORK_HSPA_PLUS_LIGHT; } else if (technology == shill::kNetworkTechnologyLte) { id = IconTypeIsDark(icon_type) ? IDR_AURA_UBER_TRAY_NETWORK_LTE_DARK : IDR_AURA_UBER_TRAY_NETWORK_LTE_LIGHT; } else if (technology == shill::kNetworkTechnologyLteAdvanced) { id = IconTypeIsDark(icon_type) ? IDR_AURA_UBER_TRAY_NETWORK_LTE_ADVANCED_DARK : IDR_AURA_UBER_TRAY_NETWORK_LTE_ADVANCED_LIGHT; } else if (technology == shill::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(); if (network->Matches(NetworkTypePattern::Ethernet())) { return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED); } else if (network->Matches(NetworkTypePattern::Wireless())) { DCHECK(strength_index > 0); return GetImageForIndex( ImageTypeForNetworkType(network->type()), icon_type, strength_index); } else if (network->Matches(NetworkTypePattern::VPN())) { return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN); } else { LOG(WARNING) << "Request for icon for unsupported type: " << network->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(NetworkTypePattern::NonVirtual()); } 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(IconType icon_type, const std::string& network_type) { if (network_type == shill::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(const std::string& path, IconType icon_type) : network_path_(path), icon_type_(icon_type), strength_index_(-1), technology_badge_(NULL), vpn_badge_(NULL), behind_captive_portal_(false) { // Default image image_ = GetDisconnectedImage(icon_type, shill::kTypeWifi); } 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; } dirty |= UpdatePortalState(network); if (network->Matches(NetworkTypePattern::Wireless())) { dirty |= UpdateWirelessStrengthIndex(network); } if (network->Matches(NetworkTypePattern::Cellular())) dirty |= UpdateCellularState(network); if (IconTypeHasVPNBadge(icon_type_) && network->Matches(NetworkTypePattern::NonVirtual())) { 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::UpdatePortalState(const NetworkState* network) { bool behind_captive_portal = false; if (network && chromeos::network_portal_detector::IsInitialized()) { NetworkPortalDetector::CaptivePortalState state = chromeos::network_portal_detector::GetInstance()->GetCaptivePortalState( network->guid()); behind_captive_portal = state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL; } if (behind_captive_portal == behind_captive_portal_) return false; behind_captive_portal_ = behind_captive_portal; return true; } bool NetworkIconImpl::UpdateVPNBadge() { const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()-> ConnectedNetworkByType(NetworkTypePattern::VPN()); 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 == shill::kTypeWifi) { if (network->security_class() != shill::kSecurityNone && IconTypeIsDark(icon_type_)) { badges->bottom_right = rb.GetImageSkiaNamed( IDR_AURA_UBER_TRAY_NETWORK_SECURE_DARK); } } else if (type == shill::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 == shill::kTypeCellular) { if (network->roaming() == shill::kRoamingStateRoaming) { // For networks that are always in roaming don't show roaming badge. const DeviceState* device = handler->GetDeviceState(network->device_path()); LOG_IF(WARNING, !device) << "Could not find device state for " << network->device_path(); if (!device || !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_; } if (behind_captive_portal_) { gfx::ImageSkia* badge = rb.GetImageSkiaNamed( IconTypeIsDark(icon_type_) ? IDR_AURA_UBER_TRAY_NETWORK_PORTAL_DARK : IDR_AURA_UBER_TRAY_NETWORK_PORTAL_LIGHT); badges->bottom_right = 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()); } namespace { NetworkIconImpl* FindAndUpdateImageImpl(const NetworkState* network, IconType 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(network->path(), 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; } } // namespace //------------------------------------------------------------------------------ // Public interface gfx::ImageSkia GetImageForNetwork(const NetworkState* network, IconType icon_type) { DCHECK(network); if (!network->visible()) return GetDisconnectedImage(icon_type, network->type()); if (network->IsConnectingState()) return GetConnectingImage(icon_type, network->type()); NetworkIconImpl* icon = FindAndUpdateImageImpl(network, icon_type); return icon->image(); } gfx::ImageSkia GetImageForConnectedNetwork(IconType icon_type, const std::string& network_type) { return GetConnectedImage(icon_type, network_type); } gfx::ImageSkia GetImageForConnectingNetwork(IconType icon_type, const std::string& network_type) { return GetConnectingImage(icon_type, network_type); } gfx::ImageSkia GetImageForDisconnectedNetwork(IconType icon_type, const std::string& network_type) { return GetDisconnectedImage(icon_type, network_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 ": [Connecting|Activating|Reconnecting]..." if (network->IsReconnecting()) { return l10n_util::GetStringFUTF16( IDS_ASH_STATUS_TRAY_NETWORK_LIST_RECONNECTING, base::UTF8ToUTF16(network->name())); } if (network->IsConnectingState()) { return l10n_util::GetStringFUTF16( IDS_ASH_STATUS_TRAY_NETWORK_LIST_CONNECTING, base::UTF8ToUTF16(network->name())); } if (activation_state == shill::kActivationStateActivating) { return l10n_util::GetStringFUTF16( IDS_ASH_STATUS_TRAY_NETWORK_LIST_ACTIVATING, base::UTF8ToUTF16(network->name())); } // Show "Activate " in list view only. if (activation_state == shill::kActivationStateNotActivated || activation_state == shill::kActivationStatePartiallyActivated) { return l10n_util::GetStringFUTF16( IDS_ASH_STATUS_TRAY_NETWORK_LIST_ACTIVATE, base::UTF8ToUTF16(network->name())); } } else { // Show "[Connected to|Connecting to|Activating|Reconnecting to] " // (non-list view). if (network->IsReconnecting()) { return l10n_util::GetStringFUTF16( IDS_ASH_STATUS_TRAY_NETWORK_RECONNECTING, base::UTF8ToUTF16(network->name())); } if (network->IsConnectedState()) { return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED, base::UTF8ToUTF16(network->name())); } if (network->IsConnectingState()) { return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_CONNECTING, base::UTF8ToUTF16(network->name())); } if (activation_state == shill::kActivationStateActivating) { return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_ACTIVATING, base::UTF8ToUTF16(network->name())); } } // Otherwise just show the network name or 'Ethernet'. if (network->Matches(NetworkTypePattern::Ethernet())) { return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ETHERNET); } else { return base::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(NetworkTypePattern::Mobile()) == 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(NetworkTypePattern::Mobile())) { 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(NetworkTypePattern::NonVirtual()); const NetworkState* connecting_network = state_handler->ConnectingNetworkByType(NetworkTypePattern::Wireless()); if (!connecting_network && icon_type == ICON_TYPE_TRAY) { connecting_network = state_handler->ConnectingNetworkByType(NetworkTypePattern::VPN()); } const NetworkState* network; // If we are connecting to a network, and there is either no connected // network, or the connection was user requested, or shill triggered a // reconnection, use the connecting network. if (connecting_network && (!connected_network || connecting_network->IsReconnecting() || 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->Matches(NetworkTypePattern::Ethernet())) { *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(NetworkTypePattern::Mobile()); if (mobile_network && (mobile_network->activation_state() == shill::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, shill::kTypeCellular); if (label) *label = l10n_util::GetStringUTF16(uninitialized_msg); *animating = true; } else { // Otherwise show the disconnected wifi icon. *image = GetImageForDisconnectedNetwork(icon_type, shill::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()->GetVisibleNetworkList( &networks); std::set 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 ui