blob: 64e6d3bc3ffd3ae4a2a2e310efd0efb3ded179ae [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/system/chromeos/network/network_state_list_detailed_view.h"
#include "ash/ash_switches.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/shell_window_ids.h"
#include "ash/system/chromeos/network/network_connect.h"
#include "ash/system/chromeos/network/network_icon.h"
#include "ash/system/chromeos/network/network_icon_animation.h"
#include "ash/system/chromeos/network/tray_network_state_observer.h"
#include "ash/system/tray/fixed_sized_scroll_view.h"
#include "ash/system/tray/hover_highlight_view.h"
#include "ash/system/tray/system_tray.h"
#include "ash/system/tray/system_tray_delegate.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/system/tray/tray_details_view.h"
#include "ash/system/tray/tray_popup_header_button.h"
#include "ash/system/tray/tray_popup_label_button.h"
#include "base/command_line.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "chromeos/chromeos_switches.h"
#include "chromeos/network/device_state.h"
#include "chromeos/network/favorite_state.h"
#include "chromeos/network/network_configuration_handler.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_state_handler.h"
#include "grit/ash_resources.h"
#include "grit/ash_strings.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#include "ui/aura/window.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/views/bubble/bubble_delegate.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/widget/widget.h"
using chromeos::DeviceState;
using chromeos::FavoriteState;
using chromeos::NetworkHandler;
using chromeos::NetworkState;
using chromeos::NetworkStateHandler;
namespace ash {
namespace internal {
namespace tray {
namespace {
// Height of the list of networks in the popup.
const int kNetworkListHeight = 203;
// Delay between scan requests.
const int kRequestScanDelaySeconds = 10;
// Create a label with the font size and color used in the network info bubble.
views::Label* CreateInfoBubbleLabel(const base::string16& text) {
views::Label* label = new views::Label(text);
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
label->SetFont(rb.GetFont(ui::ResourceBundle::SmallFont));
label->SetEnabledColor(SkColorSetARGB(127, 0, 0, 0));
return label;
}
// Create a label formatted for info items in the menu
views::Label* CreateMenuInfoLabel(const base::string16& text) {
views::Label* label = new views::Label(text);
label->set_border(views::Border::CreateEmptyBorder(
ash::kTrayPopupPaddingBetweenItems,
ash::kTrayPopupPaddingHorizontal,
ash::kTrayPopupPaddingBetweenItems, 0));
label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
label->SetEnabledColor(SkColorSetARGB(192, 0, 0, 0));
return label;
}
// Create a row of labels for the network info bubble.
views::View* CreateInfoBubbleLine(const base::string16& text_label,
const std::string& text_string) {
views::View* view = new views::View;
view->SetLayoutManager(
new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 1));
view->AddChildView(CreateInfoBubbleLabel(text_label));
view->AddChildView(CreateInfoBubbleLabel(UTF8ToUTF16(": ")));
view->AddChildView(CreateInfoBubbleLabel(UTF8ToUTF16(text_string)));
return view;
}
// A bubble that cannot be activated.
class NonActivatableSettingsBubble : public views::BubbleDelegateView {
public:
NonActivatableSettingsBubble(views::View* anchor, views::View* content)
: views::BubbleDelegateView(anchor, views::BubbleBorder::TOP_RIGHT) {
set_use_focusless(true);
set_parent_window(ash::Shell::GetContainer(
anchor->GetWidget()->GetNativeWindow()->GetRootWindow(),
ash::internal::kShellWindowId_SettingBubbleContainer));
SetLayoutManager(new views::FillLayout());
AddChildView(content);
}
virtual ~NonActivatableSettingsBubble() {}
virtual bool CanActivate() const OVERRIDE { return false; }
private:
DISALLOW_COPY_AND_ASSIGN(NonActivatableSettingsBubble);
};
} // namespace
//------------------------------------------------------------------------------
struct NetworkInfo {
NetworkInfo(const std::string& path)
: service_path(path),
disable(false),
highlight(false) {
}
std::string service_path;
base::string16 label;
gfx::ImageSkia image;
bool disable;
bool highlight;
};
//------------------------------------------------------------------------------
// NetworkStateListDetailedView
NetworkStateListDetailedView::NetworkStateListDetailedView(
SystemTrayItem* owner,
ListType list_type,
user::LoginStatus login)
: NetworkDetailedView(owner),
list_type_(list_type),
login_(login),
info_icon_(NULL),
button_wifi_(NULL),
button_mobile_(NULL),
other_wifi_(NULL),
turn_on_wifi_(NULL),
other_mobile_(NULL),
other_vpn_(NULL),
toggle_debug_preferred_networks_(NULL),
settings_(NULL),
proxy_settings_(NULL),
scanning_view_(NULL),
no_wifi_networks_view_(NULL),
no_cellular_networks_view_(NULL),
info_bubble_(NULL) {
}
NetworkStateListDetailedView::~NetworkStateListDetailedView() {
if (info_bubble_)
info_bubble_->GetWidget()->CloseNow();
network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
}
void NetworkStateListDetailedView::ManagerChanged() {
UpdateNetworkList();
UpdateHeaderButtons();
UpdateNetworkExtra();
Layout();
}
void NetworkStateListDetailedView::NetworkListChanged() {
NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
if (list_type_ == LIST_TYPE_DEBUG_PREFERRED) {
NetworkStateHandler::FavoriteStateList favorite_list;
handler->GetFavoriteList(&favorite_list);
UpdatePreferred(favorite_list);
} else {
NetworkStateHandler::NetworkStateList network_list;
handler->GetNetworkList(&network_list);
UpdateNetworks(network_list);
}
UpdateNetworkList();
UpdateHeaderButtons();
UpdateNetworkExtra();
Layout();
}
void NetworkStateListDetailedView::NetworkServiceChanged(
const NetworkState* network) {
UpdateNetworkList();
Layout();
}
void NetworkStateListDetailedView::NetworkIconChanged() {
UpdateNetworkList();
Layout();
}
// Overridden from NetworkDetailedView:
void NetworkStateListDetailedView::Init() {
Reset();
network_map_.clear();
service_path_map_.clear();
info_icon_ = NULL;
button_wifi_ = NULL;
button_mobile_ = NULL;
other_wifi_ = NULL;
turn_on_wifi_ = NULL;
other_mobile_ = NULL;
other_vpn_ = NULL;
toggle_debug_preferred_networks_ = NULL;
settings_ = NULL;
proxy_settings_ = NULL;
scanning_view_ = NULL;
no_wifi_networks_view_ = NULL;
no_cellular_networks_view_ = NULL;
CreateScrollableList();
CreateNetworkExtra();
CreateHeaderEntry();
CreateHeaderButtons();
NetworkListChanged();
CallRequestScan();
}
NetworkDetailedView::DetailedViewType
NetworkStateListDetailedView::GetViewType() const {
return STATE_LIST_VIEW;
}
// Views overrides
void NetworkStateListDetailedView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
if (sender == info_icon_) {
ToggleInfoBubble();
return;
}
// If the info bubble was visible, close it when some other item is clicked.
ResetInfoBubble();
NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
ash::SystemTrayDelegate* delegate =
ash::Shell::GetInstance()->system_tray_delegate();
if (sender == button_wifi_) {
bool enabled = handler->IsTechnologyEnabled(flimflam::kTypeWifi);
handler->SetTechnologyEnabled(
flimflam::kTypeWifi, !enabled,
chromeos::network_handler::ErrorCallback());
} else if (sender == turn_on_wifi_) {
handler->SetTechnologyEnabled(
flimflam::kTypeWifi, true,
chromeos::network_handler::ErrorCallback());
} else if (sender == button_mobile_) {
ToggleMobile();
} else if (sender == settings_) {
delegate->ShowNetworkSettings("");
} else if (sender == proxy_settings_) {
delegate->ChangeProxySettings();
} else if (sender == other_mobile_) {
delegate->ShowOtherCellular();
} else if (sender == toggle_debug_preferred_networks_) {
list_type_ = (list_type_ == LIST_TYPE_NETWORK)
? LIST_TYPE_DEBUG_PREFERRED : LIST_TYPE_NETWORK;
// Re-initialize this after processing the event.
base::MessageLoopForUI::current()->PostTask(
FROM_HERE,
base::Bind(&NetworkStateListDetailedView::Init, AsWeakPtr()));
} else if (sender == other_wifi_) {
delegate->ShowOtherWifi();
} else if (sender == other_vpn_) {
delegate->ShowOtherVPN();
} else {
NOTREACHED();
}
}
void NetworkStateListDetailedView::OnViewClicked(views::View* sender) {
// If the info bubble was visible, close it when some other item is clicked.
ResetInfoBubble();
if (sender == footer()->content()) {
RootWindowController::ForWindow(GetWidget()->GetNativeView())->
GetSystemTray()->ShowDefaultView(BUBBLE_USE_EXISTING);
return;
}
if (login_ == user::LOGGED_IN_LOCKED)
return;
std::map<views::View*, std::string>::iterator found =
network_map_.find(sender);
if (found == network_map_.end())
return;
const std::string& service_path = found->second;
if (list_type_ == LIST_TYPE_DEBUG_PREFERRED) {
NetworkHandler::Get()->network_configuration_handler()->
RemoveConfiguration(service_path,
base::Bind(&base::DoNothing),
chromeos::network_handler::ErrorCallback());
return;
}
const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
GetNetworkState(service_path);
if (!network || network->IsConnectedState() || network->IsConnectingState()) {
Shell::GetInstance()->system_tray_delegate()->ShowNetworkSettings(
service_path);
} else {
ash::network_connect::ConnectToNetwork(service_path, NULL);
}
}
// Create UI components.
void NetworkStateListDetailedView::CreateHeaderEntry() {
CreateSpecialRow(IDS_ASH_STATUS_TRAY_NETWORK, this);
}
void NetworkStateListDetailedView::CreateHeaderButtons() {
if (list_type_ != LIST_TYPE_VPN) {
button_wifi_ = new TrayPopupHeaderButton(
this,
IDR_AURA_UBER_TRAY_WIFI_ENABLED,
IDR_AURA_UBER_TRAY_WIFI_DISABLED,
IDR_AURA_UBER_TRAY_WIFI_ENABLED_HOVER,
IDR_AURA_UBER_TRAY_WIFI_DISABLED_HOVER,
IDS_ASH_STATUS_TRAY_WIFI);
button_wifi_->SetTooltipText(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISABLE_WIFI));
button_wifi_->SetToggledTooltipText(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ENABLE_WIFI));
footer()->AddButton(button_wifi_);
button_mobile_ = new TrayPopupHeaderButton(
this,
IDR_AURA_UBER_TRAY_CELLULAR_ENABLED,
IDR_AURA_UBER_TRAY_CELLULAR_DISABLED,
IDR_AURA_UBER_TRAY_CELLULAR_ENABLED_HOVER,
IDR_AURA_UBER_TRAY_CELLULAR_DISABLED_HOVER,
IDS_ASH_STATUS_TRAY_CELLULAR);
button_mobile_->SetTooltipText(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISABLE_MOBILE));
button_mobile_->SetToggledTooltipText(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ENABLE_MOBILE));
footer()->AddButton(button_mobile_);
}
info_icon_ = new TrayPopupHeaderButton(
this,
IDR_AURA_UBER_TRAY_NETWORK_INFO,
IDR_AURA_UBER_TRAY_NETWORK_INFO,
IDR_AURA_UBER_TRAY_NETWORK_INFO_HOVER,
IDR_AURA_UBER_TRAY_NETWORK_INFO_HOVER,
IDS_ASH_STATUS_TRAY_NETWORK_INFO);
info_icon_->SetTooltipText(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_INFO));
footer()->AddButton(info_icon_);
}
void NetworkStateListDetailedView::CreateNetworkExtra() {
if (login_ == user::LOGGED_IN_LOCKED)
return;
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
views::View* bottom_row = new views::View();
views::BoxLayout* layout = new views::BoxLayout(
views::BoxLayout::kHorizontal,
kTrayMenuBottomRowPadding,
kTrayMenuBottomRowPadding,
kTrayMenuBottomRowPaddingBetweenItems);
layout->set_spread_blank_space(true);
bottom_row->SetLayoutManager(layout);
if (list_type_ != LIST_TYPE_VPN) {
other_wifi_ = new TrayPopupLabelButton(
this, rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_OTHER_WIFI));
bottom_row->AddChildView(other_wifi_);
turn_on_wifi_ = new TrayPopupLabelButton(
this, rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_TURN_ON_WIFI));
bottom_row->AddChildView(turn_on_wifi_);
other_mobile_ = new TrayPopupLabelButton(
this, rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_OTHER_MOBILE));
bottom_row->AddChildView(other_mobile_);
if (CommandLine::ForCurrentProcess()->HasSwitch(
ash::switches::kAshDebugShowPreferredNetworks)) {
// Debugging UI to view and remove favorites from the status area.
std::string toggle_debug_preferred_label =
(list_type_ == LIST_TYPE_DEBUG_PREFERRED) ? "Visible" : "Preferred";
toggle_debug_preferred_networks_ = new TrayPopupLabelButton(
this, UTF8ToUTF16(toggle_debug_preferred_label));
bottom_row->AddChildView(toggle_debug_preferred_networks_);
}
} else {
other_vpn_ = new TrayPopupLabelButton(
this,
ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
IDS_ASH_STATUS_TRAY_OTHER_VPN));
bottom_row->AddChildView(other_vpn_);
}
CreateSettingsEntry();
DCHECK(settings_ || proxy_settings_);
bottom_row->AddChildView(settings_ ? settings_ : proxy_settings_);
AddChildView(bottom_row);
}
// Update UI components.
void NetworkStateListDetailedView::UpdateHeaderButtons() {
NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
if (button_wifi_)
UpdateTechnologyButton(button_wifi_, flimflam::kTypeWifi);
if (button_mobile_) {
UpdateTechnologyButton(
button_mobile_, NetworkStateHandler::kMatchTypeMobile);
}
if (proxy_settings_)
proxy_settings_->SetEnabled(handler->DefaultNetwork() != NULL);
static_cast<views::View*>(footer())->Layout();
}
void NetworkStateListDetailedView::UpdateTechnologyButton(
TrayPopupHeaderButton* button,
const std::string& technology) {
NetworkStateHandler::TechnologyState state =
NetworkHandler::Get()->network_state_handler()->
GetTechnologyState(technology);
if (state == NetworkStateHandler::TECHNOLOGY_UNAVAILABLE) {
button->SetVisible(false);
return;
}
button->SetVisible(true);
if (state == NetworkStateHandler::TECHNOLOGY_AVAILABLE) {
button->SetEnabled(true);
button->SetToggled(true);
} else if (state == NetworkStateHandler::TECHNOLOGY_ENABLED) {
button->SetEnabled(true);
button->SetToggled(false);
} else if (state == NetworkStateHandler::TECHNOLOGY_ENABLING) {
button->SetEnabled(false);
button->SetToggled(false);
} else { // Initializing
button->SetEnabled(false);
button->SetToggled(true);
}
}
void NetworkStateListDetailedView::UpdateNetworks(
const NetworkStateHandler::NetworkStateList& networks) {
DCHECK(list_type_ != LIST_TYPE_DEBUG_PREFERRED);
network_list_.clear();
for (NetworkStateHandler::NetworkStateList::const_iterator iter =
networks.begin(); iter != networks.end(); ++iter) {
const NetworkState* network = *iter;
if ((list_type_ == LIST_TYPE_NETWORK &&
network->type() != flimflam::kTypeVPN) ||
(list_type_ == LIST_TYPE_VPN &&
network->type() == flimflam::kTypeVPN)) {
NetworkInfo* info = new NetworkInfo(network->path());
network_list_.push_back(info);
}
}
}
void NetworkStateListDetailedView::UpdatePreferred(
const NetworkStateHandler::FavoriteStateList& favorites) {
DCHECK(list_type_ == LIST_TYPE_DEBUG_PREFERRED);
network_list_.clear();
for (NetworkStateHandler::FavoriteStateList::const_iterator iter =
favorites.begin(); iter != favorites.end(); ++iter) {
const FavoriteState* favorite = *iter;
NetworkInfo* info = new NetworkInfo(favorite->path());
network_list_.push_back(info);
}
}
void NetworkStateListDetailedView::UpdateNetworkList() {
NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
// First, update state for all networks
bool animating = false;
for (size_t i = 0; i < network_list_.size(); ++i) {
NetworkInfo* info = network_list_[i];
const NetworkState* network =
handler->GetNetworkState(info->service_path);
if (network) {
info->image = network_icon::GetImageForNetwork(
network, network_icon::ICON_TYPE_LIST);
info->label = network_icon::GetLabelForNetwork(
network, network_icon::ICON_TYPE_LIST);
info->highlight =
network->IsConnectedState() || network->IsConnectingState();
info->disable =
network->activation_state() == flimflam::kActivationStateActivating;
if (!animating && network->IsConnectingState())
animating = true;
} else if (list_type_ == LIST_TYPE_DEBUG_PREFERRED) {
// Favorites that are visible will use the same display info as the
// visible network. Non visible favorites will show the disconnected
// icon and the name of the network.
const FavoriteState* favorite =
handler->GetFavoriteState(info->service_path);
if (favorite) {
info->image = network_icon::GetImageForDisconnectedNetwork(
network_icon::ICON_TYPE_LIST, favorite->type());
info->label = UTF8ToUTF16(favorite->name());
}
}
}
if (animating)
network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this);
else
network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
// Get the updated list entries
network_map_.clear();
std::set<std::string> new_service_paths;
bool needs_relayout = UpdateNetworkListEntries(&new_service_paths);
// Remove old children
std::set<std::string> remove_service_paths;
for (ServicePathMap::const_iterator it = service_path_map_.begin();
it != service_path_map_.end(); ++it) {
if (new_service_paths.find(it->first) == new_service_paths.end()) {
remove_service_paths.insert(it->first);
network_map_.erase(it->second);
scroll_content()->RemoveChildView(it->second);
needs_relayout = true;
}
}
for (std::set<std::string>::const_iterator remove_it =
remove_service_paths.begin();
remove_it != remove_service_paths.end(); ++remove_it) {
service_path_map_.erase(*remove_it);
}
if (needs_relayout) {
views::View* selected_view = NULL;
for (ServicePathMap::const_iterator iter = service_path_map_.begin();
iter != service_path_map_.end(); ++iter) {
if (iter->second->hover()) {
selected_view = iter->second;
break;
}
}
scroll_content()->SizeToPreferredSize();
static_cast<views::View*>(scroller())->Layout();
if (selected_view)
scroll_content()->ScrollRectToVisible(selected_view->bounds());
}
}
bool NetworkStateListDetailedView::CreateOrUpdateInfoLabel(
int index, const base::string16& text, views::Label** label) {
if (*label == NULL) {
*label = CreateMenuInfoLabel(text);
scroll_content()->AddChildViewAt(*label, index);
return true;
} else {
(*label)->SetText(text);
return OrderChild(*label, index);
}
}
bool NetworkStateListDetailedView::UpdateNetworkChild(int index,
const NetworkInfo* info) {
bool needs_relayout = false;
HoverHighlightView* container = NULL;
ServicePathMap::const_iterator found =
service_path_map_.find(info->service_path);
gfx::Font::FontStyle font =
info->highlight ? gfx::Font::BOLD : gfx::Font::NORMAL;
if (found == service_path_map_.end()) {
container = new HoverHighlightView(this);
container->AddIconAndLabel(info->image, info->label, font);
scroll_content()->AddChildViewAt(container, index);
container->set_border(views::Border::CreateEmptyBorder(
0, kTrayPopupPaddingHorizontal, 0, 0));
needs_relayout = true;
} else {
container = found->second;
container->RemoveAllChildViews(true);
container->AddIconAndLabel(info->image, info->label, font);
container->Layout();
container->SchedulePaint();
needs_relayout = OrderChild(container, index);
}
if (info->disable)
container->SetEnabled(false);
network_map_[container] = info->service_path;
service_path_map_[info->service_path] = container;
return needs_relayout;
}
bool NetworkStateListDetailedView::OrderChild(views::View* view, int index) {
if (scroll_content()->child_at(index) != view) {
scroll_content()->ReorderChildView(view, index);
return true;
}
return false;
}
bool NetworkStateListDetailedView::UpdateNetworkListEntries(
std::set<std::string>* new_service_paths) {
bool needs_relayout = false;
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
// Insert child views
int index = 0;
// Highlighted networks
for (size_t i = 0; i < network_list_.size(); ++i) {
const NetworkInfo* info = network_list_[i];
if (info->highlight) {
if (UpdateNetworkChild(index++, info))
needs_relayout = true;
new_service_paths->insert(info->service_path);
}
}
if (list_type_ == LIST_TYPE_NETWORK) {
// Cellular initializing
int status_message_id = network_icon::GetCellularUninitializedMsg();
if (!status_message_id &&
handler->IsTechnologyEnabled(NetworkStateHandler::kMatchTypeMobile) &&
!handler->FirstNetworkByType(NetworkStateHandler::kMatchTypeMobile)) {
status_message_id = IDS_ASH_STATUS_TRAY_NO_CELLULAR_NETWORKS;
}
if (status_message_id) {
base::string16 text = rb.GetLocalizedString(status_message_id);
if (CreateOrUpdateInfoLabel(index++, text, &no_cellular_networks_view_))
needs_relayout = true;
} else if (no_cellular_networks_view_) {
scroll_content()->RemoveChildView(no_cellular_networks_view_);
no_cellular_networks_view_ = NULL;
needs_relayout = true;
}
// "Wifi Enabled / Disabled"
if (network_list_.empty()) {
int message_id = handler->IsTechnologyEnabled(flimflam::kTypeWifi) ?
IDS_ASH_STATUS_TRAY_NETWORK_WIFI_ENABLED :
IDS_ASH_STATUS_TRAY_NETWORK_WIFI_DISABLED;
base::string16 text = rb.GetLocalizedString(message_id);
if (CreateOrUpdateInfoLabel(index++, text, &no_wifi_networks_view_))
needs_relayout = true;
} else if (no_wifi_networks_view_) {
scroll_content()->RemoveChildView(no_wifi_networks_view_);
no_wifi_networks_view_ = NULL;
needs_relayout = true;
}
// "Wifi Scanning"
if (handler->GetScanningByType(flimflam::kTypeWifi)) {
base::string16 text =
rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_WIFI_SCANNING_MESSAGE);
if (CreateOrUpdateInfoLabel(index++, text, &scanning_view_))
needs_relayout = true;
} else if (scanning_view_ != NULL) {
scroll_content()->RemoveChildView(scanning_view_);
scanning_view_ = NULL;
needs_relayout = true;
}
}
// Un-highlighted networks
for (size_t i = 0; i < network_list_.size(); ++i) {
const NetworkInfo* info = network_list_[i];
if (!info->highlight) {
if (UpdateNetworkChild(index++, info))
needs_relayout = true;
new_service_paths->insert(info->service_path);
}
}
// No networks or other messages (fallback)
if (index == 0) {
base::string16 text;
if (list_type_ == LIST_TYPE_VPN)
text = rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_NETWORK_NO_VPN);
else
text = rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_NO_NETWORKS);
if (CreateOrUpdateInfoLabel(index++, text, &scanning_view_))
needs_relayout = true;
}
return needs_relayout;
}
void NetworkStateListDetailedView::UpdateNetworkExtra() {
if (login_ == user::LOGGED_IN_LOCKED)
return;
View* layout_parent = NULL; // All these buttons have the same parent.
NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
if (other_wifi_) {
DCHECK(turn_on_wifi_);
NetworkStateHandler::TechnologyState state =
handler->GetTechnologyState(flimflam::kTypeWifi);
if (state == NetworkStateHandler::TECHNOLOGY_UNAVAILABLE) {
turn_on_wifi_->SetVisible(false);
other_wifi_->SetVisible(false);
} else {
if (state == NetworkStateHandler::TECHNOLOGY_AVAILABLE) {
turn_on_wifi_->SetVisible(true);
turn_on_wifi_->SetEnabled(true);
other_wifi_->SetVisible(false);
} else if (state == NetworkStateHandler::TECHNOLOGY_ENABLED) {
turn_on_wifi_->SetVisible(false);
other_wifi_->SetVisible(true);
} else {
// Initializing or Enabling
turn_on_wifi_->SetVisible(true);
turn_on_wifi_->SetEnabled(false);
other_wifi_->SetVisible(false);
}
}
layout_parent = other_wifi_->parent();
}
if (other_mobile_) {
bool show_other_mobile = false;
NetworkStateHandler::TechnologyState state =
handler->GetTechnologyState(NetworkStateHandler::kMatchTypeMobile);
if (state != NetworkStateHandler::TECHNOLOGY_UNAVAILABLE) {
const chromeos::DeviceState* device =
handler->GetDeviceStateByType(NetworkStateHandler::kMatchTypeMobile);
show_other_mobile = (device && device->support_network_scan());
}
if (show_other_mobile) {
other_mobile_->SetVisible(true);
other_mobile_->SetEnabled(
state == NetworkStateHandler::TECHNOLOGY_ENABLED);
} else {
other_mobile_->SetVisible(false);
}
if (!layout_parent)
layout_parent = other_wifi_->parent();
}
if (layout_parent)
layout_parent->Layout();
}
void NetworkStateListDetailedView::CreateSettingsEntry() {
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
if (login_ != user::LOGGED_IN_NONE) {
// Settings, only if logged in.
settings_ = new TrayPopupLabelButton(
this, rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_NETWORK_SETTINGS));
} else {
proxy_settings_ = new TrayPopupLabelButton(
this,
rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_NETWORK_PROXY_SETTINGS));
}
}
void NetworkStateListDetailedView::ToggleInfoBubble() {
if (ResetInfoBubble())
return;
info_bubble_ = new NonActivatableSettingsBubble(
info_icon_, CreateNetworkInfoView());
views::BubbleDelegateView::CreateBubble(info_bubble_)->Show();
}
bool NetworkStateListDetailedView::ResetInfoBubble() {
if (!info_bubble_)
return false;
info_bubble_->GetWidget()->Close();
info_bubble_ = NULL;
return true;
}
views::View* NetworkStateListDetailedView::CreateNetworkInfoView() {
ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
std::string ip_address("0.0.0.0");
const NetworkState* network = handler->DefaultNetwork();
if (network)
ip_address = network->ip_address();
views::View* container = new views::View;
container->SetLayoutManager(
new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
container->set_border(views::Border::CreateEmptyBorder(0, 5, 0, 5));
std::string ethernet_address, wifi_address, vpn_address;
if (list_type_ != LIST_TYPE_VPN) {
ethernet_address =
handler->FormattedHardwareAddressForType(flimflam::kTypeEthernet);
wifi_address =
handler->FormattedHardwareAddressForType(flimflam::kTypeWifi);
} else {
vpn_address =
handler->FormattedHardwareAddressForType(flimflam::kTypeVPN);
}
if (!ip_address.empty()) {
container->AddChildView(CreateInfoBubbleLine(bundle.GetLocalizedString(
IDS_ASH_STATUS_TRAY_IP), ip_address));
}
if (!ethernet_address.empty()) {
container->AddChildView(CreateInfoBubbleLine(bundle.GetLocalizedString(
IDS_ASH_STATUS_TRAY_ETHERNET), ethernet_address));
}
if (!wifi_address.empty()) {
container->AddChildView(CreateInfoBubbleLine(bundle.GetLocalizedString(
IDS_ASH_STATUS_TRAY_WIFI), wifi_address));
}
if (!vpn_address.empty()) {
container->AddChildView(CreateInfoBubbleLine(bundle.GetLocalizedString(
IDS_ASH_STATUS_TRAY_VPN), vpn_address));
}
// Avoid an empty bubble in the unlikely event that there is no network
// information at all.
if (!container->has_children()) {
container->AddChildView(CreateInfoBubbleLabel(bundle.GetLocalizedString(
IDS_ASH_STATUS_TRAY_NO_NETWORKS)));
}
return container;
}
void NetworkStateListDetailedView::CallRequestScan() {
VLOG(1) << "Requesting Network Scan.";
NetworkHandler::Get()->network_state_handler()->RequestScan();
// Periodically request a scan while this UI is open.
base::MessageLoopForUI::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&NetworkStateListDetailedView::CallRequestScan, AsWeakPtr()),
base::TimeDelta::FromSeconds(kRequestScanDelaySeconds));
}
void NetworkStateListDetailedView::ToggleMobile() {
NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
bool enabled =
handler->IsTechnologyEnabled(NetworkStateHandler::kMatchTypeMobile);
if (enabled) {
handler->SetTechnologyEnabled(
NetworkStateHandler::kMatchTypeMobile, false,
chromeos::network_handler::ErrorCallback());
} else {
const DeviceState* mobile =
handler->GetDeviceStateByType(NetworkStateHandler::kMatchTypeMobile);
if (!mobile) {
LOG(ERROR) << "Mobile device not found.";
return;
}
if (!mobile->sim_lock_type().empty() || mobile->IsSimAbsent()) {
ash::Shell::GetInstance()->system_tray_delegate()->ShowMobileSimDialog();
} else {
handler->SetTechnologyEnabled(
NetworkStateHandler::kMatchTypeMobile, true,
chromeos::network_handler::ErrorCallback());
}
}
}
} // namespace tray
} // namespace internal
} // namespace ash