Home | History | Annotate | Download | only in status
      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.
     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);
     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);
     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);
     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 
    100 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 
    197 int NetworkMenuModel::GetItemCount() const {
    198   return static_cast<int>(menu_items_.size());
    199 }
    200 
    201 ui::MenuModel::ItemType NetworkMenuModel::GetTypeAt(int index) const {
    202   return menu_items_[index].type;
    203 }
    204 
    205 string16 NetworkMenuModel::GetLabelAt(int index) const {
    206   return menu_items_[index].label;
    207 }
    208 
    209 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 
    215 bool NetworkMenuModel::IsItemCheckedAt(int index) const {
    216   // All ui::MenuModel::TYPE_CHECK menu items are checked.
    217   return true;
    218 }
    219 
    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 
    228 bool NetworkMenuModel::IsEnabledAt(int index) const {
    229   return !(menu_items_[index].flags & FLAG_DISABLED);
    230 }
    231 
    232 ui::MenuModel* NetworkMenuModel::GetSubmenuModelAt(int index) const {
    233   return menu_items_[index].sub_menu_model;
    234 }
    235 
    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.
    289 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 
    297 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 
    305 void NetworkMenuModel::ShowOther(ConnectionType type) const {
    306   ShowNetworkConfigView(new NetworkConfigView(type));
    307 }
    308 
    309 void NetworkMenuModel::ShowOtherCellular() const {
    310   ChooseMobileNetworkDialog::ShowDialog(owner_->GetNativeWindow());
    311 }
    312 
    313 ////////////////////////////////////////////////////////////////////////////////
    314 // MainMenuModel
    315 
    316 MainMenuModel::MainMenuModel(NetworkMenu* owner)
    317     : NetworkMenuModel(owner),
    318       vpn_menu_model_(new VPNMenuModel(owner)),
    319       more_menu_model_(new MoreMenuModel(owner)) {
    320 }
    321 
    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 
    648 VPNMenuModel::VPNMenuModel(NetworkMenu* owner)
    649     : NetworkMenuModel(owner) {
    650 }
    651 
    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
    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 
    756 MoreMenuModel::MoreMenuModel(NetworkMenu* owner)
    757     : NetworkMenuModel(owner) {
    758 }
    759 
    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 
    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 
    877 NetworkMenu::~NetworkMenu() {
    878 }
    879 
    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 
    886 void NetworkMenu::CancelMenu() {
    887   network_menu_->CancelMenu();
    888 }
    889 
    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
    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
    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
    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
    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
   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 
   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
   1061 SkBitmap NetworkMenu::IconForDisplay(const SkBitmap* icon,
   1062                                      const SkBitmap* badge) {
   1063   return IconForDisplay(icon, badge, NULL, NULL);
   1064 }
   1065 
   1066 // static
   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 
   1097 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 
   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