network_menu.cc revision 5e3f23d412006dc4db4e659864679f29341e113f
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 "chrome/browser/chromeos/status/network_menu.h"
6
7#include <algorithm>
8
9#include "ash/shell.h"
10#include "ash/shell_delegate.h"
11#include "ash/system/chromeos/network/network_icon.h"
12#include "base/bind.h"
13#include "base/logging.h"
14#include "base/strings/stringprintf.h"
15#include "base/strings/utf_string_conversions.h"
16#include "chrome/browser/chromeos/choose_mobile_network_dialog.h"
17#include "chrome/browser/chromeos/login/user_manager.h"
18#include "chrome/browser/chromeos/mobile_config.h"
19#include "chrome/browser/chromeos/options/network_config_view.h"
20#include "chrome/browser/chromeos/options/network_connect.h"
21#include "chrome/browser/defaults.h"
22#include "chrome/browser/profiles/profile_manager.h"
23#include "chrome/common/url_constants.h"
24#include "chromeos/network/device_state.h"
25#include "chromeos/network/network_state.h"
26#include "chromeos/network/network_state_handler.h"
27#include "grit/ash_resources.h"
28#include "grit/ash_strings.h"
29#include "grit/generated_resources.h"
30#include "third_party/cros_system_api/dbus/service_constants.h"
31#include "ui/base/l10n/l10n_util.h"
32#include "ui/base/models/menu_model.h"
33#include "ui/base/resource/resource_bundle.h"
34#include "ui/gfx/image/image_skia.h"
35
36namespace chromeos {
37
38namespace {
39
40// Offsets for views menu ids (main menu and submenu ids use the same
41// namespace).
42const int kMainIndexMask = 0x1000;
43const int kMoreIndexMask = 0x4000;
44
45// Replace '&' in a string with "&&" to allow it to be a menu item label.
46std::string EscapeAmpersands(const std::string& input) {
47  std::string str = input;
48  size_t found = str.find('&');
49  while (found != std::string::npos) {
50    str.replace(found, 1, "&&");
51    found = str.find('&', found + 2);
52  }
53  return str;
54}
55
56// Highlight any connected or connecting networks in the UI.
57bool ShouldHighlightNetwork(const NetworkState* network) {
58  return network->IsConnectedState() || network->IsConnectingState();
59}
60
61void ToggleTechnology(const std::string& technology) {
62  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
63  bool is_enabled = handler->IsTechnologyEnabled(technology);
64  handler->SetTechnologyEnabled(technology, !is_enabled,
65                                network_handler::ErrorCallback());
66}
67
68}  // namespace
69
70class NetworkMenuModel : public ui::MenuModel {
71 public:
72  struct MenuItem {
73    MenuItem()
74        : type(ui::MenuModel::TYPE_SEPARATOR),
75          sub_menu_model(NULL),
76          flags(0) {
77    }
78    MenuItem(ui::MenuModel::ItemType type, string16 label, gfx::ImageSkia icon,
79             const std::string& service_path, int flags)
80        : type(type),
81          label(label),
82          icon(icon),
83          service_path(service_path),
84          sub_menu_model(NULL),
85          flags(flags) {
86    }
87    MenuItem(ui::MenuModel::ItemType type, string16 label, gfx::ImageSkia icon,
88             NetworkMenuModel* sub_menu_model, int flags)
89        : type(type),
90          label(label),
91          icon(icon),
92          sub_menu_model(sub_menu_model),
93          flags(flags) {
94    }
95
96    ui::MenuModel::ItemType type;
97    string16 label;
98    gfx::ImageSkia icon;
99    std::string service_path;
100    NetworkMenuModel* sub_menu_model;  // Weak ptr.
101    int flags;
102  };
103  typedef std::vector<MenuItem> MenuItemVector;
104
105  explicit NetworkMenuModel(const base::WeakPtr<NetworkMenu>& owner)
106    : owner_(owner) {}
107  virtual ~NetworkMenuModel() {}
108
109  // Connect or reconnect to the network at |index|.
110  void ConnectToNetworkAt(int index);
111
112  // Called by NetworkMenu::UpdateMenu to initialize menu items.
113  virtual void InitMenuItems(bool should_open_button_options) = 0;
114
115  // Menu item field accessors.
116  const MenuItemVector& menu_items() const { return menu_items_; }
117
118  // ui::MenuModel implementation
119  // GetCommandIdAt() must be implemented by subclasses.
120  virtual bool HasIcons() const OVERRIDE;
121  virtual int GetItemCount() const OVERRIDE;
122  virtual ui::MenuModel::ItemType GetTypeAt(int index) const OVERRIDE;
123  virtual ui::MenuSeparatorType GetSeparatorTypeAt(int index) const OVERRIDE;
124  virtual string16 GetLabelAt(int index) const OVERRIDE;
125  virtual bool IsItemDynamicAt(int index) const OVERRIDE;
126  virtual const gfx::Font* GetLabelFontAt(int index) const OVERRIDE;
127  virtual bool GetAcceleratorAt(int index,
128                                ui::Accelerator* accelerator) const OVERRIDE;
129  virtual bool IsItemCheckedAt(int index) const OVERRIDE;
130  virtual int GetGroupIdAt(int index) const OVERRIDE;
131  virtual bool GetIconAt(int index, gfx::Image* icon) OVERRIDE;
132  virtual ui::ButtonMenuItemModel* GetButtonMenuItemAt(
133      int index) const OVERRIDE;
134  virtual bool IsEnabledAt(int index) const OVERRIDE;
135  virtual bool IsVisibleAt(int index) const OVERRIDE;
136  virtual ui::MenuModel* GetSubmenuModelAt(int index) const OVERRIDE;
137  virtual void HighlightChangedTo(int index) OVERRIDE;
138  virtual void ActivatedAt(int index) OVERRIDE;
139  virtual void SetMenuModelDelegate(ui::MenuModelDelegate* delegate) OVERRIDE;
140  virtual ui::MenuModelDelegate* GetMenuModelDelegate() const OVERRIDE;
141
142 protected:
143  enum MenuItemFlags {
144    FLAG_NONE              = 0,
145    FLAG_DISABLED          = 1 << 0,
146    FLAG_TOGGLE_WIFI       = 1 << 2,
147    FLAG_TOGGLE_MOBILE     = 1 << 3,
148    FLAG_ASSOCIATED        = 1 << 5,
149    FLAG_ETHERNET          = 1 << 6,
150    FLAG_WIFI              = 1 << 7,
151    FLAG_WIMAX             = 1 << 8,
152    FLAG_CELLULAR          = 1 << 9,
153    FLAG_OPTIONS           = 1 << 10,
154    FLAG_ADD_WIFI          = 1 << 11,
155    FLAG_ADD_CELLULAR      = 1 << 12,
156  };
157
158  // Our menu items.
159  MenuItemVector menu_items_;
160
161  // Weak pointer to NetworkMenu that owns this MenuModel.
162  base::WeakPtr<NetworkMenu> owner_;
163
164  // Top up URL of the current carrier on empty string if there's none.
165  std::string top_up_url_;
166
167  // Carrier ID which top up URL is initialized for.
168  // Used to update top up URL only when cellular carrier has changed.
169  std::string carrier_id_;
170
171 private:
172  // Open a dialog to set up and connect to a network.
173  void ShowOther(const std::string& type) const;
174
175  DISALLOW_COPY_AND_ASSIGN(NetworkMenuModel);
176};
177
178class MoreMenuModel : public NetworkMenuModel {
179 public:
180  explicit MoreMenuModel(const base::WeakPtr<NetworkMenu> owner)
181    : NetworkMenuModel(owner) {}
182  virtual ~MoreMenuModel() {}
183
184  // NetworkMenuModel implementation.
185  virtual void InitMenuItems(bool should_open_button_options) OVERRIDE;
186
187  // ui::MenuModel implementation
188  virtual int GetCommandIdAt(int index) const OVERRIDE;
189
190 private:
191  DISALLOW_COPY_AND_ASSIGN(MoreMenuModel);
192};
193
194class MainMenuModel : public NetworkMenuModel {
195 public:
196  explicit MainMenuModel(const base::WeakPtr<NetworkMenu>& owner)
197      : NetworkMenuModel(owner),
198        more_menu_model_(new MoreMenuModel(owner)) {
199  }
200  virtual ~MainMenuModel() {}
201
202  // NetworkMenuModel implementation.
203  virtual void InitMenuItems(bool should_open_button_options) OVERRIDE;
204
205  // ui::MenuModel implementation
206  virtual int GetCommandIdAt(int index) const OVERRIDE;
207
208 private:
209  void AddWirelessNetworkMenuItem(const NetworkState* wifi_network, int flag);
210  void AddMessageItem(const string16& msg);
211
212  scoped_ptr<MoreMenuModel> more_menu_model_;
213
214  DISALLOW_COPY_AND_ASSIGN(MainMenuModel);
215};
216
217////////////////////////////////////////////////////////////////////////////////
218// NetworkMenuModel, public methods:
219
220void NetworkMenuModel::ConnectToNetworkAt(int index) {
221  const std::string& service_path = menu_items_[index].service_path;
222  network_connect::ConnectResult result =
223      network_connect::ConnectToNetwork(
224          service_path, owner_->delegate()->GetNativeWindow());
225  if (result == network_connect::NETWORK_NOT_FOUND) {
226    // If we are attempting to connect to a network that no longer exists,
227    // display a notification.
228    LOG(WARNING) << "Network does not exist to connect to: "
229                 << service_path;
230    // TODO(stevenjb): Show notification.
231  }
232}
233
234////////////////////////////////////////////////////////////////////////////////
235// NetworkMenuModel, ui::MenuModel implementation:
236
237bool NetworkMenuModel::HasIcons() const {
238  return true;
239}
240
241int NetworkMenuModel::GetItemCount() const {
242  return static_cast<int>(menu_items_.size());
243}
244
245ui::MenuModel::ItemType NetworkMenuModel::GetTypeAt(int index) const {
246  return menu_items_[index].type;
247}
248
249ui::MenuSeparatorType NetworkMenuModel::GetSeparatorTypeAt(int index) const {
250  return ui::NORMAL_SEPARATOR;
251}
252
253string16 NetworkMenuModel::GetLabelAt(int index) const {
254  return menu_items_[index].label;
255}
256
257bool NetworkMenuModel::IsItemDynamicAt(int index) const {
258  return false;
259}
260
261const gfx::Font* NetworkMenuModel::GetLabelFontAt(int index) const {
262  const gfx::Font* font = NULL;
263  if (menu_items_[index].flags & FLAG_ASSOCIATED) {
264    ResourceBundle& resource_bundle = ResourceBundle::GetSharedInstance();
265    font = &resource_bundle.GetFont(
266        browser_defaults::kAssociatedNetworkFontStyle);
267  }
268
269  return font;
270}
271
272bool NetworkMenuModel::GetAcceleratorAt(int index,
273                                        ui::Accelerator* accelerator) const {
274  return false;
275}
276
277bool NetworkMenuModel::IsItemCheckedAt(int index) const {
278  // All ui::MenuModel::TYPE_CHECK menu items are checked.
279  return true;
280}
281
282int NetworkMenuModel::GetGroupIdAt(int index) const {
283  return 0;
284}
285
286bool NetworkMenuModel::GetIconAt(int index, gfx::Image* icon) {
287  if (!menu_items_[index].icon.isNull()) {
288    *icon = gfx::Image(menu_items_[index].icon);
289    return true;
290  }
291  return false;
292}
293
294ui::ButtonMenuItemModel* NetworkMenuModel::GetButtonMenuItemAt(
295    int index) const {
296  return NULL;
297}
298
299bool NetworkMenuModel::IsEnabledAt(int index) const {
300  return !(menu_items_[index].flags & FLAG_DISABLED);
301}
302
303bool NetworkMenuModel::IsVisibleAt(int index) const {
304  return true;
305}
306
307ui::MenuModel* NetworkMenuModel::GetSubmenuModelAt(int index) const {
308  return menu_items_[index].sub_menu_model;
309}
310
311void NetworkMenuModel::HighlightChangedTo(int index) {
312}
313
314void NetworkMenuModel::ActivatedAt(int index) {
315  // When we are refreshing the menu, ignore menu item activation.
316  if (owner_->refreshing_menu_)
317    return;
318
319  int flags = menu_items_[index].flags;
320  if (flags & FLAG_OPTIONS) {
321    owner_->delegate()->OpenButtonOptions();
322  } else if (flags & FLAG_TOGGLE_WIFI) {
323    ToggleTechnology(flimflam::kTypeWifi);
324  } else if (flags & FLAG_TOGGLE_MOBILE) {
325    ToggleTechnology(NetworkStateHandler::kMatchTypeMobile);
326  } else if (flags & FLAG_ETHERNET) {
327    // Do nothing (used in login screen only)
328  } else if (flags & (FLAG_WIFI | FLAG_WIMAX | FLAG_CELLULAR)) {
329    ConnectToNetworkAt(index);
330  } else if (flags & FLAG_ADD_WIFI) {
331    ShowOther(flimflam::kTypeWifi);
332  } else if (flags & FLAG_ADD_CELLULAR) {
333    ShowOther(flimflam::kTypeCellular);
334  }
335}
336
337void NetworkMenuModel::SetMenuModelDelegate(ui::MenuModelDelegate* delegate) {
338}
339
340ui::MenuModelDelegate* NetworkMenuModel::GetMenuModelDelegate() const {
341  return NULL;
342}
343
344////////////////////////////////////////////////////////////////////////////////
345// NetworkMenuModel, private methods:
346
347void NetworkMenuModel::ShowOther(const std::string& type) const {
348  gfx::NativeWindow native_window = owner_->delegate()->GetNativeWindow();
349  if (type == flimflam::kTypeCellular)
350    ChooseMobileNetworkDialog::ShowDialog(native_window);
351  else
352    NetworkConfigView::ShowForType(chromeos::TYPE_WIFI, native_window);
353}
354
355////////////////////////////////////////////////////////////////////////////////
356// MainMenuModel
357
358void MainMenuModel::AddWirelessNetworkMenuItem(const NetworkState* network,
359                                               int flag) {
360  string16 label;
361  // Ampersand is a valid character in an SSID, but menu2 uses it to mark
362  // "mnemonics" for keyboard shortcuts.
363  std::string wifi_name = EscapeAmpersands(network->name());
364  if (network->IsConnectingState()) {
365    label = l10n_util::GetStringFUTF16(
366        IDS_STATUSBAR_NETWORK_DEVICE_STATUS,
367        UTF8ToUTF16(wifi_name),
368        l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CONNECTING));
369  } else {
370    label = UTF8ToUTF16(wifi_name);
371  }
372
373  // We do not have convenient access to whether or not it might be possible
374  // to connect to a wireless network (e.g. whether certs are required), so all
375  // entries are enabled.
376
377  if (ShouldHighlightNetwork(network))
378    flag |= FLAG_ASSOCIATED;
379  const gfx::ImageSkia icon = ash::network_icon::GetImageForNetwork(
380      network, ash::network_icon::ICON_TYPE_LIST);
381  menu_items_.push_back(
382      MenuItem(ui::MenuModel::TYPE_COMMAND,
383               label, icon, network->path(), flag));
384}
385
386void MainMenuModel::AddMessageItem(const string16& msg) {
387  menu_items_.push_back(MenuItem(
388      ui::MenuModel::TYPE_COMMAND, msg,
389      gfx::ImageSkia(), std::string(), FLAG_DISABLED));
390}
391
392void MainMenuModel::InitMenuItems(bool should_open_button_options) {
393  menu_items_.clear();
394
395  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
396
397  // Populate our MenuItems with the current list of networks.
398  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
399  string16 label;
400
401  // Ethernet
402  // Only display an ethernet icon if enabled, and an ethernet network exists.
403  bool ethernet_enabled = handler->IsTechnologyEnabled(flimflam::kTypeEthernet);
404  const NetworkState* ethernet_network =
405      handler->FirstNetworkByType(flimflam::kTypeEthernet);
406  if (ethernet_enabled && ethernet_network) {
407    bool ethernet_connecting = ethernet_network->IsConnectingState();
408    if (ethernet_connecting) {
409      label = l10n_util::GetStringFUTF16(
410          IDS_STATUSBAR_NETWORK_DEVICE_STATUS,
411          l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET),
412          l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CONNECTING));
413    } else {
414      label = l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET);
415    }
416    int flag = FLAG_ETHERNET;
417    if (ShouldHighlightNetwork(ethernet_network))
418      flag |= FLAG_ASSOCIATED;
419    const gfx::ImageSkia icon = ash::network_icon::GetImageForNetwork(
420        ethernet_network, ash::network_icon::ICON_TYPE_LIST);
421    menu_items_.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND,
422                                   label, icon, std::string(), flag));
423  }
424
425  // Get the list of all networks.
426  NetworkStateHandler::NetworkStateList network_list;
427  handler->GetNetworkList(&network_list);
428
429  // Cellular Networks
430  if (handler->IsTechnologyEnabled(flimflam::kTypeCellular)) {
431    // List Cellular networks.
432    for (NetworkStateHandler::NetworkStateList::const_iterator iter =
433             network_list.begin(); iter != network_list.end(); ++iter) {
434      const NetworkState* network = *iter;
435      if (network->type() != flimflam::kTypeCellular)
436        continue;
437      std::string activation_state = network->activation_state();
438
439      // This is only used in the login screen; do not show unactivated
440      // networks.
441      if (activation_state != flimflam::kActivationStateActivated)
442        continue;
443
444      // Ampersand is a valid character in a network name, but menu2 uses it
445      // to mark "mnemonics" for keyboard shortcuts.  http://crosbug.com/14697
446      std::string network_name = EscapeAmpersands(network->name());
447      if (network->IsConnectingState()) {
448        label = l10n_util::GetStringFUTF16(
449            IDS_STATUSBAR_NETWORK_DEVICE_STATUS,
450            UTF8ToUTF16(network_name),
451            l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CONNECTING));
452      } else {
453        label = UTF8ToUTF16(network_name);
454      }
455
456      int flag = FLAG_CELLULAR;
457      bool isActive = ShouldHighlightNetwork(network);
458      if (isActive)
459        flag |= FLAG_ASSOCIATED;
460      const gfx::ImageSkia icon = ash::network_icon::GetImageForNetwork(
461          network, ash::network_icon::ICON_TYPE_LIST);
462      menu_items_.push_back(
463          MenuItem(ui::MenuModel::TYPE_COMMAND,
464                   label, icon, network->path(), flag));
465    }
466
467    // For GSM add cellular network scan.
468    const DeviceState* cellular_device =
469        handler->GetDeviceStateByType(flimflam::kTypeCellular);
470    if (cellular_device && cellular_device->support_network_scan()) {
471      const gfx::ImageSkia icon =
472          ash::network_icon::GetImageForDisconnectedNetwork(
473              ash::network_icon::ICON_TYPE_LIST, flimflam::kTypeCellular);
474      menu_items_.push_back(MenuItem(
475          ui::MenuModel::TYPE_COMMAND,
476          l10n_util::GetStringUTF16(
477              IDS_OPTIONS_SETTINGS_OTHER_CELLULAR_NETWORKS),
478          icon, std::string(), FLAG_ADD_CELLULAR));
479    }
480  } else {
481    int initializing_message_id =
482        ash::network_icon::GetCellularUninitializedMsg();
483    if (initializing_message_id) {
484      // Initializing cellular modem...
485      AddMessageItem(l10n_util::GetStringUTF16(initializing_message_id));
486    }
487  }
488
489  // Wimax Networks
490  if (handler->IsTechnologyEnabled(flimflam::kTypeWimax)) {
491    // List Wimax networks.
492    for (NetworkStateHandler::NetworkStateList::const_iterator iter =
493             network_list.begin(); iter != network_list.end(); ++iter) {
494      const NetworkState* network = *iter;
495      if (network->type() != flimflam::kTypeWimax)
496        continue;
497      AddWirelessNetworkMenuItem(network, FLAG_WIMAX);
498    }
499  }
500
501  // Wifi Networks
502  if (handler->IsTechnologyEnabled(flimflam::kTypeWifi)) {
503    // List Wifi networks.
504    int scanning_msg = handler->GetScanningByType(flimflam::kTypeWifi) ?
505        IDS_ASH_STATUS_TRAY_WIFI_SCANNING_MESSAGE : 0;
506    for (NetworkStateHandler::NetworkStateList::const_iterator iter =
507             network_list.begin(); iter != network_list.end(); ++iter) {
508      const NetworkState* network = *iter;
509      if (network->type() != flimflam::kTypeWifi)
510        continue;
511      // Add 'Searching for Wi-Fi networks...' after connected networks.
512      if (scanning_msg && !network->IsConnectedState()) {
513        AddMessageItem(l10n_util::GetStringUTF16(scanning_msg));
514        scanning_msg = 0;
515      }
516      AddWirelessNetworkMenuItem(network, FLAG_WIFI);
517    }
518    if (scanning_msg)
519      AddMessageItem(l10n_util::GetStringUTF16(scanning_msg));
520    const gfx::ImageSkia icon =
521        ash::network_icon::GetImageForConnectedNetwork(
522            ash::network_icon::ICON_TYPE_LIST, flimflam::kTypeWifi);
523    menu_items_.push_back(MenuItem(
524        ui::MenuModel::TYPE_COMMAND,
525        l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_OTHER_WIFI_NETWORKS),
526        icon, std::string(), FLAG_ADD_WIFI));
527  }
528
529  if (menu_items_.empty()) {
530    // No networks available (and not initializing cellular or wifi scanning)
531    AddMessageItem(l10n_util::GetStringFUTF16(
532        IDS_STATUSBAR_NETWORK_MENU_ITEM_INDENT,
533        l10n_util::GetStringUTF16(IDS_STATUSBAR_NO_NETWORKS_MESSAGE)));
534  }
535
536  // Enable / Disable Technology
537  NetworkStateHandler::TechnologyState wifi_state =
538      handler->GetTechnologyState(flimflam::kTypeWifi);
539  bool wifi_available =
540      wifi_state != NetworkStateHandler::TECHNOLOGY_UNAVAILABLE;
541  bool wifi_enabled = wifi_state == NetworkStateHandler::TECHNOLOGY_ENABLED;
542
543  NetworkStateHandler::TechnologyState mobile_state =
544      handler->GetTechnologyState(NetworkStateHandler::kMatchTypeMobile);
545  bool mobile_available =
546      mobile_state != NetworkStateHandler::TECHNOLOGY_UNAVAILABLE;
547  bool mobile_enabled = mobile_state == NetworkStateHandler::TECHNOLOGY_ENABLED;
548
549  // Do not show disable wifi or cellular during oobe.
550  bool show_toggle_wifi = wifi_available &&
551      (should_open_button_options || !wifi_enabled);
552  bool show_toggle_mobile = mobile_available &&
553      (should_open_button_options || !mobile_enabled);
554
555  if (show_toggle_wifi || show_toggle_mobile) {
556    menu_items_.push_back(MenuItem());  // Separator
557
558    if (show_toggle_wifi) {
559      int id = wifi_enabled ? IDS_STATUSBAR_NETWORK_DEVICE_DISABLE :
560                              IDS_STATUSBAR_NETWORK_DEVICE_ENABLE;
561      label = l10n_util::GetStringFUTF16(id,
562          l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_WIFI));
563      int flag = FLAG_TOGGLE_WIFI;
564      if (wifi_state == NetworkStateHandler::TECHNOLOGY_ENABLING)
565        flag |= FLAG_DISABLED;
566      menu_items_.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND, label,
567          gfx::ImageSkia(), std::string(), flag));
568    }
569
570    if (show_toggle_mobile) {
571      const DeviceState* mobile_device =
572          handler->GetDeviceStateByType(NetworkStateHandler::kMatchTypeMobile);
573      bool is_locked = mobile_device && !mobile_device->sim_lock_type().empty();
574      int id = (mobile_enabled && !is_locked)
575          ? IDS_STATUSBAR_NETWORK_DEVICE_DISABLE
576          : IDS_STATUSBAR_NETWORK_DEVICE_ENABLE;
577      label = l10n_util::GetStringFUTF16(id,
578          l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CELLULAR));
579      gfx::ImageSkia icon;
580      if (is_locked)
581        icon = *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_SECURE_DARK);
582      int flag = FLAG_TOGGLE_MOBILE;
583      if (mobile_state == NetworkStateHandler::TECHNOLOGY_ENABLING)
584        flag |= FLAG_DISABLED;
585      menu_items_.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND, label,
586          icon, std::string(), flag));
587    }
588  }
589
590  // Additional links like:
591  // * IP Address on active interface;
592  // * Hardware addresses for wifi and ethernet.
593  more_menu_model_->InitMenuItems(should_open_button_options);
594  if (!more_menu_model_->menu_items().empty()) {
595    menu_items_.push_back(MenuItem());  // Separator
596    menu_items_.push_back(MenuItem(
597        ui::MenuModel::TYPE_SUBMENU,
598        l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_MORE),
599        gfx::ImageSkia(), more_menu_model_.get(), FLAG_NONE));
600  }
601}
602
603int MainMenuModel::GetCommandIdAt(int index) const {
604  return index + kMainIndexMask;
605}
606
607////////////////////////////////////////////////////////////////////////////////
608// MoreMenuModel
609
610void MoreMenuModel::InitMenuItems(bool should_open_button_options) {
611  menu_items_.clear();
612  MenuItemVector link_items;
613  MenuItemVector address_items;
614
615  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
616  const NetworkState* default_network = handler->DefaultNetwork();
617
618  int message_id = -1;
619  if (default_network)
620    message_id = IDS_STATUSBAR_NETWORK_OPEN_PROXY_SETTINGS_DIALOG;
621  if (message_id != -1) {
622    link_items.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND,
623                                  l10n_util::GetStringUTF16(message_id),
624                                  gfx::ImageSkia(),
625                                  std::string(),
626                                  FLAG_OPTIONS));
627  }
628
629  if (default_network) {
630    std::string ip_address = default_network->ip_address();
631    if (!ip_address.empty()) {
632      address_items.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND,
633          ASCIIToUTF16(ip_address), gfx::ImageSkia(), std::string(),
634                       FLAG_DISABLED));
635    }
636  }
637
638  std::string ethernet_address =
639      handler->FormattedHardwareAddressForType(flimflam::kTypeEthernet);
640  if (!ethernet_address.empty()) {
641    std::string label = l10n_util::GetStringUTF8(
642        IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET) + " " + ethernet_address;
643    address_items.push_back(MenuItem(
644        ui::MenuModel::TYPE_COMMAND,
645        UTF8ToUTF16(label), gfx::ImageSkia(), std::string(), FLAG_DISABLED));
646  }
647
648  std::string wifi_address =
649      handler->FormattedHardwareAddressForType(flimflam::kTypeWifi);
650  if (!wifi_address.empty()) {
651    std::string label = l10n_util::GetStringUTF8(
652        IDS_STATUSBAR_NETWORK_DEVICE_WIFI) + " " + wifi_address;
653    address_items.push_back(MenuItem(
654        ui::MenuModel::TYPE_COMMAND,
655        UTF8ToUTF16(label), gfx::ImageSkia(), std::string(), FLAG_DISABLED));
656  }
657
658  menu_items_ = link_items;
659  if (!menu_items_.empty() && address_items.size() > 1)
660    menu_items_.push_back(MenuItem());  // Separator
661  menu_items_.insert(menu_items_.end(),
662      address_items.begin(), address_items.end());
663}
664
665int MoreMenuModel::GetCommandIdAt(int index) const {
666  return index + kMoreIndexMask;
667}
668
669////////////////////////////////////////////////////////////////////////////////
670// NetworkMenu
671
672NetworkMenu::NetworkMenu(Delegate* delegate)
673    : delegate_(delegate),
674      refreshing_menu_(false),
675      weak_pointer_factory_(this) {
676  main_menu_model_.reset(new MainMenuModel(weak_pointer_factory_.GetWeakPtr()));
677}
678
679NetworkMenu::~NetworkMenu() {
680}
681
682ui::MenuModel* NetworkMenu::GetMenuModel() {
683  return main_menu_model_.get();
684}
685
686void NetworkMenu::UpdateMenu() {
687  refreshing_menu_ = true;
688  main_menu_model_->InitMenuItems(delegate_->ShouldOpenButtonOptions());
689  refreshing_menu_ = false;
690}
691
692}  // namespace chromeos
693