1 // Copyright (c) 2011 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 "chrome/browser/chromeos/status/network_menu.h"
6
7 #include <algorithm>
8
9 #include "base/logging.h"
10 #include "base/command_line.h"
11 #include "base/stringprintf.h"
12 #include "base/utf_string_conversions.h"
13 #include "chrome/browser/chromeos/choose_mobile_network_dialog.h"
14 #include "chrome/browser/chromeos/cros/cros_library.h"
15 #include "chrome/browser/chromeos/customization_document.h"
16 #include "chrome/browser/chromeos/sim_dialog_delegate.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/browser_list.h"
19 #include "chrome/browser/ui/views/window.h"
20 #include "chrome/common/url_constants.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "grit/generated_resources.h"
23 #include "grit/theme_resources.h"
24 #include "net/base/escape.h"
25 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/base/resource/resource_bundle.h"
27 #include "ui/gfx/canvas_skia.h"
28 #include "ui/gfx/skbitmap_operations.h"
29 #include "views/controls/menu/menu_2.h"
30 #include "views/window/window.h"
31
32 namespace {
33
34 // Amount to fade icons while connecting.
35 const double kConnectingImageAlpha = 0.5;
36
37 // Replace '&' in a string with "&&" to allow it to be a menu item label.
EscapeAmpersands(const std::string & input)38 std::string EscapeAmpersands(const std::string& input) {
39 std::string str = input;
40 size_t found = str.find('&');
41 while (found != std::string::npos) {
42 str.replace(found, 1, "&&");
43 found = str.find('&', found + 2);
44 }
45 return str;
46 }
47
48 } // namespace
49
50 namespace chromeos {
51
52 class MoreMenuModel : public NetworkMenuModel {
53 public:
54 explicit MoreMenuModel(NetworkMenu* owner);
~MoreMenuModel()55 virtual ~MoreMenuModel() {}
56
57 // NetworkMenuModel implementation.
58 virtual void InitMenuItems(bool is_browser_mode,
59 bool should_open_button_options);
60
61 private:
62 friend class MainMenuModel;
63 DISALLOW_COPY_AND_ASSIGN(MoreMenuModel);
64 };
65
66 class VPNMenuModel : public NetworkMenuModel {
67 public:
68 explicit VPNMenuModel(NetworkMenu* owner);
~VPNMenuModel()69 virtual ~VPNMenuModel() {}
70
71 // NetworkMenuModel implementation.
72 virtual void InitMenuItems(bool is_browser_mode,
73 bool should_open_button_options);
74
75 static SkBitmap IconForDisplay(const Network* network);
76
77 private:
78 DISALLOW_COPY_AND_ASSIGN(VPNMenuModel);
79 };
80
81 class MainMenuModel : public NetworkMenuModel {
82 public:
83 explicit MainMenuModel(NetworkMenu* owner);
~MainMenuModel()84 virtual ~MainMenuModel() {}
85
86 // NetworkMenuModel implementation.
87 virtual void InitMenuItems(bool is_browser_mode,
88 bool should_open_button_options);
89
90 private:
91 scoped_ptr<NetworkMenuModel> vpn_menu_model_;
92 scoped_ptr<MoreMenuModel> more_menu_model_;
93
94 DISALLOW_COPY_AND_ASSIGN(MainMenuModel);
95 };
96
97 ////////////////////////////////////////////////////////////////////////////////
98 // NetworkMenuModel, public methods:
99
ConnectToNetworkAt(int index,const std::string & passphrase,const std::string & ssid,int auto_connect) const100 bool NetworkMenuModel::ConnectToNetworkAt(int index,
101 const std::string& passphrase,
102 const std::string& ssid,
103 int auto_connect) const {
104 int flags = menu_items_[index].flags;
105 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
106 const std::string& service_path = menu_items_[index].service_path;
107 if (flags & FLAG_WIFI) {
108 WifiNetwork* wifi = cros->FindWifiNetworkByPath(service_path);
109 if (wifi) {
110 // Connect or reconnect.
111 if (auto_connect >= 0)
112 wifi->SetAutoConnect(auto_connect ? true : false);
113 if (wifi->connecting_or_connected()) {
114 // Show the config settings for the active network.
115 owner_->ShowTabbedNetworkSettings(wifi);
116 return true;
117 }
118 if (wifi->IsPassphraseRequired()) {
119 // Show the connection UI if we require a passphrase.
120 ShowNetworkConfigView(new NetworkConfigView(wifi));
121 return true;
122 } else {
123 cros->ConnectToWifiNetwork(wifi);
124 // Connection failures are responsible for updating the UI, including
125 // reopening dialogs.
126 return true;
127 }
128 } else {
129 // If we are attempting to connect to a network that no longer exists,
130 // display a notification.
131 LOG(WARNING) << "Wi-fi network does not exist to connect to: "
132 << service_path;
133 // TODO(stevenjb): Show notification.
134 }
135 } else if (flags & FLAG_CELLULAR) {
136 CellularNetwork* cellular = cros->FindCellularNetworkByPath(
137 service_path);
138 if (cellular) {
139 if ((cellular->activation_state() != ACTIVATION_STATE_ACTIVATED &&
140 cellular->activation_state() != ACTIVATION_STATE_UNKNOWN) ||
141 cellular->needs_new_plan()) {
142 ActivateCellular(cellular);
143 return true;
144 } else if (cellular->connecting_or_connected()) {
145 // Cellular network is connecting or connected,
146 // so we show the config settings for the cellular network.
147 owner_->ShowTabbedNetworkSettings(cellular);
148 return true;
149 }
150 // Clicked on a disconnected cellular network, so connect to it.
151 cros->ConnectToCellularNetwork(cellular);
152 } else {
153 // If we are attempting to connect to a network that no longer exists,
154 // display a notification.
155 LOG(WARNING) << "Cellular network does not exist to connect to: "
156 << service_path;
157 // TODO(stevenjb): Show notification.
158 }
159 } else if (flags & FLAG_ADD_WIFI) {
160 ShowOther(TYPE_WIFI);
161 } else if (flags & FLAG_ADD_CELLULAR) {
162 ShowOtherCellular();
163 } else if (flags & FLAG_ADD_VPN) {
164 ShowOther(TYPE_VPN);
165 } else if (flags & FLAG_VPN) {
166 VirtualNetwork* vpn = cros->FindVirtualNetworkByPath(service_path);
167 if (vpn) {
168 // Connect or reconnect.
169 if (vpn->connecting_or_connected()) {
170 // Show the config settings for the connected network.
171 if (cros->connected_network())
172 owner_->ShowTabbedNetworkSettings(cros->connected_network());
173 return true;
174 }
175 // Show the connection UI if info for a field is missing.
176 if (vpn->NeedMoreInfoToConnect()) {
177 ShowNetworkConfigView(new NetworkConfigView(vpn));
178 return true;
179 }
180 cros->ConnectToVirtualNetwork(vpn);
181 // Connection failures are responsible for updating the UI, including
182 // reopening dialogs.
183 return true;
184 } else {
185 // If we are attempting to connect to a network that no longer exists,
186 // display a notification.
187 LOG(WARNING) << "VPN does not exist to connect to: " << service_path;
188 // TODO(stevenjb): Show notification.
189 }
190 }
191 return true;
192 }
193
194 ////////////////////////////////////////////////////////////////////////////////
195 // NetworkMenuModel, ui::MenuModel implementation:
196
GetItemCount() const197 int NetworkMenuModel::GetItemCount() const {
198 return static_cast<int>(menu_items_.size());
199 }
200
GetTypeAt(int index) const201 ui::MenuModel::ItemType NetworkMenuModel::GetTypeAt(int index) const {
202 return menu_items_[index].type;
203 }
204
GetLabelAt(int index) const205 string16 NetworkMenuModel::GetLabelAt(int index) const {
206 return menu_items_[index].label;
207 }
208
GetLabelFontAt(int index) const209 const gfx::Font* NetworkMenuModel::GetLabelFontAt(int index) const {
210 return (menu_items_[index].flags & FLAG_ASSOCIATED) ?
211 &ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BoldFont) :
212 NULL;
213 }
214
IsItemCheckedAt(int index) const215 bool NetworkMenuModel::IsItemCheckedAt(int index) const {
216 // All ui::MenuModel::TYPE_CHECK menu items are checked.
217 return true;
218 }
219
GetIconAt(int index,SkBitmap * icon)220 bool NetworkMenuModel::GetIconAt(int index, SkBitmap* icon) {
221 if (!menu_items_[index].icon.empty()) {
222 *icon = menu_items_[index].icon;
223 return true;
224 }
225 return false;
226 }
227
IsEnabledAt(int index) const228 bool NetworkMenuModel::IsEnabledAt(int index) const {
229 return !(menu_items_[index].flags & FLAG_DISABLED);
230 }
231
GetSubmenuModelAt(int index) const232 ui::MenuModel* NetworkMenuModel::GetSubmenuModelAt(int index) const {
233 return menu_items_[index].sub_menu_model;
234 }
235
ActivatedAt(int index)236 void NetworkMenuModel::ActivatedAt(int index) {
237 // When we are refreshing the menu, ignore menu item activation.
238 if (owner_->refreshing_menu_)
239 return;
240
241 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
242 int flags = menu_items_[index].flags;
243 if (flags & FLAG_OPTIONS) {
244 owner_->OpenButtonOptions();
245 } else if (flags & FLAG_TOGGLE_ETHERNET) {
246 cros->EnableEthernetNetworkDevice(!cros->ethernet_enabled());
247 } else if (flags & FLAG_TOGGLE_WIFI) {
248 cros->EnableWifiNetworkDevice(!cros->wifi_enabled());
249 } else if (flags & FLAG_TOGGLE_CELLULAR) {
250 const NetworkDevice* cellular = cros->FindCellularDevice();
251 if (!cellular) {
252 LOG(ERROR) << "No cellular device found, it should be available.";
253 cros->EnableCellularNetworkDevice(!cros->cellular_enabled());
254 } else if (cellular->sim_lock_state() == SIM_UNLOCKED ||
255 cellular->sim_lock_state() == SIM_UNKNOWN) {
256 cros->EnableCellularNetworkDevice(!cros->cellular_enabled());
257 } else {
258 SimDialogDelegate::ShowDialog(owner_->GetNativeWindow(),
259 SimDialogDelegate::SIM_DIALOG_UNLOCK);
260 }
261 } else if (flags & FLAG_TOGGLE_OFFLINE) {
262 cros->EnableOfflineMode(!cros->offline_mode());
263 } else if (flags & FLAG_ETHERNET) {
264 if (cros->ethernet_connected()) {
265 owner_->ShowTabbedNetworkSettings(cros->ethernet_network());
266 }
267 } else if (flags & (FLAG_WIFI | FLAG_ADD_WIFI |
268 FLAG_CELLULAR | FLAG_ADD_CELLULAR |
269 FLAG_VPN | FLAG_ADD_VPN)) {
270 ConnectToNetworkAt(index, std::string(), std::string(), -1);
271 } else if (flags & FLAG_DISCONNECT_VPN) {
272 const VirtualNetwork* active_vpn = cros->virtual_network();
273 if (active_vpn)
274 cros->DisconnectFromNetwork(active_vpn);
275 } else if (flags & FLAG_VIEW_ACCOUNT) {
276 Browser* browser = BrowserList::GetLastActive();
277 if (browser)
278 browser->ShowSingletonTab(GURL(top_up_url_));
279 }
280 }
281
282 ////////////////////////////////////////////////////////////////////////////////
283 // NetworkMenuModel, private methods:
284
285 // TODO(stevenjb): deprecate this once we've committed to tabbed settings
286 // and the embedded menu UI (and fully deprecated NetworkConfigView).
287 // Meanwhile, if MenuUI::IsEnabled() is true, always show the settings UI,
288 // otherwise show NetworkConfigView only to get passwords when not connected.
ShowNetworkConfigView(NetworkConfigView * view) const289 void NetworkMenuModel::ShowNetworkConfigView(NetworkConfigView* view) const {
290 view->set_browser_mode(owner_->IsBrowserMode());
291 views::Window* window = browser::CreateViewsWindow(
292 owner_->GetNativeWindow(), gfx::Rect(), view);
293 window->SetIsAlwaysOnTop(true);
294 window->Show();
295 }
296
ActivateCellular(const CellularNetwork * cellular) const297 void NetworkMenuModel::ActivateCellular(const CellularNetwork* cellular) const {
298 DCHECK(cellular);
299 Browser* browser = BrowserList::GetLastActive();
300 if (!browser)
301 return;
302 browser->OpenMobilePlanTabAndActivate();
303 }
304
ShowOther(ConnectionType type) const305 void NetworkMenuModel::ShowOther(ConnectionType type) const {
306 ShowNetworkConfigView(new NetworkConfigView(type));
307 }
308
ShowOtherCellular() const309 void NetworkMenuModel::ShowOtherCellular() const {
310 ChooseMobileNetworkDialog::ShowDialog(owner_->GetNativeWindow());
311 }
312
313 ////////////////////////////////////////////////////////////////////////////////
314 // MainMenuModel
315
MainMenuModel(NetworkMenu * owner)316 MainMenuModel::MainMenuModel(NetworkMenu* owner)
317 : NetworkMenuModel(owner),
318 vpn_menu_model_(new VPNMenuModel(owner)),
319 more_menu_model_(new MoreMenuModel(owner)) {
320 }
321
InitMenuItems(bool is_browser_mode,bool should_open_button_options)322 void MainMenuModel::InitMenuItems(bool is_browser_mode,
323 bool should_open_button_options) {
324 // This gets called on initialization, so any changes should be reflected
325 // in CrosMock::SetNetworkLibraryStatusAreaExpectations().
326
327 menu_items_.clear();
328
329 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
330 if (cros->IsLocked()) {
331 menu_items_.push_back(
332 MenuItem(ui::MenuModel::TYPE_COMMAND,
333 l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_LOCKED),
334 SkBitmap(), std::string(), FLAG_DISABLED));
335 return;
336 }
337
338 // Populate our MenuItems with the current list of networks.
339 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
340 string16 label;
341
342 // Ethernet
343 bool ethernet_available = cros->ethernet_available();
344 bool ethernet_enabled = cros->ethernet_enabled();
345 if (ethernet_available && ethernet_enabled) {
346 bool ethernet_connected = cros->ethernet_connected();
347 bool ethernet_connecting = cros->ethernet_connecting();
348
349 if (ethernet_connecting) {
350 label = l10n_util::GetStringFUTF16(
351 IDS_STATUSBAR_NETWORK_DEVICE_STATUS,
352 l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET),
353 l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CONNECTING));
354 } else {
355 label = l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET);
356 }
357 const SkBitmap* icon = rb.GetBitmapNamed(IDR_STATUSBAR_WIRED_BLACK);
358 const SkBitmap* badge = ethernet_connecting || ethernet_connected ?
359 NULL : rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_DISCONNECTED);
360 int flag = FLAG_ETHERNET;
361 if (ethernet_connecting || ethernet_connected)
362 flag |= FLAG_ASSOCIATED;
363 menu_items_.push_back(
364 MenuItem(ui::MenuModel::TYPE_COMMAND, label,
365 NetworkMenu::IconForDisplay(icon, badge), std::string(),
366 flag));
367 }
368
369 // Wifi Networks
370 bool wifi_available = cros->wifi_available();
371 bool wifi_enabled = cros->wifi_enabled();
372 if (wifi_available && wifi_enabled) {
373 const WifiNetworkVector& wifi_networks = cros->wifi_networks();
374 const WifiNetwork* active_wifi = cros->wifi_network();
375
376 bool separator_added = false;
377 // List Wifi networks.
378 for (size_t i = 0; i < wifi_networks.size(); ++i) {
379 // Ampersand is a valid character in an SSID, but menu2 uses it to mark
380 // "mnemonics" for keyboard shortcuts.
381 std::string wifi_name = EscapeAmpersands(wifi_networks[i]->name());
382 if (wifi_networks[i]->connecting()) {
383 label = l10n_util::GetStringFUTF16(
384 IDS_STATUSBAR_NETWORK_DEVICE_STATUS,
385 UTF8ToUTF16(wifi_name),
386 l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CONNECTING));
387 } else {
388 label = UTF8ToUTF16(wifi_name);
389 }
390
391 // First add a separator if necessary.
392 if (!separator_added) {
393 separator_added = true;
394 if (!menu_items_.empty()) { // Don't add if first menu item.
395 menu_items_.push_back(MenuItem()); // Separator
396 }
397 }
398
399 const SkBitmap* icon = NetworkMenu::IconForNetworkStrength(
400 wifi_networks[i], true);
401 const SkBitmap* badge = wifi_networks[i]->encrypted() ?
402 rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_SECURE) : NULL;
403 int flag = FLAG_WIFI;
404 // If a network is not connectable from login/oobe, we disable it.
405 // We do not allow configuring a network (e.g. 802.1x) from login/oobe.
406 if (!owner_->IsBrowserMode() && !wifi_networks[i]->connectable())
407 flag |= FLAG_DISABLED;
408 if (active_wifi
409 && wifi_networks[i]->service_path() == active_wifi->service_path())
410 flag |= FLAG_ASSOCIATED;
411 menu_items_.push_back(
412 MenuItem(ui::MenuModel::TYPE_COMMAND, label,
413 NetworkMenu::IconForDisplay(icon, badge),
414 wifi_networks[i]->service_path(), flag));
415 }
416 if (!separator_added && !menu_items_.empty())
417 menu_items_.push_back(MenuItem());
418 menu_items_.push_back(MenuItem(
419 ui::MenuModel::TYPE_COMMAND,
420 l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_OTHER_WIFI_NETWORKS),
421 *rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_BARS0_BLACK),
422 std::string(), FLAG_ADD_WIFI));
423 }
424
425 // Cellular Networks
426 bool cellular_available = cros->cellular_available();
427 bool cellular_enabled = cros->cellular_enabled();
428 if (cellular_available && cellular_enabled) {
429 const CellularNetworkVector& cell_networks = cros->cellular_networks();
430 const CellularNetwork* active_cellular = cros->cellular_network();
431
432 bool separator_added = false;
433 // List Cellular networks.
434 for (size_t i = 0; i < cell_networks.size(); ++i) {
435 chromeos::ActivationState activation_state =
436 cell_networks[i]->activation_state();
437
438 // If we are on the OOBE/login screen, do not show activating 3G option.
439 if (!is_browser_mode && activation_state != ACTIVATION_STATE_ACTIVATED)
440 continue;
441
442 // Ampersand is a valid character in a network name, but menu2 uses it
443 // to mark "mnemonics" for keyboard shortcuts. http://crosbug.com/14697
444 std::string network_name = EscapeAmpersands(cell_networks[i]->name());
445 if (activation_state == ACTIVATION_STATE_NOT_ACTIVATED ||
446 activation_state == ACTIVATION_STATE_PARTIALLY_ACTIVATED) {
447 label = l10n_util::GetStringFUTF16(
448 IDS_STATUSBAR_NETWORK_DEVICE_ACTIVATE,
449 UTF8ToUTF16(network_name));
450 } else if (activation_state == ACTIVATION_STATE_ACTIVATING) {
451 label = l10n_util::GetStringFUTF16(
452 IDS_STATUSBAR_NETWORK_DEVICE_STATUS,
453 UTF8ToUTF16(network_name),
454 l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_ACTIVATING));
455 } else if (cell_networks[i]->connecting()) {
456 label = l10n_util::GetStringFUTF16(
457 IDS_STATUSBAR_NETWORK_DEVICE_STATUS,
458 UTF8ToUTF16(network_name),
459 l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CONNECTING));
460 } else {
461 label = UTF8ToUTF16(network_name);
462 }
463
464 // First add a separator if necessary.
465 if (!separator_added) {
466 separator_added = true;
467 if (!menu_items_.empty()) { // Don't add if first menu item.
468 menu_items_.push_back(MenuItem()); // Separator
469 }
470 }
471
472 const SkBitmap* icon = NetworkMenu::IconForNetworkStrength(
473 cell_networks[i], true);
474 const SkBitmap* badge = NetworkMenu::BadgeForNetworkTechnology(
475 cell_networks[i]);
476 const SkBitmap* roaming_badge = NetworkMenu::BadgeForRoamingStatus(
477 cell_networks[i]);
478 int flag = FLAG_CELLULAR;
479 bool isActive = active_cellular &&
480 cell_networks[i]->service_path() == active_cellular->service_path() &&
481 (cell_networks[i]->connecting() || cell_networks[i]->connected());
482 bool supports_data_plan =
483 active_cellular && active_cellular->SupportsDataPlan();
484 if (isActive)
485 flag |= FLAG_ASSOCIATED;
486 menu_items_.push_back(
487 MenuItem(ui::MenuModel::TYPE_COMMAND, label,
488 NetworkMenu::IconForDisplay(icon, badge, roaming_badge,
489 NULL),
490 cell_networks[i]->service_path(), flag));
491 if (isActive && supports_data_plan) {
492 label.clear();
493 if (active_cellular->needs_new_plan()) {
494 label = l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_NO_PLAN_LABEL);
495 } else {
496 const chromeos::CellularDataPlan* plan =
497 cros->GetSignificantDataPlan(active_cellular->service_path());
498 if (plan)
499 label = plan->GetUsageInfo();
500 }
501 if (label.length()) {
502 menu_items_.push_back(
503 MenuItem(ui::MenuModel::TYPE_COMMAND,
504 label, SkBitmap(),
505 std::string(), FLAG_DISABLED));
506 }
507 }
508 }
509 const NetworkDevice* cellular_device = cros->FindCellularDevice();
510 if (cellular_device) {
511 // Add "View Account" with top up URL if we know that.
512 ServicesCustomizationDocument* customization =
513 ServicesCustomizationDocument::GetInstance();
514 if (is_browser_mode && customization->IsReady()) {
515 std::string carrier_id = cros->GetCellularHomeCarrierId();
516 // If we don't have top up URL cached.
517 if (carrier_id != carrier_id_) {
518 // Mark that we've checked this carrier ID.
519 carrier_id_ = carrier_id;
520 top_up_url_.clear();
521 // Ignoring deal restrictions, use any carrier information available.
522 const ServicesCustomizationDocument::CarrierDeal* deal =
523 customization->GetCarrierDeal(carrier_id, false);
524 if (deal && !deal->top_up_url.empty())
525 top_up_url_ = deal->top_up_url;
526 }
527 if (!top_up_url_.empty()) {
528 menu_items_.push_back(MenuItem(
529 ui::MenuModel::TYPE_COMMAND,
530 l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_VIEW_ACCOUNT),
531 SkBitmap(),
532 std::string(), FLAG_VIEW_ACCOUNT));
533 }
534 }
535
536 if (cellular_device->support_network_scan()) {
537 // For GSM add mobile network scan.
538 if (!separator_added && !menu_items_.empty())
539 menu_items_.push_back(MenuItem());
540
541 menu_items_.push_back(MenuItem(
542 ui::MenuModel::TYPE_COMMAND,
543 l10n_util::GetStringUTF16(
544 IDS_OPTIONS_SETTINGS_OTHER_CELLULAR_NETWORKS),
545 *rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_BARS0_BLACK),
546 std::string(), FLAG_ADD_CELLULAR));
547 }
548 }
549 }
550
551 // No networks available message.
552 if (menu_items_.empty()) {
553 label = l10n_util::GetStringFUTF16(IDS_STATUSBAR_NETWORK_MENU_ITEM_INDENT,
554 l10n_util::GetStringUTF16(IDS_STATUSBAR_NO_NETWORKS_MESSAGE));
555 menu_items_.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND, label,
556 SkBitmap(), std::string(), FLAG_DISABLED));
557 }
558
559 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableVPN)) {
560 // If there's a connected network, add submenu for Private Networks.
561 const Network* connected_network = cros->connected_network();
562 if (connected_network) {
563 menu_items_.push_back(MenuItem()); // Separator
564 menu_items_.push_back(MenuItem(
565 ui::MenuModel::TYPE_SUBMENU,
566 l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_PRIVATE_NETWORKS),
567 VPNMenuModel::IconForDisplay(connected_network),
568 vpn_menu_model_.get(), FLAG_NONE));
569 vpn_menu_model_->InitMenuItems(
570 is_browser_mode, should_open_button_options);
571 }
572 }
573
574 // Enable / disable wireless.
575 if (wifi_available || cellular_available) {
576 menu_items_.push_back(MenuItem()); // Separator
577
578 if (wifi_available) {
579 // Add 'Scanning...'
580 if (cros->wifi_scanning()) {
581 label = l10n_util::GetStringUTF16(IDS_STATUSBAR_WIFI_SCANNING_MESSAGE);
582 menu_items_.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND, label,
583 SkBitmap(), std::string(), FLAG_DISABLED));
584 }
585
586 int id = wifi_enabled ? IDS_STATUSBAR_NETWORK_DEVICE_DISABLE :
587 IDS_STATUSBAR_NETWORK_DEVICE_ENABLE;
588 label = l10n_util::GetStringFUTF16(id,
589 l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_WIFI));
590 menu_items_.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND, label,
591 SkBitmap(), std::string(), FLAG_TOGGLE_WIFI));
592 }
593
594 if (cellular_available) {
595 const NetworkDevice* cellular = cros->FindCellularDevice();
596 bool is_locked = false;
597 if (!cellular) {
598 LOG(ERROR) << "Didn't find cellular device.";
599 } else {
600 // If cellular is SIM locked then show "Enable" action.
601 is_locked = cellular->sim_lock_state() == SIM_LOCKED_PIN ||
602 cellular->sim_lock_state() == SIM_LOCKED_PUK;
603 }
604 int id;
605 if (cellular_enabled && !is_locked)
606 id = IDS_STATUSBAR_NETWORK_DEVICE_DISABLE;
607 else
608 id = IDS_STATUSBAR_NETWORK_DEVICE_ENABLE;
609 label = l10n_util::GetStringFUTF16(id,
610 l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CELLULAR));
611 menu_items_.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND, label,
612 SkBitmap(), std::string(), FLAG_TOGGLE_CELLULAR));
613 }
614 }
615
616 // Offline mode.
617 // TODO(chocobo): Uncomment once we figure out how to do offline mode.
618 // menu_items_.push_back(MenuItem(cros->offline_mode() ?
619 // ui::MenuModel::TYPE_CHECK : ui::MenuModel::TYPE_COMMAND,
620 // l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_OFFLINE_MODE),
621 // SkBitmap(), std::string(), FLAG_TOGGLE_OFFLINE));
622
623 // Additional links like:
624 // * Network settings;
625 // * IP Address on active interface;
626 // * Hardware addresses for wifi and ethernet.
627 menu_items_.push_back(MenuItem()); // Separator
628 more_menu_model_->InitMenuItems(is_browser_mode, should_open_button_options);
629 if (is_browser_mode) {
630 // In browser mode we do not want separate submenu, inline items.
631 menu_items_.insert(
632 menu_items_.end(),
633 more_menu_model_->menu_items_.begin(),
634 more_menu_model_->menu_items_.end());
635 } else {
636 if (!more_menu_model_->menu_items_.empty()) {
637 menu_items_.push_back(MenuItem(
638 ui::MenuModel::TYPE_SUBMENU,
639 l10n_util::GetStringUTF16(IDS_LANGUAGES_MORE),
640 SkBitmap(), more_menu_model_.get(), FLAG_NONE));
641 }
642 }
643 }
644
645 ////////////////////////////////////////////////////////////////////////////////
646 // VPNMenuModel
647
VPNMenuModel(NetworkMenu * owner)648 VPNMenuModel::VPNMenuModel(NetworkMenu* owner)
649 : NetworkMenuModel(owner) {
650 }
651
InitMenuItems(bool is_browser_mode,bool should_open_button_options)652 void VPNMenuModel::InitMenuItems(bool is_browser_mode,
653 bool should_open_button_options) {
654 // This gets called on initialization, so any changes should be reflected
655 // in CrosMock::SetNetworkLibraryStatusAreaExpectations().
656
657 menu_items_.clear();
658
659 // VPN only applies if there's a connected underlying network.
660 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
661 const Network* connected_network = cros->connected_network();
662 if (!connected_network)
663 return;
664
665 // Populate our MenuItems with the current list of virtual networks.
666 const VirtualNetworkVector& virtual_networks = cros->virtual_networks();
667 const VirtualNetwork* active_vpn = cros->virtual_network();
668 SkBitmap icon = VPNMenuModel::IconForDisplay(connected_network);
669 bool separator_added = false;
670 string16 label;
671
672 for (size_t i = 0; i < virtual_networks.size(); ++i) {
673 const VirtualNetwork* vpn = virtual_networks[i];
674 if (vpn->connecting()) {
675 label = l10n_util::GetStringFUTF16(
676 IDS_STATUSBAR_NETWORK_DEVICE_STATUS,
677 UTF8ToUTF16(vpn->name()),
678 l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CONNECTING));
679 } else {
680 label = UTF8ToUTF16(vpn->name());
681 }
682
683 // First add a separator if necessary.
684 if (!separator_added) {
685 separator_added = true;
686 if (!menu_items_.empty()) { // Don't add if first menu item.
687 menu_items_.push_back(MenuItem()); // Separator
688 }
689 }
690
691 int flag = FLAG_VPN;
692 if (!vpn->connectable())
693 flag |= FLAG_DISABLED;
694 if (active_vpn && vpn->service_path() == active_vpn->service_path())
695 flag |= FLAG_ASSOCIATED;
696 menu_items_.push_back(
697 MenuItem(ui::MenuModel::TYPE_COMMAND, label, icon, vpn->service_path(),
698 flag));
699 }
700
701 // Add option to add/disconnect from vpn.
702 if (!menu_items_.empty()) { // Add separator if menu is not empty.
703 menu_items_.push_back(MenuItem());
704 }
705 menu_items_.push_back(MenuItem(
706 ui::MenuModel::TYPE_COMMAND,
707 l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_ADD_VPN),
708 SkBitmap(), std::string(), FLAG_ADD_VPN));
709 if (active_vpn) {
710 menu_items_.push_back(MenuItem(
711 ui::MenuModel::TYPE_COMMAND,
712 l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DISCONNECT_VPN),
713 SkBitmap(), std::string(), FLAG_DISCONNECT_VPN));
714 }
715 }
716
717 // static
IconForDisplay(const Network * network)718 SkBitmap VPNMenuModel::IconForDisplay(const Network* network) {
719 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
720 const SkBitmap* icon = NULL;
721 const SkBitmap* bottom_right_badge = NULL;
722 const SkBitmap* top_left_badge = NULL;
723 // We know for sure |network| is the active network, so no more checking
724 // is needed by BadgeForPrivateNetworkStatus, hence pass in NULL.
725 const SkBitmap* bottom_left_badge =
726 NetworkMenu::BadgeForPrivateNetworkStatus(NULL);
727
728 switch (network->type()) {
729 case TYPE_ETHERNET :
730 icon = rb.GetBitmapNamed(IDR_STATUSBAR_WIRED_BLACK);
731 break;
732 case TYPE_WIFI :
733 icon = NetworkMenu::IconForNetworkStrength(
734 static_cast<const WifiNetwork*>(network), true);
735 break;
736 case TYPE_CELLULAR : {
737 const CellularNetwork* cellular =
738 static_cast<const CellularNetwork*>(network);
739 icon = NetworkMenu::IconForNetworkStrength(cellular, true);
740 bottom_right_badge = NetworkMenu::BadgeForNetworkTechnology(cellular);
741 top_left_badge = NetworkMenu::BadgeForRoamingStatus(cellular);
742 break;
743 }
744 default:
745 LOG(WARNING) << "VPN not handled for connection type " << network->type();
746 return SkBitmap();
747 }
748
749 return NetworkMenu::IconForDisplay(icon, bottom_right_badge, top_left_badge,
750 bottom_left_badge);
751 }
752
753 ////////////////////////////////////////////////////////////////////////////////
754 // MoreMenuModel
755
MoreMenuModel(NetworkMenu * owner)756 MoreMenuModel::MoreMenuModel(NetworkMenu* owner)
757 : NetworkMenuModel(owner) {
758 }
759
InitMenuItems(bool is_browser_mode,bool should_open_button_options)760 void MoreMenuModel::InitMenuItems(
761 bool is_browser_mode, bool should_open_button_options) {
762 // This gets called on initialization, so any changes should be reflected
763 // in CrosMock::SetNetworkLibraryStatusAreaExpectations().
764
765 menu_items_.clear();
766 MenuItemVector link_items;
767 MenuItemVector address_items;
768
769 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
770 bool oobe = !should_open_button_options; // we don't show options for OOBE.
771 if (!oobe) {
772 string16 label = l10n_util::GetStringUTF16(is_browser_mode ?
773 IDS_STATUSBAR_NETWORK_OPEN_OPTIONS_DIALOG :
774 IDS_STATUSBAR_NETWORK_OPEN_PROXY_SETTINGS_DIALOG);
775 link_items.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND, label,
776 SkBitmap(), std::string(), FLAG_OPTIONS));
777 }
778
779 bool connected = cros->Connected(); // always call for test expectations.
780 if (connected) {
781 std::string ip_address = cros->IPAddress();
782 if (!ip_address.empty()) {
783 address_items.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND,
784 ASCIIToUTF16(cros->IPAddress()), SkBitmap(), std::string(),
785 FLAG_DISABLED));
786 }
787 }
788
789 if (!is_browser_mode) {
790 const NetworkDevice* ether = cros->FindEthernetDevice();
791 if (ether) {
792 std::string hardware_address;
793 cros->GetIPConfigs(ether->device_path(), &hardware_address,
794 NetworkLibrary::FORMAT_COLON_SEPARATED_HEX);
795 if (!hardware_address.empty()) {
796 std::string label = l10n_util::GetStringUTF8(
797 IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET) + " " + hardware_address;
798 address_items.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND,
799 UTF8ToUTF16(label), SkBitmap(), std::string(), FLAG_DISABLED));
800 }
801 }
802
803 if (cros->wifi_enabled()) {
804 const NetworkDevice* wifi = cros->FindWifiDevice();
805 if (wifi) {
806 std::string hardware_address;
807 cros->GetIPConfigs(wifi->device_path(),
808 &hardware_address, NetworkLibrary::FORMAT_COLON_SEPARATED_HEX);
809 if (!hardware_address.empty()) {
810 std::string label = l10n_util::GetStringUTF8(
811 IDS_STATUSBAR_NETWORK_DEVICE_WIFI) + " " + hardware_address;
812 address_items.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND,
813 UTF8ToUTF16(label), SkBitmap(), std::string(), FLAG_DISABLED));
814 }
815 }
816 }
817 }
818
819 menu_items_ = link_items;
820 if (!menu_items_.empty() && address_items.size() > 1)
821 menu_items_.push_back(MenuItem()); // Separator
822 menu_items_.insert(menu_items_.end(),
823 address_items.begin(), address_items.end());
824 }
825
826 ////////////////////////////////////////////////////////////////////////////////
827 // NetworkMenu
828
829 // static
830 const int NetworkMenu::kNumBarsImages = 4;
831
832 // NOTE: Use an array rather than just calculating a resource number to avoid
833 // creating implicit ordering dependencies on the resource values.
834 // static
835 const int NetworkMenu::kBarsImages[kNumBarsImages] = {
836 IDR_STATUSBAR_NETWORK_BARS1,
837 IDR_STATUSBAR_NETWORK_BARS2,
838 IDR_STATUSBAR_NETWORK_BARS3,
839 IDR_STATUSBAR_NETWORK_BARS4,
840 };
841 // static
842 const int NetworkMenu::kBarsImagesBlack[kNumBarsImages] = {
843 IDR_STATUSBAR_NETWORK_BARS1_BLACK,
844 IDR_STATUSBAR_NETWORK_BARS2_BLACK,
845 IDR_STATUSBAR_NETWORK_BARS3_BLACK,
846 IDR_STATUSBAR_NETWORK_BARS4_BLACK,
847 };
848
849 // static
850 const int NetworkMenu::kBarsImagesOrange[kNumBarsImages] = {
851 IDR_STATUSBAR_NETWORK_BARS1_ORANGE,
852 IDR_STATUSBAR_NETWORK_BARS2_ORANGE,
853 IDR_STATUSBAR_NETWORK_BARS3_ORANGE,
854 IDR_STATUSBAR_NETWORK_BARS4_ORANGE,
855 };
856 #if 0
857 // static
858 const int NetworkMenu::kBarsImagesVLowData[kNumBarsImages] = {
859 IDR_STATUSBAR_NETWORK_BARS1_RED,
860 IDR_STATUSBAR_NETWORK_BARS2_RED,
861 IDR_STATUSBAR_NETWORK_BARS3_RED,
862 IDR_STATUSBAR_NETWORK_BARS4_RED,
863 };
864 #endif
865
866 // static
867 SkBitmap NetworkMenu::kAnimatingImages[kNumBarsImages];
868
869 // static
870 SkBitmap NetworkMenu::kAnimatingImagesBlack[kNumBarsImages];
871
NetworkMenu()872 NetworkMenu::NetworkMenu() : min_width_(-1) {
873 main_menu_model_.reset(new MainMenuModel(this));
874 network_menu_.reset(new views::Menu2(main_menu_model_.get()));
875 }
876
~NetworkMenu()877 NetworkMenu::~NetworkMenu() {
878 }
879
SetFirstLevelMenuWidth(int width)880 void NetworkMenu::SetFirstLevelMenuWidth(int width) {
881 min_width_ = width;
882 // This actually has no effect since menu is rebuilt before showing.
883 network_menu_->SetMinimumWidth(width);
884 }
885
CancelMenu()886 void NetworkMenu::CancelMenu() {
887 network_menu_->CancelMenu();
888 }
889
UpdateMenu()890 void NetworkMenu::UpdateMenu() {
891 refreshing_menu_ = true;
892 main_menu_model_->InitMenuItems(IsBrowserMode(), ShouldOpenButtonOptions());
893 network_menu_->Rebuild();
894 refreshing_menu_ = false;
895 }
896
897 // static
IconForNetworkStrength(const WifiNetwork * wifi,bool black)898 const SkBitmap* NetworkMenu::IconForNetworkStrength(const WifiNetwork* wifi,
899 bool black) {
900 DCHECK(wifi);
901 if (wifi->strength() == 0) {
902 return ResourceBundle::GetSharedInstance().GetBitmapNamed(
903 black ? IDR_STATUSBAR_NETWORK_BARS0_BLACK :
904 IDR_STATUSBAR_NETWORK_BARS0);
905 }
906 int index = static_cast<int>(wifi->strength() / 100.0 *
907 nextafter(static_cast<float>(kNumBarsImages), 0));
908 index = std::max(std::min(index, kNumBarsImages - 1), 0);
909 const int* images = black ? kBarsImagesBlack : kBarsImages;
910 return ResourceBundle::GetSharedInstance().GetBitmapNamed(images[index]);
911 }
912
913 // static
IconForNetworkStrength(const CellularNetwork * cellular,bool black)914 const SkBitmap* NetworkMenu::IconForNetworkStrength(
915 const CellularNetwork* cellular, bool black) {
916 DCHECK(cellular);
917 // If no data, then we show 0 bars.
918 if (cellular->strength() == 0 ||
919 cellular->data_left() == CellularNetwork::DATA_NONE) {
920 return ResourceBundle::GetSharedInstance().GetBitmapNamed(
921 black ? IDR_STATUSBAR_NETWORK_BARS0_BLACK :
922 IDR_STATUSBAR_NETWORK_BARS0);
923 }
924 int index = static_cast<int>(cellular->strength() / 100.0 *
925 nextafter(static_cast<float>(kNumBarsImages), 0));
926 index = std::max(std::min(index, kNumBarsImages - 1), 0);
927 const int* images = black ? kBarsImagesBlack : kBarsImages;
928 return ResourceBundle::GetSharedInstance().GetBitmapNamed(images[index]);
929 }
930
931 // static
IconForNetworkConnecting(double animation_value,bool black)932 const SkBitmap* NetworkMenu::IconForNetworkConnecting(double animation_value,
933 bool black) {
934 // Fade bars a bit and show the different bar states.
935 const int* source_image_ids = black ? kBarsImagesBlack : kBarsImages;
936 SkBitmap* images = black ? kAnimatingImagesBlack : kAnimatingImages;
937 int index = static_cast<int>(animation_value *
938 nextafter(static_cast<float>(kNumBarsImages), 0));
939 index = std::max(std::min(index, kNumBarsImages - 1), 0);
940
941 // Lazily cache images.
942 if (images[index].empty()) {
943 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
944 SkBitmap source = *rb.GetBitmapNamed(source_image_ids[index]);
945
946 // Create an empty image to fade against.
947 SkBitmap empty_image;
948 empty_image.setConfig(SkBitmap::kARGB_8888_Config,
949 source.width(),
950 source.height(),
951 0);
952 empty_image.allocPixels();
953 empty_image.eraseARGB(0, 0, 0, 0);
954
955 images[index] =
956 SkBitmapOperations::CreateBlendedBitmap(
957 empty_image,
958 source,
959 kConnectingImageAlpha);
960 }
961 return &images[index];
962 }
963
964 // static
BadgeForNetworkTechnology(const CellularNetwork * cellular)965 const SkBitmap* NetworkMenu::BadgeForNetworkTechnology(
966 const CellularNetwork* cellular) {
967 if (!cellular)
968 return NULL;
969
970 int id = -1;
971 switch (cellular->network_technology()) {
972 case NETWORK_TECHNOLOGY_EVDO:
973 switch (cellular->data_left()) {
974 case CellularNetwork::DATA_NONE:
975 id = IDR_STATUSBAR_NETWORK_3G_ERROR;
976 break;
977 case CellularNetwork::DATA_VERY_LOW:
978 case CellularNetwork::DATA_LOW:
979 case CellularNetwork::DATA_NORMAL:
980 id = IDR_STATUSBAR_NETWORK_3G;
981 break;
982 case CellularNetwork::DATA_UNKNOWN:
983 id = IDR_STATUSBAR_NETWORK_3G_UNKNOWN;
984 break;
985 }
986 break;
987 case NETWORK_TECHNOLOGY_1XRTT:
988 switch (cellular->data_left()) {
989 case CellularNetwork::DATA_NONE:
990 id = IDR_STATUSBAR_NETWORK_1X_ERROR;
991 break;
992 case CellularNetwork::DATA_VERY_LOW:
993 case CellularNetwork::DATA_LOW:
994 case CellularNetwork::DATA_NORMAL:
995 id = IDR_STATUSBAR_NETWORK_1X;
996 break;
997 case CellularNetwork::DATA_UNKNOWN:
998 id = IDR_STATUSBAR_NETWORK_1X_UNKNOWN;
999 break;
1000 }
1001 break;
1002 // Note: we may not be able to obtain data usage info
1003 // from GSM carriers, so there may not be a reason
1004 // to create _ERROR or _UNKNOWN versions of the following
1005 // icons.
1006 case NETWORK_TECHNOLOGY_GPRS:
1007 id = IDR_STATUSBAR_NETWORK_GPRS;
1008 break;
1009 case NETWORK_TECHNOLOGY_EDGE:
1010 id = IDR_STATUSBAR_NETWORK_EDGE;
1011 break;
1012 case NETWORK_TECHNOLOGY_UMTS:
1013 id = IDR_STATUSBAR_NETWORK_3G;
1014 break;
1015 case NETWORK_TECHNOLOGY_HSPA:
1016 id = IDR_STATUSBAR_NETWORK_HSPA;
1017 break;
1018 case NETWORK_TECHNOLOGY_HSPA_PLUS:
1019 id = IDR_STATUSBAR_NETWORK_HSPA_PLUS;
1020 break;
1021 case NETWORK_TECHNOLOGY_LTE:
1022 id = IDR_STATUSBAR_NETWORK_LTE;
1023 break;
1024 case NETWORK_TECHNOLOGY_LTE_ADVANCED:
1025 id = IDR_STATUSBAR_NETWORK_LTE_ADVANCED;
1026 break;
1027 case NETWORK_TECHNOLOGY_UNKNOWN:
1028 break;
1029 }
1030 if (id == -1)
1031 return NULL;
1032 else
1033 return ResourceBundle::GetSharedInstance().GetBitmapNamed(id);
1034 }
1035
1036 // static
BadgeForRoamingStatus(const CellularNetwork * cellular)1037 const SkBitmap* NetworkMenu::BadgeForRoamingStatus(
1038 const CellularNetwork* cellular) {
1039 if (cellular->roaming_state() == ROAMING_STATE_ROAMING)
1040 return ResourceBundle::GetSharedInstance().GetBitmapNamed(
1041 IDR_STATUSBAR_NETWORK_ROAMING);
1042 else
1043 return NULL;
1044 }
1045
BadgeForPrivateNetworkStatus(const Network * network)1046 const SkBitmap* NetworkMenu::BadgeForPrivateNetworkStatus(
1047 const Network* network) {
1048 // If network is not null, check if it's the active network with vpn on it.
1049 if (network) {
1050 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
1051 if (!(cros->virtual_network() && network == cros->connected_network()))
1052 return NULL;
1053 }
1054 // TODO(kuan): yellow lock icon not ready yet; for now, return the black one
1055 // used by secure wifi network.
1056 return ResourceBundle::GetSharedInstance().GetBitmapNamed(
1057 IDR_STATUSBAR_NETWORK_SECURE);
1058 }
1059
1060 // static
IconForDisplay(const SkBitmap * icon,const SkBitmap * badge)1061 SkBitmap NetworkMenu::IconForDisplay(const SkBitmap* icon,
1062 const SkBitmap* badge) {
1063 return IconForDisplay(icon, badge, NULL, NULL);
1064 }
1065
1066 // static
IconForDisplay(const SkBitmap * icon,const SkBitmap * bottom_right_badge,const SkBitmap * top_left_badge,const SkBitmap * bottom_left_badge)1067 SkBitmap NetworkMenu::IconForDisplay(const SkBitmap* icon,
1068 const SkBitmap* bottom_right_badge,
1069 const SkBitmap* top_left_badge,
1070 const SkBitmap* bottom_left_badge) {
1071 DCHECK(icon);
1072 if (bottom_right_badge == NULL && top_left_badge == NULL &&
1073 bottom_left_badge == NULL)
1074 return *icon;
1075
1076 static const int kTopLeftBadgeX = 0;
1077 static const int kTopLeftBadgeY = 0;
1078 static const int kBottomRightBadgeX = 14;
1079 static const int kBottomRightBadgeY = 14;
1080 static const int kBottomLeftBadgeX = 0;
1081 static const int kBottomLeftBadgeY = 14;
1082
1083 gfx::CanvasSkia canvas(icon->width(), icon->height(), false);
1084 canvas.DrawBitmapInt(*icon, 0, 0);
1085 if (bottom_right_badge != NULL)
1086 canvas.DrawBitmapInt(*bottom_right_badge,
1087 kBottomRightBadgeX,
1088 kBottomRightBadgeY);
1089 if (top_left_badge != NULL)
1090 canvas.DrawBitmapInt(*top_left_badge, kTopLeftBadgeX, kTopLeftBadgeY);
1091 if (bottom_left_badge != NULL)
1092 canvas.DrawBitmapInt(*bottom_left_badge, kBottomLeftBadgeX,
1093 kBottomLeftBadgeY);
1094 return canvas.ExtractBitmap();
1095 }
1096
ShowTabbedNetworkSettings(const Network * network) const1097 void NetworkMenu::ShowTabbedNetworkSettings(const Network* network) const {
1098 DCHECK(network);
1099 Browser* browser = BrowserList::GetLastActive();
1100 if (!browser)
1101 return;
1102 std::string page = StringPrintf("%s?servicePath=%s&networkType=%d",
1103 chrome::kInternetOptionsSubPage,
1104 EscapeUrlEncodedData(network->service_path()).c_str(),
1105 network->type());
1106 browser->ShowOptionsTab(page);
1107 }
1108
1109 ////////////////////////////////////////////////////////////////////////////////
1110 // NetworkMenu, views::ViewMenuDelegate implementation:
1111
RunMenu(views::View * source,const gfx::Point & pt)1112 void NetworkMenu::RunMenu(views::View* source, const gfx::Point& pt) {
1113 refreshing_menu_ = true;
1114 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
1115 cros->RequestNetworkScan();
1116
1117 // Build initial menu items. They will be updated when UpdateMenu is
1118 // called from NetworkChanged.
1119 main_menu_model_->InitMenuItems(IsBrowserMode(), ShouldOpenButtonOptions());
1120 network_menu_->Rebuild();
1121
1122 // Restore menu width, if it was set up.
1123 // NOTE: width isn't checked for correctness here since all width-related
1124 // logic implemented inside |network_menu_|.
1125 if (min_width_ != -1)
1126 network_menu_->SetMinimumWidth(min_width_);
1127 refreshing_menu_ = false;
1128 network_menu_->RunMenuAt(pt, views::Menu2::ALIGN_TOPRIGHT);
1129 }
1130
1131 } // namespace chromeos
1132
1133
1134