1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ash/system/chromeos/network/network_icon.h" 6 7 #include "ash/shell.h" 8 #include "ash/system/chromeos/network/network_icon_animation.h" 9 #include "ash/system/chromeos/network/network_icon_animation_observer.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "chromeos/network/device_state.h" 12 #include "chromeos/network/network_connection_handler.h" 13 #include "chromeos/network/network_state.h" 14 #include "chromeos/network/network_state_handler.h" 15 #include "chromeos/network/shill_property_util.h" 16 #include "grit/ash_resources.h" 17 #include "grit/ash_strings.h" 18 #include "third_party/cros_system_api/dbus/service_constants.h" 19 #include "ui/base/l10n/l10n_util.h" 20 #include "ui/base/resource/resource_bundle.h" 21 #include "ui/gfx/canvas.h" 22 #include "ui/gfx/image/image_skia_operations.h" 23 #include "ui/gfx/image/image_skia_source.h" 24 #include "ui/gfx/rect.h" 25 #include "ui/gfx/size_conversions.h" 26 27 using chromeos::DeviceState; 28 using chromeos::NetworkConnectionHandler; 29 using chromeos::NetworkHandler; 30 using chromeos::NetworkState; 31 using chromeos::NetworkStateHandler; 32 using chromeos::NetworkTypePattern; 33 34 namespace ash { 35 namespace network_icon { 36 37 namespace { 38 39 //------------------------------------------------------------------------------ 40 // Struct to pass icon badges to NetworkIconImageSource. 41 struct Badges { 42 Badges() 43 : top_left(NULL), 44 top_right(NULL), 45 bottom_left(NULL), 46 bottom_right(NULL) { 47 } 48 const gfx::ImageSkia* top_left; 49 const gfx::ImageSkia* top_right; 50 const gfx::ImageSkia* bottom_left; 51 const gfx::ImageSkia* bottom_right; 52 }; 53 54 //------------------------------------------------------------------------------ 55 // class used for maintaining a map of network state and images. 56 class NetworkIconImpl { 57 public: 58 explicit NetworkIconImpl(IconType icon_type); 59 60 // Determines whether or not the associated network might be dirty and if so 61 // updates and generates the icon. Does nothing if network no longer exists. 62 void Update(const chromeos::NetworkState* network); 63 64 const gfx::ImageSkia& image() const { return image_; } 65 66 private: 67 // Updates |strength_index_| for wireless networks. Returns true if changed. 68 bool UpdateWirelessStrengthIndex(const chromeos::NetworkState* network); 69 70 // Updates the local state for cellular networks. Returns true if changed. 71 bool UpdateCellularState(const chromeos::NetworkState* network); 72 73 // Updates the VPN badge. Returns true if changed. 74 bool UpdateVPNBadge(); 75 76 // Gets |badges| based on |network| and the current state. 77 void GetBadges(const NetworkState* network, Badges* badges); 78 79 // Gets the appropriate icon and badges and composites the image. 80 void GenerateImage(const chromeos::NetworkState* network); 81 82 // Defines color theme and VPN badging 83 const IconType icon_type_; 84 85 // Cached state of the network when the icon was last generated. 86 std::string state_; 87 88 // Cached strength index of the network when the icon was last generated. 89 int strength_index_; 90 91 // Cached technology badge for the network when the icon was last generated. 92 const gfx::ImageSkia* technology_badge_; 93 94 // Cached vpn badge for the network when the icon was last generated. 95 const gfx::ImageSkia* vpn_badge_; 96 97 // Cached roaming state of the network when the icon was last generated. 98 std::string roaming_state_; 99 100 // Generated icon image. 101 gfx::ImageSkia image_; 102 103 DISALLOW_COPY_AND_ASSIGN(NetworkIconImpl); 104 }; 105 106 //------------------------------------------------------------------------------ 107 // Maintain a static (global) icon map. Note: Icons are never destroyed; 108 // it is assumed that a finite and reasonable number of network icons will be 109 // created during a session. 110 111 typedef std::map<std::string, NetworkIconImpl*> NetworkIconMap; 112 113 NetworkIconMap* GetIconMapInstance(IconType icon_type, bool create) { 114 typedef std::map<IconType, NetworkIconMap*> IconTypeMap; 115 static IconTypeMap* s_icon_map = NULL; 116 if (s_icon_map == NULL) { 117 if (!create) 118 return NULL; 119 s_icon_map = new IconTypeMap; 120 } 121 if (s_icon_map->count(icon_type) == 0) { 122 if (!create) 123 return NULL; 124 (*s_icon_map)[icon_type] = new NetworkIconMap; 125 } 126 return (*s_icon_map)[icon_type]; 127 } 128 129 NetworkIconMap* GetIconMap(IconType icon_type) { 130 return GetIconMapInstance(icon_type, true); 131 } 132 133 void PurgeIconMap(IconType icon_type, 134 const std::set<std::string>& network_paths) { 135 NetworkIconMap* icon_map = GetIconMapInstance(icon_type, false); 136 if (!icon_map) 137 return; 138 for (NetworkIconMap::iterator loop_iter = icon_map->begin(); 139 loop_iter != icon_map->end(); ) { 140 NetworkIconMap::iterator cur_iter = loop_iter++; 141 if (network_paths.count(cur_iter->first) == 0) { 142 delete cur_iter->second; 143 icon_map->erase(cur_iter); 144 } 145 } 146 } 147 148 //------------------------------------------------------------------------------ 149 // Utilities for generating icon images. 150 151 // 'NONE' will default to ARCS behavior where appropriate (e.g. no network or 152 // if a new type gets added). 153 enum ImageType { 154 ARCS, 155 BARS, 156 NONE 157 }; 158 159 // Amount to fade icons while connecting. 160 const double kConnectingImageAlpha = 0.5; 161 162 // Images for strength bars for wired networks. 163 const int kNumBarsImages = 5; 164 165 // Imagaes for strength arcs for wireless networks. 166 const int kNumArcsImages = 5; 167 168 // Number of discrete images to use for alpha fade animation 169 const int kNumFadeImages = 10; 170 171 //------------------------------------------------------------------------------ 172 // Classes for generating scaled images. 173 174 const SkBitmap GetEmptyBitmap(const gfx::Size pixel_size) { 175 typedef std::pair<int, int> SizeKey; 176 typedef std::map<SizeKey, SkBitmap> SizeBitmapMap; 177 static SizeBitmapMap* s_empty_bitmaps = new SizeBitmapMap; 178 179 SizeKey key(pixel_size.width(), pixel_size.height()); 180 181 SizeBitmapMap::iterator iter = s_empty_bitmaps->find(key); 182 if (iter != s_empty_bitmaps->end()) 183 return iter->second; 184 185 SkBitmap empty; 186 empty.setConfig(SkBitmap::kARGB_8888_Config, key.first, key.second); 187 empty.allocPixels(); 188 empty.eraseARGB(0, 0, 0, 0); 189 (*s_empty_bitmaps)[key] = empty; 190 return empty; 191 } 192 193 class EmptyImageSource: public gfx::ImageSkiaSource { 194 public: 195 explicit EmptyImageSource(const gfx::Size& size) 196 : size_(size) { 197 } 198 199 virtual gfx::ImageSkiaRep GetImageForScale(float scale) OVERRIDE { 200 gfx::Size pixel_size = gfx::ToFlooredSize(gfx::ScaleSize(size_, scale)); 201 SkBitmap empty_bitmap = GetEmptyBitmap(pixel_size); 202 return gfx::ImageSkiaRep(empty_bitmap, scale); 203 } 204 205 private: 206 const gfx::Size size_; 207 208 DISALLOW_COPY_AND_ASSIGN(EmptyImageSource); 209 }; 210 211 // This defines how we assemble a network icon. 212 class NetworkIconImageSource : public gfx::ImageSkiaSource { 213 public: 214 NetworkIconImageSource(const gfx::ImageSkia& icon, const Badges& badges) 215 : icon_(icon), 216 badges_(badges) { 217 } 218 virtual ~NetworkIconImageSource() {} 219 220 // TODO(pkotwicz): Figure out what to do when a new image resolution becomes 221 // available. 222 virtual gfx::ImageSkiaRep GetImageForScale(float scale) OVERRIDE { 223 gfx::ImageSkiaRep icon_rep = icon_.GetRepresentation(scale); 224 if (icon_rep.is_null()) 225 return gfx::ImageSkiaRep(); 226 gfx::Canvas canvas(icon_rep, false); 227 if (badges_.top_left) 228 canvas.DrawImageInt(*badges_.top_left, 0, 0); 229 if (badges_.top_right) 230 canvas.DrawImageInt(*badges_.top_right, 231 icon_.width() - badges_.top_right->width(), 0); 232 if (badges_.bottom_left) { 233 canvas.DrawImageInt(*badges_.bottom_left, 234 0, icon_.height() - badges_.bottom_left->height()); 235 } 236 if (badges_.bottom_right) { 237 canvas.DrawImageInt(*badges_.bottom_right, 238 icon_.width() - badges_.bottom_right->width(), 239 icon_.height() - badges_.bottom_right->height()); 240 } 241 return canvas.ExtractImageRep(); 242 } 243 244 private: 245 const gfx::ImageSkia icon_; 246 const Badges badges_; 247 248 DISALLOW_COPY_AND_ASSIGN(NetworkIconImageSource); 249 }; 250 251 //------------------------------------------------------------------------------ 252 // Utilities for extracting icon images. 253 254 bool IconTypeIsDark(IconType icon_type) { 255 return (icon_type != ICON_TYPE_TRAY); 256 } 257 258 bool IconTypeHasVPNBadge(IconType icon_type) { 259 return (icon_type != ICON_TYPE_LIST); 260 } 261 262 int NumImagesForType(ImageType type) { 263 return (type == BARS) ? kNumBarsImages : kNumArcsImages; 264 } 265 266 gfx::ImageSkia* BaseImageForType(ImageType image_type, IconType icon_type) { 267 gfx::ImageSkia* image; 268 if (image_type == BARS) { 269 image = ResourceBundle::GetSharedInstance().GetImageSkiaNamed( 270 IconTypeIsDark(icon_type) ? 271 IDR_AURA_UBER_TRAY_NETWORK_BARS_DARK : 272 IDR_AURA_UBER_TRAY_NETWORK_BARS_LIGHT); 273 } else { 274 image = ResourceBundle::GetSharedInstance().GetImageSkiaNamed( 275 IconTypeIsDark(icon_type) ? 276 IDR_AURA_UBER_TRAY_NETWORK_ARCS_DARK : 277 IDR_AURA_UBER_TRAY_NETWORK_ARCS_LIGHT); 278 } 279 return image; 280 } 281 282 ImageType ImageTypeForNetworkType(const std::string& type) { 283 if (type == shill::kTypeWifi) 284 return ARCS; 285 else if (type == shill::kTypeCellular || type == shill::kTypeWimax) 286 return BARS; 287 return NONE; 288 } 289 290 gfx::ImageSkia GetImageForIndex(ImageType image_type, 291 IconType icon_type, 292 int index) { 293 int num_images = NumImagesForType(image_type); 294 if (index < 0 || index >= num_images) 295 return gfx::ImageSkia(); 296 gfx::ImageSkia* images = BaseImageForType(image_type, icon_type); 297 int width = images->width(); 298 int height = images->height() / num_images; 299 return gfx::ImageSkiaOperations::ExtractSubset(*images, 300 gfx::Rect(0, index * height, width, height)); 301 } 302 303 const gfx::ImageSkia GetConnectedImage(const std::string& type, 304 IconType icon_type) { 305 if (type == shill::kTypeVPN) { 306 return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( 307 IDR_AURA_UBER_TRAY_NETWORK_VPN); 308 } 309 ImageType image_type = ImageTypeForNetworkType(type); 310 const int connected_index = NumImagesForType(image_type) - 1; 311 return GetImageForIndex(image_type, icon_type, connected_index); 312 } 313 314 const gfx::ImageSkia GetDisconnectedImage(const std::string& type, 315 IconType icon_type) { 316 if (type == shill::kTypeVPN) { 317 // Note: same as connected image, shouldn't normally be seen. 318 return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( 319 IDR_AURA_UBER_TRAY_NETWORK_VPN); 320 } 321 ImageType image_type = ImageTypeForNetworkType(type); 322 const int disconnected_index = 0; 323 return GetImageForIndex(image_type, icon_type, disconnected_index); 324 } 325 326 gfx::ImageSkia* ConnectingWirelessImage(ImageType image_type, 327 IconType icon_type, 328 double animation) { 329 static gfx::ImageSkia* s_bars_images_dark[kNumBarsImages - 1]; 330 static gfx::ImageSkia* s_bars_images_light[kNumBarsImages - 1]; 331 static gfx::ImageSkia* s_arcs_images_dark[kNumArcsImages - 1]; 332 static gfx::ImageSkia* s_arcs_images_light[kNumArcsImages - 1]; 333 int image_count = NumImagesForType(image_type) - 1; 334 int index = animation * nextafter(static_cast<float>(image_count), 0); 335 index = std::max(std::min(index, image_count - 1), 0); 336 gfx::ImageSkia** images; 337 bool dark = IconTypeIsDark(icon_type); 338 if (image_type == BARS) 339 images = dark ? s_bars_images_dark : s_bars_images_light; 340 else 341 images = dark ? s_arcs_images_dark : s_arcs_images_light; 342 if (!images[index]) { 343 // Lazily cache images. 344 gfx::ImageSkia source = GetImageForIndex(image_type, icon_type, index + 1); 345 images[index] = new gfx::ImageSkia( 346 gfx::ImageSkiaOperations::CreateBlendedImage( 347 gfx::ImageSkia(new EmptyImageSource(source.size()), source.size()), 348 source, 349 kConnectingImageAlpha)); 350 } 351 return images[index]; 352 } 353 354 gfx::ImageSkia* ConnectingVpnImage(double animation) { 355 int index = animation * nextafter(static_cast<float>(kNumFadeImages), 0); 356 static gfx::ImageSkia* s_vpn_images[kNumFadeImages]; 357 if (!s_vpn_images[index]) { 358 // Lazily cache images. 359 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 360 gfx::ImageSkia* icon = rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN); 361 s_vpn_images[index] = new gfx::ImageSkia( 362 gfx::ImageSkiaOperations::CreateBlendedImage( 363 gfx::ImageSkia(new EmptyImageSource(icon->size()), icon->size()), 364 *icon, 365 animation)); 366 } 367 return s_vpn_images[index]; 368 } 369 370 gfx::ImageSkia* ConnectingVpnBadge(double animation) { 371 int index = animation * nextafter(static_cast<float>(kNumFadeImages), 0); 372 static gfx::ImageSkia* s_vpn_badges[kNumFadeImages]; 373 if (!s_vpn_badges[index]) { 374 // Lazily cache images. 375 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 376 gfx::ImageSkia* icon = 377 rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED); // For size 378 gfx::ImageSkia* badge = 379 rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN_BADGE); 380 s_vpn_badges[index] = new gfx::ImageSkia( 381 gfx::ImageSkiaOperations::CreateBlendedImage( 382 gfx::ImageSkia(new EmptyImageSource(icon->size()), icon->size()), 383 *badge, 384 animation)); 385 } 386 return s_vpn_badges[index]; 387 } 388 389 int StrengthIndex(int strength, int count) { 390 // Return an index in the range [1, count-1]. 391 const float findex = (static_cast<float>(strength) / 100.0f) * 392 nextafter(static_cast<float>(count - 1), 0); 393 int index = 1 + static_cast<int>(findex); 394 index = std::max(std::min(index, count - 1), 1); 395 return index; 396 } 397 398 int GetStrengthIndex(const NetworkState* network) { 399 ImageType image_type = ImageTypeForNetworkType(network->type()); 400 if (image_type == ARCS) 401 return StrengthIndex(network->signal_strength(), kNumArcsImages); 402 else if (image_type == BARS) 403 return StrengthIndex(network->signal_strength(), kNumBarsImages); 404 return 0; 405 } 406 407 const gfx::ImageSkia* BadgeForNetworkTechnology(const NetworkState* network, 408 IconType icon_type) { 409 const int kUnknownBadgeType = -1; 410 int id = kUnknownBadgeType; 411 const std::string& technology = network->network_technology(); 412 if (technology == shill::kNetworkTechnologyEvdo) { 413 id = IconTypeIsDark(icon_type) ? 414 IDR_AURA_UBER_TRAY_NETWORK_EVDO_DARK : 415 IDR_AURA_UBER_TRAY_NETWORK_EVDO_LIGHT; 416 } else if (technology == shill::kNetworkTechnology1Xrtt) { 417 id = IDR_AURA_UBER_TRAY_NETWORK_1X; 418 } else if (technology == shill::kNetworkTechnologyGprs) { 419 id = IconTypeIsDark(icon_type) ? 420 IDR_AURA_UBER_TRAY_NETWORK_GPRS_DARK : 421 IDR_AURA_UBER_TRAY_NETWORK_GPRS_LIGHT; 422 } else if (technology == shill::kNetworkTechnologyEdge) { 423 id = IconTypeIsDark(icon_type) ? 424 IDR_AURA_UBER_TRAY_NETWORK_EDGE_DARK : 425 IDR_AURA_UBER_TRAY_NETWORK_EDGE_LIGHT; 426 } else if (technology == shill::kNetworkTechnologyUmts) { 427 id = IconTypeIsDark(icon_type) ? 428 IDR_AURA_UBER_TRAY_NETWORK_3G_DARK : 429 IDR_AURA_UBER_TRAY_NETWORK_3G_LIGHT; 430 } else if (technology == shill::kNetworkTechnologyHspa) { 431 id = IconTypeIsDark(icon_type) ? 432 IDR_AURA_UBER_TRAY_NETWORK_HSPA_DARK : 433 IDR_AURA_UBER_TRAY_NETWORK_HSPA_LIGHT; 434 } else if (technology == shill::kNetworkTechnologyHspaPlus) { 435 id = IconTypeIsDark(icon_type) ? 436 IDR_AURA_UBER_TRAY_NETWORK_HSPA_PLUS_DARK : 437 IDR_AURA_UBER_TRAY_NETWORK_HSPA_PLUS_LIGHT; 438 } else if (technology == shill::kNetworkTechnologyLte) { 439 id = IconTypeIsDark(icon_type) ? 440 IDR_AURA_UBER_TRAY_NETWORK_LTE_DARK : 441 IDR_AURA_UBER_TRAY_NETWORK_LTE_LIGHT; 442 } else if (technology == shill::kNetworkTechnologyLteAdvanced) { 443 id = IconTypeIsDark(icon_type) ? 444 IDR_AURA_UBER_TRAY_NETWORK_LTE_ADVANCED_DARK : 445 IDR_AURA_UBER_TRAY_NETWORK_LTE_ADVANCED_LIGHT; 446 } else if (technology == shill::kNetworkTechnologyGsm) { 447 id = IconTypeIsDark(icon_type) ? 448 IDR_AURA_UBER_TRAY_NETWORK_GPRS_DARK : 449 IDR_AURA_UBER_TRAY_NETWORK_GPRS_LIGHT; 450 } 451 if (id == kUnknownBadgeType) 452 return NULL; 453 else 454 return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(id); 455 } 456 457 const gfx::ImageSkia* BadgeForVPN(IconType icon_type) { 458 return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( 459 IDR_AURA_UBER_TRAY_NETWORK_VPN_BADGE); 460 } 461 462 gfx::ImageSkia GetIcon(const NetworkState* network, 463 IconType icon_type, 464 int strength_index) { 465 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 466 if (network->Matches(NetworkTypePattern::Ethernet())) { 467 return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED); 468 } else if (network->Matches(NetworkTypePattern::Wireless())) { 469 DCHECK(strength_index > 0); 470 return GetImageForIndex( 471 ImageTypeForNetworkType(network->type()), icon_type, strength_index); 472 } else if (network->Matches(NetworkTypePattern::VPN())) { 473 return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN); 474 } else { 475 LOG(WARNING) << "Request for icon for unsupported type: " 476 << network->type(); 477 return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED); 478 } 479 } 480 481 //------------------------------------------------------------------------------ 482 // Get connecting images 483 484 gfx::ImageSkia GetConnectingVpnImage(IconType icon_type) { 485 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); 486 const NetworkState* connected_network = NULL; 487 if (icon_type == ICON_TYPE_TRAY) { 488 connected_network = 489 handler->ConnectedNetworkByType(NetworkTypePattern::NonVirtual()); 490 } 491 double animation = NetworkIconAnimation::GetInstance()->GetAnimation(); 492 493 if (connected_network) { 494 gfx::ImageSkia icon = GetImageForNetwork(connected_network, icon_type); 495 Badges badges; 496 badges.bottom_left = ConnectingVpnBadge(animation); 497 return gfx::ImageSkia( 498 new NetworkIconImageSource(icon, badges), icon.size()); 499 } else { 500 gfx::ImageSkia* icon = ConnectingVpnImage(animation); 501 return gfx::ImageSkia( 502 new NetworkIconImageSource(*icon, Badges()), icon->size()); 503 } 504 } 505 506 gfx::ImageSkia GetConnectingImage(const std::string& network_type, 507 IconType icon_type) { 508 if (network_type == shill::kTypeVPN) 509 return GetConnectingVpnImage(icon_type); 510 511 ImageType image_type = ImageTypeForNetworkType(network_type); 512 double animation = NetworkIconAnimation::GetInstance()->GetAnimation(); 513 514 gfx::ImageSkia* icon = ConnectingWirelessImage( 515 image_type, icon_type, animation); 516 return gfx::ImageSkia( 517 new NetworkIconImageSource(*icon, Badges()), icon->size()); 518 } 519 520 } // namespace 521 522 //------------------------------------------------------------------------------ 523 // NetworkIconImpl 524 525 NetworkIconImpl::NetworkIconImpl(IconType icon_type) 526 : icon_type_(icon_type), 527 strength_index_(-1), 528 technology_badge_(NULL), 529 vpn_badge_(NULL) { 530 // Default image 531 image_ = GetDisconnectedImage(shill::kTypeWifi, icon_type); 532 } 533 534 void NetworkIconImpl::Update(const NetworkState* network) { 535 DCHECK(network); 536 // Determine whether or not we need to update the icon. 537 bool dirty = image_.isNull(); 538 539 // If the network state has changed, the icon needs updating. 540 if (state_ != network->connection_state()) { 541 state_ = network->connection_state(); 542 dirty = true; 543 } 544 545 if (network->Matches(NetworkTypePattern::Wireless())) 546 dirty |= UpdateWirelessStrengthIndex(network); 547 548 if (network->Matches(NetworkTypePattern::Cellular())) 549 dirty |= UpdateCellularState(network); 550 551 if (IconTypeHasVPNBadge(icon_type_) && 552 network->Matches(NetworkTypePattern::NonVirtual())) { 553 dirty |= UpdateVPNBadge(); 554 } 555 556 if (dirty) { 557 // Set the icon and badges based on the network and generate the image. 558 GenerateImage(network); 559 } 560 } 561 562 bool NetworkIconImpl::UpdateWirelessStrengthIndex(const NetworkState* network) { 563 int index = GetStrengthIndex(network); 564 if (index != strength_index_) { 565 strength_index_ = index; 566 return true; 567 } 568 return false; 569 } 570 571 bool NetworkIconImpl::UpdateCellularState(const NetworkState* network) { 572 bool dirty = false; 573 const gfx::ImageSkia* technology_badge = 574 BadgeForNetworkTechnology(network, icon_type_); 575 if (technology_badge != technology_badge_) { 576 technology_badge_ = technology_badge; 577 dirty = true; 578 } 579 std::string roaming_state = network->roaming(); 580 if (roaming_state != roaming_state_) { 581 roaming_state_ = roaming_state; 582 dirty = true; 583 } 584 return dirty; 585 } 586 587 bool NetworkIconImpl::UpdateVPNBadge() { 588 const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()-> 589 ConnectedNetworkByType(NetworkTypePattern::VPN()); 590 if (vpn && vpn_badge_ == NULL) { 591 vpn_badge_ = BadgeForVPN(icon_type_); 592 return true; 593 } else if (!vpn && vpn_badge_ != NULL) { 594 vpn_badge_ = NULL; 595 return true; 596 } 597 return false; 598 } 599 600 void NetworkIconImpl::GetBadges(const NetworkState* network, Badges* badges) { 601 DCHECK(network); 602 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 603 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); 604 605 const std::string& type = network->type(); 606 if (type == shill::kTypeWifi) { 607 if (network->security() != shill::kSecurityNone && 608 IconTypeIsDark(icon_type_)) { 609 badges->bottom_right = rb.GetImageSkiaNamed( 610 IDR_AURA_UBER_TRAY_NETWORK_SECURE_DARK); 611 } 612 } else if (type == shill::kTypeWimax) { 613 technology_badge_ = rb.GetImageSkiaNamed( 614 IconTypeIsDark(icon_type_) ? 615 IDR_AURA_UBER_TRAY_NETWORK_4G_DARK : 616 IDR_AURA_UBER_TRAY_NETWORK_4G_LIGHT); 617 } else if (type == shill::kTypeCellular) { 618 if (network->roaming() == shill::kRoamingStateRoaming) { 619 // For networks that are always in roaming don't show roaming badge. 620 const DeviceState* device = 621 handler->GetDeviceState(network->device_path()); 622 LOG_IF(WARNING, !device) << "Could not find device state for " 623 << network->device_path(); 624 if (!device || !device->provider_requires_roaming()) { 625 badges->bottom_right = rb.GetImageSkiaNamed( 626 IconTypeIsDark(icon_type_) ? 627 IDR_AURA_UBER_TRAY_NETWORK_ROAMING_DARK : 628 IDR_AURA_UBER_TRAY_NETWORK_ROAMING_LIGHT); 629 } 630 } 631 } 632 if (!network->IsConnectingState()) { 633 badges->top_left = technology_badge_; 634 badges->bottom_left = vpn_badge_; 635 } 636 } 637 638 void NetworkIconImpl::GenerateImage(const NetworkState* network) { 639 DCHECK(network); 640 gfx::ImageSkia icon = GetIcon(network, icon_type_, strength_index_); 641 Badges badges; 642 GetBadges(network, &badges); 643 image_ = gfx::ImageSkia( 644 new NetworkIconImageSource(icon, badges), icon.size()); 645 } 646 647 //------------------------------------------------------------------------------ 648 // Public interface 649 650 gfx::ImageSkia GetImageForNetwork(const NetworkState* network, 651 IconType icon_type) { 652 DCHECK(network); 653 // Handle connecting icons. 654 if (network->IsConnectingState()) 655 return GetConnectingImage(network->type(), icon_type); 656 657 // Find or add the icon. 658 NetworkIconMap* icon_map = GetIconMap(icon_type); 659 NetworkIconImpl* icon; 660 NetworkIconMap::iterator iter = icon_map->find(network->path()); 661 if (iter == icon_map->end()) { 662 icon = new NetworkIconImpl(icon_type); 663 icon_map->insert(std::make_pair(network->path(), icon)); 664 } else { 665 icon = iter->second; 666 } 667 668 // Update and return the icon's image. 669 icon->Update(network); 670 return icon->image(); 671 } 672 673 gfx::ImageSkia GetImageForConnectedNetwork(IconType icon_type, 674 const std::string& network_type) { 675 return GetConnectedImage(network_type, icon_type); 676 } 677 678 gfx::ImageSkia GetImageForConnectingNetwork(IconType icon_type, 679 const std::string& network_type) { 680 return GetConnectingImage(network_type, icon_type); 681 } 682 683 gfx::ImageSkia GetImageForDisconnectedNetwork(IconType icon_type, 684 const std::string& network_type) { 685 return GetDisconnectedImage(network_type, icon_type); 686 } 687 688 base::string16 GetLabelForNetwork(const chromeos::NetworkState* network, 689 IconType icon_type) { 690 DCHECK(network); 691 std::string activation_state = network->activation_state(); 692 if (icon_type == ICON_TYPE_LIST) { 693 // Show "<network>: [Connecting|Activating]..." 694 if (network->IsConnectingState()) { 695 return l10n_util::GetStringFUTF16( 696 IDS_ASH_STATUS_TRAY_NETWORK_LIST_CONNECTING, 697 UTF8ToUTF16(network->name())); 698 } 699 if (activation_state == shill::kActivationStateActivating) { 700 return l10n_util::GetStringFUTF16( 701 IDS_ASH_STATUS_TRAY_NETWORK_LIST_ACTIVATING, 702 UTF8ToUTF16(network->name())); 703 } 704 // Show "Activate <network>" in list view only. 705 if (activation_state == shill::kActivationStateNotActivated || 706 activation_state == shill::kActivationStatePartiallyActivated) { 707 return l10n_util::GetStringFUTF16( 708 IDS_ASH_STATUS_TRAY_NETWORK_LIST_ACTIVATE, 709 UTF8ToUTF16(network->name())); 710 } 711 } else { 712 // Show "[Connected to|Connecting to|Activating] <network>" (non-list view). 713 if (network->IsConnectedState()) { 714 return l10n_util::GetStringFUTF16( 715 IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED, UTF8ToUTF16(network->name())); 716 } 717 if (network->IsConnectingState()) { 718 return l10n_util::GetStringFUTF16( 719 IDS_ASH_STATUS_TRAY_NETWORK_CONNECTING, UTF8ToUTF16(network->name())); 720 } 721 if (activation_state == shill::kActivationStateActivating) { 722 return l10n_util::GetStringFUTF16( 723 IDS_ASH_STATUS_TRAY_NETWORK_ACTIVATING, UTF8ToUTF16(network->name())); 724 } 725 } 726 727 // Otherwise just show the network name or 'Ethernet'. 728 if (network->Matches(NetworkTypePattern::Ethernet())) { 729 return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ETHERNET); 730 } else { 731 return UTF8ToUTF16(network->name()); 732 } 733 } 734 735 int GetCellularUninitializedMsg() { 736 static base::Time s_uninitialized_state_time; 737 static int s_uninitialized_msg(0); 738 739 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); 740 if (handler->GetTechnologyState(NetworkTypePattern::Mobile()) 741 == NetworkStateHandler::TECHNOLOGY_UNINITIALIZED) { 742 s_uninitialized_msg = IDS_ASH_STATUS_TRAY_INITIALIZING_CELLULAR; 743 s_uninitialized_state_time = base::Time::Now(); 744 return s_uninitialized_msg; 745 } else if (handler->GetScanningByType(NetworkTypePattern::Mobile())) { 746 s_uninitialized_msg = IDS_ASH_STATUS_TRAY_CELLULAR_SCANNING; 747 s_uninitialized_state_time = base::Time::Now(); 748 return s_uninitialized_msg; 749 } 750 // There can be a delay between leaving the Initializing state and when 751 // a Cellular device shows up, so keep showing the initializing 752 // animation for a bit to avoid flashing the disconnect icon. 753 const int kInitializingDelaySeconds = 1; 754 base::TimeDelta dtime = base::Time::Now() - s_uninitialized_state_time; 755 if (dtime.InSeconds() < kInitializingDelaySeconds) 756 return s_uninitialized_msg; 757 return 0; 758 } 759 760 void GetDefaultNetworkImageAndLabel(IconType icon_type, 761 gfx::ImageSkia* image, 762 base::string16* label, 763 bool* animating) { 764 NetworkStateHandler* state_handler = 765 NetworkHandler::Get()->network_state_handler(); 766 NetworkConnectionHandler* connect_handler = 767 NetworkHandler::Get()->network_connection_handler(); 768 const NetworkState* connected_network = 769 state_handler->ConnectedNetworkByType(NetworkTypePattern::NonVirtual()); 770 const NetworkState* connecting_network = 771 state_handler->ConnectingNetworkByType(NetworkTypePattern::Wireless()); 772 if (!connecting_network && icon_type == ICON_TYPE_TRAY) { 773 connecting_network = 774 state_handler->ConnectingNetworkByType(NetworkTypePattern::VPN()); 775 } 776 777 const NetworkState* network; 778 // If we are connecting to a network, and there is either no connected 779 // network, or the connection was user requested, use the connecting 780 // network. 781 if (connecting_network && 782 (!connected_network || 783 connect_handler->HasConnectingNetwork(connecting_network->path()))) { 784 network = connecting_network; 785 } else { 786 network = connected_network; 787 } 788 789 // Don't show ethernet in the tray 790 if (icon_type == ICON_TYPE_TRAY && network && 791 network->Matches(NetworkTypePattern::Ethernet())) { 792 *image = gfx::ImageSkia(); 793 *animating = false; 794 return; 795 } 796 797 if (!network) { 798 // If no connecting network, check if we are activating a network. 799 const NetworkState* mobile_network = 800 state_handler->FirstNetworkByType(NetworkTypePattern::Mobile()); 801 if (mobile_network && (mobile_network->activation_state() == 802 shill::kActivationStateActivating)) { 803 network = mobile_network; 804 } 805 } 806 if (!network) { 807 // If no connecting network, check for cellular initializing. 808 int uninitialized_msg = GetCellularUninitializedMsg(); 809 if (uninitialized_msg != 0) { 810 *image = GetImageForConnectingNetwork(icon_type, shill::kTypeCellular); 811 if (label) 812 *label = l10n_util::GetStringUTF16(uninitialized_msg); 813 *animating = true; 814 } else { 815 // Otherwise show the disconnected wifi icon. 816 *image = GetImageForDisconnectedNetwork(icon_type, shill::kTypeWifi); 817 if (label) { 818 *label = l10n_util::GetStringUTF16( 819 IDS_ASH_STATUS_TRAY_NETWORK_NOT_CONNECTED); 820 } 821 *animating = false; 822 } 823 return; 824 } 825 *animating = network->IsConnectingState(); 826 // Get icon and label for connected or connecting network. 827 *image = GetImageForNetwork(network, icon_type); 828 if (label) 829 *label = GetLabelForNetwork(network, icon_type); 830 } 831 832 void PurgeNetworkIconCache() { 833 NetworkStateHandler::NetworkStateList networks; 834 NetworkHandler::Get()->network_state_handler()->GetNetworkList(&networks); 835 std::set<std::string> network_paths; 836 for (NetworkStateHandler::NetworkStateList::iterator iter = networks.begin(); 837 iter != networks.end(); ++iter) { 838 network_paths.insert((*iter)->path()); 839 } 840 PurgeIconMap(ICON_TYPE_TRAY, network_paths); 841 PurgeIconMap(ICON_TYPE_DEFAULT_VIEW, network_paths); 842 PurgeIconMap(ICON_TYPE_LIST, network_paths); 843 } 844 845 } // namespace network_icon 846 } // namespace ash 847