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

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 // NetworkIconImpl class used for maintaining a map of network state and images.
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 // Maintain a static (global) icon map. Note: Icons are never destroyed;
82 // it is assumed that a finite and reasonable number of network icons will be
83 // created during a session.
84
85 typedef std::map<std::string, NetworkIconImpl*> NetworkIconMap;
86
87 NetworkIconMap* GetIconMap(ResourceColorTheme color) {
88 if (color == COLOR_DARK) {
89 static NetworkIconMap* s_icon_map_dark = NULL;
90 if (s_icon_map_dark == NULL)
91 s_icon_map_dark = new NetworkIconMap;
92 return s_icon_map_dark;
93 } else {
94 static NetworkIconMap* s_icon_map_light = NULL;
95 if (s_icon_map_light == NULL)
96 s_icon_map_light = new NetworkIconMap;
97 return s_icon_map_light;
98 }
99 }
100
101 //------------------------------------------------------------------------------
102 // Utilities for generating icon images.
103
104 enum ImageType {
105 ARCS = 0,
106 BARS
107 };
108
109 struct Badges {
110 Badges()
111 : top_left(NULL),
112 top_right(NULL),
113 bottom_left(NULL),
114 bottom_right(NULL) {
115 }
116 const gfx::ImageSkia* top_left;
117 const gfx::ImageSkia* top_right;
118 const gfx::ImageSkia* bottom_left;
119 const gfx::ImageSkia* bottom_right;
120 };
121
122 // Animation cycle length.
123 const int kThrobDurationMs = 750;
124
125 // Amount to fade icons while connecting.
126 const double kConnectingImageAlpha = 0.5;
127
128 // Images for strength bars for wired networks.
129 const int kNumBarsImages = 5;
130 gfx::ImageSkia* kBarsImagesAnimatingDark[kNumBarsImages - 1];
131 gfx::ImageSkia* kBarsImagesAnimatingLight[kNumBarsImages - 1];
132
133 // Imagaes for strength arcs for wireless networks.
134 const int kNumArcsImages = 5;
135 gfx::ImageSkia* kArcsImagesAnimatingDark[kNumArcsImages - 1];
136 gfx::ImageSkia* kArcsImagesAnimatingLight[kNumArcsImages - 1];
137
138 //------------------------------------------------------------------------------
139 // Classes for generating scaled images.
140
141 const SkBitmap GetEmptyBitmap(const gfx::Size pixel_size) {
142 typedef std::pair<int, int> SizeKey;
143 typedef std::map<SizeKey, SkBitmap> SizeBitmapMap;
144 static SizeBitmapMap* s_empty_bitmaps = new SizeBitmapMap;
145
146 SizeKey key(pixel_size.width(), pixel_size.height());
147
148 SizeBitmapMap::iterator iter = s_empty_bitmaps->find(key);
149 if (iter != s_empty_bitmaps->end())
150 return iter->second;
151
152 SkBitmap empty;
153 empty.setConfig(SkBitmap::kARGB_8888_Config, key.first, key.second);
154 empty.allocPixels();
155 empty.eraseARGB(0, 0, 0, 0);
156 (*s_empty_bitmaps)[key] = empty;
157 return empty;
158 }
159
160 class EmptyImageSource: public gfx::ImageSkiaSource {
161 public:
162 explicit EmptyImageSource(const gfx::Size& size)
163 : size_(size) {
164 }
165
166 virtual gfx::ImageSkiaRep GetImageForScale(
167 ui::ScaleFactor scale_factor) OVERRIDE {
168 gfx::Size pixel_size = gfx::ToFlooredSize(
169 gfx::ScaleSize(size_, ui::GetScaleFactorScale(scale_factor)));
170 SkBitmap empty_bitmap = GetEmptyBitmap(pixel_size);
171 return gfx::ImageSkiaRep(empty_bitmap, scale_factor);
172 }
173 private:
174 const gfx::Size size_;
175
176 DISALLOW_COPY_AND_ASSIGN(EmptyImageSource);
177 };
178
179 // This defines how we assemble a network icon.
180 class NetworkIconImageSource : public gfx::ImageSkiaSource {
181 public:
182 NetworkIconImageSource(const gfx::ImageSkia& icon, const Badges& badges)
183 : icon_(icon),
184 badges_(badges) {
185 }
186 virtual ~NetworkIconImageSource() {}
187
188 // TODO(pkotwicz): Figure out what to do when a new image resolution becomes
189 // available.
190 virtual gfx::ImageSkiaRep GetImageForScale(
191 ui::ScaleFactor scale_factor) OVERRIDE {
192 gfx::ImageSkiaRep icon_rep = icon_.GetRepresentation(scale_factor);
193 if (icon_rep.is_null())
194 return gfx::ImageSkiaRep();
195 gfx::Canvas canvas(icon_rep, false);
196 if (badges_.top_left)
197 canvas.DrawImageInt(*badges_.top_left, 0, 0);
198 if (badges_.top_right)
199 canvas.DrawImageInt(*badges_.top_right,
200 icon_.width() - badges_.top_right->width(), 0);
201 if (badges_.bottom_left) {
202 canvas.DrawImageInt(*badges_.bottom_left,
203 0, icon_.height() - badges_.bottom_left->height());
204 }
205 if (badges_.bottom_right) {
206 canvas.DrawImageInt(*badges_.bottom_right,
207 icon_.width() - badges_.bottom_right->width(),
208 icon_.height() - badges_.bottom_right->height());
209 }
210 return canvas.ExtractImageRep();
211 }
212
213 private:
214 const gfx::ImageSkia icon_;
215 const Badges badges_;
216
217 DISALLOW_COPY_AND_ASSIGN(NetworkIconImageSource);
218 };
219
220 //------------------------------------------------------------------------------
221 // Utilities for extracting icon images.
222
223 int NumImagesForType(ImageType type) {
224 return (type == ARCS) ? kNumArcsImages : kNumBarsImages;
225 }
226
227 gfx::ImageSkia** ImageListForType(ImageType type,
228 ResourceColorTheme color) {
229 gfx::ImageSkia** images;
230 if (type == ARCS) {
231 images = (color == COLOR_DARK) ?
232 kArcsImagesAnimatingDark : kArcsImagesAnimatingLight;
233 } else {
234 images = (color == COLOR_DARK) ?
235 kBarsImagesAnimatingDark : kBarsImagesAnimatingLight;
236 }
237 return images;
238 }
239
240 gfx::ImageSkia* BaseImageForType(ImageType type,
241 ResourceColorTheme color) {
242 gfx::ImageSkia* image;
243 if (type == ARCS) {
244 image = ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
245 color == COLOR_DARK ?
246 IDR_AURA_UBER_TRAY_NETWORK_ARCS_DARK :
247 IDR_AURA_UBER_TRAY_NETWORK_ARCS_LIGHT);
248 } else {
249 image = ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
250 color == COLOR_DARK ?
251 IDR_AURA_UBER_TRAY_NETWORK_BARS_DARK :
252 IDR_AURA_UBER_TRAY_NETWORK_BARS_LIGHT);
253 }
254 return image;
255 }
256
257 gfx::ImageSkia GetImageForIndex(ImageType type,
258 ResourceColorTheme color,
259 int index) {
260 int num_images = NumImagesForType(type);
261 if (index < 0 || index >= num_images)
262 return gfx::ImageSkia();
263 gfx::ImageSkia* images = BaseImageForType(type, color);
264 int width = images->width();
265 int height = images->height() / num_images;
266 return gfx::ImageSkiaOperations::ExtractSubset(*images,
267 gfx::Rect(0, index * height, width, height));
268 }
269
270 const gfx::ImageSkia GetDisconnectedImage(ResourceColorTheme color) {
271 return GetImageForIndex(ARCS, color, 0);
272 }
273
274 int StrengthIndex(int strength, int count) {
275 // Return an index in the range [1, count-1].
276 const float findex = (static_cast<float>(strength) / 100.0f) *
277 nextafter(static_cast<float>(count - 1), 0);
278 int index = 1 + static_cast<int>(findex);
279 index = std::max(std::min(index, count - 1), 1);
280 return index;
281 }
282
283 int GetStrengthIndex(const NetworkState* network) {
284 if (network->type() == flimflam::kTypeWifi) {
285 return StrengthIndex(network->signal_strength(), kNumArcsImages);
286 } else if (network->type() == flimflam::kTypeWimax) {
287 return StrengthIndex(network->signal_strength(), kNumBarsImages);
288 } else if (network->type() == flimflam::kTypeCellular) {
289 return StrengthIndex(network->signal_strength(), kNumBarsImages);
290 }
291 return 0;
292 }
293
294 const gfx::ImageSkia* BadgeForNetworkTechnology(const NetworkState* network,
295 ResourceColorTheme color) {
296 const int kUnknownBadgeType = -1;
297 int id = kUnknownBadgeType;
298 if (network->technology() == flimflam::kNetworkTechnologyEvdo) {
299 id = (color == COLOR_DARK) ?
300 IDR_AURA_UBER_TRAY_NETWORK_3G_DARK :
301 IDR_AURA_UBER_TRAY_NETWORK_3G_LIGHT;
302 } else if (network->technology() == flimflam::kNetworkTechnology1Xrtt) {
303 id = IDR_AURA_UBER_TRAY_NETWORK_1X;
304 } else if (network->technology() == flimflam::kNetworkTechnologyGprs) {
305 id = IDR_AURA_UBER_TRAY_NETWORK_GPRS;
306 } else if (network->technology() == flimflam::kNetworkTechnologyEdge) {
307 id = (color == COLOR_DARK) ?
308 IDR_AURA_UBER_TRAY_NETWORK_EDGE_DARK :
309 IDR_AURA_UBER_TRAY_NETWORK_EDGE_LIGHT;
310 } else if (network->technology() == flimflam::kNetworkTechnologyUmts) {
311 id = (color == COLOR_DARK) ?
312 IDR_AURA_UBER_TRAY_NETWORK_3G_DARK :
313 IDR_AURA_UBER_TRAY_NETWORK_3G_LIGHT;
314 } else if (network->technology() == flimflam::kNetworkTechnologyHspa) {
315 id = IDR_AURA_UBER_TRAY_NETWORK_HSPA;
316 } else if (network->technology() == flimflam::kNetworkTechnologyHspaPlus) {
317 id = IDR_AURA_UBER_TRAY_NETWORK_HSPA_PLUS;
318 } else if (network->technology() == flimflam::kNetworkTechnologyLte) {
319 id = IDR_AURA_UBER_TRAY_NETWORK_LTE;
320 } else if (network->technology() == flimflam::kNetworkTechnologyLteAdvanced) {
321 id = IDR_AURA_UBER_TRAY_NETWORK_LTE_ADVANCED;
322 } else if (network->technology() == flimflam::kNetworkTechnologyGsm) {
323 id = IDR_AURA_UBER_TRAY_NETWORK_GPRS;
324 }
325 if (id == kUnknownBadgeType)
326 return NULL;
327 else
328 return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(id);
329 }
330
331 gfx::ImageSkia GetIcon(const NetworkState* network,
332 ResourceColorTheme color,
333 int strength_index) {
334 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
335 const std::string& type = network->type();
336 if (type == flimflam::kTypeEthernet) {
337 return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED);
338 } else if (type == flimflam::kTypeWifi) {
339 DCHECK(strength_index > 0);
340 return GetImageForIndex(ARCS, color, strength_index);
341 } else if (type == flimflam::kTypeWimax) {
342 DCHECK(strength_index > 0);
343 return GetImageForIndex(BARS, color, strength_index);
344 } else if (type == flimflam::kTypeCellular) {
345 DCHECK(strength_index > 0);
346 return GetImageForIndex(BARS, color, strength_index);
347 } else if (type == flimflam::kTypeVPN) {
348 return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN);
349 } else {
350 LOG(WARNING) << "Request for icon for unsupported type: " << type;
351 return *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_WIRED);
352 }
353 }
354
355 void GetBadges(const NetworkState* network,
356 ResourceColorTheme color,
357 Badges* badges) {
358 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
359 chromeos::NetworkStateHandler* handler = chromeos::NetworkStateHandler::Get();
360
361 bool use_dark_icons = color == COLOR_DARK;
362 const std::string& type = network->type();
363 if (type == flimflam::kTypeWifi) {
364 if (network->security() != flimflam::kSecurityNone && use_dark_icons) {
365 badges->bottom_right = rb.GetImageSkiaNamed(
366 IDR_AURA_UBER_TRAY_NETWORK_SECURE_DARK);
367 }
368 } else if (type == flimflam::kTypeWimax) {
369 badges->top_left = rb.GetImageSkiaNamed(
370 use_dark_icons ?
371 IDR_AURA_UBER_TRAY_NETWORK_4G_DARK :
372 IDR_AURA_UBER_TRAY_NETWORK_4G_LIGHT);
373 } else if (type == flimflam::kTypeCellular) {
374 if (network->roaming() == flimflam::kRoamingStateRoaming) {
375 // For networks that are always in roaming don't show roaming badge.
376 const DeviceState* device =
377 handler->GetDeviceState(network->device_path());
378 if (!device->provider_requires_roaming()) {
379 badges->bottom_right = rb.GetImageSkiaNamed(
380 use_dark_icons ?
381 IDR_AURA_UBER_TRAY_NETWORK_ROAMING_DARK :
382 IDR_AURA_UBER_TRAY_NETWORK_ROAMING_LIGHT);
383 }
384 }
385 if (!network->IsConnectingState()) {
386 badges->top_left = BadgeForNetworkTechnology(network, color);
387 }
388 }
389 }
390
391 //------------------------------------------------------------------------------
392 // Handle connecting images
393
394 class ConnectingAnimation : public ui::AnimationDelegate {
395 public:
396 ConnectingAnimation()
397 : ALLOW_THIS_IN_INITIALIZER_LIST(animation_(this)) {
398 // Set up the animation throbber.
399 animation_.SetThrobDuration(kThrobDurationMs);
400 animation_.SetTweenType(ui::Tween::LINEAR);
401 }
402
403 virtual ~ConnectingAnimation() {}
404
405 // ui::AnimationDelegate implementation.
406 virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE {
407 if (animation == &animation_) {
408 FOR_EACH_OBSERVER(AnimationObserver, observers_, NetworkIconChanged());
409 }
410 }
411
412 double GetAnimation() {
413 if (!animation_.is_animating()) {
414 animation_.Reset();
415 animation_.StartThrobbing(-1 /*throb indefinitely*/);
416 return 0;
417 }
418 return animation_.GetCurrentValue();
419 }
420
421 void AddObserver(AnimationObserver* observer) {
422 observers_.AddObserver(observer);
423 }
424
425 void RemoveObserver(AnimationObserver* observer) {
426 observers_.RemoveObserver(observer);
427 if (observers_.size() == 0)
428 animation_.Stop();
429 }
430
431 private:
432 ui::ThrobAnimation animation_;
433 ObserverList<AnimationObserver> observers_;
434 };
435
436 ConnectingAnimation* GetConnectingAnimation() {
437 static ConnectingAnimation* s_connecting_animation =
438 new ConnectingAnimation();
439 return s_connecting_animation;
440 }
441
442 gfx::ImageSkia GetConnectingImage(const std::string& type,
443 ResourceColorTheme color) {
444 ImageType image_type = (type == flimflam::kTypeWifi) ? ARCS : BARS;
445 int image_count = NumImagesForType(image_type) - 1;
446 gfx::ImageSkia** images = ImageListForType(image_type, color);
447 double animation = GetConnectingAnimation()->GetAnimation();
448 int index = animation * nextafter(static_cast<float>(image_count), 0);
449 index = std::max(std::min(index, image_count - 1), 0);
450
451 // Lazily cache images.
452 if (!images[index]) {
453 gfx::ImageSkia source = GetImageForIndex(image_type, color, index + 1);
454 images[index] = new gfx::ImageSkia(
455 gfx::ImageSkiaOperations::CreateBlendedImage(
456 gfx::ImageSkia(new EmptyImageSource(source.size()), source.size()),
457 source,
458 kConnectingImageAlpha));
459 }
460 gfx::ImageSkia& icon = *images[index];
461 return gfx::ImageSkia(
462 new NetworkIconImageSource(icon, Badges()), icon.size());
463 }
464
465 } // namespace
466
467 //------------------------------------------------------------------------------
468 // NetworkIconImpl
469
470 NetworkIconImpl::NetworkIconImpl(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 NetworkIconImpl::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 NetworkIconImpl::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 NetworkIconImpl::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 NetworkIconImpl::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 NetworkIconImpl* icon;
555 NetworkIconMap::iterator iter = icon_map->find(network->path());
556 if (iter == icon_map->end()) {
557 icon = new NetworkIconImpl(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
« no previous file with comments | « ash/system/chromeos/network/network_icon.h ('k') | ash/system/chromeos/network/network_icon_animation_observer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698