Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ui / chromeos / network / network_icon.cc
blob3d274d5866f057bb572e13cd03615899b9f6b466
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.
5 #include "ui/chromeos/network/network_icon.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chromeos/network/device_state.h"
9 #include "chromeos/network/network_connection_handler.h"
10 #include "chromeos/network/network_state.h"
11 #include "chromeos/network/network_state_handler.h"
12 #include "chromeos/network/portal_detector/network_portal_detector.h"
13 #include "grit/ui_chromeos_resources.h"
14 #include "grit/ui_chromeos_strings.h"
15 #include "third_party/cros_system_api/dbus/service_constants.h"
16 #include "ui/base/l10n/l10n_util.h"
17 #include "ui/base/resource/resource_bundle.h"
18 #include "ui/base/webui/web_ui_util.h"
19 #include "ui/chromeos/network/network_icon_animation.h"
20 #include "ui/chromeos/network/network_icon_animation_observer.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"
27 using chromeos::DeviceState;
28 using chromeos::NetworkConnectionHandler;
29 using chromeos::NetworkHandler;
30 using chromeos::NetworkPortalDetector;
31 using chromeos::NetworkState;
32 using chromeos::NetworkStateHandler;
33 using chromeos::NetworkTypePattern;
35 namespace ui {
36 namespace network_icon {
38 namespace {
40 //------------------------------------------------------------------------------
41 // Struct to pass icon badges to NetworkIconImageSource.
42 struct Badges {
43 Badges()
44 : top_left(NULL),
45 top_right(NULL),
46 bottom_left(NULL),
47 bottom_right(NULL) {
49 const gfx::ImageSkia* top_left;
50 const gfx::ImageSkia* top_right;
51 const gfx::ImageSkia* bottom_left;
52 const gfx::ImageSkia* bottom_right;
55 //------------------------------------------------------------------------------
56 // class used for maintaining a map of network state and images.
57 class NetworkIconImpl {
58 public:
59 NetworkIconImpl(const std::string& path, IconType icon_type);
61 // Determines whether or not the associated network might be dirty and if so
62 // updates and generates the icon. Does nothing if network no longer exists.
63 void Update(const chromeos::NetworkState* network);
65 // Returns the cached image url for |image_| based on |scale_factor|.
66 const std::string& GetImageUrl(float scale_factor);
68 const gfx::ImageSkia& image() const { return image_; }
70 private:
71 typedef std::map<float, std::string> ImageUrlMap;
73 // Updates |strength_index_| for wireless networks. Returns true if changed.
74 bool UpdateWirelessStrengthIndex(const chromeos::NetworkState* network);
76 // Updates the local state for cellular networks. Returns true if changed.
77 bool UpdateCellularState(const chromeos::NetworkState* network);
79 // Updates the portal state for wireless networks. Returns true if changed.
80 bool UpdatePortalState(const chromeos::NetworkState* network);
82 // Updates the VPN badge. Returns true if changed.
83 bool UpdateVPNBadge();
85 // Gets |badges| based on |network| and the current state.
86 void GetBadges(const NetworkState* network, Badges* badges);
88 // Gets the appropriate icon and badges and composites the image.
89 void GenerateImage(const chromeos::NetworkState* network);
91 // Network path, used for debugging.
92 std::string network_path_;
94 // Defines color theme and VPN badging
95 const IconType icon_type_;
97 // Cached state of the network when the icon was last generated.
98 std::string state_;
100 // Cached strength index of the network when the icon was last generated.
101 int strength_index_;
103 // Cached technology badge for the network when the icon was last generated.
104 const gfx::ImageSkia* technology_badge_;
106 // Cached vpn badge for the network when the icon was last generated.
107 const gfx::ImageSkia* vpn_badge_;
109 // Cached roaming state of the network when the icon was last generated.
110 std::string roaming_state_;
112 // Cached portal state of the network when the icon was last generated.
113 bool behind_captive_portal_;
115 // Generated icon image.
116 gfx::ImageSkia image_;
118 // Map of cached image urls by scale factor. Cleared whenever image_ is
119 // generated.
120 ImageUrlMap image_urls_;
122 DISALLOW_COPY_AND_ASSIGN(NetworkIconImpl);
125 //------------------------------------------------------------------------------
126 // Maintain a static (global) icon map. Note: Icons are never destroyed;
127 // it is assumed that a finite and reasonable number of network icons will be
128 // created during a session.
130 typedef std::map<std::string, NetworkIconImpl*> NetworkIconMap;
132 NetworkIconMap* GetIconMapInstance(IconType icon_type, bool create) {
133 typedef std::map<IconType, NetworkIconMap*> IconTypeMap;
134 static IconTypeMap* s_icon_map = NULL;
135 if (s_icon_map == NULL) {
136 if (!create)
137 return NULL;
138 s_icon_map = new IconTypeMap;
140 if (s_icon_map->count(icon_type) == 0) {
141 if (!create)
142 return NULL;
143 (*s_icon_map)[icon_type] = new NetworkIconMap;
145 return (*s_icon_map)[icon_type];
148 NetworkIconMap* GetIconMap(IconType icon_type) {
149 return GetIconMapInstance(icon_type, true);
152 void PurgeIconMap(IconType icon_type,
153 const std::set<std::string>& network_paths) {
154 NetworkIconMap* icon_map = GetIconMapInstance(icon_type, false);
155 if (!icon_map)
156 return;
157 for (NetworkIconMap::iterator loop_iter = icon_map->begin();
158 loop_iter != icon_map->end(); ) {
159 NetworkIconMap::iterator cur_iter = loop_iter++;
160 if (network_paths.count(cur_iter->first) == 0) {
161 delete cur_iter->second;
162 icon_map->erase(cur_iter);
167 //------------------------------------------------------------------------------
168 // Utilities for generating icon images.
170 // 'NONE' will default to ARCS behavior where appropriate (e.g. no network or
171 // if a new type gets added).
172 enum ImageType {
173 ARCS,
174 BARS,
175 NONE
178 // Amount to fade icons while connecting.
179 const double kConnectingImageAlpha = 0.5;
181 // Images for strength bars for wired networks.
182 const int kNumBarsImages = 5;
184 // Imagaes for strength arcs for wireless networks.
185 const int kNumArcsImages = 5;
187 // Number of discrete images to use for alpha fade animation
188 const int kNumFadeImages = 10;
190 //------------------------------------------------------------------------------
191 // Classes for generating scaled images.
193 const SkBitmap GetEmptyBitmap(const gfx::Size pixel_size) {
194 typedef std::pair<int, int> SizeKey;
195 typedef std::map<SizeKey, SkBitmap> SizeBitmapMap;
196 static SizeBitmapMap* s_empty_bitmaps = new SizeBitmapMap;
198 SizeKey key(pixel_size.width(), pixel_size.height());
200 SizeBitmapMap::iterator iter = s_empty_bitmaps->find(key);
201 if (iter != s_empty_bitmaps->end())
202 return iter->second;
204 SkBitmap empty;
205 empty.allocN32Pixels(key.first, key.second);
206 empty.eraseARGB(0, 0, 0, 0);
207 (*s_empty_bitmaps)[key] = empty;
208 return empty;
211 class EmptyImageSource: public gfx::ImageSkiaSource {
212 public:
213 explicit EmptyImageSource(const gfx::Size& size)
214 : size_(size) {
217 virtual gfx::ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
218 gfx::Size pixel_size = gfx::ToFlooredSize(gfx::ScaleSize(size_, scale));
219 SkBitmap empty_bitmap = GetEmptyBitmap(pixel_size);
220 return gfx::ImageSkiaRep(empty_bitmap, scale);
223 private:
224 const gfx::Size size_;
226 DISALLOW_COPY_AND_ASSIGN(EmptyImageSource);
229 // This defines how we assemble a network icon.
230 class NetworkIconImageSource : public gfx::ImageSkiaSource {
231 public:
232 NetworkIconImageSource(const gfx::ImageSkia& icon, const Badges& badges)
233 : icon_(icon),
234 badges_(badges) {
236 virtual ~NetworkIconImageSource() {}
238 // TODO(pkotwicz): Figure out what to do when a new image resolution becomes
239 // available.
240 virtual gfx::ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
241 gfx::ImageSkiaRep icon_rep = icon_.GetRepresentation(scale);
242 if (icon_rep.is_null())
243 return gfx::ImageSkiaRep();
244 gfx::Canvas canvas(icon_rep, false);
245 if (badges_.top_left)
246 canvas.DrawImageInt(*badges_.top_left, 0, 0);
247 if (badges_.top_right)
248 canvas.DrawImageInt(*badges_.top_right,
249 icon_.width() - badges_.top_right->width(), 0);
250 if (badges_.bottom_left) {
251 canvas.DrawImageInt(*badges_.bottom_left,
252 0, icon_.height() - badges_.bottom_left->height());
254 if (badges_.bottom_right) {
255 canvas.DrawImageInt(*badges_.bottom_right,
256 icon_.width() - badges_.bottom_right->width(),
257 icon_.height() - badges_.bottom_right->height());
259 return canvas.ExtractImageRep();
262 private:
263 const gfx::ImageSkia icon_;
264 const Badges badges_;
266 DISALLOW_COPY_AND_ASSIGN(NetworkIconImageSource);
269 //------------------------------------------------------------------------------
270 // Utilities for extracting icon images.
272 // A struct used for caching image urls.
273 struct ImageIdForNetworkType {
274 ImageIdForNetworkType(IconType icon_type,
275 const std::string& network_type,
276 float scale_factor) :
277 icon_type(icon_type),
278 network_type(network_type),
279 scale_factor(scale_factor) {}
280 bool operator<(const ImageIdForNetworkType& other) const {
281 if (icon_type != other.icon_type)
282 return icon_type < other.icon_type;
283 if (network_type != other.network_type)
284 return network_type < other.network_type;
285 return scale_factor < other.scale_factor;
287 IconType icon_type;
288 std::string network_type;
289 float scale_factor;
292 typedef std::map<ImageIdForNetworkType, std::string> ImageIdUrlMap;
294 bool IconTypeIsDark(IconType icon_type) {
295 return (icon_type != ICON_TYPE_TRAY);
298 bool IconTypeHasVPNBadge(IconType icon_type) {
299 return (icon_type != ICON_TYPE_LIST);
302 int NumImagesForType(ImageType type) {
303 return (type == BARS) ? kNumBarsImages : kNumArcsImages;
306 gfx::ImageSkia* BaseImageForType(ImageType image_type, IconType icon_type) {
307 gfx::ImageSkia* image;
308 if (image_type == BARS) {
309 image = ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
310 IconTypeIsDark(icon_type) ?
311 IDR_AURA_UBER_TRAY_NETWORK_BARS_DARK :
312 IDR_AURA_UBER_TRAY_NETWORK_BARS_LIGHT);
313 } else {
314 image = ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
315 IconTypeIsDark(icon_type) ?
316 IDR_AURA_UBER_TRAY_NETWORK_ARCS_DARK :
317 IDR_AURA_UBER_TRAY_NETWORK_ARCS_LIGHT);
319 return image;
322 ImageType ImageTypeForNetworkType(const std::string& type) {
323 if (type == shill::kTypeWifi)
324 return ARCS;
325 else if (type == shill::kTypeCellular || type == shill::kTypeWimax)
326 return BARS;
327 return NONE;
330 gfx::ImageSkia GetImageForIndex(ImageType image_type,
331 IconType icon_type,
332 int index) {
333 int num_images = NumImagesForType(image_type);
334 if (index < 0 || index >= num_images)
335 return gfx::ImageSkia();
336 gfx::ImageSkia* images = BaseImageForType(image_type, icon_type);
337 int width = images->width();
338 int height = images->height() / num_images;
339 return gfx::ImageSkiaOperations::ExtractSubset(*images,
340 gfx::Rect(0, index * height, width, height));
343 const gfx::ImageSkia GetConnectedImage(IconType icon_type,
344 const std::string& network_type) {
345 if (network_type == shill::kTypeVPN) {
346 return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
347 IDR_AURA_UBER_TRAY_NETWORK_VPN);
349 ImageType image_type = ImageTypeForNetworkType(network_type);
350 const int connected_index = NumImagesForType(image_type) - 1;
351 return GetImageForIndex(image_type, icon_type, connected_index);
354 const gfx::ImageSkia GetDisconnectedImage(IconType icon_type,
355 const std::string& network_type) {
356 if (network_type == shill::kTypeVPN) {
357 // Note: same as connected image, shouldn't normally be seen.
358 return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
359 IDR_AURA_UBER_TRAY_NETWORK_VPN);
361 ImageType image_type = ImageTypeForNetworkType(network_type);
362 const int disconnected_index = 0;
363 return GetImageForIndex(image_type, icon_type, disconnected_index);
366 gfx::ImageSkia* ConnectingWirelessImage(ImageType image_type,
367 IconType icon_type,
368 double animation) {
369 static gfx::ImageSkia* s_bars_images_dark[kNumBarsImages - 1];
370 static gfx::ImageSkia* s_bars_images_light[kNumBarsImages - 1];
371 static gfx::ImageSkia* s_arcs_images_dark[kNumArcsImages - 1];
372 static gfx::ImageSkia* s_arcs_images_light[kNumArcsImages - 1];
373 int image_count = NumImagesForType(image_type) - 1;
374 int index = animation * nextafter(static_cast<float>(image_count), 0);
375 index = std::max(std::min(index, image_count - 1), 0);
376 gfx::ImageSkia** images;
377 bool dark = IconTypeIsDark(icon_type);
378 if (image_type == BARS)
379 images = dark ? s_bars_images_dark : s_bars_images_light;
380 else
381 images = dark ? s_arcs_images_dark : s_arcs_images_light;
382 if (!images[index]) {
383 // Lazily cache images.
384 gfx::ImageSkia source = GetImageForIndex(image_type, icon_type, index + 1);
385 images[index] = new gfx::ImageSkia(
386 gfx::ImageSkiaOperations::CreateBlendedImage(
387 gfx::ImageSkia(new EmptyImageSource(source.size()), source.size()),
388 source,
389 kConnectingImageAlpha));
391 return images[index];
394 gfx::ImageSkia* ConnectingVpnImage(double animation) {
395 int index = animation * nextafter(static_cast<float>(kNumFadeImages), 0);
396 static gfx::ImageSkia* s_vpn_images[kNumFadeImages];
397 if (!s_vpn_images[index]) {
398 // Lazily cache images.
399 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
400 gfx::ImageSkia* icon = rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN);
401 s_vpn_images[index] = new gfx::ImageSkia(
402 gfx::ImageSkiaOperations::CreateBlendedImage(
403 gfx::ImageSkia(new EmptyImageSource(icon->size()), icon->size()),
404 *icon,
405 animation));
407 return s_vpn_images[index];
410 gfx::ImageSkia* ConnectingVpnBadge(double animation) {
411 int index = animation * nextafter(static_cast<float>(kNumFadeImages), 0);
412 static gfx::ImageSkia* s_vpn_badges[kNumFadeImages];
413 if (!s_vpn_badges[index]) {
414 // Lazily cache images.
415 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
416 gfx::ImageSkia* icon =
417 rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED); // For size
418 gfx::ImageSkia* badge =
419 rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN_BADGE);
420 s_vpn_badges[index] = new gfx::ImageSkia(
421 gfx::ImageSkiaOperations::CreateBlendedImage(
422 gfx::ImageSkia(new EmptyImageSource(icon->size()), icon->size()),
423 *badge,
424 animation));
426 return s_vpn_badges[index];
429 int StrengthIndex(int strength, int count) {
430 // Return an index in the range [1, count-1].
431 const float findex = (static_cast<float>(strength) / 100.0f) *
432 nextafter(static_cast<float>(count - 1), 0);
433 int index = 1 + static_cast<int>(findex);
434 index = std::max(std::min(index, count - 1), 1);
435 return index;
438 int GetStrengthIndex(const NetworkState* network) {
439 ImageType image_type = ImageTypeForNetworkType(network->type());
440 if (image_type == ARCS)
441 return StrengthIndex(network->signal_strength(), kNumArcsImages);
442 else if (image_type == BARS)
443 return StrengthIndex(network->signal_strength(), kNumBarsImages);
444 return 0;
447 const gfx::ImageSkia* BadgeForNetworkTechnology(const NetworkState* network,
448 IconType icon_type) {
449 const int kUnknownBadgeType = -1;
450 int id = kUnknownBadgeType;
451 const std::string& technology = network->network_technology();
452 if (technology == shill::kNetworkTechnologyEvdo) {
453 id = IconTypeIsDark(icon_type) ?
454 IDR_AURA_UBER_TRAY_NETWORK_EVDO_DARK :
455 IDR_AURA_UBER_TRAY_NETWORK_EVDO_LIGHT;
456 } else if (technology == shill::kNetworkTechnology1Xrtt) {
457 id = IDR_AURA_UBER_TRAY_NETWORK_1X;
458 } else if (technology == shill::kNetworkTechnologyGprs) {
459 id = IconTypeIsDark(icon_type) ?
460 IDR_AURA_UBER_TRAY_NETWORK_GPRS_DARK :
461 IDR_AURA_UBER_TRAY_NETWORK_GPRS_LIGHT;
462 } else if (technology == shill::kNetworkTechnologyEdge) {
463 id = IconTypeIsDark(icon_type) ?
464 IDR_AURA_UBER_TRAY_NETWORK_EDGE_DARK :
465 IDR_AURA_UBER_TRAY_NETWORK_EDGE_LIGHT;
466 } else if (technology == shill::kNetworkTechnologyUmts) {
467 id = IconTypeIsDark(icon_type) ?
468 IDR_AURA_UBER_TRAY_NETWORK_3G_DARK :
469 IDR_AURA_UBER_TRAY_NETWORK_3G_LIGHT;
470 } else if (technology == shill::kNetworkTechnologyHspa) {
471 id = IconTypeIsDark(icon_type) ?
472 IDR_AURA_UBER_TRAY_NETWORK_HSPA_DARK :
473 IDR_AURA_UBER_TRAY_NETWORK_HSPA_LIGHT;
474 } else if (technology == shill::kNetworkTechnologyHspaPlus) {
475 id = IconTypeIsDark(icon_type) ?
476 IDR_AURA_UBER_TRAY_NETWORK_HSPA_PLUS_DARK :
477 IDR_AURA_UBER_TRAY_NETWORK_HSPA_PLUS_LIGHT;
478 } else if (technology == shill::kNetworkTechnologyLte) {
479 id = IconTypeIsDark(icon_type) ?
480 IDR_AURA_UBER_TRAY_NETWORK_LTE_DARK :
481 IDR_AURA_UBER_TRAY_NETWORK_LTE_LIGHT;
482 } else if (technology == shill::kNetworkTechnologyLteAdvanced) {
483 id = IconTypeIsDark(icon_type) ?
484 IDR_AURA_UBER_TRAY_NETWORK_LTE_ADVANCED_DARK :
485 IDR_AURA_UBER_TRAY_NETWORK_LTE_ADVANCED_LIGHT;
486 } else if (technology == shill::kNetworkTechnologyGsm) {
487 id = IconTypeIsDark(icon_type) ?
488 IDR_AURA_UBER_TRAY_NETWORK_GPRS_DARK :
489 IDR_AURA_UBER_TRAY_NETWORK_GPRS_LIGHT;
491 if (id == kUnknownBadgeType)
492 return NULL;
493 else
494 return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(id);
497 const gfx::ImageSkia* BadgeForVPN(IconType icon_type) {
498 return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
499 IDR_AURA_UBER_TRAY_NETWORK_VPN_BADGE);
502 gfx::ImageSkia GetIcon(const NetworkState* network,
503 IconType icon_type,
504 int strength_index) {
505 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
506 if (network->Matches(NetworkTypePattern::Ethernet())) {
507 return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED);
508 } else if (network->Matches(NetworkTypePattern::Wireless())) {
509 DCHECK(strength_index > 0);
510 return GetImageForIndex(
511 ImageTypeForNetworkType(network->type()), icon_type, strength_index);
512 } else if (network->Matches(NetworkTypePattern::VPN())) {
513 return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN);
514 } else {
515 LOG(WARNING) << "Request for icon for unsupported type: "
516 << network->type();
517 return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED);
521 //------------------------------------------------------------------------------
522 // Get connecting images
524 gfx::ImageSkia GetConnectingVpnImage(IconType icon_type) {
525 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
526 const NetworkState* connected_network = NULL;
527 if (icon_type == ICON_TYPE_TRAY) {
528 connected_network =
529 handler->ConnectedNetworkByType(NetworkTypePattern::NonVirtual());
531 double animation = NetworkIconAnimation::GetInstance()->GetAnimation();
533 if (connected_network) {
534 gfx::ImageSkia icon = GetImageForNetwork(connected_network, icon_type);
535 Badges badges;
536 badges.bottom_left = ConnectingVpnBadge(animation);
537 return gfx::ImageSkia(
538 new NetworkIconImageSource(icon, badges), icon.size());
539 } else {
540 gfx::ImageSkia* icon = ConnectingVpnImage(animation);
541 return gfx::ImageSkia(
542 new NetworkIconImageSource(*icon, Badges()), icon->size());
546 gfx::ImageSkia GetConnectingImage(IconType icon_type,
547 const std::string& network_type) {
548 if (network_type == shill::kTypeVPN)
549 return GetConnectingVpnImage(icon_type);
551 ImageType image_type = ImageTypeForNetworkType(network_type);
552 double animation = NetworkIconAnimation::GetInstance()->GetAnimation();
554 gfx::ImageSkia* icon = ConnectingWirelessImage(
555 image_type, icon_type, animation);
556 return gfx::ImageSkia(
557 new NetworkIconImageSource(*icon, Badges()), icon->size());
560 std::string GetConnectingImageUrl(IconType icon_type,
561 const std::string& network_type,
562 float scale_factor) {
563 // Caching the connecting image is complicated and we will never draw more
564 // than a few per frame, so just generate the image url each time.
565 gfx::ImageSkia image = GetConnectingImage(icon_type, network_type);
566 gfx::ImageSkiaRep image_rep = image.GetRepresentation(scale_factor);
567 return webui::GetBitmapDataUrl(image_rep.sk_bitmap());
570 } // namespace
572 //------------------------------------------------------------------------------
573 // NetworkIconImpl
575 NetworkIconImpl::NetworkIconImpl(const std::string& path, IconType icon_type)
576 : network_path_(path),
577 icon_type_(icon_type),
578 strength_index_(-1),
579 technology_badge_(NULL),
580 vpn_badge_(NULL),
581 behind_captive_portal_(false) {
582 // Default image
583 image_ = GetDisconnectedImage(icon_type, shill::kTypeWifi);
586 void NetworkIconImpl::Update(const NetworkState* network) {
587 DCHECK(network);
588 // Determine whether or not we need to update the icon.
589 bool dirty = image_.isNull();
591 // If the network state has changed, the icon needs updating.
592 if (state_ != network->connection_state()) {
593 state_ = network->connection_state();
594 dirty = true;
597 dirty |= UpdatePortalState(network);
599 if (network->Matches(NetworkTypePattern::Wireless())) {
600 dirty |= UpdateWirelessStrengthIndex(network);
603 if (network->Matches(NetworkTypePattern::Cellular()))
604 dirty |= UpdateCellularState(network);
606 if (IconTypeHasVPNBadge(icon_type_) &&
607 network->Matches(NetworkTypePattern::NonVirtual())) {
608 dirty |= UpdateVPNBadge();
611 if (dirty) {
612 // Set the icon and badges based on the network and generate the image.
613 GenerateImage(network);
617 bool NetworkIconImpl::UpdateWirelessStrengthIndex(const NetworkState* network) {
618 int index = GetStrengthIndex(network);
619 if (index != strength_index_) {
620 strength_index_ = index;
621 return true;
623 return false;
626 bool NetworkIconImpl::UpdateCellularState(const NetworkState* network) {
627 bool dirty = false;
628 const gfx::ImageSkia* technology_badge =
629 BadgeForNetworkTechnology(network, icon_type_);
630 if (technology_badge != technology_badge_) {
631 technology_badge_ = technology_badge;
632 dirty = true;
634 std::string roaming_state = network->roaming();
635 if (roaming_state != roaming_state_) {
636 roaming_state_ = roaming_state;
637 dirty = true;
639 return dirty;
642 bool NetworkIconImpl::UpdatePortalState(const NetworkState* network) {
643 bool behind_captive_portal = false;
644 if (network && NetworkPortalDetector::IsInitialized()) {
645 NetworkPortalDetector::CaptivePortalState state =
646 NetworkPortalDetector::Get()->GetCaptivePortalState(network->guid());
647 behind_captive_portal =
648 state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL;
651 if (behind_captive_portal == behind_captive_portal_)
652 return false;
653 behind_captive_portal_ = behind_captive_portal;
654 return true;
657 bool NetworkIconImpl::UpdateVPNBadge() {
658 const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()->
659 ConnectedNetworkByType(NetworkTypePattern::VPN());
660 if (vpn && vpn_badge_ == NULL) {
661 vpn_badge_ = BadgeForVPN(icon_type_);
662 return true;
663 } else if (!vpn && vpn_badge_ != NULL) {
664 vpn_badge_ = NULL;
665 return true;
667 return false;
670 void NetworkIconImpl::GetBadges(const NetworkState* network, Badges* badges) {
671 DCHECK(network);
672 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
673 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
675 const std::string& type = network->type();
676 if (type == shill::kTypeWifi) {
677 if (network->security() != shill::kSecurityNone &&
678 IconTypeIsDark(icon_type_)) {
679 badges->bottom_right = rb.GetImageSkiaNamed(
680 IDR_AURA_UBER_TRAY_NETWORK_SECURE_DARK);
682 } else if (type == shill::kTypeWimax) {
683 technology_badge_ = rb.GetImageSkiaNamed(
684 IconTypeIsDark(icon_type_) ?
685 IDR_AURA_UBER_TRAY_NETWORK_4G_DARK :
686 IDR_AURA_UBER_TRAY_NETWORK_4G_LIGHT);
687 } else if (type == shill::kTypeCellular) {
688 if (network->roaming() == shill::kRoamingStateRoaming) {
689 // For networks that are always in roaming don't show roaming badge.
690 const DeviceState* device =
691 handler->GetDeviceState(network->device_path());
692 LOG_IF(WARNING, !device) << "Could not find device state for "
693 << network->device_path();
694 if (!device || !device->provider_requires_roaming()) {
695 badges->bottom_right = rb.GetImageSkiaNamed(
696 IconTypeIsDark(icon_type_) ?
697 IDR_AURA_UBER_TRAY_NETWORK_ROAMING_DARK :
698 IDR_AURA_UBER_TRAY_NETWORK_ROAMING_LIGHT);
702 if (!network->IsConnectingState()) {
703 badges->top_left = technology_badge_;
704 badges->bottom_left = vpn_badge_;
707 if (behind_captive_portal_) {
708 gfx::ImageSkia* badge = rb.GetImageSkiaNamed(
709 IconTypeIsDark(icon_type_) ?
710 IDR_AURA_UBER_TRAY_NETWORK_PORTAL_DARK :
711 IDR_AURA_UBER_TRAY_NETWORK_PORTAL_LIGHT);
712 badges->bottom_right = badge;
716 void NetworkIconImpl::GenerateImage(const NetworkState* network) {
717 DCHECK(network);
718 gfx::ImageSkia icon = GetIcon(network, icon_type_, strength_index_);
719 Badges badges;
720 GetBadges(network, &badges);
721 image_ = gfx::ImageSkia(
722 new NetworkIconImageSource(icon, badges), icon.size());
723 image_urls_.clear();
726 const std::string& NetworkIconImpl::GetImageUrl(float scale_factor) {
727 ImageUrlMap::iterator iter = image_urls_.find(scale_factor);
728 if (iter != image_urls_.end())
729 return iter->second;
731 VLOG(2) << "Generating bitmap URL for: " << network_path_;
732 gfx::ImageSkiaRep image_rep = image_.GetRepresentation(scale_factor);
733 iter = image_urls_.insert(std::make_pair(
734 scale_factor, webui::GetBitmapDataUrl(image_rep.sk_bitmap()))).first;
735 return iter->second;
738 namespace {
740 NetworkIconImpl* FindAndUpdateImageImpl(const NetworkState* network,
741 IconType icon_type) {
742 // Find or add the icon.
743 NetworkIconMap* icon_map = GetIconMap(icon_type);
744 NetworkIconImpl* icon;
745 NetworkIconMap::iterator iter = icon_map->find(network->path());
746 if (iter == icon_map->end()) {
747 icon = new NetworkIconImpl(network->path(), icon_type);
748 icon_map->insert(std::make_pair(network->path(), icon));
749 } else {
750 icon = iter->second;
753 // Update and return the icon's image.
754 icon->Update(network);
755 return icon;
758 } // namespace
760 //------------------------------------------------------------------------------
761 // Public interface
763 gfx::ImageSkia GetImageForNetwork(const NetworkState* network,
764 IconType icon_type) {
765 DCHECK(network);
766 if (!network->visible())
767 return GetDisconnectedImage(icon_type, network->type());
769 if (network->IsConnectingState())
770 return GetConnectingImage(icon_type, network->type());
772 NetworkIconImpl* icon = FindAndUpdateImageImpl(network, icon_type);
773 return icon->image();
776 std::string GetImageUrlForNetwork(const NetworkState* network,
777 IconType icon_type,
778 float scale_factor) {
779 DCHECK(network);
780 // Handle connecting icons.
781 if (network->IsConnectingState())
782 return GetConnectingImageUrl(icon_type, network->type(), scale_factor);
784 NetworkIconImpl* icon = FindAndUpdateImageImpl(network, icon_type);
785 return icon->GetImageUrl(scale_factor);
788 gfx::ImageSkia GetImageForConnectedNetwork(IconType icon_type,
789 const std::string& network_type) {
790 return GetConnectedImage(icon_type, network_type);
793 gfx::ImageSkia GetImageForConnectingNetwork(IconType icon_type,
794 const std::string& network_type) {
795 return GetConnectingImage(icon_type, network_type);
798 gfx::ImageSkia GetImageForDisconnectedNetwork(IconType icon_type,
799 const std::string& network_type) {
800 return GetDisconnectedImage(icon_type, network_type);
803 base::string16 GetLabelForNetwork(const chromeos::NetworkState* network,
804 IconType icon_type) {
805 DCHECK(network);
806 std::string activation_state = network->activation_state();
807 if (icon_type == ICON_TYPE_LIST) {
808 // Show "<network>: [Connecting|Activating]..."
809 if (network->IsConnectingState()) {
810 return l10n_util::GetStringFUTF16(
811 IDS_ASH_STATUS_TRAY_NETWORK_LIST_CONNECTING,
812 base::UTF8ToUTF16(network->name()));
814 if (activation_state == shill::kActivationStateActivating) {
815 return l10n_util::GetStringFUTF16(
816 IDS_ASH_STATUS_TRAY_NETWORK_LIST_ACTIVATING,
817 base::UTF8ToUTF16(network->name()));
819 // Show "Activate <network>" in list view only.
820 if (activation_state == shill::kActivationStateNotActivated ||
821 activation_state == shill::kActivationStatePartiallyActivated) {
822 return l10n_util::GetStringFUTF16(
823 IDS_ASH_STATUS_TRAY_NETWORK_LIST_ACTIVATE,
824 base::UTF8ToUTF16(network->name()));
826 } else {
827 // Show "[Connected to|Connecting to|Activating] <network>" (non-list view).
828 if (network->IsConnectedState()) {
829 return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED,
830 base::UTF8ToUTF16(network->name()));
832 if (network->IsConnectingState()) {
833 return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_CONNECTING,
834 base::UTF8ToUTF16(network->name()));
836 if (activation_state == shill::kActivationStateActivating) {
837 return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_ACTIVATING,
838 base::UTF8ToUTF16(network->name()));
842 // Otherwise just show the network name or 'Ethernet'.
843 if (network->Matches(NetworkTypePattern::Ethernet())) {
844 return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ETHERNET);
845 } else {
846 return base::UTF8ToUTF16(network->name());
850 int GetCellularUninitializedMsg() {
851 static base::Time s_uninitialized_state_time;
852 static int s_uninitialized_msg(0);
854 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
855 if (handler->GetTechnologyState(NetworkTypePattern::Mobile())
856 == NetworkStateHandler::TECHNOLOGY_UNINITIALIZED) {
857 s_uninitialized_msg = IDS_ASH_STATUS_TRAY_INITIALIZING_CELLULAR;
858 s_uninitialized_state_time = base::Time::Now();
859 return s_uninitialized_msg;
860 } else if (handler->GetScanningByType(NetworkTypePattern::Mobile())) {
861 s_uninitialized_msg = IDS_ASH_STATUS_TRAY_CELLULAR_SCANNING;
862 s_uninitialized_state_time = base::Time::Now();
863 return s_uninitialized_msg;
865 // There can be a delay between leaving the Initializing state and when
866 // a Cellular device shows up, so keep showing the initializing
867 // animation for a bit to avoid flashing the disconnect icon.
868 const int kInitializingDelaySeconds = 1;
869 base::TimeDelta dtime = base::Time::Now() - s_uninitialized_state_time;
870 if (dtime.InSeconds() < kInitializingDelaySeconds)
871 return s_uninitialized_msg;
872 return 0;
875 void GetDefaultNetworkImageAndLabel(IconType icon_type,
876 gfx::ImageSkia* image,
877 base::string16* label,
878 bool* animating) {
879 NetworkStateHandler* state_handler =
880 NetworkHandler::Get()->network_state_handler();
881 NetworkConnectionHandler* connect_handler =
882 NetworkHandler::Get()->network_connection_handler();
883 const NetworkState* connected_network =
884 state_handler->ConnectedNetworkByType(NetworkTypePattern::NonVirtual());
885 const NetworkState* connecting_network =
886 state_handler->ConnectingNetworkByType(NetworkTypePattern::Wireless());
887 if (!connecting_network && icon_type == ICON_TYPE_TRAY) {
888 connecting_network =
889 state_handler->ConnectingNetworkByType(NetworkTypePattern::VPN());
892 const NetworkState* network;
893 // If we are connecting to a network, and there is either no connected
894 // network, or the connection was user requested, use the connecting
895 // network.
896 if (connecting_network &&
897 (!connected_network ||
898 connect_handler->HasConnectingNetwork(connecting_network->path()))) {
899 network = connecting_network;
900 } else {
901 network = connected_network;
904 // Don't show ethernet in the tray
905 if (icon_type == ICON_TYPE_TRAY && network &&
906 network->Matches(NetworkTypePattern::Ethernet())) {
907 *image = gfx::ImageSkia();
908 *animating = false;
909 return;
912 if (!network) {
913 // If no connecting network, check if we are activating a network.
914 const NetworkState* mobile_network =
915 state_handler->FirstNetworkByType(NetworkTypePattern::Mobile());
916 if (mobile_network && (mobile_network->activation_state() ==
917 shill::kActivationStateActivating)) {
918 network = mobile_network;
921 if (!network) {
922 // If no connecting network, check for cellular initializing.
923 int uninitialized_msg = GetCellularUninitializedMsg();
924 if (uninitialized_msg != 0) {
925 *image = GetImageForConnectingNetwork(icon_type, shill::kTypeCellular);
926 if (label)
927 *label = l10n_util::GetStringUTF16(uninitialized_msg);
928 *animating = true;
929 } else {
930 // Otherwise show the disconnected wifi icon.
931 *image = GetImageForDisconnectedNetwork(icon_type, shill::kTypeWifi);
932 if (label) {
933 *label = l10n_util::GetStringUTF16(
934 IDS_ASH_STATUS_TRAY_NETWORK_NOT_CONNECTED);
936 *animating = false;
938 return;
940 *animating = network->IsConnectingState();
941 // Get icon and label for connected or connecting network.
942 *image = GetImageForNetwork(network, icon_type);
943 if (label)
944 *label = GetLabelForNetwork(network, icon_type);
947 void PurgeNetworkIconCache() {
948 NetworkStateHandler::NetworkStateList networks;
949 NetworkHandler::Get()->network_state_handler()->GetVisibleNetworkList(
950 &networks);
951 std::set<std::string> network_paths;
952 for (NetworkStateHandler::NetworkStateList::iterator iter = networks.begin();
953 iter != networks.end(); ++iter) {
954 network_paths.insert((*iter)->path());
956 PurgeIconMap(ICON_TYPE_TRAY, network_paths);
957 PurgeIconMap(ICON_TYPE_DEFAULT_VIEW, network_paths);
958 PurgeIconMap(ICON_TYPE_LIST, network_paths);
961 } // namespace network_icon
962 } // namespace ui