Upstream version 7.35.139.0
[platform/framework/web/crosswalk.git] / src / ash / system / chromeos / network / network_state_list_detailed_view.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ash/system/chromeos/network/network_state_list_detailed_view.h"
6
7 #include "ash/ash_switches.h"
8 #include "ash/metrics/user_metrics_recorder.h"
9 #include "ash/root_window_controller.h"
10 #include "ash/shell.h"
11 #include "ash/shell_delegate.h"
12 #include "ash/shell_window_ids.h"
13 #include "ash/system/chromeos/network/network_connect.h"
14 #include "ash/system/chromeos/network/network_icon.h"
15 #include "ash/system/chromeos/network/network_icon_animation.h"
16 #include "ash/system/chromeos/network/tray_network_state_observer.h"
17 #include "ash/system/tray/fixed_sized_scroll_view.h"
18 #include "ash/system/tray/hover_highlight_view.h"
19 #include "ash/system/tray/system_tray.h"
20 #include "ash/system/tray/system_tray_delegate.h"
21 #include "ash/system/tray/tray_constants.h"
22 #include "ash/system/tray/tray_details_view.h"
23 #include "ash/system/tray/tray_popup_header_button.h"
24 #include "ash/system/tray/tray_popup_label_button.h"
25 #include "base/command_line.h"
26 #include "base/message_loop/message_loop.h"
27 #include "base/strings/utf_string_conversions.h"
28 #include "base/time/time.h"
29 #include "chromeos/chromeos_switches.h"
30 #include "chromeos/network/device_state.h"
31 #include "chromeos/network/network_configuration_handler.h"
32 #include "chromeos/network/network_state.h"
33 #include "chromeos/network/network_state_handler.h"
34 #include "chromeos/network/shill_property_util.h"
35 #include "grit/ash_resources.h"
36 #include "grit/ash_strings.h"
37 #include "third_party/cros_system_api/dbus/service_constants.h"
38 #include "ui/aura/window.h"
39 #include "ui/base/l10n/l10n_util.h"
40 #include "ui/base/resource/resource_bundle.h"
41 #include "ui/views/bubble/bubble_delegate.h"
42 #include "ui/views/controls/label.h"
43 #include "ui/views/layout/box_layout.h"
44 #include "ui/views/layout/fill_layout.h"
45 #include "ui/views/widget/widget.h"
46
47 using chromeos::DeviceState;
48 using chromeos::NetworkHandler;
49 using chromeos::NetworkState;
50 using chromeos::NetworkStateHandler;
51 using chromeos::NetworkTypePattern;
52
53 namespace ash {
54 namespace internal {
55 namespace tray {
56
57 namespace {
58
59 // Delay between scan requests.
60 const int kRequestScanDelaySeconds = 10;
61
62 // Create a label with the font size and color used in the network info bubble.
63 views::Label* CreateInfoBubbleLabel(const base::string16& text) {
64   views::Label* label = new views::Label(text);
65   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
66   label->SetFontList(rb.GetFontList(ui::ResourceBundle::SmallFont));
67   label->SetEnabledColor(SkColorSetARGB(127, 0, 0, 0));
68   return label;
69 }
70
71 // Create a label formatted for info items in the menu
72 views::Label* CreateMenuInfoLabel(const base::string16& text) {
73   views::Label* label = new views::Label(text);
74   label->SetBorder(
75       views::Border::CreateEmptyBorder(ash::kTrayPopupPaddingBetweenItems,
76                                        ash::kTrayPopupPaddingHorizontal,
77                                        ash::kTrayPopupPaddingBetweenItems,
78                                        0));
79   label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
80   label->SetEnabledColor(SkColorSetARGB(192, 0, 0, 0));
81   return label;
82 }
83
84 // Create a row of labels for the network info bubble.
85 views::View* CreateInfoBubbleLine(const base::string16& text_label,
86                                   const std::string& text_string) {
87   views::View* view = new views::View;
88   view->SetLayoutManager(
89       new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 1));
90   view->AddChildView(CreateInfoBubbleLabel(text_label));
91   view->AddChildView(CreateInfoBubbleLabel(base::UTF8ToUTF16(": ")));
92   view->AddChildView(CreateInfoBubbleLabel(base::UTF8ToUTF16(text_string)));
93   return view;
94 }
95
96 }  // namespace
97
98
99 //------------------------------------------------------------------------------
100
101 struct NetworkInfo {
102   NetworkInfo(const std::string& path)
103       : service_path(path),
104         disable(false),
105         highlight(false) {
106   }
107
108   std::string service_path;
109   base::string16 label;
110   gfx::ImageSkia image;
111   bool disable;
112   bool highlight;
113 };
114
115 //------------------------------------------------------------------------------
116
117 // A bubble which displays network info.
118 class NetworkStateListDetailedView::InfoBubble
119     : public views::BubbleDelegateView {
120  public:
121   InfoBubble(views::View* anchor,
122              views::View* content,
123              NetworkStateListDetailedView* detailed_view)
124       : views::BubbleDelegateView(anchor, views::BubbleBorder::TOP_RIGHT),
125         detailed_view_(detailed_view) {
126     set_use_focusless(true);
127     set_parent_window(ash::Shell::GetContainer(
128         anchor->GetWidget()->GetNativeWindow()->GetRootWindow(),
129         ash::internal::kShellWindowId_SettingBubbleContainer));
130     SetLayoutManager(new views::FillLayout());
131     AddChildView(content);
132   }
133
134   virtual ~InfoBubble() {
135     detailed_view_->OnInfoBubbleDestroyed();
136   }
137
138   virtual bool CanActivate() const OVERRIDE { return false; }
139
140  private:
141   // Not owned.
142   NetworkStateListDetailedView* detailed_view_;
143
144   DISALLOW_COPY_AND_ASSIGN(InfoBubble);
145 };
146
147 //------------------------------------------------------------------------------
148 // NetworkStateListDetailedView
149
150 NetworkStateListDetailedView::NetworkStateListDetailedView(
151     SystemTrayItem* owner,
152     ListType list_type,
153     user::LoginStatus login)
154     : NetworkDetailedView(owner),
155       list_type_(list_type),
156       login_(login),
157       info_icon_(NULL),
158       button_wifi_(NULL),
159       button_mobile_(NULL),
160       other_wifi_(NULL),
161       turn_on_wifi_(NULL),
162       other_mobile_(NULL),
163       other_vpn_(NULL),
164       settings_(NULL),
165       proxy_settings_(NULL),
166       scanning_view_(NULL),
167       no_wifi_networks_view_(NULL),
168       no_cellular_networks_view_(NULL),
169       info_bubble_(NULL) {
170 }
171
172 NetworkStateListDetailedView::~NetworkStateListDetailedView() {
173   if (info_bubble_)
174     info_bubble_->GetWidget()->CloseNow();
175   network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
176 }
177
178 void NetworkStateListDetailedView::ManagerChanged() {
179   UpdateNetworkList();
180   UpdateHeaderButtons();
181   UpdateNetworkExtra();
182   Layout();
183 }
184
185 void NetworkStateListDetailedView::NetworkListChanged() {
186   NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
187   NetworkStateHandler::NetworkStateList network_list;
188   handler->GetNetworkList(&network_list);
189   UpdateNetworks(network_list);
190   UpdateNetworkList();
191   UpdateHeaderButtons();
192   UpdateNetworkExtra();
193   Layout();
194 }
195
196 void NetworkStateListDetailedView::NetworkServiceChanged(
197     const NetworkState* network) {
198   UpdateNetworkList();
199   Layout();
200 }
201
202 void NetworkStateListDetailedView::NetworkIconChanged() {
203   UpdateNetworkList();
204   Layout();
205 }
206
207 // Overridden from NetworkDetailedView:
208
209 void NetworkStateListDetailedView::Init() {
210   Reset();
211   network_map_.clear();
212   service_path_map_.clear();
213   info_icon_ = NULL;
214   button_wifi_ = NULL;
215   button_mobile_ = NULL;
216   other_wifi_ = NULL;
217   turn_on_wifi_ = NULL;
218   other_mobile_ = NULL;
219   other_vpn_ = NULL;
220   settings_ = NULL;
221   proxy_settings_ = NULL;
222   scanning_view_ = NULL;
223   no_wifi_networks_view_ = NULL;
224   no_cellular_networks_view_ = NULL;
225
226   CreateScrollableList();
227   CreateNetworkExtra();
228   CreateHeaderEntry();
229   CreateHeaderButtons();
230
231   NetworkListChanged();
232
233   CallRequestScan();
234 }
235
236 NetworkDetailedView::DetailedViewType
237 NetworkStateListDetailedView::GetViewType() const {
238   return STATE_LIST_VIEW;
239 }
240
241 // Views overrides
242
243 void NetworkStateListDetailedView::ButtonPressed(views::Button* sender,
244                                                  const ui::Event& event) {
245   if (sender == info_icon_) {
246     ToggleInfoBubble();
247     return;
248   }
249
250   // If the info bubble was visible, close it when some other item is clicked.
251   ResetInfoBubble();
252
253   NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
254   ash::SystemTrayDelegate* delegate =
255       ash::Shell::GetInstance()->system_tray_delegate();
256   if (sender == button_wifi_) {
257     bool enabled = handler->IsTechnologyEnabled(
258         NetworkTypePattern::WiFi());
259     handler->SetTechnologyEnabled(NetworkTypePattern::WiFi(),
260                                   !enabled,
261                                   chromeos::network_handler::ErrorCallback());
262   } else if (sender == turn_on_wifi_) {
263     handler->SetTechnologyEnabled(NetworkTypePattern::WiFi(),
264                                   true,
265                                   chromeos::network_handler::ErrorCallback());
266   } else if (sender == button_mobile_) {
267     ToggleMobile();
268   } else if (sender == settings_) {
269     Shell::GetInstance()->metrics()->RecordUserMetricsAction(
270         list_type_ == LIST_TYPE_VPN ?
271         ash::UMA_STATUS_AREA_VPN_SETTINGS_CLICKED :
272         ash::UMA_STATUS_AREA_NETWORK_SETTINGS_CLICKED);
273     delegate->ShowNetworkSettings("");
274   } else if (sender == proxy_settings_) {
275     delegate->ChangeProxySettings();
276   } else if (sender == other_mobile_) {
277     delegate->ShowOtherNetworkDialog(shill::kTypeCellular);
278   } else if (sender == other_wifi_) {
279     Shell::GetInstance()->metrics()->RecordUserMetricsAction(
280         ash::UMA_STATUS_AREA_NETWORK_JOIN_OTHER_CLICKED);
281     delegate->ShowOtherNetworkDialog(shill::kTypeWifi);
282   } else if (sender == other_vpn_) {
283     Shell::GetInstance()->metrics()->RecordUserMetricsAction(
284         ash::UMA_STATUS_AREA_VPN_JOIN_OTHER_CLICKED);
285     delegate->ShowOtherNetworkDialog(shill::kTypeVPN);
286   } else {
287     NOTREACHED();
288   }
289 }
290
291 void NetworkStateListDetailedView::OnViewClicked(views::View* sender) {
292   // If the info bubble was visible, close it when some other item is clicked.
293   ResetInfoBubble();
294
295   if (sender == footer()->content()) {
296     TransitionToDefaultView();
297     return;
298   }
299
300   if (login_ == user::LOGGED_IN_LOCKED)
301     return;
302
303   std::map<views::View*, std::string>::iterator found =
304       network_map_.find(sender);
305   if (found == network_map_.end())
306     return;
307
308   const std::string& service_path = found->second;
309   const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
310       GetNetworkState(service_path);
311   if (!network || network->IsConnectedState() || network->IsConnectingState()) {
312     Shell::GetInstance()->metrics()->RecordUserMetricsAction(
313         list_type_ == LIST_TYPE_VPN ?
314         ash::UMA_STATUS_AREA_SHOW_NETWORK_CONNECTION_DETAILS :
315         ash::UMA_STATUS_AREA_SHOW_VPN_CONNECTION_DETAILS);
316     Shell::GetInstance()->system_tray_delegate()->ShowNetworkSettings(
317         service_path);
318   } else {
319     Shell::GetInstance()->metrics()->RecordUserMetricsAction(
320         list_type_ == LIST_TYPE_VPN ?
321         ash::UMA_STATUS_AREA_CONNECT_TO_VPN :
322         ash::UMA_STATUS_AREA_CONNECT_TO_CONFIGURED_NETWORK);
323     ash::network_connect::ConnectToNetwork(service_path, NULL);
324   }
325 }
326
327 // Create UI components.
328
329 void NetworkStateListDetailedView::CreateHeaderEntry() {
330   CreateSpecialRow(IDS_ASH_STATUS_TRAY_NETWORK, this);
331 }
332
333 void NetworkStateListDetailedView::CreateHeaderButtons() {
334   if (list_type_ != LIST_TYPE_VPN) {
335     button_wifi_ = new TrayPopupHeaderButton(
336         this,
337         IDR_AURA_UBER_TRAY_WIFI_ENABLED,
338         IDR_AURA_UBER_TRAY_WIFI_DISABLED,
339         IDR_AURA_UBER_TRAY_WIFI_ENABLED_HOVER,
340         IDR_AURA_UBER_TRAY_WIFI_DISABLED_HOVER,
341         IDS_ASH_STATUS_TRAY_WIFI);
342     button_wifi_->SetTooltipText(
343         l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISABLE_WIFI));
344     button_wifi_->SetToggledTooltipText(
345         l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ENABLE_WIFI));
346     footer()->AddButton(button_wifi_);
347
348     button_mobile_ = new TrayPopupHeaderButton(
349         this,
350         IDR_AURA_UBER_TRAY_CELLULAR_ENABLED,
351         IDR_AURA_UBER_TRAY_CELLULAR_DISABLED,
352         IDR_AURA_UBER_TRAY_CELLULAR_ENABLED_HOVER,
353         IDR_AURA_UBER_TRAY_CELLULAR_DISABLED_HOVER,
354         IDS_ASH_STATUS_TRAY_CELLULAR);
355     button_mobile_->SetTooltipText(
356         l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISABLE_MOBILE));
357     button_mobile_->SetToggledTooltipText(
358         l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ENABLE_MOBILE));
359     footer()->AddButton(button_mobile_);
360   }
361
362   info_icon_ = new TrayPopupHeaderButton(
363       this,
364       IDR_AURA_UBER_TRAY_NETWORK_INFO,
365       IDR_AURA_UBER_TRAY_NETWORK_INFO,
366       IDR_AURA_UBER_TRAY_NETWORK_INFO_HOVER,
367       IDR_AURA_UBER_TRAY_NETWORK_INFO_HOVER,
368       IDS_ASH_STATUS_TRAY_NETWORK_INFO);
369   info_icon_->SetTooltipText(
370       l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_INFO));
371   footer()->AddButton(info_icon_);
372 }
373
374 void NetworkStateListDetailedView::CreateNetworkExtra() {
375   if (login_ == user::LOGGED_IN_LOCKED)
376     return;
377
378   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
379
380   views::View* bottom_row = new views::View();
381   views::BoxLayout* layout = new views::BoxLayout(
382       views::BoxLayout::kHorizontal,
383       kTrayMenuBottomRowPadding,
384       kTrayMenuBottomRowPadding,
385       kTrayMenuBottomRowPaddingBetweenItems);
386   layout->set_spread_blank_space(true);
387   bottom_row->SetLayoutManager(layout);
388
389   if (list_type_ != LIST_TYPE_VPN) {
390     other_wifi_ = new TrayPopupLabelButton(
391         this, rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_OTHER_WIFI));
392     bottom_row->AddChildView(other_wifi_);
393
394     turn_on_wifi_ = new TrayPopupLabelButton(
395         this, rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_TURN_ON_WIFI));
396     bottom_row->AddChildView(turn_on_wifi_);
397
398     other_mobile_ = new TrayPopupLabelButton(
399         this, rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_OTHER_MOBILE));
400     bottom_row->AddChildView(other_mobile_);
401   } else {
402     other_vpn_ = new TrayPopupLabelButton(
403         this,
404         ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
405             IDS_ASH_STATUS_TRAY_OTHER_VPN));
406     bottom_row->AddChildView(other_vpn_);
407   }
408
409   CreateSettingsEntry();
410
411   // Both settings_ and proxy_settings_ can be NULL. This happens when
412   // we're logged in but showing settings page is not enabled.
413   // Example: supervised user creation flow where user session is active
414   // but all action happens on the login window.
415   // Allowing opening proxy settigns dialog will break assumption in
416   //  SystemTrayDelegateChromeOS::ChangeProxySettings(), see CHECK.
417   if (settings_ || proxy_settings_)
418     bottom_row->AddChildView(settings_ ? settings_ : proxy_settings_);
419
420   AddChildView(bottom_row);
421 }
422
423 // Update UI components.
424
425 void NetworkStateListDetailedView::UpdateHeaderButtons() {
426   NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
427   if (button_wifi_)
428     UpdateTechnologyButton(button_wifi_, NetworkTypePattern::WiFi());
429   if (button_mobile_) {
430     UpdateTechnologyButton(button_mobile_, NetworkTypePattern::Mobile());
431   }
432   if (proxy_settings_)
433     proxy_settings_->SetEnabled(handler->DefaultNetwork() != NULL);
434
435   static_cast<views::View*>(footer())->Layout();
436 }
437
438 void NetworkStateListDetailedView::UpdateTechnologyButton(
439     TrayPopupHeaderButton* button,
440     const NetworkTypePattern& technology) {
441   NetworkStateHandler::TechnologyState state =
442       NetworkHandler::Get()->network_state_handler()->GetTechnologyState(
443           technology);
444   if (state == NetworkStateHandler::TECHNOLOGY_UNAVAILABLE) {
445     button->SetVisible(false);
446     return;
447   }
448   button->SetVisible(true);
449   if (state == NetworkStateHandler::TECHNOLOGY_AVAILABLE) {
450     button->SetEnabled(true);
451     button->SetToggled(true);
452   } else if (state == NetworkStateHandler::TECHNOLOGY_ENABLED) {
453     button->SetEnabled(true);
454     button->SetToggled(false);
455   } else if (state == NetworkStateHandler::TECHNOLOGY_ENABLING) {
456     button->SetEnabled(false);
457     button->SetToggled(false);
458   } else {  // Initializing
459     button->SetEnabled(false);
460     button->SetToggled(true);
461   }
462 }
463
464 void NetworkStateListDetailedView::UpdateNetworks(
465     const NetworkStateHandler::NetworkStateList& networks) {
466   network_list_.clear();
467   for (NetworkStateHandler::NetworkStateList::const_iterator iter =
468            networks.begin(); iter != networks.end(); ++iter) {
469     const NetworkState* network = *iter;
470     if ((list_type_ == LIST_TYPE_NETWORK &&
471          network->type() != shill::kTypeVPN) ||
472         (list_type_ == LIST_TYPE_VPN &&
473          network->type() == shill::kTypeVPN)) {
474       NetworkInfo* info = new NetworkInfo(network->path());
475       network_list_.push_back(info);
476     }
477   }
478 }
479
480 void NetworkStateListDetailedView::UpdateNetworkList() {
481   NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
482
483   // First, update state for all networks
484   bool animating = false;
485   for (size_t i = 0; i < network_list_.size(); ++i) {
486     NetworkInfo* info = network_list_[i];
487     const NetworkState* network =
488         handler->GetNetworkState(info->service_path);
489     if (!network)
490       continue;
491     info->image = network_icon::GetImageForNetwork(
492         network, network_icon::ICON_TYPE_LIST);
493     info->label = network_icon::GetLabelForNetwork(
494         network, network_icon::ICON_TYPE_LIST);
495     info->highlight =
496         network->IsConnectedState() || network->IsConnectingState();
497     info->disable =
498         network->activation_state() == shill::kActivationStateActivating;
499     if (!animating && network->IsConnectingState())
500       animating = true;
501   }
502   if (animating)
503     network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this);
504   else
505     network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
506
507   // Get the updated list entries
508   network_map_.clear();
509   std::set<std::string> new_service_paths;
510   bool needs_relayout = UpdateNetworkListEntries(&new_service_paths);
511
512   // Remove old children
513   std::set<std::string> remove_service_paths;
514   for (ServicePathMap::const_iterator it = service_path_map_.begin();
515        it != service_path_map_.end(); ++it) {
516     if (new_service_paths.find(it->first) == new_service_paths.end()) {
517       remove_service_paths.insert(it->first);
518       network_map_.erase(it->second);
519       scroll_content()->RemoveChildView(it->second);
520       needs_relayout = true;
521     }
522   }
523
524   for (std::set<std::string>::const_iterator remove_it =
525            remove_service_paths.begin();
526        remove_it != remove_service_paths.end(); ++remove_it) {
527     service_path_map_.erase(*remove_it);
528   }
529
530   if (needs_relayout) {
531     views::View* selected_view = NULL;
532     for (ServicePathMap::const_iterator iter = service_path_map_.begin();
533          iter != service_path_map_.end(); ++iter) {
534       if (iter->second->hover()) {
535         selected_view = iter->second;
536         break;
537       }
538     }
539     scroll_content()->SizeToPreferredSize();
540     static_cast<views::View*>(scroller())->Layout();
541     if (selected_view)
542       scroll_content()->ScrollRectToVisible(selected_view->bounds());
543   }
544 }
545
546 bool NetworkStateListDetailedView::CreateOrUpdateInfoLabel(
547     int index, const base::string16& text, views::Label** label) {
548   if (*label == NULL) {
549     *label = CreateMenuInfoLabel(text);
550     scroll_content()->AddChildViewAt(*label, index);
551     return true;
552   } else {
553     (*label)->SetText(text);
554     return OrderChild(*label, index);
555   }
556 }
557
558 bool NetworkStateListDetailedView::UpdateNetworkChild(int index,
559                                                       const NetworkInfo* info) {
560   bool needs_relayout = false;
561   HoverHighlightView* container = NULL;
562   ServicePathMap::const_iterator found =
563       service_path_map_.find(info->service_path);
564   gfx::Font::FontStyle font =
565       info->highlight ? gfx::Font::BOLD : gfx::Font::NORMAL;
566   if (found == service_path_map_.end()) {
567     container = new HoverHighlightView(this);
568     container->AddIconAndLabel(info->image, info->label, font);
569     scroll_content()->AddChildViewAt(container, index);
570     container->SetBorder(
571         views::Border::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal, 0, 0));
572     needs_relayout = true;
573   } else {
574     container = found->second;
575     container->RemoveAllChildViews(true);
576     container->AddIconAndLabel(info->image, info->label, font);
577     container->Layout();
578     container->SchedulePaint();
579     needs_relayout = OrderChild(container, index);
580   }
581   if (info->disable)
582     container->SetEnabled(false);
583   network_map_[container] = info->service_path;
584   service_path_map_[info->service_path] = container;
585   return needs_relayout;
586 }
587
588 bool NetworkStateListDetailedView::OrderChild(views::View* view, int index) {
589   if (scroll_content()->child_at(index) != view) {
590     scroll_content()->ReorderChildView(view, index);
591     return true;
592   }
593   return false;
594 }
595
596 bool NetworkStateListDetailedView::UpdateNetworkListEntries(
597     std::set<std::string>* new_service_paths) {
598   bool needs_relayout = false;
599   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
600   NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
601
602   // Insert child views
603   int index = 0;
604
605   // Highlighted networks
606   for (size_t i = 0; i < network_list_.size(); ++i) {
607     const NetworkInfo* info = network_list_[i];
608     if (info->highlight) {
609       if (UpdateNetworkChild(index++, info))
610         needs_relayout = true;
611       new_service_paths->insert(info->service_path);
612     }
613   }
614
615   if (list_type_ == LIST_TYPE_NETWORK) {
616     // Cellular initializing
617     int status_message_id = network_icon::GetCellularUninitializedMsg();
618     if (!status_message_id &&
619         handler->IsTechnologyEnabled(NetworkTypePattern::Mobile()) &&
620         !handler->FirstNetworkByType(NetworkTypePattern::Mobile())) {
621       status_message_id = IDS_ASH_STATUS_TRAY_NO_CELLULAR_NETWORKS;
622     }
623     if (status_message_id) {
624       base::string16 text = rb.GetLocalizedString(status_message_id);
625       if (CreateOrUpdateInfoLabel(index++, text, &no_cellular_networks_view_))
626         needs_relayout = true;
627     } else if (no_cellular_networks_view_) {
628       scroll_content()->RemoveChildView(no_cellular_networks_view_);
629       no_cellular_networks_view_ = NULL;
630       needs_relayout = true;
631     }
632
633     // "Wifi Enabled / Disabled"
634     if (network_list_.empty()) {
635       int message_id = handler->IsTechnologyEnabled(NetworkTypePattern::WiFi())
636                            ? IDS_ASH_STATUS_TRAY_NETWORK_WIFI_ENABLED
637                            : IDS_ASH_STATUS_TRAY_NETWORK_WIFI_DISABLED;
638       base::string16 text = rb.GetLocalizedString(message_id);
639       if (CreateOrUpdateInfoLabel(index++, text, &no_wifi_networks_view_))
640         needs_relayout = true;
641     } else if (no_wifi_networks_view_) {
642       scroll_content()->RemoveChildView(no_wifi_networks_view_);
643       no_wifi_networks_view_ = NULL;
644       needs_relayout = true;
645     }
646
647     // "Wifi Scanning"
648     if (handler->GetScanningByType(NetworkTypePattern::WiFi())) {
649       base::string16 text =
650           rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_WIFI_SCANNING_MESSAGE);
651       if (CreateOrUpdateInfoLabel(index++, text, &scanning_view_))
652         needs_relayout = true;
653     } else if (scanning_view_ != NULL) {
654       scroll_content()->RemoveChildView(scanning_view_);
655       scanning_view_ = NULL;
656       needs_relayout = true;
657     }
658   }
659
660   // Un-highlighted networks
661   for (size_t i = 0; i < network_list_.size(); ++i) {
662     const NetworkInfo* info = network_list_[i];
663     if (!info->highlight) {
664       if (UpdateNetworkChild(index++, info))
665         needs_relayout = true;
666       new_service_paths->insert(info->service_path);
667     }
668   }
669
670   // No networks or other messages (fallback)
671   if (index == 0) {
672     base::string16 text;
673     if (list_type_ == LIST_TYPE_VPN)
674       text = rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_NETWORK_NO_VPN);
675     else
676       text = rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_NO_NETWORKS);
677     if (CreateOrUpdateInfoLabel(index++, text, &scanning_view_))
678       needs_relayout = true;
679   }
680
681   return needs_relayout;
682 }
683
684 void NetworkStateListDetailedView::UpdateNetworkExtra() {
685   if (login_ == user::LOGGED_IN_LOCKED)
686     return;
687
688   View* layout_parent = NULL;  // All these buttons have the same parent.
689   NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
690   if (other_wifi_) {
691     DCHECK(turn_on_wifi_);
692     NetworkStateHandler::TechnologyState state =
693         handler->GetTechnologyState(NetworkTypePattern::WiFi());
694     if (state == NetworkStateHandler::TECHNOLOGY_UNAVAILABLE) {
695       turn_on_wifi_->SetVisible(false);
696       other_wifi_->SetVisible(false);
697     } else {
698       if (state == NetworkStateHandler::TECHNOLOGY_AVAILABLE) {
699         turn_on_wifi_->SetVisible(true);
700         turn_on_wifi_->SetEnabled(true);
701         other_wifi_->SetVisible(false);
702       } else if (state == NetworkStateHandler::TECHNOLOGY_ENABLED) {
703         turn_on_wifi_->SetVisible(false);
704         other_wifi_->SetVisible(true);
705       } else {
706         // Initializing or Enabling
707         turn_on_wifi_->SetVisible(true);
708         turn_on_wifi_->SetEnabled(false);
709         other_wifi_->SetVisible(false);
710       }
711     }
712     layout_parent = other_wifi_->parent();
713   }
714
715   if (other_mobile_) {
716     bool show_other_mobile = false;
717     NetworkStateHandler::TechnologyState state =
718         handler->GetTechnologyState(NetworkTypePattern::Mobile());
719     if (state != NetworkStateHandler::TECHNOLOGY_UNAVAILABLE) {
720       const chromeos::DeviceState* device =
721           handler->GetDeviceStateByType(NetworkTypePattern::Mobile());
722       show_other_mobile = (device && device->support_network_scan());
723     }
724     if (show_other_mobile) {
725       other_mobile_->SetVisible(true);
726       other_mobile_->SetEnabled(
727           state == NetworkStateHandler::TECHNOLOGY_ENABLED);
728     } else {
729       other_mobile_->SetVisible(false);
730     }
731     if (!layout_parent)
732       layout_parent = other_wifi_->parent();
733   }
734
735   if (layout_parent)
736     layout_parent->Layout();
737 }
738
739 void NetworkStateListDetailedView::CreateSettingsEntry() {
740   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
741   bool show_settings = ash::Shell::GetInstance()->
742       system_tray_delegate()->ShouldShowSettings();
743   if (login_ != user::LOGGED_IN_NONE) {
744     // Allow user access settings only if user is logged in
745     // and showing settings is allowed. There're situations (supervised user
746     // creation flow) when session is started but UI flow continues within
747     // login UI i.e. no browser window is yet avaialable.
748     if (show_settings) {
749       settings_ = new TrayPopupLabelButton(
750           this, rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_NETWORK_SETTINGS));
751     }
752   } else  {
753     // Allow users to change proxy settings only when not logged in.
754     proxy_settings_ = new TrayPopupLabelButton(
755         this,
756         rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_NETWORK_PROXY_SETTINGS));
757   }
758 }
759
760 void NetworkStateListDetailedView::ToggleInfoBubble() {
761   if (ResetInfoBubble())
762     return;
763
764   info_bubble_ = new InfoBubble(
765       info_icon_, CreateNetworkInfoView(), this);
766   views::BubbleDelegateView::CreateBubble(info_bubble_)->Show();
767 }
768
769 bool NetworkStateListDetailedView::ResetInfoBubble() {
770   if (!info_bubble_)
771     return false;
772   info_bubble_->GetWidget()->Close();
773   info_bubble_ = NULL;
774   return true;
775 }
776
777 void NetworkStateListDetailedView::OnInfoBubbleDestroyed() {
778   info_bubble_ = NULL;
779 }
780
781 views::View* NetworkStateListDetailedView::CreateNetworkInfoView() {
782   ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
783   NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
784
785   std::string ip_address("0.0.0.0");
786   const NetworkState* network = handler->DefaultNetwork();
787   if (network)
788     ip_address = network->ip_address();
789
790   views::View* container = new views::View;
791   container->SetLayoutManager(
792       new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
793   container->SetBorder(views::Border::CreateEmptyBorder(0, 5, 0, 5));
794
795   std::string ethernet_address, wifi_address, vpn_address;
796   if (list_type_ != LIST_TYPE_VPN) {
797     ethernet_address = handler->FormattedHardwareAddressForType(
798         NetworkTypePattern::Ethernet());
799     wifi_address =
800         handler->FormattedHardwareAddressForType(NetworkTypePattern::WiFi());
801   } else {
802     vpn_address =
803         handler->FormattedHardwareAddressForType(NetworkTypePattern::VPN());
804   }
805
806   if (!ip_address.empty()) {
807     container->AddChildView(CreateInfoBubbleLine(bundle.GetLocalizedString(
808         IDS_ASH_STATUS_TRAY_IP), ip_address));
809   }
810   if (!ethernet_address.empty()) {
811     container->AddChildView(CreateInfoBubbleLine(bundle.GetLocalizedString(
812         IDS_ASH_STATUS_TRAY_ETHERNET), ethernet_address));
813   }
814   if (!wifi_address.empty()) {
815     container->AddChildView(CreateInfoBubbleLine(bundle.GetLocalizedString(
816         IDS_ASH_STATUS_TRAY_WIFI), wifi_address));
817   }
818   if (!vpn_address.empty()) {
819     container->AddChildView(CreateInfoBubbleLine(bundle.GetLocalizedString(
820         IDS_ASH_STATUS_TRAY_VPN), vpn_address));
821   }
822
823   // Avoid an empty bubble in the unlikely event that there is no network
824   // information at all.
825   if (!container->has_children()) {
826     container->AddChildView(CreateInfoBubbleLabel(bundle.GetLocalizedString(
827         IDS_ASH_STATUS_TRAY_NO_NETWORKS)));
828   }
829
830   return container;
831 }
832
833 void NetworkStateListDetailedView::CallRequestScan() {
834   VLOG(1) << "Requesting Network Scan.";
835   NetworkHandler::Get()->network_state_handler()->RequestScan();
836   // Periodically request a scan while this UI is open.
837   base::MessageLoopForUI::current()->PostDelayedTask(
838       FROM_HERE,
839       base::Bind(&NetworkStateListDetailedView::CallRequestScan, AsWeakPtr()),
840       base::TimeDelta::FromSeconds(kRequestScanDelaySeconds));
841 }
842
843 void NetworkStateListDetailedView::ToggleMobile() {
844   NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
845   bool enabled =
846       handler->IsTechnologyEnabled(NetworkTypePattern::Mobile());
847   ash::network_connect::SetTechnologyEnabled(NetworkTypePattern::Mobile(),
848                                              !enabled);
849 }
850
851 }  // namespace tray
852 }  // namespace internal
853 }  // namespace ash