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

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

Powered by Google App Engine
This is Rietveld 408576698