// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/chromeos/status/network_menu_icon.h" #include #include #include #include #include "ash/system/chromeos/network/network_icon_animation.h" #include "base/utf_string_conversions.h" #include "chrome/browser/chromeos/accessibility/accessibility_util.h" #include "chrome/browser/chromeos/cros/cros_library.h" #include "grit/ash_resources.h" #include "grit/ash_strings.h" #include "grit/generated_resources.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/size_conversions.h" using std::max; using std::min; using ash::network_icon::NetworkIconAnimation; namespace chromeos { namespace { // 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]; // Badge offsets. The right and bottom offsets are computed based on the size // of the network icon and the badge in order to accomodate multiple icon // resolutions (ie. standard and high DPI). const int kBadgeLeftX = 0; const int kBadgeTopY = 0; int StrengthIndex(int strength, int count) { if (strength == 0) { return 0; } else { // Return an index in the range [1, count]. const float findex = (static_cast(strength) / 100.0f) * nextafter(static_cast(count), 0); int index = 1 + static_cast(findex); index = max(min(index, count), 1); return index; } } int WifiStrengthIndex(const WifiNetwork* wifi) { return StrengthIndex(wifi->strength(), kNumArcsImages - 1); } int WimaxStrengthIndex(const WimaxNetwork* wimax) { return StrengthIndex(wimax->strength(), kNumBarsImages - 1); } int CellularStrengthIndex(const CellularNetwork* cellular) { return StrengthIndex(cellular->strength(), kNumBarsImages - 1); } const gfx::ImageSkia* BadgeForNetworkTechnology( const CellularNetwork* cellular, NetworkMenuIcon::ResourceColorTheme color) { const int kUnknownBadgeType = -1; int id = kUnknownBadgeType; switch (cellular->network_technology()) { case NETWORK_TECHNOLOGY_EVDO: id = (color == NetworkMenuIcon::COLOR_DARK) ? IDR_AURA_UBER_TRAY_NETWORK_3G_DARK : IDR_AURA_UBER_TRAY_NETWORK_3G_LIGHT; break; case NETWORK_TECHNOLOGY_1XRTT: id = IDR_AURA_UBER_TRAY_NETWORK_1X; break; case NETWORK_TECHNOLOGY_GPRS: id = (color == NetworkMenuIcon::COLOR_DARK) ? IDR_AURA_UBER_TRAY_NETWORK_GPRS_DARK : IDR_AURA_UBER_TRAY_NETWORK_GPRS_LIGHT; break; case NETWORK_TECHNOLOGY_EDGE: id = (color == NetworkMenuIcon::COLOR_DARK) ? IDR_AURA_UBER_TRAY_NETWORK_EDGE_DARK : IDR_AURA_UBER_TRAY_NETWORK_EDGE_LIGHT; break; case NETWORK_TECHNOLOGY_UMTS: id = (color == NetworkMenuIcon::COLOR_DARK) ? IDR_AURA_UBER_TRAY_NETWORK_3G_DARK : IDR_AURA_UBER_TRAY_NETWORK_3G_LIGHT; break; case NETWORK_TECHNOLOGY_HSPA: id = (color == NetworkMenuIcon::COLOR_DARK) ? IDR_AURA_UBER_TRAY_NETWORK_HSPA_DARK : IDR_AURA_UBER_TRAY_NETWORK_HSPA_LIGHT; break; case NETWORK_TECHNOLOGY_HSPA_PLUS: id = (color == NetworkMenuIcon::COLOR_DARK) ? IDR_AURA_UBER_TRAY_NETWORK_HSPA_PLUS_DARK : IDR_AURA_UBER_TRAY_NETWORK_HSPA_PLUS_LIGHT; break; case NETWORK_TECHNOLOGY_LTE: id = (color == NetworkMenuIcon::COLOR_DARK) ? IDR_AURA_UBER_TRAY_NETWORK_LTE_DARK : IDR_AURA_UBER_TRAY_NETWORK_LTE_LIGHT; break; case NETWORK_TECHNOLOGY_LTE_ADVANCED: id = (color == NetworkMenuIcon::COLOR_DARK) ? IDR_AURA_UBER_TRAY_NETWORK_LTE_ADVANCED_DARK : IDR_AURA_UBER_TRAY_NETWORK_LTE_ADVANCED_LIGHT; break; case NETWORK_TECHNOLOGY_GSM: id = (color == NetworkMenuIcon::COLOR_DARK) ? IDR_AURA_UBER_TRAY_NETWORK_GPRS_DARK : IDR_AURA_UBER_TRAY_NETWORK_GPRS_LIGHT; break; case NETWORK_TECHNOLOGY_UNKNOWN: break; } if (id == kUnknownBadgeType) return NULL; else return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(id); } const SkBitmap GetEmptyBitmap(const gfx::Size pixel_size) { typedef std::pair SizeKey; typedef std::map SizeBitmapMap; static SizeBitmapMap* empty_bitmaps_ = new SizeBitmapMap; 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 gfx::ImageSkia* top_left_badge, const gfx::ImageSkia* top_right_badge, const gfx::ImageSkia* bottom_left_badge, const gfx::ImageSkia* bottom_right_badge) : icon_(icon), top_left_badge_(top_left_badge), top_right_badge_(top_right_badge), bottom_left_badge_(bottom_left_badge), bottom_right_badge_(bottom_right_badge) { } virtual ~NetworkIconImageSource() {} 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 (top_left_badge_) canvas.DrawImageInt(*top_left_badge_, kBadgeLeftX, kBadgeTopY); if (top_right_badge_) canvas.DrawImageInt(*top_right_badge_, icon_.width() - top_right_badge_->width(), kBadgeTopY); if (bottom_left_badge_) { canvas.DrawImageInt(*bottom_left_badge_, kBadgeLeftX, icon_.height() - bottom_left_badge_->height()); } if (bottom_right_badge_) { canvas.DrawImageInt(*bottom_right_badge_, icon_.width() - bottom_right_badge_->width(), icon_.height() - bottom_right_badge_->height()); } return canvas.ExtractImageRep(); } private: const gfx::ImageSkia icon_; const gfx::ImageSkia *top_left_badge_; const gfx::ImageSkia *top_right_badge_; const gfx::ImageSkia *bottom_left_badge_; const gfx::ImageSkia *bottom_right_badge_; DISALLOW_COPY_AND_ASSIGN(NetworkIconImageSource); }; gfx::ImageSkia GetEmptyImage(const gfx::Size& size) { return gfx::ImageSkia(new EmptyImageSource(size), size); } } // namespace //////////////////////////////////////////////////////////////////////////////// // NetworkIcon // Sets up and generates an ImageSkia for a Network icon. class NetworkIcon { public: // Default constructor is used by the status bar icon (NetworkMenuIcon). explicit NetworkIcon(NetworkMenuIcon::ResourceColorTheme color); // Service path constructor for cached network service icons. NetworkIcon(const std::string& service_path, NetworkMenuIcon::ResourceColorTheme color); ~NetworkIcon(); // Resets the icon state. void ClearIconAndBadges(); // Resets the saved state to force an update. void SetDirty(); // Updates |vpn_connected_|, returns true if it changed. bool SetOrClearVpnConnected(const Network* network); // 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(); // Sets up the base icon image. void SetIcon(const Network* network); // Sets up the various badges: // top_left: cellular roaming // top_right: libcros warning // bottom_left: VPN // bottom_right: disconnected / secure / technology / warning void SetBadges(const Network* network); // Clears any previous state then sets the base icon and badges. void UpdateIcon(const Network* network); // Generates the image. Call after setting the icon and badges. void GenerateImage(); const gfx::ImageSkia GetImage() const { return image_; } bool ShouldShowInTray() const; ConnectionType type() { return type_; } void set_type(ConnectionType type) { type_ = type; } void set_state(ConnectionState state) { state_ = state; } void set_icon(const gfx::ImageSkia& icon) { icon_ = icon; } void set_top_left_badge(const gfx::ImageSkia* badge) { top_left_badge_ = badge; } void set_top_right_badge(const gfx::ImageSkia* badge) { top_right_badge_ = badge; } void set_bottom_left_badge(const gfx::ImageSkia* badge) { bottom_left_badge_ = badge; } void set_bottom_right_badge(const gfx::ImageSkia* badge) { bottom_right_badge_ = badge; } private: // Updates strength_index_ for wifi or cellular networks. // Returns true if |strength_index_| changed. bool UpdateWirelessStrengthIndex(const Network* network); // Updates the local state for cellular networks. bool UpdateCellularState(const Network* network); std::string service_path_; ConnectionType type_; ConnectionState state_; NetworkMenuIcon::ResourceColorTheme resource_color_theme_; int strength_index_; gfx::ImageSkia image_; gfx::ImageSkia icon_; const gfx::ImageSkia* top_left_badge_; const gfx::ImageSkia* top_right_badge_; const gfx::ImageSkia* bottom_left_badge_; const gfx::ImageSkia* bottom_right_badge_; bool is_status_bar_; const Network* connected_network_; // weak pointer; used for VPN icons. bool vpn_connected_; NetworkRoamingState roaming_state_; DISALLOW_COPY_AND_ASSIGN(NetworkIcon); }; //////////////////////////////////////////////////////////////////////////////// // NetworkIcon NetworkIcon::NetworkIcon(NetworkMenuIcon::ResourceColorTheme color) : type_(TYPE_UNKNOWN), state_(STATE_UNKNOWN), resource_color_theme_(color), strength_index_(-1), top_left_badge_(NULL), top_right_badge_(NULL), bottom_left_badge_(NULL), bottom_right_badge_(NULL), is_status_bar_(true), connected_network_(NULL), vpn_connected_(false), roaming_state_(ROAMING_STATE_UNKNOWN) { } NetworkIcon::NetworkIcon(const std::string& service_path, NetworkMenuIcon::ResourceColorTheme color) : service_path_(service_path), type_(TYPE_UNKNOWN), state_(STATE_UNKNOWN), resource_color_theme_(color), strength_index_(-1), top_left_badge_(NULL), top_right_badge_(NULL), bottom_left_badge_(NULL), bottom_right_badge_(NULL), is_status_bar_(false), connected_network_(NULL), vpn_connected_(false), roaming_state_(ROAMING_STATE_UNKNOWN) { } NetworkIcon::~NetworkIcon() { } void NetworkIcon::ClearIconAndBadges() { icon_ = gfx::ImageSkia(); top_left_badge_ = NULL; top_right_badge_ = NULL; bottom_left_badge_ = NULL; bottom_right_badge_ = NULL; } void NetworkIcon::SetDirty() { state_ = STATE_UNKNOWN; strength_index_ = -1; } bool NetworkIcon::SetOrClearVpnConnected(const Network* network) { if (network->type() == TYPE_VPN) return false; // Never show the VPN badge for a VPN network. chromeos::NetworkLibrary* cros = chromeos::CrosLibrary::Get()->GetNetworkLibrary(); bool vpn_connected = (network->connected() && cros->virtual_network() && cros->virtual_network()->connected()); if (vpn_connected_ != vpn_connected) { vpn_connected_ = vpn_connected; return true; } return false; } void NetworkIcon::Update() { chromeos::NetworkLibrary* cros = chromeos::CrosLibrary::Get()->GetNetworkLibrary(); // First look for a visible network. const Network* network = cros->FindNetworkByPath(service_path_); if (!network) { // If not a visible network, check for a remembered network. network = cros->FindRememberedNetworkByPath(service_path_); if (!network) { LOG(WARNING) << "Unable to find network:" << service_path_; return; } } // 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; } type_ = network->type(); if (type_ == TYPE_WIFI || type_ == TYPE_WIMAX || type_ == TYPE_CELLULAR) { if (UpdateWirelessStrengthIndex(network)) dirty = true; } if (type_ == TYPE_CELLULAR) { if (UpdateCellularState(network)) dirty = true; } if (type_ == TYPE_VPN) { // For VPN, check to see if the connected network has changed. if (cros->connected_network() != connected_network_) { connected_network_ = cros->connected_network(); dirty = true; } } if (dirty) { // Set the icon and badges based on the network. UpdateIcon(network); // Generate the image from the icon. GenerateImage(); } } void NetworkIcon::SetIcon(const Network* network) { ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); set_type(network->type()); set_state(network->state()); switch (type_) { case TYPE_ETHERNET: { icon_ = *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED); break; } case TYPE_WIFI: { const WifiNetwork* wifi = static_cast(network); if (strength_index_ == -1) strength_index_ = WifiStrengthIndex(wifi); icon_ = NetworkMenuIcon::GetImage( NetworkMenuIcon::ARCS, strength_index_, resource_color_theme_); break; } case TYPE_WIMAX: { const WimaxNetwork* wimax = static_cast(network); if (strength_index_ == -1) strength_index_ = WimaxStrengthIndex(wimax); icon_ = NetworkMenuIcon::GetImage( NetworkMenuIcon::BARS, strength_index_, resource_color_theme_); break; } case TYPE_CELLULAR: { const CellularNetwork* cellular = static_cast(network); if (strength_index_ == -1) strength_index_ = CellularStrengthIndex(cellular); icon_ = NetworkMenuIcon::GetImage( NetworkMenuIcon::BARS, strength_index_, resource_color_theme_); break; } case TYPE_VPN: { icon_ = *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN); break; } default: { LOG(WARNING) << "Request for icon for unsupported type: " << type_; icon_ = *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED); break; } } } void NetworkIcon::SetBadges(const Network* network) { ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); chromeos::NetworkLibrary* cros = chromeos::CrosLibrary::Get()->GetNetworkLibrary(); bool use_dark_icons = resource_color_theme_ == NetworkMenuIcon::COLOR_DARK; switch (network->type()) { case TYPE_ETHERNET: break; case TYPE_WIFI: { const WifiNetwork* wifi = static_cast(network); if (wifi->encrypted() && use_dark_icons) { bottom_right_badge_ = rb.GetImageSkiaNamed( IDR_AURA_UBER_TRAY_NETWORK_SECURE_DARK); } break; } case TYPE_WIMAX: { top_left_badge_ = rb.GetImageSkiaNamed( use_dark_icons ? IDR_AURA_UBER_TRAY_NETWORK_4G_DARK : IDR_AURA_UBER_TRAY_NETWORK_4G_LIGHT); break; } case TYPE_CELLULAR: { const CellularNetwork* cellular = static_cast(network); if (cellular->roaming_state() == ROAMING_STATE_ROAMING && !cros->IsCellularAlwaysInRoaming()) { // For cellular that always in roaming don't show roaming badge. bottom_right_badge_ = rb.GetImageSkiaNamed(use_dark_icons ? IDR_AURA_UBER_TRAY_NETWORK_ROAMING_DARK : IDR_AURA_UBER_TRAY_NETWORK_ROAMING_LIGHT); } if (!cellular->connecting()) { top_left_badge_ = BadgeForNetworkTechnology(cellular, resource_color_theme_); } break; } default: break; } if (vpn_connected_ && network->type() != TYPE_VPN) { bottom_left_badge_ = rb.GetImageSkiaNamed( IDR_AURA_UBER_TRAY_NETWORK_VPN_BADGE); } } void NetworkIcon::UpdateIcon(const Network* network) { ClearIconAndBadges(); SetIcon(network); SetBadges(network); } void NetworkIcon::GenerateImage() { if (icon_.isNull()) { set_icon(NetworkMenuIcon::GetDisconnectedImage( NetworkMenuIcon::ARCS, resource_color_theme_)); } image_ = NetworkMenuIcon::GenerateImageFromComponents(icon_, top_left_badge_, top_right_badge_, bottom_left_badge_, bottom_right_badge_); } bool NetworkIcon::ShouldShowInTray() const { if (type_ != TYPE_ETHERNET) return true; if (!Network::IsConnectedState(state_)) return true; NetworkLibrary* crosnet = CrosLibrary::Get()->GetNetworkLibrary(); if (crosnet->virtual_network()) return true; return false; } bool NetworkIcon::UpdateWirelessStrengthIndex(const Network* network) { bool dirty = false; ConnectionType type = network->type(); int index = 0; if (type == TYPE_WIFI) { index = WifiStrengthIndex(static_cast(network)); } else if (type == TYPE_WIMAX) { index = WimaxStrengthIndex(static_cast(network)); } else if (type == TYPE_CELLULAR) { index = CellularStrengthIndex(static_cast(network)); } if (index != strength_index_) { strength_index_ = index; dirty = true; } return dirty; } bool NetworkIcon::UpdateCellularState(const Network* network) { if (network->type() != TYPE_CELLULAR) return false; bool dirty = false; const CellularNetwork* cellular = static_cast(network); const gfx::ImageSkia* technology_badge = BadgeForNetworkTechnology( cellular, resource_color_theme_); if (technology_badge != top_left_badge_) { dirty = true; } if (cellular->roaming_state() != roaming_state_) { roaming_state_ = cellular->roaming_state(); dirty = true; } return dirty; } //////////////////////////////////////////////////////////////////////////////// // NetworkMenuIcon NetworkMenuIcon::NetworkMenuIcon(Delegate* delegate, Mode mode) : mode_(mode), delegate_(delegate), resource_color_theme_(COLOR_DARK), connecting_index_(-1) { // Initialize the icon. icon_.reset(new NetworkIcon(resource_color_theme_)); } NetworkMenuIcon::~NetworkMenuIcon() { // Remove itself from NetworkIconAnimation's observer list just in case // it has been added before and not been removed yet. NetworkIconAnimation::GetInstance()->RemoveObserver(this); } // Public methods: void NetworkMenuIcon::SetResourceColorTheme(ResourceColorTheme color) { if (color == resource_color_theme_) return; resource_color_theme_ = color; icon_.reset(new NetworkIcon(resource_color_theme_)); } bool NetworkMenuIcon::ShouldShowIconInTray() { if (!icon_.get()) return false; return icon_->ShouldShowInTray(); } const gfx::ImageSkia NetworkMenuIcon::GetIconAndText(string16* text) { if (SetIconAndText()) NetworkIconAnimation::GetInstance()->AddObserver(this); else NetworkIconAnimation::GetInstance()->RemoveObserver(this); if (text) *text = text_; icon_->GenerateImage(); return icon_->GetImage(); } const gfx::ImageSkia NetworkMenuIcon::GetVpnIconAndText(string16* text) { if (SetVpnIconAndText()) NetworkIconAnimation::GetInstance()->AddObserver(this); else NetworkIconAnimation::GetInstance()->RemoveObserver(this); if (text) *text = text_; icon_->GenerateImage(); return icon_->GetImage(); } void NetworkMenuIcon::NetworkIconChanged() { if (!delegate_ || !icon_.get()) return; // Only send a message when the icon would change. int connecting_index = GetConnectingIndex(); if (connecting_index != connecting_index_) { connecting_index_ = connecting_index; delegate_->NetworkMenuIconChanged(); } } // Private methods: // If disconnected: returns any connecting non-ethernet network. // Otherwise, only return a network if the conenction was user initiated. const Network* NetworkMenuIcon::GetConnectingNetwork() { NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); const Network* connecting_network = cros->connecting_network(); if (connecting_network && connecting_network->type() != TYPE_ETHERNET && (!cros->connected_network() || connecting_network->connection_started())) { return connecting_network; } return NULL; } double NetworkMenuIcon::GetAnimation() { return NetworkIconAnimation::GetInstance()->GetAnimation(); } int NetworkMenuIcon::GetConnectingIndex() { DCHECK(icon_.get()); double animation = GetAnimation(); int image_count = (icon_->type() == TYPE_WIFI) ? kNumArcsImages - 1 : kNumBarsImages - 1; int index = animation * nextafter(static_cast(image_count), 0); return std::max(std::min(index, image_count - 1), 0); } // TODO(stevenjb): move below SetIconAndText. void NetworkMenuIcon::SetConnectingIconAndText( const Network* connecting_network) { connecting_network_ = connecting_network; ConnectionType type; ConnectionState state; if (connecting_network_) { type = connecting_network_->type(); state = connecting_network_->state(); if (mode_ == MENU_MODE) { text_ = l10n_util::GetStringFUTF16( IDS_STATUSBAR_NETWORK_CONNECTING_TOOLTIP, UTF8ToUTF16(connecting_network_->name())); } else { text_ = UTF8ToUTF16(connecting_network_->name()); } } else { // When called with no connecting network, cellular is initializing. type = TYPE_CELLULAR; state = STATE_ASSOCIATION; text_ = l10n_util::GetStringUTF16( IDS_ASH_STATUS_TRAY_INITIALIZING_CELLULAR); } icon_->set_type(type); icon_->set_state(state); ImageType image_type; gfx::ImageSkia** images; if (type == TYPE_WIFI) { image_type = ARCS; images = resource_color_theme_ == COLOR_DARK ? kArcsImagesAnimatingDark : kArcsImagesAnimatingLight; } else { image_type = BARS; images = resource_color_theme_ == COLOR_DARK ? kBarsImagesAnimatingDark : kBarsImagesAnimatingLight; } int index = GetConnectingIndex(); // Lazily cache images. if (!images[index]) { gfx::ImageSkia source = GetImage(image_type, index + 1, resource_color_theme_); images[index] = new gfx::ImageSkia(NetworkMenuIcon::GenerateConnectingImage(source)); } icon_->set_icon(*images[index]); if (connecting_network_) icon_->SetBadges(connecting_network_); } // Sets up the icon and badges for GenerateBitmap(). bool NetworkMenuIcon::SetIconAndText() { NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); DCHECK(cros); icon_->ClearIconAndBadges(); // If we are connecting to a network and it was user-initiated or we are // not connected, display that. const Network* connecting_network = GetConnectingNetwork(); if (connecting_network) { SetConnectingIconAndText(connecting_network); return true; } // If not connecting to a network, show the active or connected network. const Network* network; if (mode_ == DROPDOWN_MODE && cros->connected_network()) network = cros->connected_network(); else network = cros->active_nonvirtual_network(); if (network) return SetActiveNetworkIconAndText(network); // If no connected network, check if we are initializing Cellular. if (mode_ != DROPDOWN_MODE && cros->cellular_initializing()) { initialize_state_time_ = base::Time::Now(); SetConnectingIconAndText(NULL); return true; } // 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 few extra seconds to avoid flashing the disconnect icon. const int kInitializingDelaySeconds = 1; base::TimeDelta dtime = base::Time::Now() - initialize_state_time_; if (dtime.InSeconds() < kInitializingDelaySeconds) { SetConnectingIconAndText(NULL); return true; } // No connecting, connected, or active network. SetDisconnectedIconAndText(); return false; } bool NetworkMenuIcon::SetVpnIconAndText() { NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); DCHECK(cros); icon_->ClearIconAndBadges(); const VirtualNetwork* vpn = cros->virtual_network(); if (!vpn) { LOG(WARNING) << "SetVpnIconAndText called with no VPN"; SetDisconnectedIconAndText(); return false; } if (vpn->connecting()) { SetConnectingIconAndText(vpn); return true; } // If not connecting to a VPN, show the active/connected VPN. return SetActiveNetworkIconAndText(vpn); } bool NetworkMenuIcon::SetActiveNetworkIconAndText(const Network* network) { NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); bool animating = false; // Set icon and badges. Call SetDirty() since network may have changed. icon_->SetDirty(); icon_->SetOrClearVpnConnected(network); icon_->UpdateIcon(network); // Overlay the VPN badge if connecting to a VPN. if (network->type() != TYPE_VPN && cros->virtual_network() && cros->virtual_network()->connecting()) { const gfx::ImageSkia* vpn_badge = rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN_BADGE); const double animation = GetAnimation(); animating = true; // Even though this is the only place we use vpn_connecting_badge_, // it is important that this is a member variable since we set a // pointer to it and access that pointer in icon_->GenerateImage(). vpn_connecting_badge_ = gfx::ImageSkiaOperations::CreateBlendedImage( GetEmptyImage(vpn_badge->size()), *vpn_badge, animation); icon_->set_bottom_left_badge(&vpn_connecting_badge_); } // Set the text to display. if (network->type() == TYPE_ETHERNET) { if (mode_ == MENU_MODE) { text_ = l10n_util::GetStringFUTF16( IDS_STATUSBAR_NETWORK_CONNECTED_TOOLTIP, l10n_util::GetStringUTF16( IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET)); } else { text_ = l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET); } } else { if (mode_ == MENU_MODE) { text_ = l10n_util::GetStringFUTF16( IDS_STATUSBAR_NETWORK_CONNECTED_TOOLTIP, UTF8ToUTF16(network->name())); } else { text_ = UTF8ToUTF16(network->name()); } } return animating; } void NetworkMenuIcon::SetDisconnectedIconAndText() { icon_->set_icon(GetDisconnectedImage(ARCS, resource_color_theme_)); if (mode_ == MENU_MODE) { text_ = l10n_util::GetStringUTF16( IDS_ASH_STATUS_TRAY_NETWORK_NOT_CONNECTED); } else { text_ = l10n_util::GetStringUTF16(IDS_NETWORK_SELECTION_NONE_SELECTED); } } //////////////////////////////////////////////////////////////////////////////// // Static functions for generating network icon images: // This defines how we assemble a network icon. // Currently we iterate over all the available resolutions in |icon|. This will // be wrong once we dynamically load image resolutions. // TODO(pkotwicz): Figure out what to do when a new image resolution becomes // available. const gfx::ImageSkia NetworkMenuIcon::GenerateImageFromComponents( const gfx::ImageSkia& icon, const gfx::ImageSkia* top_left_badge, const gfx::ImageSkia* top_right_badge, const gfx::ImageSkia* bottom_left_badge, const gfx::ImageSkia* bottom_right_badge) { return gfx::ImageSkia(new NetworkIconImageSource(icon, top_left_badge, top_right_badge, bottom_left_badge, bottom_right_badge), icon.size()); } // We blend connecting icons with a black image to generate a faded icon. const gfx::ImageSkia NetworkMenuIcon::GenerateConnectingImage( const gfx::ImageSkia& source) { return gfx::ImageSkiaOperations::CreateBlendedImage( GetEmptyImage(source.size()), source, kConnectingImageAlpha); } // Generates and caches an icon image for a network's current state. const gfx::ImageSkia NetworkMenuIcon::GetImage(const Network* network, ResourceColorTheme color) { DCHECK(network); // 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; static NetworkIconMap* icon_map_dark = NULL; static NetworkIconMap* icon_map_light = NULL; if (icon_map_dark == NULL) icon_map_dark = new NetworkIconMap; if (icon_map_light == NULL) icon_map_light = new NetworkIconMap; NetworkIconMap* icon_map = color == COLOR_DARK ? icon_map_dark : icon_map_light; // Find or add the icon. NetworkIcon* icon; NetworkIconMap::iterator iter = icon_map->find(network->service_path()); if (iter == icon_map->end()) { icon = new NetworkIcon(network->service_path(), color); icon_map->insert(std::make_pair(network->service_path(), icon)); } else { icon = iter->second; } // Update and return the icon's image. icon->Update(); return icon->GetImage(); } const gfx::ImageSkia NetworkMenuIcon::GetImage(ImageType type, int index, ResourceColorTheme color) { int width, height = 0; gfx::ImageSkia* images = NULL; if (type == NetworkMenuIcon::ARCS) { if (index >= kNumArcsImages) return gfx::ImageSkia(); images = ResourceBundle::GetSharedInstance().GetImageSkiaNamed( color == NetworkMenuIcon::COLOR_DARK ? IDR_AURA_UBER_TRAY_NETWORK_ARCS_DARK : IDR_AURA_UBER_TRAY_NETWORK_ARCS_LIGHT); width = images->width(); height = images->height() / kNumArcsImages; } else { if (index >= kNumBarsImages) return gfx::ImageSkia(); images = ResourceBundle::GetSharedInstance().GetImageSkiaNamed( color == NetworkMenuIcon::COLOR_DARK ? IDR_AURA_UBER_TRAY_NETWORK_BARS_DARK : IDR_AURA_UBER_TRAY_NETWORK_BARS_LIGHT); width = images->width(); height = images->height() / kNumBarsImages; } return gfx::ImageSkiaOperations::ExtractSubset(*images, gfx::Rect(0, index * height, width, height)); } const gfx::ImageSkia NetworkMenuIcon::GetDisconnectedImage( ImageType type, ResourceColorTheme color) { return GetImage(type, 0, color); } const gfx::ImageSkia NetworkMenuIcon::GetConnectedImage(ImageType type, ResourceColorTheme color) { return GetImage(type, NumImages(type) - 1, color); } gfx::ImageSkia* NetworkMenuIcon::GetVirtualNetworkImage() { return ResourceBundle::GetSharedInstance().GetImageSkiaNamed( IDR_AURA_UBER_TRAY_NETWORK_VPN); } int NetworkMenuIcon::NumImages(ImageType type) { return (type == ARCS) ? kNumArcsImages : kNumBarsImages; } } // chromeos