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 "grit/ash_resources.h" 16 #include "grit/ash_strings.h" 17 #include "third_party/cros_system_api/dbus/service_constants.h" 18 #include "ui/base/l10n/l10n_util.h" 19 #include "ui/base/resource/resource_bundle.h" 20 #include "ui/gfx/canvas.h" 21 #include "ui/gfx/image/image_skia_operations.h" 22 #include "ui/gfx/image/image_skia_source.h" 23 #include "ui/gfx/rect.h" 24 #include "ui/gfx/size_conversions.h" 25 26 using chromeos::DeviceState; 27 using chromeos::NetworkConnectionHandler; 28 using chromeos::NetworkHandler; 29 using chromeos::NetworkState; 30 using chromeos::NetworkStateHandler; 31 32 namespace ash { 33 namespace network_icon { 34 35 namespace { 36 37 //------------------------------------------------------------------------------ 38 // Struct to pass icon badges to NetworkIconImageSource. 39 struct Badges { 40 Badges() 41 : top_left(NULL), 42 top_right(NULL), 43 bottom_left(NULL), 44 bottom_right(NULL) { 45 } 46 const gfx::ImageSkia* top_left; 47 const gfx::ImageSkia* top_right; 48 const gfx::ImageSkia* bottom_left; 49 const gfx::ImageSkia* bottom_right; 50 }; 51 52 //------------------------------------------------------------------------------ 53 // class used for maintaining a map of network state and images. 54 class NetworkIconImpl { 55 public: 56 explicit NetworkIconImpl(IconType icon_type); 57 58 // Determines whether or not the associated network might be dirty and if so 59 // updates and generates the icon. Does nothing if network no longer exists. 60 void Update(const chromeos::NetworkState* network); 61 62 const gfx::ImageSkia& image() const { return image_; } 63 64 private: 65 // Updates |strength_index_| for wireless networks. Returns true if changed. 66 bool UpdateWirelessStrengthIndex(const chromeos::NetworkState* network); 67 68 // Updates the local state for cellular networks. Returns true if changed. 69 bool UpdateCellularState(const chromeos::NetworkState* network); 70 71 // Updates the VPN badge. Returns true if changed. 72 bool UpdateVPNBadge(); 73 74 // Gets |badges| based on |network| and the current state. 75 void GetBadges(const NetworkState* network, Badges* badges); 76 77 // Gets the appropriate icon and badges and composites the image. 78 void GenerateImage(const chromeos::NetworkState* network); 79 80 // Defines color theme and VPN badging 81 const IconType icon_type_; 82 83 // Cached state of the network when the icon was last generated. 84 std::string state_; 85 86 // Cached strength index of the network when the icon was last generated. 87 int strength_index_; 88 89 // Cached technology badge for the network when the icon was last generated. 90 const gfx::ImageSkia* technology_badge_; 91 92 // Cached vpn badge for the network when the icon was last generated. 93 const gfx::ImageSkia* vpn_badge_; 94 95 // Cached roaming state of the network when the icon was last generated. 96 std::string roaming_state_; 97 98 // Generated icon image. 99 gfx::ImageSkia image_; 100 101 DISALLOW_COPY_AND_ASSIGN(NetworkIconImpl); 102 }; 103 104 //------------------------------------------------------------------------------ 105 // Maintain a static (global) icon map. Note: Icons are never destroyed; 106 // it is assumed that a finite and reasonable number of network icons will be 107 // created during a session. 108 109 typedef std::map<std::string, NetworkIconImpl*> NetworkIconMap; 110 111 NetworkIconMap* GetIconMapInstance(IconType icon_type, bool create) { 112 typedef std::map<IconType, NetworkIconMap*> IconTypeMap; 113 static IconTypeMap* s_icon_map = NULL; 114 if (s_icon_map == NULL) { 115 if (!create) 116 return NULL; 117 s_icon_map = new IconTypeMap; 118 } 119 if (s_icon_map->count(icon_type) == 0) { 120 if (!create) 121 return NULL; 122 (*s_icon_map)[icon_type] = new NetworkIconMap; 123 } 124 return (*s_icon_map)[icon_type]; 125 } 126 127 NetworkIconMap* GetIconMap(IconType icon_type) { 128 return GetIconMapInstance(icon_type, true); 129 } 130 131 void PurgeIconMap(IconType icon_type, 132 const std::set<std::string>& network_paths) { 133 NetworkIconMap* icon_map = GetIconMapInstance(icon_type, false); 134 if (!icon_map) 135 return; 136 for (NetworkIconMap::iterator loop_iter = icon_map->begin(); 137 loop_iter != icon_map->end(); ) { 138 NetworkIconMap::iterator cur_iter = loop_iter++; 139 if (network_paths.count(cur_iter->first) == 0) { 140 delete cur_iter->second; 141 icon_map->erase(cur_iter); 142 } 143 } 144 } 145 146 //------------------------------------------------------------------------------ 147 // Utilities for generating icon images. 148 149 // 'NONE' will default to ARCS behavior where appropriate (e.g. no network or 150 // if a new type gets added). 151 enum ImageType { 152 ARCS, 153 BARS, 154 NONE 155 }; 156 157 // Amount to fade icons while connecting. 158 const double kConnectingImageAlpha = 0.5; 159 160 // Images for strength bars for wired networks. 161 const int kNumBarsImages = 5; 162 163 // Imagaes for strength arcs for wireless networks. 164 const int kNumArcsImages = 5; 165 166 // Number of discrete images to use for alpha fade animation 167 const int kNumFadeImages = 10; 168 169 //------------------------------------------------------------------------------ 170 // Classes for generating scaled images. 171 172 const SkBitmap GetEmptyBitmap(const gfx::Size pixel_size) { 173 typedef std::pair<int, int> SizeKey; 174 typedef std::map<SizeKey, SkBitmap> SizeBitmapMap; 175 static SizeBitmapMap* s_empty_bitmaps = new SizeBitmapMap; 176 177 SizeKey key(pixel_size.width(), pixel_size.height()); 178 179 SizeBitmapMap::iterator iter = s_empty_bitmaps->find(key); 180 if (iter != s_empty_bitmaps->end()) 181 return iter->second; 182 183 SkBitmap empty; 184 empty.setConfig(SkBitmap::kARGB_8888_Config, key.first, key.second); 185 empty.allocPixels(); 186 empty.eraseARGB(0, 0, 0, 0); 187 (*s_empty_bitmaps)[key] = empty; 188 return empty; 189 } 190 191 class EmptyImageSource: public gfx::ImageSkiaSource { 192 public: 193 explicit EmptyImageSource(const gfx::Size& size) 194 : size_(size) { 195 } 196 197 virtual gfx::ImageSkiaRep GetImageForScale( 198 ui::ScaleFactor scale_factor) OVERRIDE { 199 gfx::Size pixel_size = gfx::ToFlooredSize( 200 gfx::ScaleSize(size_, ui::GetScaleFactorScale(scale_factor))); 201 SkBitmap empty_bitmap = GetEmptyBitmap(pixel_size); 202 return gfx::ImageSkiaRep(empty_bitmap, scale_factor); 203 } 204 private: 205 const gfx::Size size_; 206 207 DISALLOW_COPY_AND_ASSIGN(EmptyImageSource); 208 }; 209 210 // This defines how we assemble a network icon. 211 class NetworkIconImageSource : public gfx::ImageSkiaSource { 212 public: 213 NetworkIconImageSource(const gfx::ImageSkia& icon, const Badges& badges) 214 : icon_(icon), 215 badges_(badges) { 216 } 217 virtual ~NetworkIconImageSource() {} 218 219 // TODO(pkotwicz): Figure out what to do when a new image resolution becomes 220 // available. 221 virtual gfx::ImageSkiaRep GetImageForScale( 222 ui::ScaleFactor scale_factor) OVERRIDE { 223 gfx::ImageSkiaRep icon_rep = icon_.GetRepresentation(scale_factor); 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 == flimflam::kTypeWifi) 284 return ARCS; 285 else if (type == flimflam::kTypeCellular || type == flimflam::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 == flimflam::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 == flimflam::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 == flimflam::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 == flimflam::kNetworkTechnology1Xrtt) { 417 id = IDR_AURA_UBER_TRAY_NETWORK_1X; 418 } else if (technology == flimflam::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 == flimflam::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 == flimflam::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 == flimflam::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 == flimflam::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 == flimflam::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 == flimflam::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 == flimflam::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 const std::string& type = network->type(); 467 if (type == flimflam::kTypeEthernet) { 468 return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED); 469 } else if (type == flimflam::kTypeWifi || 470 type == flimflam::kTypeWimax || 471 type == flimflam::kTypeCellular) { 472 DCHECK(strength_index > 0); 473 return GetImageForIndex( 474 ImageTypeForNetworkType(type), icon_type, strength_index); 475 } else if (type == flimflam::kTypeVPN) { 476 return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN); 477 } else { 478 LOG(WARNING) << "Request for icon for unsupported type: " << type; 479 return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED); 480 } 481 } 482 483 //------------------------------------------------------------------------------ 484 // Get connecting images 485 486 gfx::ImageSkia GetConnectingVpnImage(IconType icon_type) { 487 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); 488 const NetworkState* connected_network = NULL; 489 if (icon_type == ICON_TYPE_TRAY) { 490 connected_network = handler->ConnectedNetworkByType( 491 NetworkStateHandler::kMatchTypeNonVirtual); 492 } 493 double animation = NetworkIconAnimation::GetInstance()->GetAnimation(); 494 495 if (connected_network) { 496 gfx::ImageSkia icon = GetImageForNetwork(connected_network, icon_type); 497 Badges badges; 498 badges.bottom_left = ConnectingVpnBadge(animation); 499 return gfx::ImageSkia( 500 new NetworkIconImageSource(icon, badges), icon.size()); 501 } else { 502 gfx::ImageSkia* icon = ConnectingVpnImage(animation); 503 return gfx::ImageSkia( 504 new NetworkIconImageSource(*icon, Badges()), icon->size()); 505 } 506 } 507 508 gfx::ImageSkia GetConnectingImage(const std::string& network_type, 509 IconType icon_type) { 510 if (network_type == flimflam::kTypeVPN) 511 return GetConnectingVpnImage(icon_type); 512 513 ImageType image_type = ImageTypeForNetworkType(network_type); 514 double animation = NetworkIconAnimation::GetInstance()->GetAnimation(); 515 516 gfx::ImageSkia* icon = ConnectingWirelessImage( 517 image_type, icon_type, animation); 518 return gfx::ImageSkia( 519 new NetworkIconImageSource(*icon, Badges()), icon->size()); 520 } 521 522 } // namespace 523 524 //------------------------------------------------------------------------------ 525 // NetworkIconImpl 526 527 NetworkIconImpl::NetworkIconImpl(IconType icon_type) 528 : icon_type_(icon_type), 529 strength_index_(-1), 530 technology_badge_(NULL), 531 vpn_badge_(NULL) { 532 // Default image 533 image_ = GetDisconnectedImage(flimflam::kTypeWifi, icon_type); 534 } 535 536 void NetworkIconImpl::Update(const NetworkState* network) { 537 DCHECK(network); 538 // Determine whether or not we need to update the icon. 539 bool dirty = image_.isNull(); 540 541 // If the network state has changed, the icon needs updating. 542 if (state_ != network->connection_state()) { 543 state_ = network->connection_state(); 544 dirty = true; 545 } 546 547 const std::string& type = network->type(); 548 if (type != flimflam::kTypeEthernet) 549 dirty |= UpdateWirelessStrengthIndex(network); 550 551 if (type == flimflam::kTypeCellular) 552 dirty |= UpdateCellularState(network); 553 554 if (IconTypeHasVPNBadge(icon_type_) && type != flimflam::kTypeVPN) 555 dirty |= UpdateVPNBadge(); 556 557 if (dirty) { 558 // Set the icon and badges based on the network and generate the image. 559 GenerateImage(network); 560 } 561 } 562 563 bool NetworkIconImpl::UpdateWirelessStrengthIndex(const NetworkState* network) { 564 int index = GetStrengthIndex(network); 565 if (index != strength_index_) { 566 strength_index_ = index; 567 return true; 568 } 569 return false; 570 } 571 572 bool NetworkIconImpl::UpdateCellularState(const NetworkState* network) { 573 bool dirty = false; 574 const gfx::ImageSkia* technology_badge = 575 BadgeForNetworkTechnology(network, icon_type_); 576 if (technology_badge != technology_badge_) { 577 technology_badge_ = technology_badge; 578 dirty = true; 579 } 580 std::string roaming_state = network->roaming(); 581 if (roaming_state != roaming_state_) { 582 roaming_state_ = roaming_state; 583 dirty = true; 584 } 585 return dirty; 586 } 587 588 bool NetworkIconImpl::UpdateVPNBadge() { 589 const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()-> 590 ConnectedNetworkByType(flimflam::kTypeVPN); 591 if (vpn && vpn_badge_ == NULL) { 592 vpn_badge_ = BadgeForVPN(icon_type_); 593 return true; 594 } else if (!vpn && vpn_badge_ != NULL) { 595 vpn_badge_ = NULL; 596 return true; 597 } 598 return false; 599 } 600 601 void NetworkIconImpl::GetBadges(const NetworkState* network, Badges* badges) { 602 DCHECK(network); 603 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 604 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); 605 606 const std::string& type = network->type(); 607 if (type == flimflam::kTypeWifi) { 608 if (network->security() != flimflam::kSecurityNone && 609 IconTypeIsDark(icon_type_)) { 610 badges->bottom_right = rb.GetImageSkiaNamed( 611 IDR_AURA_UBER_TRAY_NETWORK_SECURE_DARK); 612 } 613 } else if (type == flimflam::kTypeWimax) { 614 technology_badge_ = rb.GetImageSkiaNamed( 615 IconTypeIsDark(icon_type_) ? 616 IDR_AURA_UBER_TRAY_NETWORK_4G_DARK : 617 IDR_AURA_UBER_TRAY_NETWORK_4G_LIGHT); 618 } else if (type == flimflam::kTypeCellular) { 619 if (network->roaming() == flimflam::kRoamingStateRoaming) { 620 // For networks that are always in roaming don't show roaming badge. 621 const DeviceState* device = 622 handler->GetDeviceState(network->device_path()); 623 LOG_IF(WARNING, !device) << "Could not find device state for " 624 << network->device_path(); 625 if (!device || !device->provider_requires_roaming()) { 626 badges->bottom_right = rb.GetImageSkiaNamed( 627 IconTypeIsDark(icon_type_) ? 628 IDR_AURA_UBER_TRAY_NETWORK_ROAMING_DARK : 629 IDR_AURA_UBER_TRAY_NETWORK_ROAMING_LIGHT); 630 } 631 } 632 } 633 if (!network->IsConnectingState()) { 634 badges->top_left = technology_badge_; 635 badges->bottom_left = vpn_badge_; 636 } 637 } 638 639 void NetworkIconImpl::GenerateImage(const NetworkState* network) { 640 DCHECK(network); 641 gfx::ImageSkia icon = GetIcon(network, icon_type_, strength_index_); 642 Badges badges; 643 GetBadges(network, &badges); 644 image_ = gfx::ImageSkia( 645 new NetworkIconImageSource(icon, badges), icon.size()); 646 } 647 648 //------------------------------------------------------------------------------ 649 // Public interface 650 651 gfx::ImageSkia GetImageForNetwork(const NetworkState* network, 652 IconType icon_type) { 653 DCHECK(network); 654 // Handle connecting icons. 655 if (network->IsConnectingState()) 656 return GetConnectingImage(network->type(), icon_type); 657 658 // Find or add the icon. 659 NetworkIconMap* icon_map = GetIconMap(icon_type); 660 NetworkIconImpl* icon; 661 NetworkIconMap::iterator iter = icon_map->find(network->path()); 662 if (iter == icon_map->end()) { 663 icon = new NetworkIconImpl(icon_type); 664 icon_map->insert(std::make_pair(network->path(), icon)); 665 } else { 666 icon = iter->second; 667 } 668 669 // Update and return the icon's image. 670 icon->Update(network); 671 return icon->image(); 672 } 673 674 gfx::ImageSkia GetImageForConnectedNetwork(IconType icon_type, 675 const std::string& network_type) { 676 return GetConnectedImage(network_type, icon_type); 677 } 678 679 gfx::ImageSkia GetImageForConnectingNetwork(IconType icon_type, 680 const std::string& network_type) { 681 return GetConnectingImage(network_type, icon_type); 682 } 683 684 gfx::ImageSkia GetImageForDisconnectedNetwork(IconType icon_type, 685 const std::string& network_type) { 686 return GetDisconnectedImage(network_type, icon_type); 687 } 688 689 base::string16 GetLabelForNetwork(const chromeos::NetworkState* network, 690 IconType icon_type) { 691 DCHECK(network); 692 std::string activation_state = network->activation_state(); 693 if (icon_type == ICON_TYPE_LIST) { 694 // Show "<network>: [Connecting|Activating]..." 695 if (network->IsConnectingState()) { 696 return l10n_util::GetStringFUTF16( 697 IDS_ASH_STATUS_TRAY_NETWORK_LIST_CONNECTING, 698 UTF8ToUTF16(network->name())); 699 } 700 if (activation_state == flimflam::kActivationStateActivating) { 701 return l10n_util::GetStringFUTF16( 702 IDS_ASH_STATUS_TRAY_NETWORK_LIST_ACTIVATING, 703 UTF8ToUTF16(network->name())); 704 } 705 // Show "Activate <network>" in list view only. 706 if (activation_state == flimflam::kActivationStateNotActivated || 707 activation_state == flimflam::kActivationStatePartiallyActivated) { 708 return l10n_util::GetStringFUTF16( 709 IDS_ASH_STATUS_TRAY_NETWORK_LIST_ACTIVATE, 710 UTF8ToUTF16(network->name())); 711 } 712 } else { 713 // Show "[Connected to|Connecting to|Activating] <network>" (non-list view). 714 if (network->IsConnectedState()) { 715 return l10n_util::GetStringFUTF16( 716 IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED, UTF8ToUTF16(network->name())); 717 } 718 if (network->IsConnectingState()) { 719 return l10n_util::GetStringFUTF16( 720 IDS_ASH_STATUS_TRAY_NETWORK_CONNECTING, UTF8ToUTF16(network->name())); 721 } 722 if (activation_state == flimflam::kActivationStateActivating) { 723 return l10n_util::GetStringFUTF16( 724 IDS_ASH_STATUS_TRAY_NETWORK_ACTIVATING, UTF8ToUTF16(network->name())); 725 } 726 } 727 728 // Otherwise just show the network name or 'Ethernet'. 729 if (network->type() == flimflam::kTypeEthernet) { 730 return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ETHERNET); 731 } else { 732 return UTF8ToUTF16(network->name()); 733 } 734 } 735 736 int GetCellularUninitializedMsg() { 737 static base::Time s_uninitialized_state_time; 738 static int s_uninitialized_msg(0); 739 740 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); 741 if (handler->GetTechnologyState(NetworkStateHandler::kMatchTypeMobile) 742 == NetworkStateHandler::TECHNOLOGY_UNINITIALIZED) { 743 s_uninitialized_msg = IDS_ASH_STATUS_TRAY_INITIALIZING_CELLULAR; 744 s_uninitialized_state_time = base::Time::Now(); 745 return s_uninitialized_msg; 746 } else if (handler->GetScanningByType( 747 NetworkStateHandler::kMatchTypeMobile)) { 748 s_uninitialized_msg = IDS_ASH_STATUS_TRAY_CELLULAR_SCANNING; 749 s_uninitialized_state_time = base::Time::Now(); 750 return s_uninitialized_msg; 751 } 752 // There can be a delay between leaving the Initializing state and when 753 // a Cellular device shows up, so keep showing the initializing 754 // animation for a bit to avoid flashing the disconnect icon. 755 const int kInitializingDelaySeconds = 1; 756 base::TimeDelta dtime = base::Time::Now() - s_uninitialized_state_time; 757 if (dtime.InSeconds() < kInitializingDelaySeconds) 758 return s_uninitialized_msg; 759 return 0; 760 } 761 762 void GetDefaultNetworkImageAndLabel(IconType icon_type, 763 gfx::ImageSkia* image, 764 base::string16* label, 765 bool* animating) { 766 NetworkStateHandler* state_handler = 767 NetworkHandler::Get()->network_state_handler(); 768 NetworkConnectionHandler* connect_handler = 769 NetworkHandler::Get()->network_connection_handler(); 770 const NetworkState* connected_network = 771 state_handler->ConnectedNetworkByType( 772 NetworkStateHandler::kMatchTypeNonVirtual); 773 const NetworkState* connecting_network = 774 state_handler->ConnectingNetworkByType( 775 NetworkStateHandler::kMatchTypeWireless); 776 if (!connecting_network && icon_type == ICON_TYPE_TRAY) { 777 connecting_network = 778 state_handler->ConnectingNetworkByType(flimflam::kTypeVPN); 779 } 780 781 const NetworkState* network; 782 // If we are connecting to a network, and there is either no connected 783 // network, or the connection was user requested, use the connecting 784 // network. 785 if (connecting_network && 786 (!connected_network || 787 connect_handler->HasConnectingNetwork(connecting_network->path()))) { 788 network = connecting_network; 789 } else { 790 network = connected_network; 791 } 792 793 // Don't show ethernet in the tray 794 if (icon_type == ICON_TYPE_TRAY && 795 network && network->type() == flimflam::kTypeEthernet) { 796 *image = gfx::ImageSkia(); 797 *animating = false; 798 return; 799 } 800 801 if (!network) { 802 // If no connecting network, check if we are activating a network. 803 const NetworkState* mobile_network = state_handler->FirstNetworkByType( 804 NetworkStateHandler::kMatchTypeMobile); 805 if (mobile_network && (mobile_network->activation_state() == 806 flimflam::kActivationStateActivating)) { 807 network = mobile_network; 808 } 809 } 810 if (!network) { 811 // If no connecting network, check for cellular initializing. 812 int uninitialized_msg = GetCellularUninitializedMsg(); 813 if (uninitialized_msg != 0) { 814 *image = GetImageForConnectingNetwork(icon_type, flimflam::kTypeCellular); 815 if (label) 816 *label = l10n_util::GetStringUTF16(uninitialized_msg); 817 *animating = true; 818 } else { 819 // Otherwise show the disconnected wifi icon. 820 *image = GetImageForDisconnectedNetwork(icon_type, flimflam::kTypeWifi); 821 if (label) { 822 *label = l10n_util::GetStringUTF16( 823 IDS_ASH_STATUS_TRAY_NETWORK_NOT_CONNECTED); 824 } 825 *animating = false; 826 } 827 return; 828 } 829 *animating = network->IsConnectingState(); 830 // Get icon and label for connected or connecting network. 831 *image = GetImageForNetwork(network, icon_type); 832 if (label) 833 *label = GetLabelForNetwork(network, icon_type); 834 } 835 836 void PurgeNetworkIconCache() { 837 NetworkStateHandler::NetworkStateList networks; 838 NetworkHandler::Get()->network_state_handler()->GetNetworkList(&networks); 839 std::set<std::string> network_paths; 840 for (NetworkStateHandler::NetworkStateList::iterator iter = networks.begin(); 841 iter != networks.end(); ++iter) { 842 network_paths.insert((*iter)->path()); 843 } 844 PurgeIconMap(ICON_TYPE_TRAY, network_paths); 845 PurgeIconMap(ICON_TYPE_DEFAULT_VIEW, network_paths); 846 PurgeIconMap(ICON_TYPE_LIST, network_paths); 847 } 848 849 } // namespace network_icon 850 } // namespace ash 851