OLD | NEW |
| (Empty) |
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/system/chromeos/network/network_icon_animation.h" | |
8 #include "ash/system/chromeos/network/network_icon_animation_observer.h" | |
9 #include "base/strings/utf_string_conversions.h" | |
10 #include "chromeos/network/device_state.h" | |
11 #include "chromeos/network/network_connection_handler.h" | |
12 #include "chromeos/network/network_state.h" | |
13 #include "chromeos/network/network_state_handler.h" | |
14 #include "chromeos/network/portal_detector/network_portal_detector.h" | |
15 #include "grit/ash_resources.h" | |
16 #include "grit/ash_strings.h" | |
17 #include "third_party/cros_system_api/dbus/service_constants.h" | |
18 #include "ui/base/l10n/l10n_util.h" | |
19 #include "ui/base/resource/resource_bundle.h" | |
20 #include "ui/base/webui/web_ui_util.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 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 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 | |
68 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 | |
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 | |
148 NetworkIconMap* GetIconMap(IconType icon_type) { | |
149 return GetIconMapInstance(icon_type, true); | |
150 } | |
151 | |
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 | |
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: | |
213 explicit EmptyImageSource(const gfx::Size& size) | |
214 : size_(size) { | |
215 } | |
216 | |
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: | |
232 NetworkIconImageSource(const gfx::ImageSkia& icon, const Badges& badges) | |
233 : icon_(icon), | |
234 badges_(badges) { | |
235 } | |
236 virtual ~NetworkIconImageSource() {} | |
237 | |
238 // TODO(pkotwicz): Figure out what to do when a new image resolution becomes | |
239 // available. | |
240 virtual gfx::ImageSkiaRep GetImageForScale(float scale) OVERRIDE { | |
241 gfx::ImageSkiaRep icon_rep = icon_.GetRepresentation(scale); | |
242 if (icon_rep.is_null()) | |
243 return gfx::ImageSkiaRep(); | |
244 gfx::Canvas canvas(icon_rep, false); | |
245 if (badges_.top_left) | |
246 canvas.DrawImageInt(*badges_.top_left, 0, 0); | |
247 if (badges_.top_right) | |
248 canvas.DrawImageInt(*badges_.top_right, | |
249 icon_.width() - badges_.top_right->width(), 0); | |
250 if (badges_.bottom_left) { | |
251 canvas.DrawImageInt(*badges_.bottom_left, | |
252 0, icon_.height() - badges_.bottom_left->height()); | |
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 { | |
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; | |
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 | |
294 bool IconTypeIsDark(IconType icon_type) { | |
295 return (icon_type != ICON_TYPE_TRAY); | |
296 } | |
297 | |
298 bool IconTypeHasVPNBadge(IconType icon_type) { | |
299 return (icon_type != ICON_TYPE_LIST); | |
300 } | |
301 | |
302 int NumImagesForType(ImageType type) { | |
303 return (type == BARS) ? kNumBarsImages : kNumArcsImages; | |
304 } | |
305 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
497 const gfx::ImageSkia* BadgeForVPN(IconType icon_type) { | |
498 return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( | |
499 IDR_AURA_UBER_TRAY_NETWORK_VPN_BADGE); | |
500 } | |
501 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
642 bool NetworkIconImpl::UpdatePortalState(const NetworkState* network) { | |
643 bool behind_captive_portal = false; | |
644 if (network) { | |
645 NetworkPortalDetector::CaptivePortalState state = | |
646 NetworkPortalDetector::Get()->GetCaptivePortalState(network->path()); | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
788 gfx::ImageSkia GetImageForConnectedNetwork(IconType icon_type, | |
789 const std::string& network_type) { | |
790 return GetConnectedImage(icon_type, network_type); | |
791 } | |
792 | |
793 gfx::ImageSkia GetImageForConnectingNetwork(IconType icon_type, | |
794 const std::string& network_type) { | |
795 return GetConnectingImage(icon_type, network_type); | |
796 } | |
797 | |
798 gfx::ImageSkia GetImageForDisconnectedNetwork(IconType icon_type, | |
799 const std::string& network_type) { | |
800 return GetDisconnectedImage(icon_type, network_type); | |
801 } | |
802 | |
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 | |
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 | |
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 | |
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 ash | |
OLD | NEW |