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