| OLD | NEW |
| (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 | |
| OLD | NEW |