Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(170)

Side by Side Diff: ash/common/system/chromeos/network/network_icon.cc

Issue 2734653002: chromeos: Move files in //ash/common to //ash (Closed)
Patch Set: fix a11y tests, fix docs Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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/common/system/chromeos/network/network_icon.h"
6
7 #include "ash/common/system/chromeos/network/network_icon_animation.h"
8 #include "ash/common/system/chromeos/network/network_icon_animation_observer.h"
9 #include "ash/common/system/tray/tray_constants.h"
10 #include "ash/resources/grit/ash_resources.h"
11 #include "ash/resources/vector_icons/vector_icons.h"
12 #include "ash/strings/grit/ash_strings.h"
13 #include "base/macros.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "chromeos/network/device_state.h"
16 #include "chromeos/network/network_connection_handler.h"
17 #include "chromeos/network/network_state.h"
18 #include "chromeos/network/network_state_handler.h"
19 #include "chromeos/network/portal_detector/network_portal_detector.h"
20 #include "third_party/cros_system_api/dbus/service_constants.h"
21 #include "third_party/skia/include/core/SkPaint.h"
22 #include "third_party/skia/include/core/SkPath.h"
23 #include "ui/base/l10n/l10n_util.h"
24 #include "ui/base/resource/resource_bundle.h"
25 #include "ui/gfx/canvas.h"
26 #include "ui/gfx/color_palette.h"
27 #include "ui/gfx/geometry/insets.h"
28 #include "ui/gfx/geometry/rect.h"
29 #include "ui/gfx/geometry/size_conversions.h"
30 #include "ui/gfx/image/canvas_image_source.h"
31 #include "ui/gfx/image/image_skia_operations.h"
32 #include "ui/gfx/image/image_skia_source.h"
33 #include "ui/gfx/paint_vector_icon.h"
34 #include "ui/gfx/skia_util.h"
35 #include "ui/gfx/vector_icon_types.h"
36
37 using chromeos::DeviceState;
38 using chromeos::NetworkConnectionHandler;
39 using chromeos::NetworkHandler;
40 using chromeos::NetworkPortalDetector;
41 using chromeos::NetworkState;
42 using chromeos::NetworkStateHandler;
43 using chromeos::NetworkTypePattern;
44
45 namespace ash {
46 namespace network_icon {
47
48 namespace {
49
50 // Constants for offseting the badge displayed on top of the signal strength
51 // icon. The badge will extend outside of the base icon bounds by these amounts.
52 // All values are in dp.
53
54 // The badge offsets are different depending on whether the icon is in the tray
55 // or menu.
56 const int kTrayIconBadgeOffset = 3;
57 const int kMenuIconBadgeOffset = 2;
58
59 //------------------------------------------------------------------------------
60 // Struct to pass icon badges to NetworkIconImageSource.
61 struct Badges {
62 gfx::ImageSkia top_left;
63 gfx::ImageSkia top_right;
64 gfx::ImageSkia bottom_left;
65 gfx::ImageSkia bottom_right;
66 };
67
68 //------------------------------------------------------------------------------
69 // class used for maintaining a map of network state and images.
70 class NetworkIconImpl {
71 public:
72 NetworkIconImpl(const std::string& path, IconType icon_type);
73
74 // Determines whether or not the associated network might be dirty and if so
75 // updates and generates the icon. Does nothing if network no longer exists.
76 void Update(const chromeos::NetworkState* network);
77
78 const gfx::ImageSkia& image() const { return image_; }
79
80 private:
81 // Updates |strength_index_| for wireless networks. Returns true if changed.
82 bool UpdateWirelessStrengthIndex(const chromeos::NetworkState* network);
83
84 // Updates the local state for cellular networks. Returns true if changed.
85 bool UpdateCellularState(const chromeos::NetworkState* network);
86
87 // Updates the portal state for wireless networks. Returns true if changed.
88 bool UpdatePortalState(const chromeos::NetworkState* network);
89
90 // Updates the VPN badge. Returns true if changed.
91 bool UpdateVPNBadge();
92
93 // Gets |badges| based on |network| and the current state.
94 void GetBadges(const NetworkState* network, Badges* badges);
95
96 // Gets the appropriate icon and badges and composites the image.
97 void GenerateImage(const chromeos::NetworkState* network);
98
99 // Network path, used for debugging.
100 std::string network_path_;
101
102 // Defines color theme and VPN badging
103 const IconType icon_type_;
104
105 // Cached state of the network when the icon was last generated.
106 std::string state_;
107
108 // Cached strength index of the network when the icon was last generated.
109 int strength_index_;
110
111 // Cached technology badge for the network when the icon was last generated.
112 gfx::ImageSkia technology_badge_;
113
114 // Cached vpn badge for the network when the icon was last generated.
115 gfx::ImageSkia vpn_badge_;
116
117 // Cached roaming state of the network when the icon was last generated.
118 std::string roaming_state_;
119
120 // Cached portal state of the network when the icon was last generated.
121 bool behind_captive_portal_;
122
123 // Generated icon image.
124 gfx::ImageSkia image_;
125
126 DISALLOW_COPY_AND_ASSIGN(NetworkIconImpl);
127 };
128
129 //------------------------------------------------------------------------------
130 // Maintain a static (global) icon map. Note: Icons are never destroyed;
131 // it is assumed that a finite and reasonable number of network icons will be
132 // created during a session.
133
134 typedef std::map<std::string, NetworkIconImpl*> NetworkIconMap;
135
136 NetworkIconMap* GetIconMapInstance(IconType icon_type, bool create) {
137 typedef std::map<IconType, NetworkIconMap*> IconTypeMap;
138 static IconTypeMap* s_icon_map = nullptr;
139 if (s_icon_map == nullptr) {
140 if (!create)
141 return nullptr;
142 s_icon_map = new IconTypeMap;
143 }
144 if (s_icon_map->count(icon_type) == 0) {
145 if (!create)
146 return nullptr;
147 (*s_icon_map)[icon_type] = new NetworkIconMap;
148 }
149 return (*s_icon_map)[icon_type];
150 }
151
152 NetworkIconMap* GetIconMap(IconType icon_type) {
153 return GetIconMapInstance(icon_type, true);
154 }
155
156 void PurgeIconMap(IconType icon_type,
157 const std::set<std::string>& network_paths) {
158 NetworkIconMap* icon_map = GetIconMapInstance(icon_type, false);
159 if (!icon_map)
160 return;
161 for (NetworkIconMap::iterator loop_iter = icon_map->begin();
162 loop_iter != icon_map->end();) {
163 NetworkIconMap::iterator cur_iter = loop_iter++;
164 if (network_paths.count(cur_iter->first) == 0) {
165 delete cur_iter->second;
166 icon_map->erase(cur_iter);
167 }
168 }
169 }
170
171 //------------------------------------------------------------------------------
172 // Utilities for generating icon images.
173
174 // 'NONE' will default to ARCS behavior where appropriate (e.g. no network or
175 // if a new type gets added).
176 enum ImageType { ARCS, BARS, NONE };
177
178 // Amount to fade icons while connecting.
179 const double kConnectingImageAlpha = 0.5;
180
181 // Images for strength arcs for wireless networks or strength bars for cellular
182 // networks.
183 const int kNumNetworkImages = 5;
184
185 // Number of discrete images to use for alpha fade animation
186 const int kNumFadeImages = 10;
187
188 SkColor GetDefaultColorForIconType(IconType icon_type) {
189 return icon_type == ICON_TYPE_TRAY ? kTrayIconColor : kMenuIconColor;
190 }
191
192 bool IconTypeIsDark(IconType icon_type) {
193 return (icon_type != ICON_TYPE_TRAY);
194 }
195
196 bool IconTypeHasVPNBadge(IconType icon_type) {
197 return (icon_type != ICON_TYPE_LIST && icon_type != ICON_TYPE_MENU_LIST);
198 }
199
200 // This defines how we assemble a network icon.
201 class NetworkIconImageSource : public gfx::CanvasImageSource {
202 public:
203 static gfx::ImageSkia CreateImage(const gfx::ImageSkia& icon,
204 const Badges& badges) {
205 auto* source = new NetworkIconImageSource(icon, badges);
206 return gfx::ImageSkia(source, source->size());
207 }
208
209 // gfx::CanvasImageSource:
210 void Draw(gfx::Canvas* canvas) override {
211 const int width = size().width();
212 const int height = size().height();
213
214 // The base icon is centered in both dimensions.
215 const int icon_y = (height - icon_.height()) / 2;
216 canvas->DrawImageInt(icon_, (width - icon_.width()) / 2, icon_y);
217
218 // The badges are flush against the edges of the canvas, except at the top,
219 // where the badge is only 1dp higher than the base image.
220 const int top_badge_y = icon_y - 1;
221 if (!badges_.top_left.isNull())
222 canvas->DrawImageInt(badges_.top_left, 0, top_badge_y);
223 if (!badges_.top_right.isNull()) {
224 canvas->DrawImageInt(badges_.top_right, width - badges_.top_right.width(),
225 top_badge_y);
226 }
227 if (!badges_.bottom_left.isNull()) {
228 canvas->DrawImageInt(badges_.bottom_left, 0,
229 height - badges_.bottom_left.height());
230 }
231 if (!badges_.bottom_right.isNull()) {
232 canvas->DrawImageInt(badges_.bottom_right,
233 width - badges_.bottom_right.width(),
234 height - badges_.bottom_right.height());
235 }
236 }
237
238 bool HasRepresentationAtAllScales() const override { return true; }
239
240 private:
241 NetworkIconImageSource(const gfx::ImageSkia& icon, const Badges& badges)
242 : CanvasImageSource(GetSizeForBaseIconSize(icon.size()), false),
243 icon_(icon),
244 badges_(badges) {}
245 ~NetworkIconImageSource() override {}
246
247 static gfx::Size GetSizeForBaseIconSize(const gfx::Size& base_icon_size) {
248 gfx::Size size = base_icon_size;
249 const int badge_offset = base_icon_size.width() == kTrayIconSize
250 ? kTrayIconBadgeOffset
251 : kMenuIconBadgeOffset;
252 size.Enlarge(badge_offset * 2, badge_offset * 2);
253 return size;
254 }
255
256 const gfx::ImageSkia icon_;
257 const Badges badges_;
258
259 DISALLOW_COPY_AND_ASSIGN(NetworkIconImageSource);
260 };
261
262 // Depicts a given signal strength using arcs (e.g. for WiFi connections) or
263 // bars (e.g. for cell connections).
264 class SignalStrengthImageSource : public gfx::CanvasImageSource {
265 public:
266 SignalStrengthImageSource(ImageType image_type,
267 IconType icon_type,
268 int signal_strength)
269 : CanvasImageSource(GetSizeForIconType(icon_type), false),
270 image_type_(image_type),
271 icon_type_(icon_type),
272 color_(GetDefaultColorForIconType(icon_type_)),
273 signal_strength_(signal_strength) {
274 if (image_type_ == NONE)
275 image_type_ = ARCS;
276
277 DCHECK_GE(signal_strength, 0);
278 DCHECK_LT(signal_strength, kNumNetworkImages);
279 }
280 ~SignalStrengthImageSource() override {}
281
282 void set_color(SkColor color) { color_ = color; }
283
284 // gfx::CanvasImageSource:
285 void Draw(gfx::Canvas* canvas) override {
286 if (image_type_ == ARCS)
287 DrawArcs(canvas);
288 else
289 DrawBars(canvas);
290 }
291
292 bool HasRepresentationAtAllScales() const override { return true; }
293
294 private:
295 static gfx::Size GetSizeForIconType(IconType icon_type) {
296 int side = icon_type == ICON_TYPE_TRAY ? kTrayIconSize : kMenuIconSize;
297 return gfx::Size(side, side);
298 }
299
300 void DrawArcs(gfx::Canvas* canvas) {
301 gfx::RectF oval_bounds((gfx::Rect(size())));
302 oval_bounds.Inset(gfx::Insets(kIconInset));
303 // Double the width and height. The new midpoint should be the former
304 // bottom center.
305 oval_bounds.Inset(-oval_bounds.width() / 2, 0, -oval_bounds.width() / 2,
306 -oval_bounds.height());
307
308 const SkScalar kAngleAboveHorizontal = 51.f;
309 const SkScalar kStartAngle = 180.f + kAngleAboveHorizontal;
310 const SkScalar kSweepAngle = 180.f - 2 * kAngleAboveHorizontal;
311
312 cc::PaintFlags flags;
313 flags.setAntiAlias(true);
314 flags.setStyle(cc::PaintFlags::kFill_Style);
315 // Background. Skip drawing for full signal.
316 if (signal_strength_ != kNumNetworkImages - 1) {
317 flags.setColor(SkColorSetA(color_, kBgAlpha));
318 canvas->sk_canvas()->drawArc(gfx::RectFToSkRect(oval_bounds), kStartAngle,
319 kSweepAngle, true, flags);
320 }
321 // Foreground (signal strength).
322 if (signal_strength_ != 0) {
323 flags.setColor(color_);
324 // Percent of the height of the background wedge that we draw the
325 // foreground wedge, indexed by signal strength.
326 static const float kWedgeHeightPercentages[] = {0.f, 0.375f, 0.5833f,
327 0.75f, 1.f};
328 const float wedge_percent = kWedgeHeightPercentages[signal_strength_];
329 oval_bounds.Inset(
330 gfx::InsetsF((oval_bounds.height() / 2) * (1.f - wedge_percent)));
331 canvas->sk_canvas()->drawArc(gfx::RectFToSkRect(oval_bounds), kStartAngle,
332 kSweepAngle, true, flags);
333 }
334 }
335
336 void DrawBars(gfx::Canvas* canvas) {
337 // Undo the canvas's device scaling and round values to the nearest whole
338 // number so we can draw on exact pixel boundaries.
339 const float dsf = canvas->UndoDeviceScaleFactor();
340 auto scale = [dsf](SkScalar dimension) {
341 return std::round(dimension * dsf);
342 };
343
344 // Length of short side of an isosceles right triangle, in dip.
345 const SkScalar kFullTriangleSide =
346 SkIntToScalar(size().width()) - kIconInset * 2;
347
348 auto make_triangle = [scale, kFullTriangleSide](SkScalar side) {
349 SkPath triangle;
350 triangle.moveTo(scale(kIconInset), scale(kIconInset + kFullTriangleSide));
351 triangle.rLineTo(scale(side), 0);
352 triangle.rLineTo(0, -scale(side));
353 triangle.close();
354 return triangle;
355 };
356
357 cc::PaintFlags flags;
358 flags.setAntiAlias(true);
359 flags.setStyle(cc::PaintFlags::kFill_Style);
360 // Background. Skip drawing for full signal.
361 if (signal_strength_ != kNumNetworkImages - 1) {
362 flags.setColor(SkColorSetA(color_, kBgAlpha));
363 canvas->DrawPath(make_triangle(kFullTriangleSide), flags);
364 }
365 // Foreground (signal strength).
366 if (signal_strength_ != 0) {
367 flags.setColor(color_);
368 // As a percentage of the bg triangle, the length of one of the short
369 // sides of the fg triangle, indexed by signal strength.
370 static const float kTriangleSidePercents[] = {0.f, 0.5f, 0.625f, 0.75f,
371 1.f};
372 canvas->DrawPath(make_triangle(kTriangleSidePercents[signal_strength_] *
373 kFullTriangleSide),
374 flags);
375 }
376 }
377
378 ImageType image_type_;
379 IconType icon_type_;
380 SkColor color_;
381
382 // On a scale of 0 to kNum{Arcs,Bars}Images - 1, how connected we are.
383 int signal_strength_;
384
385 // Padding between outside of icon and edge of the canvas, in dp. This value
386 // stays the same regardless of the canvas size (which depends on
387 // |icon_type_|).
388 static constexpr int kIconInset = 2;
389
390 // TODO(estade): share this alpha with other things in ash (battery, etc.).
391 // See crbug.com/623987 and crbug.com/632827
392 static constexpr int kBgAlpha = 0x4D;
393
394 DISALLOW_COPY_AND_ASSIGN(SignalStrengthImageSource);
395 };
396
397 //------------------------------------------------------------------------------
398 // Utilities for extracting icon images.
399
400 ImageType ImageTypeForNetworkType(const std::string& type) {
401 if (type == shill::kTypeWifi)
402 return ARCS;
403 else if (type == shill::kTypeCellular || type == shill::kTypeWimax)
404 return BARS;
405 return NONE;
406 }
407
408 gfx::ImageSkia GetImageForIndex(ImageType image_type,
409 IconType icon_type,
410 int index) {
411 gfx::CanvasImageSource* source =
412 new SignalStrengthImageSource(image_type, icon_type, index);
413 return gfx::ImageSkia(source, source->size());
414 }
415
416 const gfx::ImageSkia GetDisconnectedImage(IconType icon_type,
417 const std::string& network_type) {
418 DCHECK_NE(shill::kTypeVPN, network_type);
419 ImageType image_type = ImageTypeForNetworkType(network_type);
420 const int disconnected_index = 0;
421 return GetImageForIndex(image_type, icon_type, disconnected_index);
422 }
423
424 gfx::ImageSkia* ConnectingWirelessImage(ImageType image_type,
425 IconType icon_type,
426 double animation) {
427 static const int kImageCount = kNumNetworkImages - 1;
428 static gfx::ImageSkia* s_bars_images_dark[kImageCount];
429 static gfx::ImageSkia* s_bars_images_light[kImageCount];
430 static gfx::ImageSkia* s_arcs_images_dark[kImageCount];
431 static gfx::ImageSkia* s_arcs_images_light[kImageCount];
432 int index = animation * nextafter(static_cast<float>(kImageCount), 0);
433 index = std::max(std::min(index, kImageCount - 1), 0);
434 gfx::ImageSkia** images;
435 bool dark = IconTypeIsDark(icon_type);
436 if (image_type == BARS)
437 images = dark ? s_bars_images_dark : s_bars_images_light;
438 else
439 images = dark ? s_arcs_images_dark : s_arcs_images_light;
440 if (!images[index]) {
441 // Lazily cache images.
442 // TODO(estade): should the alpha be applied in SignalStrengthImageSource?
443 gfx::ImageSkia source = GetImageForIndex(image_type, icon_type, index + 1);
444 images[index] =
445 new gfx::ImageSkia(gfx::ImageSkiaOperations::CreateTransparentImage(
446 source, kConnectingImageAlpha));
447 }
448 return images[index];
449 }
450
451 gfx::ImageSkia ConnectingVpnImage(double animation) {
452 int index = animation * nextafter(static_cast<float>(kNumFadeImages), 0);
453 static gfx::ImageSkia* s_vpn_images[kNumFadeImages];
454 if (!s_vpn_images[index]) {
455 // Lazily cache images.
456 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
457 // TODO(estade): update this icon to MD. See crbug.com/690176
458 gfx::ImageSkia* icon = rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN);
459 s_vpn_images[index] = new gfx::ImageSkia(
460 gfx::ImageSkiaOperations::CreateTransparentImage(*icon, animation));
461 }
462 return *s_vpn_images[index];
463 }
464
465 gfx::ImageSkia ConnectingVpnBadge(double animation, IconType icon_type) {
466 int index = animation * nextafter(static_cast<float>(kNumFadeImages), 0);
467 static gfx::ImageSkia* s_vpn_badges[kNumFadeImages];
468 if (!s_vpn_badges[index]) {
469 // Lazily cache images.
470 gfx::ImageSkia badge = gfx::CreateVectorIcon(
471 kNetworkBadgeVpnIcon, GetDefaultColorForIconType(icon_type));
472 s_vpn_badges[index] = new gfx::ImageSkia(
473 gfx::ImageSkiaOperations::CreateTransparentImage(badge, animation));
474 }
475 return *s_vpn_badges[index];
476 }
477
478 int StrengthIndex(int strength) {
479 // Return an index in the range [1, kNumNetworkImages - 1].
480 const float findex = (static_cast<float>(strength) / 100.0f) *
481 nextafter(static_cast<float>(kNumNetworkImages - 1), 0);
482 int index = 1 + static_cast<int>(findex);
483 index = std::max(std::min(index, kNumNetworkImages - 1), 1);
484 return index;
485 }
486
487 gfx::ImageSkia BadgeForNetworkTechnology(const NetworkState* network,
488 IconType icon_type) {
489 const std::string& technology = network->network_technology();
490 const gfx::VectorIcon* icon = &gfx::kNoneIcon;
491 if (technology == shill::kNetworkTechnologyEvdo) {
492 icon = &kNetworkBadgeTechnologyEvdoIcon;
493 } else if (technology == shill::kNetworkTechnology1Xrtt) {
494 icon = &kNetworkBadgeTechnology1xIcon;
495 } else if (technology == shill::kNetworkTechnologyGprs ||
496 technology == shill::kNetworkTechnologyGsm) {
497 icon = &kNetworkBadgeTechnologyGprsIcon;
498 } else if (technology == shill::kNetworkTechnologyEdge) {
499 icon = &kNetworkBadgeTechnologyEdgeIcon;
500 } else if (technology == shill::kNetworkTechnologyUmts) {
501 icon = &kNetworkBadgeTechnology3gIcon;
502 } else if (technology == shill::kNetworkTechnologyHspa) {
503 icon = &kNetworkBadgeTechnologyHspaIcon;
504 } else if (technology == shill::kNetworkTechnologyHspaPlus) {
505 icon = &kNetworkBadgeTechnologyHspaPlusIcon;
506 } else if (technology == shill::kNetworkTechnologyLte) {
507 icon = &kNetworkBadgeTechnologyLteIcon;
508 } else if (technology == shill::kNetworkTechnologyLteAdvanced) {
509 icon = &kNetworkBadgeTechnologyLteAdvancedIcon;
510 } else {
511 return gfx::ImageSkia();
512 }
513 return gfx::CreateVectorIcon(*icon, GetDefaultColorForIconType(icon_type));
514 }
515
516 gfx::ImageSkia GetIcon(const NetworkState* network,
517 IconType icon_type,
518 int strength_index) {
519 if (network->Matches(NetworkTypePattern::Ethernet())) {
520 DCHECK_NE(ICON_TYPE_TRAY, icon_type);
521 return gfx::CreateVectorIcon(kNetworkEthernetIcon,
522 GetDefaultColorForIconType(ICON_TYPE_LIST));
523 } else if (network->Matches(NetworkTypePattern::Wireless())) {
524 DCHECK(strength_index > 0);
525 return GetImageForIndex(ImageTypeForNetworkType(network->type()), icon_type,
526 strength_index);
527 } else if (network->Matches(NetworkTypePattern::VPN())) {
528 DCHECK_NE(ICON_TYPE_TRAY, icon_type);
529 return gfx::CreateVectorIcon(kNetworkVpnIcon,
530 GetDefaultColorForIconType(ICON_TYPE_LIST));
531 }
532
533 NOTREACHED() << "Request for icon for unsupported type: " << network->type();
534 return gfx::ImageSkia();
535 }
536
537 //------------------------------------------------------------------------------
538 // Get connecting images
539
540 gfx::ImageSkia GetConnectingVpnImage(IconType icon_type) {
541 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
542 const NetworkState* connected_network = nullptr;
543 if (icon_type == ICON_TYPE_TRAY) {
544 connected_network =
545 handler->ConnectedNetworkByType(NetworkTypePattern::NonVirtual());
546 }
547 double animation = NetworkIconAnimation::GetInstance()->GetAnimation();
548
549 gfx::ImageSkia icon;
550 Badges badges;
551 if (connected_network) {
552 icon = GetImageForNetwork(connected_network, icon_type);
553 badges.bottom_left = ConnectingVpnBadge(animation, icon_type);
554 } else {
555 icon = ConnectingVpnImage(animation);
556 }
557 return NetworkIconImageSource::CreateImage(icon, badges);
558 }
559
560 gfx::ImageSkia GetConnectingImage(IconType icon_type,
561 const std::string& network_type) {
562 if (network_type == shill::kTypeVPN)
563 return GetConnectingVpnImage(icon_type);
564
565 ImageType image_type = ImageTypeForNetworkType(network_type);
566 double animation = NetworkIconAnimation::GetInstance()->GetAnimation();
567
568 return NetworkIconImageSource::CreateImage(
569 *ConnectingWirelessImage(image_type, icon_type, animation), Badges());
570 }
571
572 } // namespace
573
574 //------------------------------------------------------------------------------
575 // NetworkIconImpl
576
577 NetworkIconImpl::NetworkIconImpl(const std::string& path, IconType icon_type)
578 : network_path_(path),
579 icon_type_(icon_type),
580 strength_index_(-1),
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 = StrengthIndex(network->signal_strength());
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.BackedBySameObjectAs(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 && chromeos::network_portal_detector::IsInitialized()) {
645 NetworkPortalDetector::CaptivePortalState state =
646 chromeos::network_portal_detector::GetInstance()->GetCaptivePortalState(
647 network->guid());
648 behind_captive_portal =
649 state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL;
650 }
651
652 if (behind_captive_portal == behind_captive_portal_)
653 return false;
654 behind_captive_portal_ = behind_captive_portal;
655 return true;
656 }
657
658 bool NetworkIconImpl::UpdateVPNBadge() {
659 const NetworkState* vpn =
660 NetworkHandler::Get()->network_state_handler()->ConnectedNetworkByType(
661 NetworkTypePattern::VPN());
662 if (vpn && vpn_badge_.isNull()) {
663 vpn_badge_ = gfx::CreateVectorIcon(kNetworkBadgeVpnIcon,
664 GetDefaultColorForIconType(icon_type_));
665 return true;
666 }
667 if (!vpn && !vpn_badge_.isNull()) {
668 vpn_badge_ = gfx::ImageSkia();
669 return true;
670 }
671 return false;
672 }
673
674 void NetworkIconImpl::GetBadges(const NetworkState* network, Badges* badges) {
675 DCHECK(network);
676
677 const std::string& type = network->type();
678 const SkColor icon_color = GetDefaultColorForIconType(icon_type_);
679 if (type == shill::kTypeWifi) {
680 if (network->security_class() != shill::kSecurityNone &&
681 IconTypeIsDark(icon_type_)) {
682 badges->bottom_right =
683 gfx::CreateVectorIcon(kNetworkBadgeSecureIcon, icon_color);
684 }
685 } else if (type == shill::kTypeWimax) {
686 technology_badge_ =
687 gfx::CreateVectorIcon(kNetworkBadgeTechnology4gIcon, icon_color);
688 } else if (type == shill::kTypeCellular) {
689 if (network->roaming() == shill::kRoamingStateRoaming) {
690 // For networks that are always in roaming don't show roaming badge.
691 const DeviceState* device =
692 NetworkHandler::Get()->network_state_handler()->GetDeviceState(
693 network->device_path());
694 LOG_IF(WARNING, !device) << "Could not find device state for "
695 << network->device_path();
696 if (!device || !device->provider_requires_roaming()) {
697 badges->bottom_right =
698 gfx::CreateVectorIcon(kNetworkBadgeRoamingIcon, icon_color);
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 badges->bottom_right =
709 gfx::CreateVectorIcon(kNetworkBadgeCaptivePortalIcon, icon_color);
710 }
711 }
712
713 void NetworkIconImpl::GenerateImage(const NetworkState* network) {
714 DCHECK(network);
715 gfx::ImageSkia icon = GetIcon(network, icon_type_, strength_index_);
716 Badges badges;
717 GetBadges(network, &badges);
718 image_ = NetworkIconImageSource::CreateImage(icon, badges);
719 }
720
721 namespace {
722
723 NetworkIconImpl* FindAndUpdateImageImpl(const NetworkState* network,
724 IconType icon_type) {
725 // Find or add the icon.
726 NetworkIconMap* icon_map = GetIconMap(icon_type);
727 NetworkIconImpl* icon;
728 NetworkIconMap::iterator iter = icon_map->find(network->path());
729 if (iter == icon_map->end()) {
730 icon = new NetworkIconImpl(network->path(), icon_type);
731 icon_map->insert(std::make_pair(network->path(), icon));
732 } else {
733 icon = iter->second;
734 }
735
736 // Update and return the icon's image.
737 icon->Update(network);
738 return icon;
739 }
740
741 } // namespace
742
743 //------------------------------------------------------------------------------
744 // Public interface
745
746 gfx::ImageSkia GetImageForNetwork(const NetworkState* network,
747 IconType icon_type) {
748 DCHECK(network);
749 if (!network->visible())
750 return GetDisconnectedImage(icon_type, network->type());
751
752 if (network->IsConnectingState())
753 return GetConnectingImage(icon_type, network->type());
754
755 NetworkIconImpl* icon = FindAndUpdateImageImpl(network, icon_type);
756 return icon->image();
757 }
758
759 gfx::ImageSkia GetImageForConnectedMobileNetwork() {
760 ImageType image_type = ImageTypeForNetworkType(shill::kTypeWifi);
761 const IconType icon_type = ICON_TYPE_LIST;
762 const int connected_index = kNumNetworkImages - 1;
763 return GetImageForIndex(image_type, icon_type, connected_index);
764 }
765
766 gfx::ImageSkia GetImageForDisconnectedCellNetwork() {
767 return GetDisconnectedImage(ICON_TYPE_LIST, shill::kTypeCellular);
768 }
769
770 gfx::ImageSkia GetImageForNewWifiNetwork(SkColor icon_color,
771 SkColor badge_color) {
772 SignalStrengthImageSource* source =
773 new SignalStrengthImageSource(ImageTypeForNetworkType(shill::kTypeWifi),
774 ICON_TYPE_LIST, kNumNetworkImages - 1);
775 source->set_color(icon_color);
776 gfx::ImageSkia icon = gfx::ImageSkia(source, source->size());
777 Badges badges;
778 badges.bottom_right =
779 gfx::CreateVectorIcon(kNetworkBadgeAddOtherIcon, badge_color);
780 return NetworkIconImageSource::CreateImage(icon, badges);
781 }
782
783 base::string16 GetLabelForNetwork(const chromeos::NetworkState* network,
784 IconType icon_type) {
785 DCHECK(network);
786 std::string activation_state = network->activation_state();
787 if (icon_type == ICON_TYPE_LIST || icon_type == ICON_TYPE_MENU_LIST) {
788 // Show "<network>: [Connecting|Activating|Reconnecting]..."
789 // TODO(varkha): Remaining states should migrate to secondary status in the
790 // network item and no longer be part of the label.
791 // See http://crbug.com/676181 .
792 if (network->IsReconnecting()) {
793 return l10n_util::GetStringFUTF16(
794 IDS_ASH_STATUS_TRAY_NETWORK_LIST_RECONNECTING,
795 base::UTF8ToUTF16(network->name()));
796 }
797 if (icon_type != ICON_TYPE_MENU_LIST && network->IsConnectingState()) {
798 return l10n_util::GetStringFUTF16(
799 IDS_ASH_STATUS_TRAY_NETWORK_LIST_CONNECTING,
800 base::UTF8ToUTF16(network->name()));
801 }
802 if (activation_state == shill::kActivationStateActivating) {
803 return l10n_util::GetStringFUTF16(
804 IDS_ASH_STATUS_TRAY_NETWORK_LIST_ACTIVATING,
805 base::UTF8ToUTF16(network->name()));
806 }
807 // Show "Activate <network>" in list view only.
808 if (activation_state == shill::kActivationStateNotActivated ||
809 activation_state == shill::kActivationStatePartiallyActivated) {
810 return l10n_util::GetStringFUTF16(
811 IDS_ASH_STATUS_TRAY_NETWORK_LIST_ACTIVATE,
812 base::UTF8ToUTF16(network->name()));
813 }
814 } else {
815 // Show "[Connected to|Connecting to|Activating|Reconnecting to] <network>"
816 // (non-list view).
817 if (network->IsReconnecting()) {
818 return l10n_util::GetStringFUTF16(
819 IDS_ASH_STATUS_TRAY_NETWORK_RECONNECTING,
820 base::UTF8ToUTF16(network->name()));
821 }
822 if (network->IsConnectedState()) {
823 return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED,
824 base::UTF8ToUTF16(network->name()));
825 }
826 if (network->IsConnectingState()) {
827 return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_CONNECTING,
828 base::UTF8ToUTF16(network->name()));
829 }
830 if (activation_state == shill::kActivationStateActivating) {
831 return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_ACTIVATING,
832 base::UTF8ToUTF16(network->name()));
833 }
834 }
835
836 // Otherwise just show the network name or 'Ethernet'.
837 if (network->Matches(NetworkTypePattern::Ethernet())) {
838 return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ETHERNET);
839 } else {
840 return base::UTF8ToUTF16(network->name());
841 }
842 }
843
844 int GetCellularUninitializedMsg() {
845 static base::Time s_uninitialized_state_time;
846 static int s_uninitialized_msg(0);
847
848 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
849 if (handler->GetTechnologyState(NetworkTypePattern::Mobile()) ==
850 NetworkStateHandler::TECHNOLOGY_UNINITIALIZED) {
851 s_uninitialized_msg = IDS_ASH_STATUS_TRAY_INITIALIZING_CELLULAR;
852 s_uninitialized_state_time = base::Time::Now();
853 return s_uninitialized_msg;
854 } else if (handler->GetScanningByType(NetworkTypePattern::Mobile())) {
855 s_uninitialized_msg = IDS_ASH_STATUS_TRAY_MOBILE_SCANNING;
856 s_uninitialized_state_time = base::Time::Now();
857 return s_uninitialized_msg;
858 }
859 // There can be a delay between leaving the Initializing state and when
860 // a Cellular device shows up, so keep showing the initializing
861 // animation for a bit to avoid flashing the disconnect icon.
862 const int kInitializingDelaySeconds = 1;
863 base::TimeDelta dtime = base::Time::Now() - s_uninitialized_state_time;
864 if (dtime.InSeconds() < kInitializingDelaySeconds)
865 return s_uninitialized_msg;
866 return 0;
867 }
868
869 void GetDefaultNetworkImageAndLabel(IconType icon_type,
870 gfx::ImageSkia* image,
871 base::string16* label,
872 bool* animating) {
873 NetworkStateHandler* state_handler =
874 NetworkHandler::Get()->network_state_handler();
875 NetworkConnectionHandler* connect_handler =
876 NetworkHandler::Get()->network_connection_handler();
877 const NetworkState* connected_network =
878 state_handler->ConnectedNetworkByType(NetworkTypePattern::NonVirtual());
879 const NetworkState* connecting_network =
880 state_handler->ConnectingNetworkByType(NetworkTypePattern::Wireless());
881 if (!connecting_network && icon_type == ICON_TYPE_TRAY) {
882 connecting_network =
883 state_handler->ConnectingNetworkByType(NetworkTypePattern::VPN());
884 }
885
886 const NetworkState* network;
887 // If we are connecting to a network, and there is either no connected
888 // network, or the connection was user requested, or shill triggered a
889 // reconnection, use the connecting network.
890 if (connecting_network &&
891 (!connected_network || connecting_network->IsReconnecting() ||
892 connect_handler->HasConnectingNetwork(connecting_network->path()))) {
893 network = connecting_network;
894 } else {
895 network = connected_network;
896 }
897
898 // Don't show ethernet in the tray
899 if (icon_type == ICON_TYPE_TRAY && network &&
900 network->Matches(NetworkTypePattern::Ethernet())) {
901 *image = gfx::ImageSkia();
902 *animating = false;
903 return;
904 }
905
906 if (!network) {
907 // If no connecting network, check if we are activating a network.
908 const NetworkState* mobile_network =
909 state_handler->FirstNetworkByType(NetworkTypePattern::Mobile());
910 if (mobile_network && (mobile_network->activation_state() ==
911 shill::kActivationStateActivating)) {
912 network = mobile_network;
913 }
914 }
915 if (!network) {
916 // If no connecting network, check for cellular initializing.
917 int uninitialized_msg = GetCellularUninitializedMsg();
918 if (uninitialized_msg != 0) {
919 *image = GetConnectingImage(icon_type, shill::kTypeCellular);
920 if (label)
921 *label = l10n_util::GetStringUTF16(uninitialized_msg);
922 *animating = true;
923 } else {
924 // Otherwise show the disconnected wifi icon.
925 *image = GetDisconnectedImage(icon_type, shill::kTypeWifi);
926 if (label) {
927 *label = l10n_util::GetStringUTF16(
928 IDS_ASH_STATUS_TRAY_NETWORK_NOT_CONNECTED);
929 }
930 *animating = false;
931 }
932 return;
933 }
934 *animating = network->IsConnectingState();
935 // Get icon and label for connected or connecting network.
936 *image = GetImageForNetwork(network, icon_type);
937 if (label)
938 *label = GetLabelForNetwork(network, icon_type);
939 }
940
941 void PurgeNetworkIconCache() {
942 NetworkStateHandler::NetworkStateList networks;
943 NetworkHandler::Get()->network_state_handler()->GetVisibleNetworkList(
944 &networks);
945 std::set<std::string> network_paths;
946 for (NetworkStateHandler::NetworkStateList::iterator iter = networks.begin();
947 iter != networks.end(); ++iter) {
948 network_paths.insert((*iter)->path());
949 }
950 PurgeIconMap(ICON_TYPE_TRAY, network_paths);
951 PurgeIconMap(ICON_TYPE_DEFAULT_VIEW, network_paths);
952 PurgeIconMap(ICON_TYPE_LIST, network_paths);
953 PurgeIconMap(ICON_TYPE_MENU_LIST, network_paths);
954 }
955
956 } // namespace network_icon
957 } // namespace ash
OLDNEW
« no previous file with comments | « ash/common/system/chromeos/network/network_icon.h ('k') | ash/common/system/chromeos/network/network_icon_animation.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698