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