OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/status/network_menu_button.h" | 5 #include "chrome/browser/chromeos/status/network_menu_button.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <limits> | 8 #include <limits> |
9 | 9 |
10 #include "app/l10n_util.h" | 10 #include "app/l10n_util.h" |
11 #include "app/resource_bundle.h" | 11 #include "app/resource_bundle.h" |
12 #include "base/string_util.h" | 12 #include "base/string_util.h" |
13 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" |
14 #include "chrome/browser/chromeos/cros/cros_library.h" | 14 #include "chrome/browser/chromeos/cros/cros_library.h" |
15 #include "chrome/browser/chromeos/options/network_config_view.h" | 15 #include "chrome/browser/chromeos/options/network_config_view.h" |
16 #include "chrome/browser/chromeos/status/status_area_host.h" | 16 #include "chrome/browser/chromeos/status/status_area_host.h" |
17 #include "gfx/canvas_skia.h" | 17 #include "gfx/canvas_skia.h" |
18 #include "gfx/skbitmap_operations.h" | |
19 #include "grit/generated_resources.h" | 18 #include "grit/generated_resources.h" |
20 #include "grit/theme_resources.h" | 19 #include "grit/theme_resources.h" |
21 #include "views/widget/widget.h" | |
22 #include "views/window/window.h" | 20 #include "views/window/window.h" |
23 | 21 |
24 namespace chromeos { | 22 namespace chromeos { |
25 | 23 |
26 //////////////////////////////////////////////////////////////////////////////// | 24 //////////////////////////////////////////////////////////////////////////////// |
27 // NetworkMenuButton | 25 // NetworkMenuButton |
28 | 26 |
29 // static | 27 // static |
30 const int NetworkMenuButton::kNumWifiImages = 9; | |
31 const int NetworkMenuButton::kThrobDuration = 1000; | 28 const int NetworkMenuButton::kThrobDuration = 1000; |
32 | 29 |
33 NetworkMenuButton::NetworkMenuButton(StatusAreaHost* host) | 30 NetworkMenuButton::NetworkMenuButton(StatusAreaHost* host) |
34 : StatusAreaButton(this), | 31 : StatusAreaButton(this), |
| 32 NetworkMenu(), |
35 host_(host), | 33 host_(host), |
36 ALLOW_THIS_IN_INITIALIZER_LIST(network_menu_(this)), | |
37 ALLOW_THIS_IN_INITIALIZER_LIST(animation_connecting_(this)) { | 34 ALLOW_THIS_IN_INITIALIZER_LIST(animation_connecting_(this)) { |
38 animation_connecting_.SetThrobDuration(kThrobDuration); | 35 animation_connecting_.SetThrobDuration(kThrobDuration); |
39 animation_connecting_.SetTweenType(Tween::LINEAR); | 36 animation_connecting_.SetTweenType(Tween::LINEAR); |
40 NetworkChanged(CrosLibrary::Get()->GetNetworkLibrary()); | 37 NetworkChanged(CrosLibrary::Get()->GetNetworkLibrary()); |
41 CrosLibrary::Get()->GetNetworkLibrary()->AddObserver(this); | 38 CrosLibrary::Get()->GetNetworkLibrary()->AddObserver(this); |
42 } | 39 } |
43 | 40 |
44 NetworkMenuButton::~NetworkMenuButton() { | 41 NetworkMenuButton::~NetworkMenuButton() { |
45 CrosLibrary::Get()->GetNetworkLibrary()->RemoveObserver(this); | 42 CrosLibrary::Get()->GetNetworkLibrary()->RemoveObserver(this); |
46 } | 43 } |
47 | 44 |
48 //////////////////////////////////////////////////////////////////////////////// | 45 //////////////////////////////////////////////////////////////////////////////// |
49 // NetworkMenuButton, menus::MenuModel implementation: | |
50 | |
51 int NetworkMenuButton::GetItemCount() const { | |
52 return static_cast<int>(menu_items_.size()); | |
53 } | |
54 | |
55 menus::MenuModel::ItemType NetworkMenuButton::GetTypeAt(int index) const { | |
56 return menu_items_[index].type; | |
57 } | |
58 | |
59 string16 NetworkMenuButton::GetLabelAt(int index) const { | |
60 return menu_items_[index].label; | |
61 } | |
62 | |
63 const gfx::Font* NetworkMenuButton::GetLabelFontAt(int index) const { | |
64 return (menu_items_[index].flags & FLAG_ASSOCIATED) ? | |
65 &ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BoldFont) : | |
66 NULL; | |
67 } | |
68 | |
69 bool NetworkMenuButton::IsItemCheckedAt(int index) const { | |
70 // All menus::MenuModel::TYPE_CHECK menu items are checked. | |
71 return true; | |
72 } | |
73 | |
74 bool NetworkMenuButton::GetIconAt(int index, SkBitmap* icon) const { | |
75 if (!menu_items_[index].icon.empty()) { | |
76 *icon = menu_items_[index].icon; | |
77 return true; | |
78 } | |
79 return false; | |
80 } | |
81 | |
82 bool NetworkMenuButton::IsEnabledAt(int index) const { | |
83 return !(menu_items_[index].flags & FLAG_DISABLED); | |
84 } | |
85 | |
86 void NetworkMenuButton::ActivatedAt(int index) { | |
87 // When we are refreshing the menu, ignore menu item activation. | |
88 if (refreshing_menu_) | |
89 return; | |
90 | |
91 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); | |
92 int flags = menu_items_[index].flags; | |
93 if (flags & FLAG_OPTIONS) { | |
94 host_->OpenButtonOptions(this); | |
95 } else if (flags & FLAG_TOGGLE_ETHERNET) { | |
96 cros->EnableEthernetNetworkDevice(!cros->ethernet_enabled()); | |
97 } else if (flags & FLAG_TOGGLE_WIFI) { | |
98 cros->EnableWifiNetworkDevice(!cros->wifi_enabled()); | |
99 } else if (flags & FLAG_TOGGLE_CELLULAR) { | |
100 cros->EnableCellularNetworkDevice(!cros->cellular_enabled()); | |
101 } else if (flags & FLAG_TOGGLE_OFFLINE) { | |
102 cros->EnableOfflineMode(!cros->offline_mode()); | |
103 } else if (flags & FLAG_OTHER_NETWORK) { | |
104 NetworkConfigView* view = new NetworkConfigView(); | |
105 view->set_browser_mode(host_->IsBrowserMode()); | |
106 views::Window* window = views::Window::CreateChromeWindow( | |
107 host_->GetNativeWindow(), gfx::Rect(), view); | |
108 window->SetIsAlwaysOnTop(true); | |
109 window->Show(); | |
110 view->SetLoginTextfieldFocus(); | |
111 } else if (flags & FLAG_ETHERNET) { | |
112 if (cros->ethernet_connected()) { | |
113 NetworkConfigView* view = new NetworkConfigView(cros->ethernet_network()); | |
114 view->set_browser_mode(host_->IsBrowserMode()); | |
115 views::Window* window = views::Window::CreateChromeWindow( | |
116 host_->GetNativeWindow(), gfx::Rect(), view); | |
117 window->SetIsAlwaysOnTop(true); | |
118 window->Show(); | |
119 } | |
120 } else if (flags & FLAG_WIFI) { | |
121 WifiNetwork wifi; | |
122 bool wifi_exists = cros->FindWifiNetworkByPath( | |
123 menu_items_[index].wireless_path, &wifi); | |
124 if (!wifi_exists) { | |
125 // If we are attempting to connect to a network that no longer exists, | |
126 // display a notification. | |
127 // TODO(stevenjb): Show notification. | |
128 } else if (wifi.name() == cros->wifi_name()) { | |
129 if (cros->wifi_connected()) { | |
130 // If we are already connected, open the config dialog. | |
131 NetworkConfigView* view = new NetworkConfigView(wifi, false); | |
132 view->set_browser_mode(host_->IsBrowserMode()); | |
133 views::Window* window = views::Window::CreateChromeWindow( | |
134 host_->GetNativeWindow(), gfx::Rect(), view); | |
135 window->SetIsAlwaysOnTop(true); | |
136 window->Show(); | |
137 } else { | |
138 // TODO(stevenjb): Connection in progress. Show dialog? | |
139 } | |
140 } else { | |
141 // If wifi network is not encrypted, then directly connect. | |
142 // Otherwise, we open password dialog window. | |
143 if (!wifi.encrypted()) { | |
144 cros->ConnectToWifiNetwork(wifi, std::string(), | |
145 std::string(), std::string()); | |
146 } else { | |
147 NetworkConfigView* view = new NetworkConfigView(wifi, true); | |
148 view->set_browser_mode(host_->IsBrowserMode()); | |
149 views::Window* window = views::Window::CreateChromeWindow( | |
150 host_->GetNativeWindow(), gfx::Rect(), view); | |
151 window->SetIsAlwaysOnTop(true); | |
152 window->Show(); | |
153 view->SetLoginTextfieldFocus(); | |
154 } | |
155 } | |
156 } else if (flags & FLAG_CELLULAR) { | |
157 CellularNetwork cellular; | |
158 bool cellular_exists = cros->FindCellularNetworkByPath( | |
159 menu_items_[index].wireless_path, &cellular); | |
160 | |
161 if (!cellular_exists) { | |
162 // If we are attempting to connect to a network that no longer exists, | |
163 // display a notification. | |
164 // TODO(stevenjb): Show notification. | |
165 } else if (cellular.name() == cros->cellular_name()) { | |
166 // If clicked on a network that we are already connected to or we are | |
167 // currently trying to connect to, then open config dialog. | |
168 if (cros->cellular_connected()) { | |
169 NetworkConfigView* view = new NetworkConfigView(cellular); | |
170 view->set_browser_mode(host_->IsBrowserMode()); | |
171 views::Window* window = views::Window::CreateChromeWindow( | |
172 host_->GetNativeWindow(), gfx::Rect(), view); | |
173 window->SetIsAlwaysOnTop(true); | |
174 window->Show(); | |
175 } else { | |
176 // TODO(stevenjb): Connection in progress. Show dialog? | |
177 } | |
178 } else { | |
179 cros->ConnectToCellularNetwork(cellular); | |
180 } | |
181 } | |
182 } | |
183 | |
184 //////////////////////////////////////////////////////////////////////////////// | |
185 // NetworkMenuButton, AnimationDelegate implementation: | 46 // NetworkMenuButton, AnimationDelegate implementation: |
186 | 47 |
187 void NetworkMenuButton::AnimationProgressed(const Animation* animation) { | 48 void NetworkMenuButton::AnimationProgressed(const Animation* animation) { |
188 if (animation == &animation_connecting_) { | 49 if (animation == &animation_connecting_) { |
189 // Figure out which image to draw. We want a value between 0-100. | 50 // Figure out which image to draw. We want a value between 0-100. |
190 // 0 reperesents no signal and 100 represents full signal strength. | 51 // 0 reperesents no signal and 100 represents full signal strength. |
191 int value = static_cast<int>(animation_connecting_.GetCurrentValue()*100.0); | 52 int value = static_cast<int>(animation_connecting_.GetCurrentValue()*100.0); |
192 if (value < 0) | 53 if (value < 0) |
193 value = 0; | 54 value = 0; |
194 else if (value > 100) | 55 else if (value > 100) |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
286 IDS_STATUSBAR_NETWORK_NO_NETWORK_TOOLTIP)); | 147 IDS_STATUSBAR_NETWORK_NO_NETWORK_TOOLTIP)); |
287 } | 148 } |
288 | 149 |
289 SchedulePaint(); | 150 SchedulePaint(); |
290 } | 151 } |
291 | 152 |
292 void NetworkMenuButton::SetBadge(const SkBitmap& badge) { | 153 void NetworkMenuButton::SetBadge(const SkBitmap& badge) { |
293 badge_ = badge; | 154 badge_ = badge; |
294 } | 155 } |
295 | 156 |
296 // static | 157 //////////////////////////////////////////////////////////////////////////////// |
297 SkBitmap NetworkMenuButton::IconForNetworkStrength(int strength, bool black) { | 158 // NetworkMenuButton, NetworkMenu implementation: |
298 // Compose wifi icon by superimposing various icons. | |
299 // NOTE: Use an array rather than just calculating a resource number to avoid | |
300 // creating implicit ordering dependencies on the resource values. | |
301 static const int kBarsImages[kNumWifiImages] = { | |
302 IDR_STATUSBAR_NETWORK_BARS1, | |
303 IDR_STATUSBAR_NETWORK_BARS2, | |
304 IDR_STATUSBAR_NETWORK_BARS3, | |
305 IDR_STATUSBAR_NETWORK_BARS4, | |
306 IDR_STATUSBAR_NETWORK_BARS5, | |
307 IDR_STATUSBAR_NETWORK_BARS6, | |
308 IDR_STATUSBAR_NETWORK_BARS7, | |
309 IDR_STATUSBAR_NETWORK_BARS8, | |
310 IDR_STATUSBAR_NETWORK_BARS9, | |
311 }; | |
312 static const int kBarsBlackImages[kNumWifiImages] = { | |
313 IDR_STATUSBAR_NETWORK_BARS1_BLACK, | |
314 IDR_STATUSBAR_NETWORK_BARS2_BLACK, | |
315 IDR_STATUSBAR_NETWORK_BARS3_BLACK, | |
316 IDR_STATUSBAR_NETWORK_BARS4_BLACK, | |
317 IDR_STATUSBAR_NETWORK_BARS5_BLACK, | |
318 IDR_STATUSBAR_NETWORK_BARS6_BLACK, | |
319 IDR_STATUSBAR_NETWORK_BARS7_BLACK, | |
320 IDR_STATUSBAR_NETWORK_BARS8_BLACK, | |
321 IDR_STATUSBAR_NETWORK_BARS9_BLACK, | |
322 }; | |
323 | 159 |
324 int index = static_cast<int>(strength / 100.0 * | 160 bool NetworkMenuButton::IsBrowserMode() const { |
325 nextafter(static_cast<float>(kNumWifiImages), 0)); | 161 return host_->IsBrowserMode(); |
326 index = std::max(std::min(index, kNumWifiImages - 1), 0); | |
327 return *ResourceBundle::GetSharedInstance().GetBitmapNamed( | |
328 black ? kBarsBlackImages[index] : kBarsImages[index]); | |
329 } | 162 } |
330 | 163 |
331 // static | 164 gfx::NativeWindow NetworkMenuButton::GetNativeWindow() const { |
332 SkBitmap NetworkMenuButton::IconForDisplay(SkBitmap icon, SkBitmap badge) { | 165 return host_->GetNativeWindow(); |
333 // Icons are 24x24. | |
334 static const int kIconWidth = 24; | |
335 static const int kIconHeight = 24; | |
336 // Draw the network icon 3 pixels down to center it. | |
337 static const int kIconX = 0; | |
338 static const int kIconY = 3; | |
339 // Draw badge at (14,14). | |
340 static const int kBadgeX = 14; | |
341 static const int kBadgeY = 14; | |
342 | |
343 gfx::CanvasSkia canvas(kIconWidth, kIconHeight, false); | |
344 canvas.DrawBitmapInt(icon, kIconX, kIconY); | |
345 if (!badge.empty()) | |
346 canvas.DrawBitmapInt(badge, kBadgeX, kBadgeY); | |
347 return canvas.ExtractBitmap(); | |
348 } | 166 } |
349 | 167 |
350 //////////////////////////////////////////////////////////////////////////////// | 168 void NetworkMenuButton::OpenButtonOptions() const { |
351 // NetworkMenuButton, views::ViewMenuDelegate implementation: | 169 host_->OpenButtonOptions(this); |
352 | |
353 void NetworkMenuButton::RunMenu(views::View* source, const gfx::Point& pt) { | |
354 refreshing_menu_ = true; | |
355 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); | |
356 cros->RequestWifiScan(); | |
357 cros->UpdateSystemInfo(); | |
358 InitMenuItems(); | |
359 network_menu_.Rebuild(); | |
360 network_menu_.UpdateStates(); | |
361 refreshing_menu_ = false; | |
362 network_menu_.RunMenuAt(pt, views::Menu2::ALIGN_TOPRIGHT); | |
363 } | 170 } |
364 | 171 |
365 void NetworkMenuButton::InitMenuItems() { | 172 bool NetworkMenuButton::ShouldOpenButtonOptions() const { |
366 menu_items_.clear(); | 173 return host_->ShouldOpenButtonOptions(this); |
367 // Populate our MenuItems with the current list of wifi networks. | |
368 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); | |
369 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
370 | |
371 // Ethernet (if enabled, which means it's available)) | |
372 if (cros->ethernet_enabled()) { | |
373 string16 label = l10n_util::GetStringUTF16( | |
374 IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET); | |
375 SkBitmap icon = *rb.GetBitmapNamed(IDR_STATUSBAR_WIRED_BLACK); | |
376 SkBitmap badge = cros->ethernet_connecting() || cros->ethernet_connected() ? | |
377 SkBitmap() : *rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_DISCONNECTED); | |
378 int flag = (cros->ethernet_connecting() || cros->ethernet_connected()) ? | |
379 FLAG_ETHERNET | FLAG_ASSOCIATED : FLAG_ETHERNET; | |
380 menu_items_.push_back(MenuItem(menus::MenuModel::TYPE_COMMAND, label, | |
381 IconForDisplay(icon, badge), std::string(), flag)); | |
382 } | |
383 | |
384 // Wifi | |
385 const WifiNetworkVector& wifi_networks = cros->wifi_networks(); | |
386 // Wifi networks ssids. | |
387 for (size_t i = 0; i < wifi_networks.size(); ++i) { | |
388 string16 label = ASCIIToUTF16(wifi_networks[i].name()); | |
389 SkBitmap icon = IconForNetworkStrength(wifi_networks[i].strength(), true); | |
390 SkBitmap badge = wifi_networks[i].encrypted() ? | |
391 *rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_SECURE) : SkBitmap(); | |
392 int flag = (wifi_networks[i].name() == cros->wifi_name()) ? | |
393 FLAG_WIFI | FLAG_ASSOCIATED : FLAG_WIFI; | |
394 menu_items_.push_back(MenuItem(menus::MenuModel::TYPE_COMMAND, label, | |
395 IconForDisplay(icon, badge), wifi_networks[i].service_path(), flag)); | |
396 } | |
397 | |
398 // Cellular | |
399 const CellularNetworkVector& cell_networks = cros->cellular_networks(); | |
400 // Cellular networks ssids. | |
401 for (size_t i = 0; i < cell_networks.size(); ++i) { | |
402 string16 label = ASCIIToUTF16(cell_networks[i].name()); | |
403 SkBitmap icon = IconForNetworkStrength(cell_networks[i].strength(), true); | |
404 // TODO(chocobo): Check cellular network 3g/edge. | |
405 SkBitmap badge = *rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_3G); | |
406 // SkBitmap badge = *rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_EDGE); | |
407 int flag = (cell_networks[i].name() == cros->cellular_name()) ? | |
408 FLAG_CELLULAR | FLAG_ASSOCIATED : FLAG_CELLULAR; | |
409 menu_items_.push_back(MenuItem(menus::MenuModel::TYPE_COMMAND, label, | |
410 IconForDisplay(icon, badge), cell_networks[i].service_path(), flag)); | |
411 } | |
412 | |
413 // No networks available message. | |
414 if (wifi_networks.empty() && cell_networks.empty()) { | |
415 string16 label = l10n_util::GetStringFUTF16( | |
416 IDS_STATUSBAR_NETWORK_MENU_ITEM_INDENT, | |
417 l10n_util::GetStringUTF16(IDS_STATUSBAR_NO_NETWORKS_MESSAGE)); | |
418 menu_items_.push_back(MenuItem(menus::MenuModel::TYPE_COMMAND, label, | |
419 SkBitmap(), std::string(), FLAG_DISABLED)); | |
420 } | |
421 | |
422 // Add "Other..." if wifi is enabled. | |
423 if (cros->wifi_enabled()) { | |
424 menu_items_.push_back(MenuItem(menus::MenuModel::TYPE_COMMAND, | |
425 l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_OTHER_NETWORKS), | |
426 IconForDisplay(*rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_BARS0), | |
427 SkBitmap()), | |
428 std::string(), FLAG_OTHER_NETWORK)); | |
429 } | |
430 | |
431 if (cros->wifi_available() || cros->cellular_available()) { | |
432 // Separator. | |
433 menu_items_.push_back(MenuItem()); | |
434 | |
435 // Turn Wifi Off. (only if wifi available) | |
436 if (cros->wifi_available()) { | |
437 int id = cros->wifi_enabled() ? IDS_STATUSBAR_NETWORK_DEVICE_DISABLE : | |
438 IDS_STATUSBAR_NETWORK_DEVICE_ENABLE; | |
439 string16 label = l10n_util::GetStringFUTF16(id, | |
440 l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_WIFI)); | |
441 menu_items_.push_back(MenuItem(menus::MenuModel::TYPE_COMMAND, label, | |
442 SkBitmap(), std::string(), FLAG_TOGGLE_WIFI)); | |
443 } | |
444 | |
445 // Turn Cellular Off. (only if cellular available) | |
446 if (cros->cellular_available()) { | |
447 int id = cros->cellular_enabled() ? IDS_STATUSBAR_NETWORK_DEVICE_DISABLE : | |
448 IDS_STATUSBAR_NETWORK_DEVICE_ENABLE; | |
449 string16 label = l10n_util::GetStringFUTF16(id, | |
450 l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CELLULAR)); | |
451 menu_items_.push_back(MenuItem(menus::MenuModel::TYPE_COMMAND, label, | |
452 SkBitmap(), std::string(), FLAG_TOGGLE_CELLULAR)); | |
453 } | |
454 } | |
455 | |
456 // TODO(chocobo): Uncomment once we figure out how to do offline mode. | |
457 // Offline mode. | |
458 // menu_items_.push_back(MenuItem(cros->offline_mode() ? | |
459 // menus::MenuModel::TYPE_CHECK : menus::MenuModel::TYPE_COMMAND, | |
460 // l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_OFFLINE_MODE), | |
461 // SkBitmap(), std::string(), FLAG_TOGGLE_OFFLINE)); | |
462 | |
463 if (cros->Connected() || host_->ShouldOpenButtonOptions(this)) { | |
464 // Separator. | |
465 menu_items_.push_back(MenuItem()); | |
466 | |
467 // IP address | |
468 if (cros->Connected()) { | |
469 menu_items_.push_back(MenuItem(menus::MenuModel::TYPE_COMMAND, | |
470 ASCIIToUTF16(cros->IPAddress()), SkBitmap(), | |
471 std::string(), FLAG_DISABLED)); | |
472 } | |
473 | |
474 // Network settings. | |
475 if (host_->ShouldOpenButtonOptions(this)) { | |
476 string16 label = | |
477 l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_OPEN_OPTIONS_DIALOG); | |
478 menu_items_.push_back(MenuItem(menus::MenuModel::TYPE_COMMAND, label, | |
479 SkBitmap(), std::string(), FLAG_OPTIONS)); | |
480 } | |
481 } | |
482 } | 174 } |
483 | 175 |
484 } // namespace chromeos | 176 } // namespace chromeos |
OLD | NEW |