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

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

Issue 11361274: Add NetworkStateListDetailedView (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix clang warning Created 8 years 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 | Annotate | Revision Log
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/system/chromeos/network/network_icon.h"
6
7 #include "ash/shell.h"
8 #include "base/observer_list.h"
9 #include "chromeos/network/device_state.h"
10 #include "chromeos/network/network_state.h"
11 #include "chromeos/network/network_state_handler.h"
12 #include "grit/ash_resources.h"
13 #include "third_party/cros_system_api/dbus/service_constants.h"
14 #include "ui/base/animation/animation_delegate.h"
15 #include "ui/base/animation/throb_animation.h"
16 #include "ui/base/resource/resource_bundle.h"
17 #include "ui/gfx/canvas.h"
18 #include "ui/gfx/image/image_skia_operations.h"
19 #include "ui/gfx/image/image_skia_source.h"
20 #include "ui/gfx/rect.h"
21 #include "ui/gfx/size_conversions.h"
22
23 using chromeos::DeviceState;
24 using chromeos::NetworkStateHandler;
25 using chromeos::NetworkState;
26
27 namespace ash {
28 namespace network_icon {
29
30 //------------------------------------------------------------------------------
31 // NetworkIcon class declaration
32
33 class NetworkIcon {
gauravsh 2012/11/27 20:48:09 Is there a reason why this is not declared in netw
stevenjb 2012/11/27 22:19:19 network_icon.h defines the network_icon namespace.
34 public:
35 NetworkIcon(const std::string& service_path, ResourceColorTheme color);
36
37 // Determines whether or not the associated network might be dirty and if so
38 // updates and generates the icon. Does nothing if network no longer exists.
39 void Update(const chromeos::NetworkState* network);
40
41 const gfx::ImageSkia& image() const { return image_; }
42
43 private:
44 // Updates |strength_index_| for wireless networks. Returns true if changed.
45 bool UpdateWirelessStrengthIndex(const chromeos::NetworkState* network);
46
47 // Updates the local state for cellular networks. Returns true if changed.
48 bool UpdateCellularState(const chromeos::NetworkState* network);
49
50 // Gets the appropriate icon and badges and composites the image.
51 void GenerateImage(const chromeos::NetworkState* network);
52
53 // Service path for the network this icon is associated with.
54 std::string service_path_;
55
56 // Color theme for the icon.
57 ResourceColorTheme color_;
58
59 // Cached state of the network when the icon was last generated.
60 std::string state_;
61
62 // Cached strength index of the network when the icon was last generated.
63 int strength_index_;
64
65 // Cached technology badge for the network when the icon was last generated.
66 const gfx::ImageSkia* technology_badge_;
67
68 // Cached roaming state of the network when the icon was last generated.
69 std::string roaming_state_;
70
71 // Generated icon image.
72 gfx::ImageSkia image_;
73
74 DISALLOW_COPY_AND_ASSIGN(NetworkIcon);
75 };
76
77 namespace {
78
79 //------------------------------------------------------------------------------
80 // Utilities for generating icon images.
81
82 enum ImageType {
83 ARCS = 0,
84 BARS
85 };
86
87 struct Badges {
88 Badges()
89 : top_left(NULL),
90 top_right(NULL),
91 bottom_left(NULL),
92 bottom_right(NULL) {
93 }
94 const gfx::ImageSkia* top_left;
95 const gfx::ImageSkia* top_right;
96 const gfx::ImageSkia* bottom_left;
97 const gfx::ImageSkia* bottom_right;
98 };
99
100 // Animation cycle length.
101 const int kThrobDurationMs = 750;
102
103 // Amount to fade icons while connecting.
104 const double kConnectingImageAlpha = 0.5;
105
106 // Images for strength bars for wired networks.
107 const int kNumBarsImages = 5;
108 gfx::ImageSkia* kBarsImagesAnimatingDark[kNumBarsImages - 1];
109 gfx::ImageSkia* kBarsImagesAnimatingLight[kNumBarsImages - 1];
110
111 // Imagaes for strength arcs for wireless networks.
112 const int kNumArcsImages = 5;
113 gfx::ImageSkia* kArcsImagesAnimatingDark[kNumArcsImages - 1];
114 gfx::ImageSkia* kArcsImagesAnimatingLight[kNumArcsImages - 1];
115
116 //------------------------------------------------------------------------------
117 // Classes for generating scaled images.
118
119 const SkBitmap GetEmptyBitmap(const gfx::Size pixel_size) {
120 typedef std::pair<int, int> SizeKey;
121 typedef std::map<SizeKey, SkBitmap> SizeBitmapMap;
122 static SizeBitmapMap* s_empty_bitmaps = new SizeBitmapMap;
123
124 SizeKey key(pixel_size.width(), pixel_size.height());
125
126 SizeBitmapMap::iterator iter = s_empty_bitmaps->find(key);
127 if (iter != s_empty_bitmaps->end())
128 return iter->second;
129
130 SkBitmap empty;
131 empty.setConfig(SkBitmap::kARGB_8888_Config, key.first, key.second);
132 empty.allocPixels();
133 empty.eraseARGB(0, 0, 0, 0);
134 (*s_empty_bitmaps)[key] = empty;
135 return empty;
136 }
137
138 class EmptyImageSource: public gfx::ImageSkiaSource {
139 public:
140 explicit EmptyImageSource(const gfx::Size& size)
141 : size_(size) {
142 }
143
144 virtual gfx::ImageSkiaRep GetImageForScale(
145 ui::ScaleFactor scale_factor) OVERRIDE {
146 gfx::Size pixel_size = gfx::ToFlooredSize(
147 gfx::ScaleSize(size_, ui::GetScaleFactorScale(scale_factor)));
148 SkBitmap empty_bitmap = GetEmptyBitmap(pixel_size);
149 return gfx::ImageSkiaRep(empty_bitmap, scale_factor);
150 }
151 private:
152 const gfx::Size size_;
153
154 DISALLOW_COPY_AND_ASSIGN(EmptyImageSource);
155 };
156
157 // This defines how we assemble a network icon.
158 class NetworkIconImageSource : public gfx::ImageSkiaSource {
159 public:
160 NetworkIconImageSource(const gfx::ImageSkia& icon, const Badges& badges)
161 : icon_(icon),
162 badges_(badges) {
163 }
164 virtual ~NetworkIconImageSource() {}
165
166 // TODO(pkotwicz): Figure out what to do when a new image resolution becomes
167 // available.
168 virtual gfx::ImageSkiaRep GetImageForScale(
169 ui::ScaleFactor scale_factor) OVERRIDE {
170 gfx::ImageSkiaRep icon_rep = icon_.GetRepresentation(scale_factor);
171 if (icon_rep.is_null())
172 return gfx::ImageSkiaRep();
173 gfx::Canvas canvas(icon_rep, false);
174 if (badges_.top_left)
175 canvas.DrawImageInt(*badges_.top_left, 0, 0);
176 if (badges_.top_right)
177 canvas.DrawImageInt(*badges_.top_right,
178 icon_.width() - badges_.top_right->width(), 0);
179 if (badges_.bottom_left) {
180 canvas.DrawImageInt(*badges_.bottom_left,
181 0, icon_.height() - badges_.bottom_left->height());
182 }
183 if (badges_.bottom_right) {
184 canvas.DrawImageInt(*badges_.bottom_right,
185 icon_.width() - badges_.bottom_right->width(),
186 icon_.height() - badges_.bottom_right->height());
187 }
188 return canvas.ExtractImageRep();
189 }
190
191 private:
192 const gfx::ImageSkia icon_;
193 const Badges badges_;
194
195 DISALLOW_COPY_AND_ASSIGN(NetworkIconImageSource);
196 };
197
198 //------------------------------------------------------------------------------
199 // Utilities for extracting icon images.
200
201 int NumImagesForType(ImageType type) {
202 return (type == ARCS) ? kNumArcsImages : kNumBarsImages;
203 }
204
205 gfx::ImageSkia** ImageListForType(ImageType type,
206 ResourceColorTheme color) {
207 gfx::ImageSkia** images;
208 if (type == ARCS) {
209 images = (color == COLOR_DARK) ?
210 kArcsImagesAnimatingDark : kArcsImagesAnimatingLight;
211 } else {
212 images = (color == COLOR_DARK) ?
213 kBarsImagesAnimatingDark : kBarsImagesAnimatingLight;
214 }
215 return images;
216 }
217
218 gfx::ImageSkia* BaseImageForType(ImageType type,
219 ResourceColorTheme color) {
220 gfx::ImageSkia* image;
221 if (type == ARCS) {
222 image = ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
223 color == COLOR_DARK ?
224 IDR_AURA_UBER_TRAY_NETWORK_ARCS_DARK :
225 IDR_AURA_UBER_TRAY_NETWORK_ARCS_LIGHT);
226 } else {
227 image = ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
228 color == COLOR_DARK ?
229 IDR_AURA_UBER_TRAY_NETWORK_BARS_DARK :
230 IDR_AURA_UBER_TRAY_NETWORK_BARS_LIGHT);
231 }
232 return image;
233 }
234
235 gfx::ImageSkia GetImageForIndex(ImageType type,
236 ResourceColorTheme color,
237 int index) {
238 int num_images = NumImagesForType(type);
239 if (index < 0 || index >= num_images)
240 return gfx::ImageSkia();
241 gfx::ImageSkia* images = BaseImageForType(type, color);
242 int width = images->width();
243 int height = images->height() / num_images;
244 return gfx::ImageSkiaOperations::ExtractSubset(*images,
245 gfx::Rect(0, index * height, width, height));
246 }
247
248 const gfx::ImageSkia GetDisconnectedImage(ResourceColorTheme color) {
249 return GetImageForIndex(ARCS, color, 0);
250 }
251
252 int StrengthIndex(int strength, int count) {
253 // Return an index in the range [1, count-1].
254 const float findex = (static_cast<float>(strength) / 100.0f) *
255 nextafter(static_cast<float>(count - 1), 0);
256 int index = 1 + static_cast<int>(findex);
257 index = std::max(std::min(index, count - 1), 1);
258 return index;
259 }
260
261 int GetStrengthIndex(const NetworkState* network) {
262 if (network->type() == flimflam::kTypeWifi) {
263 return StrengthIndex(network->signal_strength(), kNumArcsImages);
264 } else if (network->type() == flimflam::kTypeWimax) {
265 return StrengthIndex(network->signal_strength(), kNumBarsImages);
266 } else if (network->type() == flimflam::kTypeCellular) {
267 return StrengthIndex(network->signal_strength(), kNumBarsImages);
268 }
269 return 0;
270 }
271
272 const gfx::ImageSkia* BadgeForNetworkTechnology(const NetworkState* network,
273 ResourceColorTheme color) {
274 const int kUnknownBadgeType = -1;
275 int id = kUnknownBadgeType;
276 if (network->technology() == flimflam::kNetworkTechnologyEvdo) {
277 id = (color == COLOR_DARK) ?
278 IDR_AURA_UBER_TRAY_NETWORK_3G_DARK :
279 IDR_AURA_UBER_TRAY_NETWORK_3G_LIGHT;
280 } else if (network->technology() == flimflam::kNetworkTechnology1Xrtt) {
281 id = IDR_AURA_UBER_TRAY_NETWORK_1X;
282 } else if (network->technology() == flimflam::kNetworkTechnologyGprs) {
283 id = IDR_AURA_UBER_TRAY_NETWORK_GPRS;
284 } else if (network->technology() == flimflam::kNetworkTechnologyEdge) {
285 id = (color == COLOR_DARK) ?
286 IDR_AURA_UBER_TRAY_NETWORK_EDGE_DARK :
287 IDR_AURA_UBER_TRAY_NETWORK_EDGE_LIGHT;
288 } else if (network->technology() == flimflam::kNetworkTechnologyUmts) {
289 id = (color == COLOR_DARK) ?
290 IDR_AURA_UBER_TRAY_NETWORK_3G_DARK :
291 IDR_AURA_UBER_TRAY_NETWORK_3G_LIGHT;
292 } else if (network->technology() == flimflam::kNetworkTechnologyHspa) {
293 id = IDR_AURA_UBER_TRAY_NETWORK_HSPA;
294 } else if (network->technology() == flimflam::kNetworkTechnologyHspaPlus) {
295 id = IDR_AURA_UBER_TRAY_NETWORK_HSPA_PLUS;
296 } else if (network->technology() == flimflam::kNetworkTechnologyLte) {
297 id = IDR_AURA_UBER_TRAY_NETWORK_LTE;
298 } else if (network->technology() == flimflam::kNetworkTechnologyLteAdvanced) {
299 id = IDR_AURA_UBER_TRAY_NETWORK_LTE_ADVANCED;
300 } else if (network->technology() == flimflam::kNetworkTechnologyGsm) {
301 id = IDR_AURA_UBER_TRAY_NETWORK_GPRS;
302 }
303 if (id == kUnknownBadgeType)
304 return NULL;
305 else
306 return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(id);
307 }
308
309 gfx::ImageSkia GetIcon(const NetworkState* network,
310 ResourceColorTheme color,
311 int strength_index) {
312 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
313 const std::string& type = network->type();
314 if (type == flimflam::kTypeEthernet) {
315 return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED);
316 } else if (type == flimflam::kTypeWifi) {
317 DCHECK(strength_index > 0);
318 return GetImageForIndex(ARCS, color, strength_index);
319 } else if (type == flimflam::kTypeWimax) {
320 DCHECK(strength_index > 0);
321 return GetImageForIndex(BARS, color, strength_index);
322 } else if (type == flimflam::kTypeCellular) {
323 DCHECK(strength_index > 0);
324 return GetImageForIndex(BARS, color, strength_index);
325 } else if (type == flimflam::kTypeVPN) {
326 return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN);
327 } else {
328 LOG(WARNING) << "Request for icon for unsupported type: " << type;
329 return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED);
330 }
331 }
332
333 void GetBadges(const NetworkState* network,
334 ResourceColorTheme color,
335 Badges* badges) {
336 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
337 chromeos::NetworkStateHandler* handler = chromeos::NetworkStateHandler::Get();
338
339 bool use_dark_icons = color == COLOR_DARK;
340 const std::string& type = network->type();
341 if (type == flimflam::kTypeWifi) {
342 if (network->security() != flimflam::kSecurityNone && use_dark_icons) {
343 badges->bottom_right = rb.GetImageSkiaNamed(
344 IDR_AURA_UBER_TRAY_NETWORK_SECURE_DARK);
345 }
346 } else if (type == flimflam::kTypeWimax) {
347 badges->top_left = rb.GetImageSkiaNamed(
348 use_dark_icons ?
349 IDR_AURA_UBER_TRAY_NETWORK_4G_DARK :
350 IDR_AURA_UBER_TRAY_NETWORK_4G_LIGHT);
351 } else if (type == flimflam::kTypeCellular) {
352 if (network->roaming() == flimflam::kRoamingStateRoaming) {
353 // For networks that are always in roaming don't show roaming badge.
354 const DeviceState* device =
355 handler->GetDeviceState(network->device_path());
356 if (!device->provider_requires_roaming()) {
357 badges->bottom_right = rb.GetImageSkiaNamed(
358 use_dark_icons ?
359 IDR_AURA_UBER_TRAY_NETWORK_ROAMING_DARK :
360 IDR_AURA_UBER_TRAY_NETWORK_ROAMING_LIGHT);
361 }
362 }
363 if (!network->IsConnectingState()) {
364 badges->top_left = BadgeForNetworkTechnology(network, color);
365 }
366 }
367 }
368
369 //------------------------------------------------------------------------------
370 // Handle connecting images
371
372 class ConnectingAnimation : public ui::AnimationDelegate {
373 public:
374 ConnectingAnimation()
375 : ALLOW_THIS_IN_INITIALIZER_LIST(animation_(this)) {
376 // Set up the animation throbber.
377 animation_.SetThrobDuration(kThrobDurationMs);
378 animation_.SetTweenType(ui::Tween::LINEAR);
379 }
380
381 virtual ~ConnectingAnimation() {}
382
383 // ui::AnimationDelegate implementation.
384 virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE {
385 if (animation == &animation_) {
386 FOR_EACH_OBSERVER(AnimationObserver, observers_, NetworkIconChanged());
387 }
388 }
389
390 double GetAnimation() {
391 if (!animation_.is_animating()) {
392 animation_.Reset();
393 animation_.StartThrobbing(-1 /*throb indefinitely*/);
394 return 0;
395 }
396 return animation_.GetCurrentValue();
397 }
398
399 void AddObserver(AnimationObserver* observer) {
400 observers_.AddObserver(observer);
401 }
402
403 void RemoveObserver(AnimationObserver* observer) {
404 observers_.RemoveObserver(observer);
405 if (observers_.size() == 0)
406 animation_.Stop();
407 }
408
409 private:
410 ui::ThrobAnimation animation_;
411 ObserverList<AnimationObserver> observers_;
412 };
413
414 ConnectingAnimation* GetConnectingAnimation() {
415 static ConnectingAnimation* s_connecting_animation =
416 new ConnectingAnimation();
417 return s_connecting_animation;
418 }
419
420 gfx::ImageSkia GetConnectingImage(const std::string& type,
421 ResourceColorTheme color) {
422 ImageType image_type = (type == flimflam::kTypeWifi) ? ARCS : BARS;
423 int image_count = NumImagesForType(image_type) - 1;
424 gfx::ImageSkia** images = ImageListForType(image_type, color);
425 double animation = GetConnectingAnimation()->GetAnimation();
426 int index = animation * nextafter(static_cast<float>(image_count), 0);
427 index = std::max(std::min(index, image_count - 1), 0);
428
429 // Lazily cache images.
430 if (!images[index]) {
431 gfx::ImageSkia source = GetImageForIndex(image_type, color, index + 1);
432 images[index] = new gfx::ImageSkia(
433 gfx::ImageSkiaOperations::CreateBlendedImage(
434 gfx::ImageSkia(new EmptyImageSource(source.size()), source.size()),
435 source,
436 kConnectingImageAlpha));
437 }
438 gfx::ImageSkia& icon = *images[index];
439 return gfx::ImageSkia(
440 new NetworkIconImageSource(icon, Badges()), icon.size());
441 }
442
443
444 //------------------------------------------------------------------------------
445 // Maintain a static (global) icon map. Note: Icons are never destroyed;
446 // it is assumed that a finite and reasonable number of network icons will be
447 // created during a session.
448
449 typedef std::map<std::string, NetworkIcon*> NetworkIconMap;
450
451 NetworkIconMap* GetIconMap(ResourceColorTheme color) {
452 if (color == COLOR_DARK) {
453 static NetworkIconMap* s_icon_map_dark = NULL;
454 if (s_icon_map_dark == NULL)
455 s_icon_map_dark = new NetworkIconMap;
456 return s_icon_map_dark;
457 } else {
458 static NetworkIconMap* s_icon_map_light = NULL;
459 if (s_icon_map_light == NULL)
460 s_icon_map_light = new NetworkIconMap;
461 return s_icon_map_light;
462 }
463 }
464
465 } // namespace
466
467 //------------------------------------------------------------------------------
468 // NetworkIcon
469
470 NetworkIcon::NetworkIcon(const std::string& service_path,
471 ResourceColorTheme color)
472 : service_path_(service_path),
473 color_(color),
474 strength_index_(-1),
475 technology_badge_(NULL) {
476 // Default image
477 image_ = GetDisconnectedImage(color);
478 }
479
480 void NetworkIcon::Update(const NetworkState* network) {
481 // Determine whether or not we need to update the icon.
482 bool dirty = image_.isNull();
483
484 // If the network state has changed, the icon needs updating.
485 if (state_ != network->state()) {
486 state_ = network->state();
487 dirty = true;
488 }
489
490 const std::string& type = network->type();
491 if (type != flimflam::kTypeEthernet)
492 dirty |= UpdateWirelessStrengthIndex(network);
493
494 if (type == flimflam::kTypeCellular)
495 dirty |= UpdateCellularState(network);
496
497 if (dirty) {
498 // Set the icon and badges based on the network and generate the image.
499 GenerateImage(network);
500 }
501 }
502
503 bool NetworkIcon::UpdateWirelessStrengthIndex(const NetworkState* network) {
504 int index = GetStrengthIndex(network);
505 if (index != strength_index_) {
506 strength_index_ = index;
507 return true;
508 }
509 return false;
510 }
511
512 bool NetworkIcon::UpdateCellularState(const NetworkState* network) {
513 bool dirty = false;
514 const gfx::ImageSkia* technology_badge =
515 BadgeForNetworkTechnology(network, color_);
516 if (technology_badge != technology_badge_) {
517 technology_badge_ = technology_badge;
518 dirty = true;
519 }
520 std::string roaming_state = network->roaming();
521 if (roaming_state != roaming_state_) {
522 roaming_state_ = roaming_state;
523 dirty = true;
524 }
525 return dirty;
526 }
527
528 void NetworkIcon::GenerateImage(const NetworkState* network) {
529 gfx::ImageSkia icon = GetIcon(network, color_, strength_index_);
530 Badges badges;
531 GetBadges(network, color_, &badges);
532 image_ = gfx::ImageSkia(
533 new NetworkIconImageSource(icon, badges), icon.size());
534 }
535
536 //------------------------------------------------------------------------------
537 // Public interface
538
539 gfx::ImageSkia GetImageForNetwork(const NetworkState* network,
540 ResourceColorTheme color,
541 AnimationObserver* observer) {
542 if (network->IsConnectingState()) {
543 if (observer)
544 GetConnectingAnimation()->AddObserver(observer);
545 return GetConnectingImage(network->type(), color);
546 }
547 // Not connecting, remove observer.
548 if (observer)
549 GetConnectingAnimation()->RemoveObserver(observer);
550
551 NetworkIconMap* icon_map = GetIconMap(color);
552
553 // Find or add the icon.
554 NetworkIcon* icon;
555 NetworkIconMap::iterator iter = icon_map->find(network->path());
556 if (iter == icon_map->end()) {
557 icon = new NetworkIcon(network->path(), color);
558 icon_map->insert(std::make_pair(network->path(), icon));
559 } else {
560 icon = iter->second;
561 }
562
563 // Update and return the icon's image.
564 icon->Update(network);
565 return icon->image();
566 }
567
568 } // namespace network_icon
569 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698