Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / chromeos / network / network_icon.cc
blob51cd7c26bcbe891ded2f78b10f2deae9b6af46e2
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/geometry/rect.h"
23 #include "ui/gfx/geometry/size_conversions.h"
24 #include "ui/gfx/image/image_skia_operations.h"
25 #include "ui/gfx/image/image_skia_source.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 const gfx::ImageSkia& image() const { return image_; }
67 private:
68 // Updates |strength_index_| for wireless networks. Returns true if changed.
69 bool UpdateWirelessStrengthIndex(const chromeos::NetworkState* network);
71 // Updates the local state for cellular networks. Returns true if changed.
72 bool UpdateCellularState(const chromeos::NetworkState* network);
74 // Updates the portal state for wireless networks. Returns true if changed.
75 bool UpdatePortalState(const chromeos::NetworkState* network);
77 // Updates the VPN badge. Returns true if changed.
78 bool UpdateVPNBadge();
80 // Gets |badges| based on |network| and the current state.
81 void GetBadges(const NetworkState* network, Badges* badges);
83 // Gets the appropriate icon and badges and composites the image.
84 void GenerateImage(const chromeos::NetworkState* network);
86 // Network path, used for debugging.
87 std::string network_path_;
89 // Defines color theme and VPN badging
90 const IconType icon_type_;
92 // Cached state of the network when the icon was last generated.
93 std::string state_;
95 // Cached strength index of the network when the icon was last generated.
96 int strength_index_;
98 // Cached technology badge for the network when the icon was last generated.
99 const gfx::ImageSkia* technology_badge_;
101 // Cached vpn badge for the network when the icon was last generated.
102 const gfx::ImageSkia* vpn_badge_;
104 // Cached roaming state of the network when the icon was last generated.
105 std::string roaming_state_;
107 // Cached portal state of the network when the icon was last generated.
108 bool behind_captive_portal_;
110 // Generated icon image.
111 gfx::ImageSkia image_;
113 DISALLOW_COPY_AND_ASSIGN(NetworkIconImpl);
116 //------------------------------------------------------------------------------
117 // Maintain a static (global) icon map. Note: Icons are never destroyed;
118 // it is assumed that a finite and reasonable number of network icons will be
119 // created during a session.
121 typedef std::map<std::string, NetworkIconImpl*> NetworkIconMap;
123 NetworkIconMap* GetIconMapInstance(IconType icon_type, bool create) {
124 typedef std::map<IconType, NetworkIconMap*> IconTypeMap;
125 static IconTypeMap* s_icon_map = NULL;
126 if (s_icon_map == NULL) {
127 if (!create)
128 return NULL;
129 s_icon_map = new IconTypeMap;
131 if (s_icon_map->count(icon_type) == 0) {
132 if (!create)
133 return NULL;
134 (*s_icon_map)[icon_type] = new NetworkIconMap;
136 return (*s_icon_map)[icon_type];
139 NetworkIconMap* GetIconMap(IconType icon_type) {
140 return GetIconMapInstance(icon_type, true);
143 void PurgeIconMap(IconType icon_type,
144 const std::set<std::string>& network_paths) {
145 NetworkIconMap* icon_map = GetIconMapInstance(icon_type, false);
146 if (!icon_map)
147 return;
148 for (NetworkIconMap::iterator loop_iter = icon_map->begin();
149 loop_iter != icon_map->end(); ) {
150 NetworkIconMap::iterator cur_iter = loop_iter++;
151 if (network_paths.count(cur_iter->first) == 0) {
152 delete cur_iter->second;
153 icon_map->erase(cur_iter);
158 //------------------------------------------------------------------------------
159 // Utilities for generating icon images.
161 // 'NONE' will default to ARCS behavior where appropriate (e.g. no network or
162 // if a new type gets added).
163 enum ImageType {
164 ARCS,
165 BARS,
166 NONE
169 // Amount to fade icons while connecting.
170 const double kConnectingImageAlpha = 0.5;
172 // Images for strength bars for wired networks.
173 const int kNumBarsImages = 5;
175 // Imagaes for strength arcs for wireless networks.
176 const int kNumArcsImages = 5;
178 // Number of discrete images to use for alpha fade animation
179 const int kNumFadeImages = 10;
181 //------------------------------------------------------------------------------
182 // Classes for generating scaled images.
184 const SkBitmap GetEmptyBitmap(const gfx::Size pixel_size) {
185 typedef std::pair<int, int> SizeKey;
186 typedef std::map<SizeKey, SkBitmap> SizeBitmapMap;
187 static SizeBitmapMap* s_empty_bitmaps = new SizeBitmapMap;
189 SizeKey key(pixel_size.width(), pixel_size.height());
191 SizeBitmapMap::iterator iter = s_empty_bitmaps->find(key);
192 if (iter != s_empty_bitmaps->end())
193 return iter->second;
195 SkBitmap empty;
196 empty.allocN32Pixels(key.first, key.second);
197 empty.eraseARGB(0, 0, 0, 0);
198 (*s_empty_bitmaps)[key] = empty;
199 return empty;
202 class EmptyImageSource: public gfx::ImageSkiaSource {
203 public:
204 explicit EmptyImageSource(const gfx::Size& size)
205 : size_(size) {
208 gfx::ImageSkiaRep GetImageForScale(float scale) override {
209 gfx::Size pixel_size = gfx::ToFlooredSize(gfx::ScaleSize(size_, scale));
210 SkBitmap empty_bitmap = GetEmptyBitmap(pixel_size);
211 return gfx::ImageSkiaRep(empty_bitmap, scale);
214 private:
215 const gfx::Size size_;
217 DISALLOW_COPY_AND_ASSIGN(EmptyImageSource);
220 // This defines how we assemble a network icon.
221 class NetworkIconImageSource : public gfx::ImageSkiaSource {
222 public:
223 NetworkIconImageSource(const gfx::ImageSkia& icon, const Badges& badges)
224 : icon_(icon),
225 badges_(badges) {
227 ~NetworkIconImageSource() override {}
229 // TODO(pkotwicz): Figure out what to do when a new image resolution becomes
230 // available.
231 gfx::ImageSkiaRep GetImageForScale(float scale) override {
232 gfx::ImageSkiaRep icon_rep = icon_.GetRepresentation(scale);
233 if (icon_rep.is_null())
234 return gfx::ImageSkiaRep();
235 gfx::Canvas canvas(icon_rep, false);
236 if (badges_.top_left)
237 canvas.DrawImageInt(*badges_.top_left, 0, 0);
238 if (badges_.top_right)
239 canvas.DrawImageInt(*badges_.top_right,
240 icon_.width() - badges_.top_right->width(), 0);
241 if (badges_.bottom_left) {
242 canvas.DrawImageInt(*badges_.bottom_left,
243 0, icon_.height() - badges_.bottom_left->height());
245 if (badges_.bottom_right) {
246 canvas.DrawImageInt(*badges_.bottom_right,
247 icon_.width() - badges_.bottom_right->width(),
248 icon_.height() - badges_.bottom_right->height());
250 return canvas.ExtractImageRep();
253 private:
254 const gfx::ImageSkia icon_;
255 const Badges badges_;
257 DISALLOW_COPY_AND_ASSIGN(NetworkIconImageSource);
260 //------------------------------------------------------------------------------
261 // Utilities for extracting icon images.
263 bool IconTypeIsDark(IconType icon_type) {
264 return (icon_type != ICON_TYPE_TRAY);
267 bool IconTypeHasVPNBadge(IconType icon_type) {
268 return (icon_type != ICON_TYPE_LIST);
271 int NumImagesForType(ImageType type) {
272 return (type == BARS) ? kNumBarsImages : kNumArcsImages;
275 gfx::ImageSkia* BaseImageForType(ImageType image_type, IconType icon_type) {
276 gfx::ImageSkia* image;
277 if (image_type == BARS) {
278 image = ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
279 IconTypeIsDark(icon_type) ?
280 IDR_AURA_UBER_TRAY_NETWORK_BARS_DARK :
281 IDR_AURA_UBER_TRAY_NETWORK_BARS_LIGHT);
282 } else {
283 image = ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
284 IconTypeIsDark(icon_type) ?
285 IDR_AURA_UBER_TRAY_NETWORK_ARCS_DARK :
286 IDR_AURA_UBER_TRAY_NETWORK_ARCS_LIGHT);
288 return image;
291 ImageType ImageTypeForNetworkType(const std::string& type) {
292 if (type == shill::kTypeWifi)
293 return ARCS;
294 else if (type == shill::kTypeCellular || type == shill::kTypeWimax)
295 return BARS;
296 return NONE;
299 gfx::ImageSkia GetImageForIndex(ImageType image_type,
300 IconType icon_type,
301 int index) {
302 int num_images = NumImagesForType(image_type);
303 if (index < 0 || index >= num_images)
304 return gfx::ImageSkia();
305 gfx::ImageSkia* images = BaseImageForType(image_type, icon_type);
306 int width = images->width();
307 int height = images->height() / num_images;
308 return gfx::ImageSkiaOperations::ExtractSubset(*images,
309 gfx::Rect(0, index * height, width, height));
312 const gfx::ImageSkia GetConnectedImage(IconType icon_type,
313 const std::string& network_type) {
314 if (network_type == shill::kTypeVPN) {
315 return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
316 IDR_AURA_UBER_TRAY_NETWORK_VPN);
318 ImageType image_type = ImageTypeForNetworkType(network_type);
319 const int connected_index = NumImagesForType(image_type) - 1;
320 return GetImageForIndex(image_type, icon_type, connected_index);
323 const gfx::ImageSkia GetDisconnectedImage(IconType icon_type,
324 const std::string& network_type) {
325 if (network_type == shill::kTypeVPN) {
326 // Note: same as connected image, shouldn't normally be seen.
327 return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
328 IDR_AURA_UBER_TRAY_NETWORK_VPN);
330 ImageType image_type = ImageTypeForNetworkType(network_type);
331 const int disconnected_index = 0;
332 return GetImageForIndex(image_type, icon_type, disconnected_index);
335 gfx::ImageSkia* ConnectingWirelessImage(ImageType image_type,
336 IconType icon_type,
337 double animation) {
338 static gfx::ImageSkia* s_bars_images_dark[kNumBarsImages - 1];
339 static gfx::ImageSkia* s_bars_images_light[kNumBarsImages - 1];
340 static gfx::ImageSkia* s_arcs_images_dark[kNumArcsImages - 1];
341 static gfx::ImageSkia* s_arcs_images_light[kNumArcsImages - 1];
342 int image_count = NumImagesForType(image_type) - 1;
343 int index = animation * nextafter(static_cast<float>(image_count), 0);
344 index = std::max(std::min(index, image_count - 1), 0);
345 gfx::ImageSkia** images;
346 bool dark = IconTypeIsDark(icon_type);
347 if (image_type == BARS)
348 images = dark ? s_bars_images_dark : s_bars_images_light;
349 else
350 images = dark ? s_arcs_images_dark : s_arcs_images_light;
351 if (!images[index]) {
352 // Lazily cache images.
353 gfx::ImageSkia source = GetImageForIndex(image_type, icon_type, index + 1);
354 images[index] = new gfx::ImageSkia(
355 gfx::ImageSkiaOperations::CreateBlendedImage(
356 gfx::ImageSkia(new EmptyImageSource(source.size()), source.size()),
357 source,
358 kConnectingImageAlpha));
360 return images[index];
363 gfx::ImageSkia* ConnectingVpnImage(double animation) {
364 int index = animation * nextafter(static_cast<float>(kNumFadeImages), 0);
365 static gfx::ImageSkia* s_vpn_images[kNumFadeImages];
366 if (!s_vpn_images[index]) {
367 // Lazily cache images.
368 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
369 gfx::ImageSkia* icon = rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN);
370 s_vpn_images[index] = new gfx::ImageSkia(
371 gfx::ImageSkiaOperations::CreateBlendedImage(
372 gfx::ImageSkia(new EmptyImageSource(icon->size()), icon->size()),
373 *icon,
374 animation));
376 return s_vpn_images[index];
379 gfx::ImageSkia* ConnectingVpnBadge(double animation) {
380 int index = animation * nextafter(static_cast<float>(kNumFadeImages), 0);
381 static gfx::ImageSkia* s_vpn_badges[kNumFadeImages];
382 if (!s_vpn_badges[index]) {
383 // Lazily cache images.
384 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
385 gfx::ImageSkia* icon =
386 rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED); // For size
387 gfx::ImageSkia* badge =
388 rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN_BADGE);
389 s_vpn_badges[index] = new gfx::ImageSkia(
390 gfx::ImageSkiaOperations::CreateBlendedImage(
391 gfx::ImageSkia(new EmptyImageSource(icon->size()), icon->size()),
392 *badge,
393 animation));
395 return s_vpn_badges[index];
398 int StrengthIndex(int strength, int count) {
399 // Return an index in the range [1, count-1].
400 const float findex = (static_cast<float>(strength) / 100.0f) *
401 nextafter(static_cast<float>(count - 1), 0);
402 int index = 1 + static_cast<int>(findex);
403 index = std::max(std::min(index, count - 1), 1);
404 return index;
407 int GetStrengthIndex(const NetworkState* network) {
408 ImageType image_type = ImageTypeForNetworkType(network->type());
409 if (image_type == ARCS)
410 return StrengthIndex(network->signal_strength(), kNumArcsImages);
411 else if (image_type == BARS)
412 return StrengthIndex(network->signal_strength(), kNumBarsImages);
413 return 0;
416 const gfx::ImageSkia* BadgeForNetworkTechnology(const NetworkState* network,
417 IconType icon_type) {
418 const int kUnknownBadgeType = -1;
419 int id = kUnknownBadgeType;
420 const std::string& technology = network->network_technology();
421 if (technology == shill::kNetworkTechnologyEvdo) {
422 id = IconTypeIsDark(icon_type) ?
423 IDR_AURA_UBER_TRAY_NETWORK_EVDO_DARK :
424 IDR_AURA_UBER_TRAY_NETWORK_EVDO_LIGHT;
425 } else if (technology == shill::kNetworkTechnology1Xrtt) {
426 id = IDR_AURA_UBER_TRAY_NETWORK_1X;
427 } else if (technology == shill::kNetworkTechnologyGprs) {
428 id = IconTypeIsDark(icon_type) ?
429 IDR_AURA_UBER_TRAY_NETWORK_GPRS_DARK :
430 IDR_AURA_UBER_TRAY_NETWORK_GPRS_LIGHT;
431 } else if (technology == shill::kNetworkTechnologyEdge) {
432 id = IconTypeIsDark(icon_type) ?
433 IDR_AURA_UBER_TRAY_NETWORK_EDGE_DARK :
434 IDR_AURA_UBER_TRAY_NETWORK_EDGE_LIGHT;
435 } else if (technology == shill::kNetworkTechnologyUmts) {
436 id = IconTypeIsDark(icon_type) ?
437 IDR_AURA_UBER_TRAY_NETWORK_3G_DARK :
438 IDR_AURA_UBER_TRAY_NETWORK_3G_LIGHT;
439 } else if (technology == shill::kNetworkTechnologyHspa) {
440 id = IconTypeIsDark(icon_type) ?
441 IDR_AURA_UBER_TRAY_NETWORK_HSPA_DARK :
442 IDR_AURA_UBER_TRAY_NETWORK_HSPA_LIGHT;
443 } else if (technology == shill::kNetworkTechnologyHspaPlus) {
444 id = IconTypeIsDark(icon_type) ?
445 IDR_AURA_UBER_TRAY_NETWORK_HSPA_PLUS_DARK :
446 IDR_AURA_UBER_TRAY_NETWORK_HSPA_PLUS_LIGHT;
447 } else if (technology == shill::kNetworkTechnologyLte) {
448 id = IconTypeIsDark(icon_type) ?
449 IDR_AURA_UBER_TRAY_NETWORK_LTE_DARK :
450 IDR_AURA_UBER_TRAY_NETWORK_LTE_LIGHT;
451 } else if (technology == shill::kNetworkTechnologyLteAdvanced) {
452 id = IconTypeIsDark(icon_type) ?
453 IDR_AURA_UBER_TRAY_NETWORK_LTE_ADVANCED_DARK :
454 IDR_AURA_UBER_TRAY_NETWORK_LTE_ADVANCED_LIGHT;
455 } else if (technology == shill::kNetworkTechnologyGsm) {
456 id = IconTypeIsDark(icon_type) ?
457 IDR_AURA_UBER_TRAY_NETWORK_GPRS_DARK :
458 IDR_AURA_UBER_TRAY_NETWORK_GPRS_LIGHT;
460 if (id == kUnknownBadgeType)
461 return NULL;
462 else
463 return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(id);
466 const gfx::ImageSkia* BadgeForVPN(IconType icon_type) {
467 return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
468 IDR_AURA_UBER_TRAY_NETWORK_VPN_BADGE);
471 gfx::ImageSkia GetIcon(const NetworkState* network,
472 IconType icon_type,
473 int strength_index) {
474 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
475 if (network->Matches(NetworkTypePattern::Ethernet())) {
476 return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED);
477 } else if (network->Matches(NetworkTypePattern::Wireless())) {
478 DCHECK(strength_index > 0);
479 return GetImageForIndex(
480 ImageTypeForNetworkType(network->type()), icon_type, strength_index);
481 } else if (network->Matches(NetworkTypePattern::VPN())) {
482 return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN);
483 } else {
484 LOG(WARNING) << "Request for icon for unsupported type: "
485 << network->type();
486 return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED);
490 //------------------------------------------------------------------------------
491 // Get connecting images
493 gfx::ImageSkia GetConnectingVpnImage(IconType icon_type) {
494 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
495 const NetworkState* connected_network = NULL;
496 if (icon_type == ICON_TYPE_TRAY) {
497 connected_network =
498 handler->ConnectedNetworkByType(NetworkTypePattern::NonVirtual());
500 double animation = NetworkIconAnimation::GetInstance()->GetAnimation();
502 if (connected_network) {
503 gfx::ImageSkia icon = GetImageForNetwork(connected_network, icon_type);
504 Badges badges;
505 badges.bottom_left = ConnectingVpnBadge(animation);
506 return gfx::ImageSkia(
507 new NetworkIconImageSource(icon, badges), icon.size());
508 } else {
509 gfx::ImageSkia* icon = ConnectingVpnImage(animation);
510 return gfx::ImageSkia(
511 new NetworkIconImageSource(*icon, Badges()), icon->size());
515 gfx::ImageSkia GetConnectingImage(IconType icon_type,
516 const std::string& network_type) {
517 if (network_type == shill::kTypeVPN)
518 return GetConnectingVpnImage(icon_type);
520 ImageType image_type = ImageTypeForNetworkType(network_type);
521 double animation = NetworkIconAnimation::GetInstance()->GetAnimation();
523 gfx::ImageSkia* icon = ConnectingWirelessImage(
524 image_type, icon_type, animation);
525 return gfx::ImageSkia(
526 new NetworkIconImageSource(*icon, Badges()), icon->size());
529 } // namespace
531 //------------------------------------------------------------------------------
532 // NetworkIconImpl
534 NetworkIconImpl::NetworkIconImpl(const std::string& path, IconType icon_type)
535 : network_path_(path),
536 icon_type_(icon_type),
537 strength_index_(-1),
538 technology_badge_(NULL),
539 vpn_badge_(NULL),
540 behind_captive_portal_(false) {
541 // Default image
542 image_ = GetDisconnectedImage(icon_type, shill::kTypeWifi);
545 void NetworkIconImpl::Update(const NetworkState* network) {
546 DCHECK(network);
547 // Determine whether or not we need to update the icon.
548 bool dirty = image_.isNull();
550 // If the network state has changed, the icon needs updating.
551 if (state_ != network->connection_state()) {
552 state_ = network->connection_state();
553 dirty = true;
556 dirty |= UpdatePortalState(network);
558 if (network->Matches(NetworkTypePattern::Wireless())) {
559 dirty |= UpdateWirelessStrengthIndex(network);
562 if (network->Matches(NetworkTypePattern::Cellular()))
563 dirty |= UpdateCellularState(network);
565 if (IconTypeHasVPNBadge(icon_type_) &&
566 network->Matches(NetworkTypePattern::NonVirtual())) {
567 dirty |= UpdateVPNBadge();
570 if (dirty) {
571 // Set the icon and badges based on the network and generate the image.
572 GenerateImage(network);
576 bool NetworkIconImpl::UpdateWirelessStrengthIndex(const NetworkState* network) {
577 int index = GetStrengthIndex(network);
578 if (index != strength_index_) {
579 strength_index_ = index;
580 return true;
582 return false;
585 bool NetworkIconImpl::UpdateCellularState(const NetworkState* network) {
586 bool dirty = false;
587 const gfx::ImageSkia* technology_badge =
588 BadgeForNetworkTechnology(network, icon_type_);
589 if (technology_badge != technology_badge_) {
590 technology_badge_ = technology_badge;
591 dirty = true;
593 std::string roaming_state = network->roaming();
594 if (roaming_state != roaming_state_) {
595 roaming_state_ = roaming_state;
596 dirty = true;
598 return dirty;
601 bool NetworkIconImpl::UpdatePortalState(const NetworkState* network) {
602 bool behind_captive_portal = false;
603 if (network && NetworkPortalDetector::IsInitialized()) {
604 NetworkPortalDetector::CaptivePortalState state =
605 NetworkPortalDetector::Get()->GetCaptivePortalState(network->guid());
606 behind_captive_portal =
607 state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL;
610 if (behind_captive_portal == behind_captive_portal_)
611 return false;
612 behind_captive_portal_ = behind_captive_portal;
613 return true;
616 bool NetworkIconImpl::UpdateVPNBadge() {
617 const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()->
618 ConnectedNetworkByType(NetworkTypePattern::VPN());
619 if (vpn && vpn_badge_ == NULL) {
620 vpn_badge_ = BadgeForVPN(icon_type_);
621 return true;
622 } else if (!vpn && vpn_badge_ != NULL) {
623 vpn_badge_ = NULL;
624 return true;
626 return false;
629 void NetworkIconImpl::GetBadges(const NetworkState* network, Badges* badges) {
630 DCHECK(network);
631 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
632 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
634 const std::string& type = network->type();
635 if (type == shill::kTypeWifi) {
636 if (network->security_class() != shill::kSecurityNone &&
637 IconTypeIsDark(icon_type_)) {
638 badges->bottom_right = rb.GetImageSkiaNamed(
639 IDR_AURA_UBER_TRAY_NETWORK_SECURE_DARK);
641 } else if (type == shill::kTypeWimax) {
642 technology_badge_ = rb.GetImageSkiaNamed(
643 IconTypeIsDark(icon_type_) ?
644 IDR_AURA_UBER_TRAY_NETWORK_4G_DARK :
645 IDR_AURA_UBER_TRAY_NETWORK_4G_LIGHT);
646 } else if (type == shill::kTypeCellular) {
647 if (network->roaming() == shill::kRoamingStateRoaming) {
648 // For networks that are always in roaming don't show roaming badge.
649 const DeviceState* device =
650 handler->GetDeviceState(network->device_path());
651 LOG_IF(WARNING, !device) << "Could not find device state for "
652 << network->device_path();
653 if (!device || !device->provider_requires_roaming()) {
654 badges->bottom_right = rb.GetImageSkiaNamed(
655 IconTypeIsDark(icon_type_) ?
656 IDR_AURA_UBER_TRAY_NETWORK_ROAMING_DARK :
657 IDR_AURA_UBER_TRAY_NETWORK_ROAMING_LIGHT);
661 if (!network->IsConnectingState()) {
662 badges->top_left = technology_badge_;
663 badges->bottom_left = vpn_badge_;
666 if (behind_captive_portal_) {
667 gfx::ImageSkia* badge = rb.GetImageSkiaNamed(
668 IconTypeIsDark(icon_type_) ?
669 IDR_AURA_UBER_TRAY_NETWORK_PORTAL_DARK :
670 IDR_AURA_UBER_TRAY_NETWORK_PORTAL_LIGHT);
671 badges->bottom_right = badge;
675 void NetworkIconImpl::GenerateImage(const NetworkState* network) {
676 DCHECK(network);
677 gfx::ImageSkia icon = GetIcon(network, icon_type_, strength_index_);
678 Badges badges;
679 GetBadges(network, &badges);
680 image_ = gfx::ImageSkia(
681 new NetworkIconImageSource(icon, badges), icon.size());
684 namespace {
686 NetworkIconImpl* FindAndUpdateImageImpl(const NetworkState* network,
687 IconType icon_type) {
688 // Find or add the icon.
689 NetworkIconMap* icon_map = GetIconMap(icon_type);
690 NetworkIconImpl* icon;
691 NetworkIconMap::iterator iter = icon_map->find(network->path());
692 if (iter == icon_map->end()) {
693 icon = new NetworkIconImpl(network->path(), icon_type);
694 icon_map->insert(std::make_pair(network->path(), icon));
695 } else {
696 icon = iter->second;
699 // Update and return the icon's image.
700 icon->Update(network);
701 return icon;
704 } // namespace
706 //------------------------------------------------------------------------------
707 // Public interface
709 gfx::ImageSkia GetImageForNetwork(const NetworkState* network,
710 IconType icon_type) {
711 DCHECK(network);
712 if (!network->visible())
713 return GetDisconnectedImage(icon_type, network->type());
715 if (network->IsConnectingState())
716 return GetConnectingImage(icon_type, network->type());
718 NetworkIconImpl* icon = FindAndUpdateImageImpl(network, icon_type);
719 return icon->image();
722 gfx::ImageSkia GetImageForConnectedNetwork(IconType icon_type,
723 const std::string& network_type) {
724 return GetConnectedImage(icon_type, network_type);
727 gfx::ImageSkia GetImageForConnectingNetwork(IconType icon_type,
728 const std::string& network_type) {
729 return GetConnectingImage(icon_type, network_type);
732 gfx::ImageSkia GetImageForDisconnectedNetwork(IconType icon_type,
733 const std::string& network_type) {
734 return GetDisconnectedImage(icon_type, network_type);
737 base::string16 GetLabelForNetwork(const chromeos::NetworkState* network,
738 IconType icon_type) {
739 DCHECK(network);
740 std::string activation_state = network->activation_state();
741 if (icon_type == ICON_TYPE_LIST) {
742 // Show "<network>: [Connecting|Activating]..."
743 if (network->IsConnectingState()) {
744 return l10n_util::GetStringFUTF16(
745 IDS_ASH_STATUS_TRAY_NETWORK_LIST_CONNECTING,
746 base::UTF8ToUTF16(network->name()));
748 if (activation_state == shill::kActivationStateActivating) {
749 return l10n_util::GetStringFUTF16(
750 IDS_ASH_STATUS_TRAY_NETWORK_LIST_ACTIVATING,
751 base::UTF8ToUTF16(network->name()));
753 // Show "Activate <network>" in list view only.
754 if (activation_state == shill::kActivationStateNotActivated ||
755 activation_state == shill::kActivationStatePartiallyActivated) {
756 return l10n_util::GetStringFUTF16(
757 IDS_ASH_STATUS_TRAY_NETWORK_LIST_ACTIVATE,
758 base::UTF8ToUTF16(network->name()));
760 } else {
761 // Show "[Connected to|Connecting to|Activating] <network>" (non-list view).
762 if (network->IsConnectedState()) {
763 return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED,
764 base::UTF8ToUTF16(network->name()));
766 if (network->IsConnectingState()) {
767 return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_CONNECTING,
768 base::UTF8ToUTF16(network->name()));
770 if (activation_state == shill::kActivationStateActivating) {
771 return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_ACTIVATING,
772 base::UTF8ToUTF16(network->name()));
776 // Otherwise just show the network name or 'Ethernet'.
777 if (network->Matches(NetworkTypePattern::Ethernet())) {
778 return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ETHERNET);
779 } else {
780 return base::UTF8ToUTF16(network->name());
784 int GetCellularUninitializedMsg() {
785 static base::Time s_uninitialized_state_time;
786 static int s_uninitialized_msg(0);
788 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
789 if (handler->GetTechnologyState(NetworkTypePattern::Mobile())
790 == NetworkStateHandler::TECHNOLOGY_UNINITIALIZED) {
791 s_uninitialized_msg = IDS_ASH_STATUS_TRAY_INITIALIZING_CELLULAR;
792 s_uninitialized_state_time = base::Time::Now();
793 return s_uninitialized_msg;
794 } else if (handler->GetScanningByType(NetworkTypePattern::Mobile())) {
795 s_uninitialized_msg = IDS_ASH_STATUS_TRAY_CELLULAR_SCANNING;
796 s_uninitialized_state_time = base::Time::Now();
797 return s_uninitialized_msg;
799 // There can be a delay between leaving the Initializing state and when
800 // a Cellular device shows up, so keep showing the initializing
801 // animation for a bit to avoid flashing the disconnect icon.
802 const int kInitializingDelaySeconds = 1;
803 base::TimeDelta dtime = base::Time::Now() - s_uninitialized_state_time;
804 if (dtime.InSeconds() < kInitializingDelaySeconds)
805 return s_uninitialized_msg;
806 return 0;
809 void GetDefaultNetworkImageAndLabel(IconType icon_type,
810 gfx::ImageSkia* image,
811 base::string16* label,
812 bool* animating) {
813 NetworkStateHandler* state_handler =
814 NetworkHandler::Get()->network_state_handler();
815 NetworkConnectionHandler* connect_handler =
816 NetworkHandler::Get()->network_connection_handler();
817 const NetworkState* connected_network =
818 state_handler->ConnectedNetworkByType(NetworkTypePattern::NonVirtual());
819 const NetworkState* connecting_network =
820 state_handler->ConnectingNetworkByType(NetworkTypePattern::Wireless());
821 if (!connecting_network && icon_type == ICON_TYPE_TRAY) {
822 connecting_network =
823 state_handler->ConnectingNetworkByType(NetworkTypePattern::VPN());
826 const NetworkState* network;
827 // If we are connecting to a network, and there is either no connected
828 // network, or the connection was user requested, use the connecting
829 // network.
830 if (connecting_network &&
831 (!connected_network ||
832 connect_handler->HasConnectingNetwork(connecting_network->path()))) {
833 network = connecting_network;
834 } else {
835 network = connected_network;
838 // Don't show ethernet in the tray
839 if (icon_type == ICON_TYPE_TRAY && network &&
840 network->Matches(NetworkTypePattern::Ethernet())) {
841 *image = gfx::ImageSkia();
842 *animating = false;
843 return;
846 if (!network) {
847 // If no connecting network, check if we are activating a network.
848 const NetworkState* mobile_network =
849 state_handler->FirstNetworkByType(NetworkTypePattern::Mobile());
850 if (mobile_network && (mobile_network->activation_state() ==
851 shill::kActivationStateActivating)) {
852 network = mobile_network;
855 if (!network) {
856 // If no connecting network, check for cellular initializing.
857 int uninitialized_msg = GetCellularUninitializedMsg();
858 if (uninitialized_msg != 0) {
859 *image = GetImageForConnectingNetwork(icon_type, shill::kTypeCellular);
860 if (label)
861 *label = l10n_util::GetStringUTF16(uninitialized_msg);
862 *animating = true;
863 } else {
864 // Otherwise show the disconnected wifi icon.
865 *image = GetImageForDisconnectedNetwork(icon_type, shill::kTypeWifi);
866 if (label) {
867 *label = l10n_util::GetStringUTF16(
868 IDS_ASH_STATUS_TRAY_NETWORK_NOT_CONNECTED);
870 *animating = false;
872 return;
874 *animating = network->IsConnectingState();
875 // Get icon and label for connected or connecting network.
876 *image = GetImageForNetwork(network, icon_type);
877 if (label)
878 *label = GetLabelForNetwork(network, icon_type);
881 void PurgeNetworkIconCache() {
882 NetworkStateHandler::NetworkStateList networks;
883 NetworkHandler::Get()->network_state_handler()->GetVisibleNetworkList(
884 &networks);
885 std::set<std::string> network_paths;
886 for (NetworkStateHandler::NetworkStateList::iterator iter = networks.begin();
887 iter != networks.end(); ++iter) {
888 network_paths.insert((*iter)->path());
890 PurgeIconMap(ICON_TYPE_TRAY, network_paths);
891 PurgeIconMap(ICON_TYPE_DEFAULT_VIEW, network_paths);
892 PurgeIconMap(ICON_TYPE_LIST, network_paths);
895 } // namespace network_icon
896 } // namespace ui