• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "ui/chromeos/network/network_icon.h"
6 
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"
26 
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;
34 
35 namespace ui {
36 namespace network_icon {
37 
38 namespace {
39 
40 //------------------------------------------------------------------------------
41 // Struct to pass icon badges to NetworkIconImageSource.
42 struct Badges {
Badgesui::network_icon::__anona99b355d0111::Badges43   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   NetworkIconImpl(const std::string& path, 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   // Returns the cached image url for |image_| based on |scale_factor|.
66   const std::string& GetImageUrl(float scale_factor);
67 
image() const68   const gfx::ImageSkia& image() const { return image_; }
69 
70  private:
71   typedef std::map<float, std::string> ImageUrlMap;
72 
73   // Updates |strength_index_| for wireless networks. Returns true if changed.
74   bool UpdateWirelessStrengthIndex(const chromeos::NetworkState* network);
75 
76   // Updates the local state for cellular networks. Returns true if changed.
77   bool UpdateCellularState(const chromeos::NetworkState* network);
78 
79   // Updates the portal state for wireless networks. Returns true if changed.
80   bool UpdatePortalState(const chromeos::NetworkState* network);
81 
82   // Updates the VPN badge. Returns true if changed.
83   bool UpdateVPNBadge();
84 
85   // Gets |badges| based on |network| and the current state.
86   void GetBadges(const NetworkState* network, Badges* badges);
87 
88   // Gets the appropriate icon and badges and composites the image.
89   void GenerateImage(const chromeos::NetworkState* network);
90 
91   // Network path, used for debugging.
92   std::string network_path_;
93 
94   // Defines color theme and VPN badging
95   const IconType icon_type_;
96 
97   // Cached state of the network when the icon was last generated.
98   std::string state_;
99 
100   // Cached strength index of the network when the icon was last generated.
101   int strength_index_;
102 
103   // Cached technology badge for the network when the icon was last generated.
104   const gfx::ImageSkia* technology_badge_;
105 
106   // Cached vpn badge for the network when the icon was last generated.
107   const gfx::ImageSkia* vpn_badge_;
108 
109   // Cached roaming state of the network when the icon was last generated.
110   std::string roaming_state_;
111 
112   // Cached portal state of the network when the icon was last generated.
113   bool behind_captive_portal_;
114 
115   // Generated icon image.
116   gfx::ImageSkia image_;
117 
118   // Map of cached image urls by scale factor. Cleared whenever image_ is
119   // generated.
120   ImageUrlMap image_urls_;
121 
122   DISALLOW_COPY_AND_ASSIGN(NetworkIconImpl);
123 };
124 
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.
129 
130 typedef std::map<std::string, NetworkIconImpl*> NetworkIconMap;
131 
GetIconMapInstance(IconType icon_type,bool create)132 NetworkIconMap* GetIconMapInstance(IconType icon_type, bool create) {
133   typedef std::map<IconType, NetworkIconMap*> IconTypeMap;
134   static IconTypeMap* s_icon_map = NULL;
135   if (s_icon_map == NULL) {
136     if (!create)
137       return NULL;
138     s_icon_map = new IconTypeMap;
139   }
140   if (s_icon_map->count(icon_type) == 0) {
141     if (!create)
142       return NULL;
143     (*s_icon_map)[icon_type] = new NetworkIconMap;
144   }
145   return (*s_icon_map)[icon_type];
146 }
147 
GetIconMap(IconType icon_type)148 NetworkIconMap* GetIconMap(IconType icon_type) {
149   return GetIconMapInstance(icon_type, true);
150 }
151 
PurgeIconMap(IconType icon_type,const std::set<std::string> & network_paths)152 void PurgeIconMap(IconType icon_type,
153                   const std::set<std::string>& network_paths) {
154   NetworkIconMap* icon_map = GetIconMapInstance(icon_type, false);
155   if (!icon_map)
156     return;
157   for (NetworkIconMap::iterator loop_iter = icon_map->begin();
158        loop_iter != icon_map->end(); ) {
159     NetworkIconMap::iterator cur_iter = loop_iter++;
160     if (network_paths.count(cur_iter->first) == 0) {
161       delete cur_iter->second;
162       icon_map->erase(cur_iter);
163     }
164   }
165 }
166 
167 //------------------------------------------------------------------------------
168 // Utilities for generating icon images.
169 
170 // 'NONE' will default to ARCS behavior where appropriate (e.g. no network or
171 // if a new type gets added).
172 enum ImageType {
173   ARCS,
174   BARS,
175   NONE
176 };
177 
178 // Amount to fade icons while connecting.
179 const double kConnectingImageAlpha = 0.5;
180 
181 // Images for strength bars for wired networks.
182 const int kNumBarsImages = 5;
183 
184 // Imagaes for strength arcs for wireless networks.
185 const int kNumArcsImages = 5;
186 
187 // Number of discrete images to use for alpha fade animation
188 const int kNumFadeImages = 10;
189 
190 //------------------------------------------------------------------------------
191 // Classes for generating scaled images.
192 
GetEmptyBitmap(const gfx::Size pixel_size)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;
197 
198   SizeKey key(pixel_size.width(), pixel_size.height());
199 
200   SizeBitmapMap::iterator iter = s_empty_bitmaps->find(key);
201   if (iter != s_empty_bitmaps->end())
202     return iter->second;
203 
204   SkBitmap empty;
205   empty.allocN32Pixels(key.first, key.second);
206   empty.eraseARGB(0, 0, 0, 0);
207   (*s_empty_bitmaps)[key] = empty;
208   return empty;
209 }
210 
211 class EmptyImageSource: public gfx::ImageSkiaSource {
212  public:
EmptyImageSource(const gfx::Size & size)213   explicit EmptyImageSource(const gfx::Size& size)
214       : size_(size) {
215   }
216 
GetImageForScale(float scale)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);
221   }
222 
223  private:
224   const gfx::Size size_;
225 
226   DISALLOW_COPY_AND_ASSIGN(EmptyImageSource);
227 };
228 
229 // This defines how we assemble a network icon.
230 class NetworkIconImageSource : public gfx::ImageSkiaSource {
231  public:
NetworkIconImageSource(const gfx::ImageSkia & icon,const Badges & badges)232   NetworkIconImageSource(const gfx::ImageSkia& icon, const Badges& badges)
233       : icon_(icon),
234         badges_(badges) {
235   }
~NetworkIconImageSource()236   virtual ~NetworkIconImageSource() {}
237 
238   // TODO(pkotwicz): Figure out what to do when a new image resolution becomes
239   // available.
GetImageForScale(float scale)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());
253     }
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());
258     }
259     return canvas.ExtractImageRep();
260   }
261 
262  private:
263   const gfx::ImageSkia icon_;
264   const Badges badges_;
265 
266   DISALLOW_COPY_AND_ASSIGN(NetworkIconImageSource);
267 };
268 
269 //------------------------------------------------------------------------------
270 // Utilities for extracting icon images.
271 
272 // A struct used for caching image urls.
273 struct ImageIdForNetworkType {
ImageIdForNetworkTypeui::network_icon::__anona99b355d0111::ImageIdForNetworkType274   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) {}
operator <ui::network_icon::__anona99b355d0111::ImageIdForNetworkType280   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;
286   }
287   IconType icon_type;
288   std::string network_type;
289   float scale_factor;
290 };
291 
292 typedef std::map<ImageIdForNetworkType, std::string> ImageIdUrlMap;
293 
IconTypeIsDark(IconType icon_type)294 bool IconTypeIsDark(IconType icon_type) {
295   return (icon_type != ICON_TYPE_TRAY);
296 }
297 
IconTypeHasVPNBadge(IconType icon_type)298 bool IconTypeHasVPNBadge(IconType icon_type) {
299   return (icon_type != ICON_TYPE_LIST);
300 }
301 
NumImagesForType(ImageType type)302 int NumImagesForType(ImageType type) {
303   return (type == BARS) ? kNumBarsImages : kNumArcsImages;
304 }
305 
BaseImageForType(ImageType image_type,IconType icon_type)306 gfx::ImageSkia* BaseImageForType(ImageType image_type, IconType icon_type) {
307   gfx::ImageSkia* image;
308   if (image_type == BARS) {
309     image =  ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
310         IconTypeIsDark(icon_type) ?
311         IDR_AURA_UBER_TRAY_NETWORK_BARS_DARK :
312         IDR_AURA_UBER_TRAY_NETWORK_BARS_LIGHT);
313   } else {
314     image =  ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
315         IconTypeIsDark(icon_type) ?
316         IDR_AURA_UBER_TRAY_NETWORK_ARCS_DARK :
317         IDR_AURA_UBER_TRAY_NETWORK_ARCS_LIGHT);
318   }
319   return image;
320 }
321 
ImageTypeForNetworkType(const std::string & type)322 ImageType ImageTypeForNetworkType(const std::string& type) {
323   if (type == shill::kTypeWifi)
324     return ARCS;
325   else if (type == shill::kTypeCellular || type == shill::kTypeWimax)
326     return BARS;
327   return NONE;
328 }
329 
GetImageForIndex(ImageType image_type,IconType icon_type,int index)330 gfx::ImageSkia GetImageForIndex(ImageType image_type,
331                                 IconType icon_type,
332                                 int index) {
333   int num_images = NumImagesForType(image_type);
334   if (index < 0 || index >= num_images)
335     return gfx::ImageSkia();
336   gfx::ImageSkia* images = BaseImageForType(image_type, icon_type);
337   int width = images->width();
338   int height = images->height() / num_images;
339   return gfx::ImageSkiaOperations::ExtractSubset(*images,
340       gfx::Rect(0, index * height, width, height));
341 }
342 
GetConnectedImage(IconType icon_type,const std::string & network_type)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);
348   }
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);
352 }
353 
GetDisconnectedImage(IconType icon_type,const std::string & network_type)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);
360   }
361   ImageType image_type = ImageTypeForNetworkType(network_type);
362   const int disconnected_index = 0;
363   return GetImageForIndex(image_type, icon_type, disconnected_index);
364 }
365 
ConnectingWirelessImage(ImageType image_type,IconType icon_type,double animation)366 gfx::ImageSkia* ConnectingWirelessImage(ImageType image_type,
367                                         IconType icon_type,
368                                         double animation) {
369   static gfx::ImageSkia* s_bars_images_dark[kNumBarsImages - 1];
370   static gfx::ImageSkia* s_bars_images_light[kNumBarsImages - 1];
371   static gfx::ImageSkia* s_arcs_images_dark[kNumArcsImages - 1];
372   static gfx::ImageSkia* s_arcs_images_light[kNumArcsImages - 1];
373   int image_count = NumImagesForType(image_type) - 1;
374   int index = animation * nextafter(static_cast<float>(image_count), 0);
375   index = std::max(std::min(index, image_count - 1), 0);
376   gfx::ImageSkia** images;
377   bool dark = IconTypeIsDark(icon_type);
378   if (image_type == BARS)
379     images = dark ? s_bars_images_dark : s_bars_images_light;
380   else
381     images = dark ? s_arcs_images_dark : s_arcs_images_light;
382   if (!images[index]) {
383     // Lazily cache images.
384     gfx::ImageSkia source = GetImageForIndex(image_type, icon_type, index + 1);
385     images[index] = new gfx::ImageSkia(
386         gfx::ImageSkiaOperations::CreateBlendedImage(
387             gfx::ImageSkia(new EmptyImageSource(source.size()), source.size()),
388             source,
389             kConnectingImageAlpha));
390   }
391   return images[index];
392 }
393 
ConnectingVpnImage(double animation)394 gfx::ImageSkia* ConnectingVpnImage(double animation) {
395   int index = animation * nextafter(static_cast<float>(kNumFadeImages), 0);
396   static gfx::ImageSkia* s_vpn_images[kNumFadeImages];
397   if (!s_vpn_images[index]) {
398     // Lazily cache images.
399     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
400     gfx::ImageSkia* icon = rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN);
401     s_vpn_images[index] = new gfx::ImageSkia(
402         gfx::ImageSkiaOperations::CreateBlendedImage(
403             gfx::ImageSkia(new EmptyImageSource(icon->size()), icon->size()),
404             *icon,
405             animation));
406   }
407   return s_vpn_images[index];
408 }
409 
ConnectingVpnBadge(double animation)410 gfx::ImageSkia* ConnectingVpnBadge(double animation) {
411   int index = animation * nextafter(static_cast<float>(kNumFadeImages), 0);
412   static gfx::ImageSkia* s_vpn_badges[kNumFadeImages];
413   if (!s_vpn_badges[index]) {
414     // Lazily cache images.
415     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
416     gfx::ImageSkia* icon =
417         rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED);  // For size
418     gfx::ImageSkia* badge =
419         rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN_BADGE);
420     s_vpn_badges[index] = new gfx::ImageSkia(
421         gfx::ImageSkiaOperations::CreateBlendedImage(
422             gfx::ImageSkia(new EmptyImageSource(icon->size()), icon->size()),
423             *badge,
424             animation));
425   }
426   return s_vpn_badges[index];
427 }
428 
StrengthIndex(int strength,int count)429 int StrengthIndex(int strength, int count) {
430   // Return an index in the range [1, count-1].
431   const float findex = (static_cast<float>(strength) / 100.0f) *
432       nextafter(static_cast<float>(count - 1), 0);
433   int index = 1 + static_cast<int>(findex);
434   index = std::max(std::min(index, count - 1), 1);
435   return index;
436 }
437 
GetStrengthIndex(const NetworkState * network)438 int GetStrengthIndex(const NetworkState* network) {
439   ImageType image_type = ImageTypeForNetworkType(network->type());
440   if (image_type == ARCS)
441     return StrengthIndex(network->signal_strength(), kNumArcsImages);
442   else if (image_type == BARS)
443     return StrengthIndex(network->signal_strength(), kNumBarsImages);
444   return 0;
445 }
446 
BadgeForNetworkTechnology(const NetworkState * network,IconType icon_type)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;
490   }
491   if (id == kUnknownBadgeType)
492     return NULL;
493   else
494     return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(id);
495 }
496 
BadgeForVPN(IconType icon_type)497 const gfx::ImageSkia* BadgeForVPN(IconType icon_type) {
498   return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
499       IDR_AURA_UBER_TRAY_NETWORK_VPN_BADGE);
500 }
501 
GetIcon(const NetworkState * network,IconType icon_type,int strength_index)502 gfx::ImageSkia GetIcon(const NetworkState* network,
503                        IconType icon_type,
504                        int strength_index) {
505   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
506   if (network->Matches(NetworkTypePattern::Ethernet())) {
507     return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED);
508   } else if (network->Matches(NetworkTypePattern::Wireless())) {
509     DCHECK(strength_index > 0);
510     return GetImageForIndex(
511         ImageTypeForNetworkType(network->type()), icon_type, strength_index);
512   } else if (network->Matches(NetworkTypePattern::VPN())) {
513     return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN);
514   } else {
515     LOG(WARNING) << "Request for icon for unsupported type: "
516                  << network->type();
517     return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED);
518   }
519 }
520 
521 //------------------------------------------------------------------------------
522 // Get connecting images
523 
GetConnectingVpnImage(IconType icon_type)524 gfx::ImageSkia GetConnectingVpnImage(IconType icon_type) {
525   NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
526   const NetworkState* connected_network = NULL;
527   if (icon_type == ICON_TYPE_TRAY) {
528     connected_network =
529         handler->ConnectedNetworkByType(NetworkTypePattern::NonVirtual());
530   }
531   double animation = NetworkIconAnimation::GetInstance()->GetAnimation();
532 
533   if (connected_network) {
534     gfx::ImageSkia icon = GetImageForNetwork(connected_network, icon_type);
535     Badges badges;
536     badges.bottom_left = ConnectingVpnBadge(animation);
537     return gfx::ImageSkia(
538         new NetworkIconImageSource(icon, badges), icon.size());
539   } else {
540     gfx::ImageSkia* icon = ConnectingVpnImage(animation);
541     return gfx::ImageSkia(
542         new NetworkIconImageSource(*icon, Badges()), icon->size());
543   }
544 }
545 
GetConnectingImage(IconType icon_type,const std::string & network_type)546 gfx::ImageSkia GetConnectingImage(IconType icon_type,
547                                   const std::string& network_type) {
548   if (network_type == shill::kTypeVPN)
549     return GetConnectingVpnImage(icon_type);
550 
551   ImageType image_type = ImageTypeForNetworkType(network_type);
552   double animation = NetworkIconAnimation::GetInstance()->GetAnimation();
553 
554   gfx::ImageSkia* icon = ConnectingWirelessImage(
555       image_type, icon_type, animation);
556   return gfx::ImageSkia(
557       new NetworkIconImageSource(*icon, Badges()), icon->size());
558 }
559 
GetConnectingImageUrl(IconType icon_type,const std::string & network_type,float scale_factor)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());
568 }
569 
570 }  // namespace
571 
572 //------------------------------------------------------------------------------
573 // NetworkIconImpl
574 
NetworkIconImpl(const std::string & path,IconType icon_type)575 NetworkIconImpl::NetworkIconImpl(const std::string& path, IconType icon_type)
576     : network_path_(path),
577       icon_type_(icon_type),
578       strength_index_(-1),
579       technology_badge_(NULL),
580       vpn_badge_(NULL),
581       behind_captive_portal_(false) {
582   // Default image
583   image_ = GetDisconnectedImage(icon_type, shill::kTypeWifi);
584 }
585 
Update(const NetworkState * network)586 void NetworkIconImpl::Update(const NetworkState* network) {
587   DCHECK(network);
588   // Determine whether or not we need to update the icon.
589   bool dirty = image_.isNull();
590 
591   // If the network state has changed, the icon needs updating.
592   if (state_ != network->connection_state()) {
593     state_ = network->connection_state();
594     dirty = true;
595   }
596 
597   dirty |= UpdatePortalState(network);
598 
599   if (network->Matches(NetworkTypePattern::Wireless())) {
600     dirty |= UpdateWirelessStrengthIndex(network);
601   }
602 
603   if (network->Matches(NetworkTypePattern::Cellular()))
604     dirty |= UpdateCellularState(network);
605 
606   if (IconTypeHasVPNBadge(icon_type_) &&
607       network->Matches(NetworkTypePattern::NonVirtual())) {
608     dirty |= UpdateVPNBadge();
609   }
610 
611   if (dirty) {
612     // Set the icon and badges based on the network and generate the image.
613     GenerateImage(network);
614   }
615 }
616 
UpdateWirelessStrengthIndex(const NetworkState * network)617 bool NetworkIconImpl::UpdateWirelessStrengthIndex(const NetworkState* network) {
618   int index = GetStrengthIndex(network);
619   if (index != strength_index_) {
620     strength_index_ = index;
621     return true;
622   }
623   return false;
624 }
625 
UpdateCellularState(const NetworkState * network)626 bool NetworkIconImpl::UpdateCellularState(const NetworkState* network) {
627   bool dirty = false;
628   const gfx::ImageSkia* technology_badge =
629       BadgeForNetworkTechnology(network, icon_type_);
630   if (technology_badge != technology_badge_) {
631     technology_badge_ = technology_badge;
632     dirty = true;
633   }
634   std::string roaming_state = network->roaming();
635   if (roaming_state != roaming_state_) {
636     roaming_state_ = roaming_state;
637     dirty = true;
638   }
639   return dirty;
640 }
641 
UpdatePortalState(const NetworkState * network)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;
649   }
650 
651   if (behind_captive_portal == behind_captive_portal_)
652     return false;
653   behind_captive_portal_ = behind_captive_portal;
654   return true;
655 }
656 
UpdateVPNBadge()657 bool NetworkIconImpl::UpdateVPNBadge() {
658   const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()->
659       ConnectedNetworkByType(NetworkTypePattern::VPN());
660   if (vpn && vpn_badge_ == NULL) {
661     vpn_badge_ = BadgeForVPN(icon_type_);
662     return true;
663   } else if (!vpn && vpn_badge_ != NULL) {
664     vpn_badge_ = NULL;
665     return true;
666   }
667   return false;
668 }
669 
GetBadges(const NetworkState * network,Badges * badges)670 void NetworkIconImpl::GetBadges(const NetworkState* network, Badges* badges) {
671   DCHECK(network);
672   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
673   NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
674 
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);
681     }
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);
699       }
700     }
701   }
702   if (!network->IsConnectingState()) {
703     badges->top_left = technology_badge_;
704     badges->bottom_left = vpn_badge_;
705   }
706 
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;
713   }
714 }
715 
GenerateImage(const NetworkState * network)716 void NetworkIconImpl::GenerateImage(const NetworkState* network) {
717   DCHECK(network);
718   gfx::ImageSkia icon = GetIcon(network, icon_type_, strength_index_);
719   Badges badges;
720   GetBadges(network, &badges);
721   image_ = gfx::ImageSkia(
722       new NetworkIconImageSource(icon, badges), icon.size());
723   image_urls_.clear();
724 }
725 
GetImageUrl(float scale_factor)726 const std::string& NetworkIconImpl::GetImageUrl(float scale_factor) {
727   ImageUrlMap::iterator iter = image_urls_.find(scale_factor);
728   if (iter != image_urls_.end())
729     return iter->second;
730 
731   VLOG(2) << "Generating bitmap URL for: " << network_path_;
732   gfx::ImageSkiaRep image_rep = image_.GetRepresentation(scale_factor);
733   iter = image_urls_.insert(std::make_pair(
734       scale_factor, webui::GetBitmapDataUrl(image_rep.sk_bitmap()))).first;
735   return iter->second;
736 }
737 
738 namespace {
739 
FindAndUpdateImageImpl(const NetworkState * network,IconType icon_type)740 NetworkIconImpl* FindAndUpdateImageImpl(const NetworkState* network,
741                                         IconType icon_type) {
742   // Find or add the icon.
743   NetworkIconMap* icon_map = GetIconMap(icon_type);
744   NetworkIconImpl* icon;
745   NetworkIconMap::iterator iter = icon_map->find(network->path());
746   if (iter == icon_map->end()) {
747     icon = new NetworkIconImpl(network->path(), icon_type);
748     icon_map->insert(std::make_pair(network->path(), icon));
749   } else {
750     icon = iter->second;
751   }
752 
753   // Update and return the icon's image.
754   icon->Update(network);
755   return icon;
756 }
757 
758 }  // namespace
759 
760 //------------------------------------------------------------------------------
761 // Public interface
762 
GetImageForNetwork(const NetworkState * network,IconType icon_type)763 gfx::ImageSkia GetImageForNetwork(const NetworkState* network,
764                                   IconType icon_type) {
765   DCHECK(network);
766   if (!network->visible())
767     return GetDisconnectedImage(icon_type, network->type());
768 
769   if (network->IsConnectingState())
770     return GetConnectingImage(icon_type, network->type());
771 
772   NetworkIconImpl* icon = FindAndUpdateImageImpl(network, icon_type);
773   return icon->image();
774 }
775 
GetImageUrlForNetwork(const NetworkState * network,IconType icon_type,float scale_factor)776 std::string GetImageUrlForNetwork(const NetworkState* network,
777                                   IconType icon_type,
778                                   float scale_factor) {
779   DCHECK(network);
780   // Handle connecting icons.
781   if (network->IsConnectingState())
782     return GetConnectingImageUrl(icon_type, network->type(), scale_factor);
783 
784   NetworkIconImpl* icon = FindAndUpdateImageImpl(network, icon_type);
785   return icon->GetImageUrl(scale_factor);
786 }
787 
GetImageForConnectedNetwork(IconType icon_type,const std::string & network_type)788 gfx::ImageSkia GetImageForConnectedNetwork(IconType icon_type,
789                                            const std::string& network_type) {
790   return GetConnectedImage(icon_type, network_type);
791 }
792 
GetImageForConnectingNetwork(IconType icon_type,const std::string & network_type)793 gfx::ImageSkia GetImageForConnectingNetwork(IconType icon_type,
794                                             const std::string& network_type) {
795   return GetConnectingImage(icon_type, network_type);
796 }
797 
GetImageForDisconnectedNetwork(IconType icon_type,const std::string & network_type)798 gfx::ImageSkia GetImageForDisconnectedNetwork(IconType icon_type,
799                                               const std::string& network_type) {
800   return GetDisconnectedImage(icon_type, network_type);
801 }
802 
GetLabelForNetwork(const chromeos::NetworkState * network,IconType icon_type)803 base::string16 GetLabelForNetwork(const chromeos::NetworkState* network,
804                                   IconType icon_type) {
805   DCHECK(network);
806   std::string activation_state = network->activation_state();
807   if (icon_type == ICON_TYPE_LIST) {
808     // Show "<network>: [Connecting|Activating]..."
809     if (network->IsConnectingState()) {
810       return l10n_util::GetStringFUTF16(
811           IDS_ASH_STATUS_TRAY_NETWORK_LIST_CONNECTING,
812           base::UTF8ToUTF16(network->name()));
813     }
814     if (activation_state == shill::kActivationStateActivating) {
815       return l10n_util::GetStringFUTF16(
816           IDS_ASH_STATUS_TRAY_NETWORK_LIST_ACTIVATING,
817           base::UTF8ToUTF16(network->name()));
818     }
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()));
825     }
826   } else {
827     // Show "[Connected to|Connecting to|Activating] <network>" (non-list view).
828     if (network->IsConnectedState()) {
829       return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED,
830                                         base::UTF8ToUTF16(network->name()));
831     }
832     if (network->IsConnectingState()) {
833       return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_CONNECTING,
834                                         base::UTF8ToUTF16(network->name()));
835     }
836     if (activation_state == shill::kActivationStateActivating) {
837       return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_ACTIVATING,
838                                         base::UTF8ToUTF16(network->name()));
839     }
840   }
841 
842   // Otherwise just show the network name or 'Ethernet'.
843   if (network->Matches(NetworkTypePattern::Ethernet())) {
844     return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ETHERNET);
845   } else {
846     return base::UTF8ToUTF16(network->name());
847   }
848 }
849 
GetCellularUninitializedMsg()850 int GetCellularUninitializedMsg() {
851   static base::Time s_uninitialized_state_time;
852   static int s_uninitialized_msg(0);
853 
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;
864   }
865   // There can be a delay between leaving the Initializing state and when
866   // a Cellular device shows up, so keep showing the initializing
867   // animation for a bit to avoid flashing the disconnect icon.
868   const int kInitializingDelaySeconds = 1;
869   base::TimeDelta dtime = base::Time::Now() - s_uninitialized_state_time;
870   if (dtime.InSeconds() < kInitializingDelaySeconds)
871     return s_uninitialized_msg;
872   return 0;
873 }
874 
GetDefaultNetworkImageAndLabel(IconType icon_type,gfx::ImageSkia * image,base::string16 * label,bool * animating)875 void GetDefaultNetworkImageAndLabel(IconType icon_type,
876                                     gfx::ImageSkia* image,
877                                     base::string16* label,
878                                     bool* animating) {
879   NetworkStateHandler* state_handler =
880       NetworkHandler::Get()->network_state_handler();
881   NetworkConnectionHandler* connect_handler =
882       NetworkHandler::Get()->network_connection_handler();
883   const NetworkState* connected_network =
884       state_handler->ConnectedNetworkByType(NetworkTypePattern::NonVirtual());
885   const NetworkState* connecting_network =
886       state_handler->ConnectingNetworkByType(NetworkTypePattern::Wireless());
887   if (!connecting_network && icon_type == ICON_TYPE_TRAY) {
888     connecting_network =
889         state_handler->ConnectingNetworkByType(NetworkTypePattern::VPN());
890   }
891 
892   const NetworkState* network;
893   // If we are connecting to a network, and there is either no connected
894   // network, or the connection was user requested, use the connecting
895   // network.
896   if (connecting_network &&
897       (!connected_network ||
898        connect_handler->HasConnectingNetwork(connecting_network->path()))) {
899     network = connecting_network;
900   } else {
901     network = connected_network;
902   }
903 
904   // Don't show ethernet in the tray
905   if (icon_type == ICON_TYPE_TRAY && network &&
906       network->Matches(NetworkTypePattern::Ethernet())) {
907     *image = gfx::ImageSkia();
908     *animating = false;
909     return;
910   }
911 
912   if (!network) {
913     // If no connecting network, check if we are activating a network.
914     const NetworkState* mobile_network =
915         state_handler->FirstNetworkByType(NetworkTypePattern::Mobile());
916     if (mobile_network && (mobile_network->activation_state() ==
917                            shill::kActivationStateActivating)) {
918       network = mobile_network;
919     }
920   }
921   if (!network) {
922     // If no connecting network, check for cellular initializing.
923     int uninitialized_msg = GetCellularUninitializedMsg();
924     if (uninitialized_msg != 0) {
925       *image = GetImageForConnectingNetwork(icon_type, shill::kTypeCellular);
926       if (label)
927         *label = l10n_util::GetStringUTF16(uninitialized_msg);
928       *animating = true;
929     } else {
930       // Otherwise show the disconnected wifi icon.
931       *image = GetImageForDisconnectedNetwork(icon_type, shill::kTypeWifi);
932       if (label) {
933         *label = l10n_util::GetStringUTF16(
934             IDS_ASH_STATUS_TRAY_NETWORK_NOT_CONNECTED);
935       }
936       *animating = false;
937     }
938     return;
939   }
940   *animating = network->IsConnectingState();
941   // Get icon and label for connected or connecting network.
942   *image = GetImageForNetwork(network, icon_type);
943   if (label)
944     *label = GetLabelForNetwork(network, icon_type);
945 }
946 
PurgeNetworkIconCache()947 void PurgeNetworkIconCache() {
948   NetworkStateHandler::NetworkStateList networks;
949   NetworkHandler::Get()->network_state_handler()->GetVisibleNetworkList(
950       &networks);
951   std::set<std::string> network_paths;
952   for (NetworkStateHandler::NetworkStateList::iterator iter = networks.begin();
953        iter != networks.end(); ++iter) {
954     network_paths.insert((*iter)->path());
955   }
956   PurgeIconMap(ICON_TYPE_TRAY, network_paths);
957   PurgeIconMap(ICON_TYPE_DEFAULT_VIEW, network_paths);
958   PurgeIconMap(ICON_TYPE_LIST, network_paths);
959 }
960 
961 }  // namespace network_icon
962 }  // namespace ui
963