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_connect.h"
12#include "ash/system/chromeos/network/network_icon.h"
13#include "base/bind.h"
14#include "base/logging.h"
15#include "base/strings/stringprintf.h"
16#include "base/strings/utf_string_conversions.h"
17#include "chrome/browser/chromeos/choose_mobile_network_dialog.h"
18#include "chrome/browser/chromeos/login/user_manager.h"
19#include "chrome/browser/chromeos/mobile_config.h"
20#include "chrome/browser/chromeos/options/network_config_view.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  gfx::NativeWindow native_window = owner_->delegate()->GetNativeWindow();
223  ash::network_connect::ConnectToNetwork(service_path, native_window);
224  owner_->delegate()->OnConnectToNetworkRequested(service_path);
225}
226
227////////////////////////////////////////////////////////////////////////////////
228// NetworkMenuModel, ui::MenuModel implementation:
229
230bool NetworkMenuModel::HasIcons() const {
231  return true;
232}
233
234int NetworkMenuModel::GetItemCount() const {
235  return static_cast<int>(menu_items_.size());
236}
237
238ui::MenuModel::ItemType NetworkMenuModel::GetTypeAt(int index) const {
239  return menu_items_[index].type;
240}
241
242ui::MenuSeparatorType NetworkMenuModel::GetSeparatorTypeAt(int index) const {
243  return ui::NORMAL_SEPARATOR;
244}
245
246string16 NetworkMenuModel::GetLabelAt(int index) const {
247  return menu_items_[index].label;
248}
249
250bool NetworkMenuModel::IsItemDynamicAt(int index) const {
251  return false;
252}
253
254const gfx::Font* NetworkMenuModel::GetLabelFontAt(int index) const {
255  const gfx::Font* font = NULL;
256  if (menu_items_[index].flags & FLAG_ASSOCIATED) {
257    ResourceBundle& resource_bundle = ResourceBundle::GetSharedInstance();
258    font = &resource_bundle.GetFont(
259        browser_defaults::kAssociatedNetworkFontStyle);
260  }
261
262  return font;
263}
264
265bool NetworkMenuModel::GetAcceleratorAt(int index,
266                                        ui::Accelerator* accelerator) const {
267  return false;
268}
269
270bool NetworkMenuModel::IsItemCheckedAt(int index) const {
271  // All ui::MenuModel::TYPE_CHECK menu items are checked.
272  return true;
273}
274
275int NetworkMenuModel::GetGroupIdAt(int index) const {
276  return 0;
277}
278
279bool NetworkMenuModel::GetIconAt(int index, gfx::Image* icon) {
280  if (!menu_items_[index].icon.isNull()) {
281    *icon = gfx::Image(menu_items_[index].icon);
282    return true;
283  }
284  return false;
285}
286
287ui::ButtonMenuItemModel* NetworkMenuModel::GetButtonMenuItemAt(
288    int index) const {
289  return NULL;
290}
291
292bool NetworkMenuModel::IsEnabledAt(int index) const {
293  return !(menu_items_[index].flags & FLAG_DISABLED);
294}
295
296bool NetworkMenuModel::IsVisibleAt(int index) const {
297  return true;
298}
299
300ui::MenuModel* NetworkMenuModel::GetSubmenuModelAt(int index) const {
301  return menu_items_[index].sub_menu_model;
302}
303
304void NetworkMenuModel::HighlightChangedTo(int index) {
305}
306
307void NetworkMenuModel::ActivatedAt(int index) {
308  // When we are refreshing the menu, ignore menu item activation.
309  if (owner_->refreshing_menu_)
310    return;
311
312  int flags = menu_items_[index].flags;
313  if (flags & FLAG_OPTIONS) {
314    owner_->delegate()->OpenButtonOptions();
315  } else if (flags & FLAG_TOGGLE_WIFI) {
316    ToggleTechnology(flimflam::kTypeWifi);
317  } else if (flags & FLAG_TOGGLE_MOBILE) {
318    ToggleTechnology(NetworkStateHandler::kMatchTypeMobile);
319  } else if (flags & FLAG_ETHERNET) {
320    // Do nothing (used in login screen only)
321  } else if (flags & (FLAG_WIFI | FLAG_WIMAX | FLAG_CELLULAR)) {
322    ConnectToNetworkAt(index);
323  } else if (flags & FLAG_ADD_WIFI) {
324    ShowOther(flimflam::kTypeWifi);
325  } else if (flags & FLAG_ADD_CELLULAR) {
326    ShowOther(flimflam::kTypeCellular);
327  }
328}
329
330void NetworkMenuModel::SetMenuModelDelegate(ui::MenuModelDelegate* delegate) {
331}
332
333ui::MenuModelDelegate* NetworkMenuModel::GetMenuModelDelegate() const {
334  return NULL;
335}
336
337////////////////////////////////////////////////////////////////////////////////
338// NetworkMenuModel, private methods:
339
340void NetworkMenuModel::ShowOther(const std::string& type) const {
341  gfx::NativeWindow native_window = owner_->delegate()->GetNativeWindow();
342  if (type == flimflam::kTypeCellular)
343    ChooseMobileNetworkDialog::ShowDialog(native_window);
344  else
345    NetworkConfigView::ShowForType(flimflam::kTypeWifi, native_window);
346}
347
348////////////////////////////////////////////////////////////////////////////////
349// MainMenuModel
350
351void MainMenuModel::AddWirelessNetworkMenuItem(const NetworkState* network,
352                                               int flag) {
353  string16 label;
354  // Ampersand is a valid character in an SSID, but menu2 uses it to mark
355  // "mnemonics" for keyboard shortcuts.
356  std::string wifi_name = EscapeAmpersands(network->name());
357  if (network->IsConnectingState()) {
358    label = l10n_util::GetStringFUTF16(
359        IDS_STATUSBAR_NETWORK_DEVICE_STATUS,
360        UTF8ToUTF16(wifi_name),
361        l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CONNECTING));
362  } else {
363    label = UTF8ToUTF16(wifi_name);
364  }
365
366  // We do not have convenient access to whether or not it might be possible
367  // to connect to a wireless network (e.g. whether certs are required), so all
368  // entries are enabled.
369
370  if (ShouldHighlightNetwork(network))
371    flag |= FLAG_ASSOCIATED;
372  const gfx::ImageSkia icon = ash::network_icon::GetImageForNetwork(
373      network, ash::network_icon::ICON_TYPE_LIST);
374  menu_items_.push_back(
375      MenuItem(ui::MenuModel::TYPE_COMMAND,
376               label, icon, network->path(), flag));
377}
378
379void MainMenuModel::AddMessageItem(const string16& msg) {
380  menu_items_.push_back(MenuItem(
381      ui::MenuModel::TYPE_COMMAND, msg,
382      gfx::ImageSkia(), std::string(), FLAG_DISABLED));
383}
384
385void MainMenuModel::InitMenuItems(bool should_open_button_options) {
386  menu_items_.clear();
387
388  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
389
390  // Populate our MenuItems with the current list of networks.
391  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
392  string16 label;
393
394  // Ethernet
395  // Only display an ethernet icon if enabled, and an ethernet network exists.
396  bool ethernet_enabled = handler->IsTechnologyEnabled(flimflam::kTypeEthernet);
397  const NetworkState* ethernet_network =
398      handler->FirstNetworkByType(flimflam::kTypeEthernet);
399  if (ethernet_enabled && ethernet_network) {
400    bool ethernet_connecting = ethernet_network->IsConnectingState();
401    if (ethernet_connecting) {
402      label = l10n_util::GetStringFUTF16(
403          IDS_STATUSBAR_NETWORK_DEVICE_STATUS,
404          l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET),
405          l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CONNECTING));
406    } else {
407      label = l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET);
408    }
409    int flag = FLAG_ETHERNET;
410    if (ShouldHighlightNetwork(ethernet_network))
411      flag |= FLAG_ASSOCIATED;
412    const gfx::ImageSkia icon = ash::network_icon::GetImageForNetwork(
413        ethernet_network, ash::network_icon::ICON_TYPE_LIST);
414    menu_items_.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND,
415                                   label, icon, std::string(), flag));
416  }
417
418  // Get the list of all networks.
419  NetworkStateHandler::NetworkStateList network_list;
420  handler->GetNetworkList(&network_list);
421
422  // Cellular Networks
423  if (handler->IsTechnologyEnabled(flimflam::kTypeCellular)) {
424    // List Cellular networks.
425    for (NetworkStateHandler::NetworkStateList::const_iterator iter =
426             network_list.begin(); iter != network_list.end(); ++iter) {
427      const NetworkState* network = *iter;
428      if (network->type() != flimflam::kTypeCellular)
429        continue;
430      std::string activation_state = network->activation_state();
431
432      // This is only used in the login screen; do not show unactivated
433      // networks.
434      if (activation_state != flimflam::kActivationStateActivated)
435        continue;
436
437      // Ampersand is a valid character in a network name, but menu2 uses it
438      // to mark "mnemonics" for keyboard shortcuts.  http://crosbug.com/14697
439      std::string network_name = EscapeAmpersands(network->name());
440      if (network->IsConnectingState()) {
441        label = l10n_util::GetStringFUTF16(
442            IDS_STATUSBAR_NETWORK_DEVICE_STATUS,
443            UTF8ToUTF16(network_name),
444            l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CONNECTING));
445      } else {
446        label = UTF8ToUTF16(network_name);
447      }
448
449      int flag = FLAG_CELLULAR;
450      bool isActive = ShouldHighlightNetwork(network);
451      if (isActive)
452        flag |= FLAG_ASSOCIATED;
453      const gfx::ImageSkia icon = ash::network_icon::GetImageForNetwork(
454          network, ash::network_icon::ICON_TYPE_LIST);
455      menu_items_.push_back(
456          MenuItem(ui::MenuModel::TYPE_COMMAND,
457                   label, icon, network->path(), flag));
458    }
459
460    // For GSM add cellular network scan.
461    const DeviceState* cellular_device =
462        handler->GetDeviceStateByType(flimflam::kTypeCellular);
463    if (cellular_device && cellular_device->support_network_scan()) {
464      const gfx::ImageSkia icon =
465          ash::network_icon::GetImageForDisconnectedNetwork(
466              ash::network_icon::ICON_TYPE_LIST, flimflam::kTypeCellular);
467      menu_items_.push_back(MenuItem(
468          ui::MenuModel::TYPE_COMMAND,
469          l10n_util::GetStringUTF16(
470              IDS_OPTIONS_SETTINGS_OTHER_CELLULAR_NETWORKS),
471          icon, std::string(), FLAG_ADD_CELLULAR));
472    }
473  } else {
474    int initializing_message_id =
475        ash::network_icon::GetCellularUninitializedMsg();
476    if (initializing_message_id) {
477      // Initializing cellular modem...
478      AddMessageItem(l10n_util::GetStringUTF16(initializing_message_id));
479    }
480  }
481
482  // Wimax Networks
483  if (handler->IsTechnologyEnabled(flimflam::kTypeWimax)) {
484    // List Wimax networks.
485    for (NetworkStateHandler::NetworkStateList::const_iterator iter =
486             network_list.begin(); iter != network_list.end(); ++iter) {
487      const NetworkState* network = *iter;
488      if (network->type() != flimflam::kTypeWimax)
489        continue;
490      AddWirelessNetworkMenuItem(network, FLAG_WIMAX);
491    }
492  }
493
494  // Wifi Networks
495  if (handler->IsTechnologyEnabled(flimflam::kTypeWifi)) {
496    // List Wifi networks.
497    int scanning_msg = handler->GetScanningByType(flimflam::kTypeWifi) ?
498        IDS_ASH_STATUS_TRAY_WIFI_SCANNING_MESSAGE : 0;
499    for (NetworkStateHandler::NetworkStateList::const_iterator iter =
500             network_list.begin(); iter != network_list.end(); ++iter) {
501      const NetworkState* network = *iter;
502      if (network->type() != flimflam::kTypeWifi)
503        continue;
504      // Add 'Searching for Wi-Fi networks...' after connected networks.
505      if (scanning_msg && !network->IsConnectedState()) {
506        AddMessageItem(l10n_util::GetStringUTF16(scanning_msg));
507        scanning_msg = 0;
508      }
509      AddWirelessNetworkMenuItem(network, FLAG_WIFI);
510    }
511    if (scanning_msg)
512      AddMessageItem(l10n_util::GetStringUTF16(scanning_msg));
513    const gfx::ImageSkia icon =
514        ash::network_icon::GetImageForConnectedNetwork(
515            ash::network_icon::ICON_TYPE_LIST, flimflam::kTypeWifi);
516    menu_items_.push_back(MenuItem(
517        ui::MenuModel::TYPE_COMMAND,
518        l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_OTHER_WIFI_NETWORKS),
519        icon, std::string(), FLAG_ADD_WIFI));
520  }
521
522  if (menu_items_.empty()) {
523    // No networks available (and not initializing cellular or wifi scanning)
524    AddMessageItem(l10n_util::GetStringFUTF16(
525        IDS_STATUSBAR_NETWORK_MENU_ITEM_INDENT,
526        l10n_util::GetStringUTF16(IDS_STATUSBAR_NO_NETWORKS_MESSAGE)));
527  }
528
529  // Enable / Disable Technology
530  NetworkStateHandler::TechnologyState wifi_state =
531      handler->GetTechnologyState(flimflam::kTypeWifi);
532  bool wifi_available =
533      wifi_state != NetworkStateHandler::TECHNOLOGY_UNAVAILABLE;
534  bool wifi_enabled = wifi_state == NetworkStateHandler::TECHNOLOGY_ENABLED;
535
536  NetworkStateHandler::TechnologyState mobile_state =
537      handler->GetTechnologyState(NetworkStateHandler::kMatchTypeMobile);
538  bool mobile_available =
539      mobile_state != NetworkStateHandler::TECHNOLOGY_UNAVAILABLE;
540  bool mobile_enabled = mobile_state == NetworkStateHandler::TECHNOLOGY_ENABLED;
541
542  // Do not show disable wifi or cellular during oobe.
543  bool show_toggle_wifi = wifi_available &&
544      (should_open_button_options || !wifi_enabled);
545  bool show_toggle_mobile = mobile_available &&
546      (should_open_button_options || !mobile_enabled);
547
548  if (show_toggle_wifi || show_toggle_mobile) {
549    menu_items_.push_back(MenuItem());  // Separator
550
551    if (show_toggle_wifi) {
552      int id = wifi_enabled ? IDS_STATUSBAR_NETWORK_DEVICE_DISABLE :
553                              IDS_STATUSBAR_NETWORK_DEVICE_ENABLE;
554      label = l10n_util::GetStringFUTF16(id,
555          l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_WIFI));
556      int flag = FLAG_TOGGLE_WIFI;
557      if (wifi_state == NetworkStateHandler::TECHNOLOGY_ENABLING)
558        flag |= FLAG_DISABLED;
559      menu_items_.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND, label,
560          gfx::ImageSkia(), std::string(), flag));
561    }
562
563    if (show_toggle_mobile) {
564      const DeviceState* mobile_device =
565          handler->GetDeviceStateByType(NetworkStateHandler::kMatchTypeMobile);
566      bool is_locked = mobile_device && !mobile_device->sim_lock_type().empty();
567      int id = (mobile_enabled && !is_locked)
568          ? IDS_STATUSBAR_NETWORK_DEVICE_DISABLE
569          : IDS_STATUSBAR_NETWORK_DEVICE_ENABLE;
570      label = l10n_util::GetStringFUTF16(id,
571          l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CELLULAR));
572      gfx::ImageSkia icon;
573      if (is_locked)
574        icon = *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_SECURE_DARK);
575      int flag = FLAG_TOGGLE_MOBILE;
576      if (mobile_state == NetworkStateHandler::TECHNOLOGY_ENABLING)
577        flag |= FLAG_DISABLED;
578      menu_items_.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND, label,
579          icon, std::string(), flag));
580    }
581  }
582
583  // Additional links like:
584  // * IP Address on active interface;
585  // * Hardware addresses for wifi and ethernet.
586  more_menu_model_->InitMenuItems(should_open_button_options);
587  if (!more_menu_model_->menu_items().empty()) {
588    menu_items_.push_back(MenuItem());  // Separator
589    menu_items_.push_back(MenuItem(
590        ui::MenuModel::TYPE_SUBMENU,
591        l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_MORE),
592        gfx::ImageSkia(), more_menu_model_.get(), FLAG_NONE));
593  }
594}
595
596int MainMenuModel::GetCommandIdAt(int index) const {
597  return index + kMainIndexMask;
598}
599
600////////////////////////////////////////////////////////////////////////////////
601// MoreMenuModel
602
603void MoreMenuModel::InitMenuItems(bool should_open_button_options) {
604  menu_items_.clear();
605  MenuItemVector link_items;
606  MenuItemVector address_items;
607
608  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
609  const NetworkState* default_network = handler->DefaultNetwork();
610
611  int message_id = -1;
612  if (default_network)
613    message_id = IDS_STATUSBAR_NETWORK_OPEN_PROXY_SETTINGS_DIALOG;
614  if (message_id != -1) {
615    link_items.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND,
616                                  l10n_util::GetStringUTF16(message_id),
617                                  gfx::ImageSkia(),
618                                  std::string(),
619                                  FLAG_OPTIONS));
620  }
621
622  if (default_network) {
623    std::string ip_address = default_network->ip_address();
624    if (!ip_address.empty()) {
625      address_items.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND,
626          ASCIIToUTF16(ip_address), gfx::ImageSkia(), std::string(),
627                       FLAG_DISABLED));
628    }
629  }
630
631  std::string ethernet_address =
632      handler->FormattedHardwareAddressForType(flimflam::kTypeEthernet);
633  if (!ethernet_address.empty()) {
634    std::string label = l10n_util::GetStringUTF8(
635        IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET) + " " + ethernet_address;
636    address_items.push_back(MenuItem(
637        ui::MenuModel::TYPE_COMMAND,
638        UTF8ToUTF16(label), gfx::ImageSkia(), std::string(), FLAG_DISABLED));
639  }
640
641  std::string wifi_address =
642      handler->FormattedHardwareAddressForType(flimflam::kTypeWifi);
643  if (!wifi_address.empty()) {
644    std::string label = l10n_util::GetStringUTF8(
645        IDS_STATUSBAR_NETWORK_DEVICE_WIFI) + " " + wifi_address;
646    address_items.push_back(MenuItem(
647        ui::MenuModel::TYPE_COMMAND,
648        UTF8ToUTF16(label), gfx::ImageSkia(), std::string(), FLAG_DISABLED));
649  }
650
651  menu_items_ = link_items;
652  if (!menu_items_.empty() && address_items.size() > 1)
653    menu_items_.push_back(MenuItem());  // Separator
654  menu_items_.insert(menu_items_.end(),
655      address_items.begin(), address_items.end());
656}
657
658int MoreMenuModel::GetCommandIdAt(int index) const {
659  return index + kMoreIndexMask;
660}
661
662////////////////////////////////////////////////////////////////////////////////
663// NetworkMenu
664
665NetworkMenu::Delegate::~Delegate() {
666}
667
668NetworkMenu::NetworkMenu(Delegate* delegate)
669    : delegate_(delegate),
670      refreshing_menu_(false),
671      weak_pointer_factory_(this) {
672  main_menu_model_.reset(new MainMenuModel(weak_pointer_factory_.GetWeakPtr()));
673}
674
675NetworkMenu::~NetworkMenu() {
676}
677
678ui::MenuModel* NetworkMenu::GetMenuModel() {
679  return main_menu_model_.get();
680}
681
682void NetworkMenu::UpdateMenu() {
683  refreshing_menu_ = true;
684  main_menu_model_->InitMenuItems(delegate_->ShouldOpenButtonOptions());
685  refreshing_menu_ = false;
686}
687
688}  // namespace chromeos
689