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
;
36 namespace network_icon
{
40 //------------------------------------------------------------------------------
41 // Struct to pass icon badges to NetworkIconImageSource.
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
{
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_
; }
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.
100 // Cached strength index of the network when the icon was last generated.
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
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
) {
138 s_icon_map
= new IconTypeMap
;
140 if (s_icon_map
->count(icon_type
) == 0) {
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);
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).
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())
205 empty
.allocN32Pixels(key
.first
, key
.second
);
206 empty
.eraseARGB(0, 0, 0, 0);
207 (*s_empty_bitmaps
)[key
] = empty
;
211 class EmptyImageSource
: public gfx::ImageSkiaSource
{
213 explicit EmptyImageSource(const gfx::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
);
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
{
232 NetworkIconImageSource(const gfx::ImageSkia
& icon
, const Badges
& badges
)
236 virtual ~NetworkIconImageSource() {}
238 // TODO(pkotwicz): Figure out what to do when a new image resolution becomes
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();
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
;
288 std::string network_type
;
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
);
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
);
322 ImageType
ImageTypeForNetworkType(const std::string
& type
) {
323 if (type
== shill::kTypeWifi
)
325 else if (type
== shill::kTypeCellular
|| type
== shill::kTypeWimax
)
330 gfx::ImageSkia
GetImageForIndex(ImageType image_type
,
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
,
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
;
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()),
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()),
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()),
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);
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
);
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
)
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
,
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
);
515 LOG(WARNING
) << "Request for icon for unsupported 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
) {
529 handler
->ConnectedNetworkByType(NetworkTypePattern::NonVirtual());
531 double animation
= NetworkIconAnimation::GetInstance()->GetAnimation();
533 if (connected_network
) {
534 gfx::ImageSkia icon
= GetImageForNetwork(connected_network
, icon_type
);
536 badges
.bottom_left
= ConnectingVpnBadge(animation
);
537 return gfx::ImageSkia(
538 new NetworkIconImageSource(icon
, badges
), icon
.size());
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());
572 //------------------------------------------------------------------------------
575 NetworkIconImpl::NetworkIconImpl(const std::string
& path
, IconType icon_type
)
576 : network_path_(path
),
577 icon_type_(icon_type
),
579 technology_badge_(NULL
),
581 behind_captive_portal_(false) {
583 image_
= GetDisconnectedImage(icon_type
, shill::kTypeWifi
);
586 void NetworkIconImpl::Update(const NetworkState
* 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();
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();
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
;
626 bool NetworkIconImpl::UpdateCellularState(const NetworkState
* network
) {
628 const gfx::ImageSkia
* technology_badge
=
629 BadgeForNetworkTechnology(network
, icon_type_
);
630 if (technology_badge
!= technology_badge_
) {
631 technology_badge_
= technology_badge
;
634 std::string roaming_state
= network
->roaming();
635 if (roaming_state
!= roaming_state_
) {
636 roaming_state_
= roaming_state
;
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_
)
653 behind_captive_portal_
= behind_captive_portal
;
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_
);
663 } else if (!vpn
&& vpn_badge_
!= NULL
) {
670 void NetworkIconImpl::GetBadges(const NetworkState
* network
, Badges
* badges
) {
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
) {
718 gfx::ImageSkia icon
= GetIcon(network
, icon_type_
, strength_index_
);
720 GetBadges(network
, &badges
);
721 image_
= gfx::ImageSkia(
722 new NetworkIconImageSource(icon
, badges
), icon
.size());
726 const std::string
& NetworkIconImpl::GetImageUrl(float scale_factor
) {
727 ImageUrlMap::iterator iter
= image_urls_
.find(scale_factor
);
728 if (iter
!= image_urls_
.end())
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
;
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
));
753 // Update and return the icon's image.
754 icon
->Update(network
);
760 //------------------------------------------------------------------------------
763 gfx::ImageSkia
GetImageForNetwork(const NetworkState
* network
,
764 IconType icon_type
) {
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
,
778 float scale_factor
) {
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
) {
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()));
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
);
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
;
875 void GetDefaultNetworkImageAndLabel(IconType icon_type
,
876 gfx::ImageSkia
* image
,
877 base::string16
* label
,
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
) {
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
896 if (connecting_network
&&
897 (!connected_network
||
898 connect_handler
->HasConnectingNetwork(connecting_network
->path()))) {
899 network
= connecting_network
;
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();
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
;
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
);
927 *label
= l10n_util::GetStringUTF16(uninitialized_msg
);
930 // Otherwise show the disconnected wifi icon.
931 *image
= GetImageForDisconnectedNetwork(icon_type
, shill::kTypeWifi
);
933 *label
= l10n_util::GetStringUTF16(
934 IDS_ASH_STATUS_TRAY_NETWORK_NOT_CONNECTED
);
940 *animating
= network
->IsConnectingState();
941 // Get icon and label for connected or connecting network.
942 *image
= GetImageForNetwork(network
, icon_type
);
944 *label
= GetLabelForNetwork(network
, icon_type
);
947 void PurgeNetworkIconCache() {
948 NetworkStateHandler::NetworkStateList networks
;
949 NetworkHandler::Get()->network_state_handler()->GetVisibleNetworkList(
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