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

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

Powered by Google App Engine
This is Rietveld 408576698