blob: fb0d801f5d40c06c51b49b3a6875ff2ef4273ed4 [file] [log] [blame]
// Copyright 2019 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/network/active_network_icon.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/network/network_icon.h"
#include "ash/system/tray/tray_constants.h"
#include "chromeos/network/network_handler.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_state_handler.h"
#include "chromeos/network/network_type_pattern.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/paint_vector_icon.h"
using chromeos::NetworkStateHandler;
using chromeos::NetworkTypePattern;
namespace ash {
using network_icon::NetworkIconState;
namespace {
bool IsTrayIcon(network_icon::IconType icon_type) {
return icon_type == network_icon::ICON_TYPE_TRAY_REGULAR ||
icon_type == network_icon::ICON_TYPE_TRAY_OOBE;
}
SkColor GetDefaultColorForIconType(network_icon::IconType icon_type) {
if (icon_type == network_icon::ICON_TYPE_TRAY_REGULAR)
return kTrayIconColor;
if (icon_type == network_icon::ICON_TYPE_TRAY_OOBE)
return kOobeTrayIconColor;
return kUnifiedMenuIconColor;
}
base::Optional<NetworkIconState> GetConnectingOrConnected(
const chromeos::NetworkState* connecting_network,
const chromeos::NetworkState* connected_network) {
if (connecting_network &&
(!connected_network || connecting_network->connect_requested())) {
// If connecting to a network, and there is either no connected network or
// the connection was user requested, use the connecting network.
return base::make_optional<NetworkIconState>(connecting_network);
}
if (connected_network)
return base::make_optional<NetworkIconState>(connected_network);
return base::nullopt;
}
} // namespace
ActiveNetworkIcon::ActiveNetworkIcon() {
// NetworkHandler may not be initialized in tests.
if (chromeos::NetworkHandler::IsInitialized()) {
InitializeNetworkStateHandler(
chromeos::NetworkHandler::Get()->network_state_handler());
}
}
ActiveNetworkIcon::~ActiveNetworkIcon() {
ShutdownNetworkStateHandler();
}
base::string16 ActiveNetworkIcon::GetDefaultLabel(
network_icon::IconType icon_type) {
if (!default_network_) {
if (cellular_uninitialized_msg_ != 0)
return l10n_util::GetStringUTF16(cellular_uninitialized_msg_);
return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_NOT_CONNECTED);
}
return network_icon::GetLabelForNetwork(*default_network_, icon_type);
}
gfx::ImageSkia ActiveNetworkIcon::GetSingleImage(
network_icon::IconType icon_type,
bool* animating) {
// If no network, check for cellular initializing.
if (!default_network_ && cellular_uninitialized_msg_ != 0) {
if (animating)
*animating = true;
return network_icon::GetConnectingImageForNetworkType(
network_icon::NetworkType::kCellular, icon_type);
}
return GetDefaultImageImpl(default_network_, icon_type, animating);
}
gfx::ImageSkia ActiveNetworkIcon::GetDualImagePrimary(
network_icon::IconType icon_type,
bool* animating) {
if (default_network_ &&
default_network_->type == network_icon::NetworkType::kCellular) {
if (network_icon::IsConnected(*default_network_)) {
// TODO: Show proper technology badges.
if (animating)
*animating = false;
return gfx::CreateVectorIcon(kNetworkBadgeTechnologyLteIcon,
GetDefaultColorForIconType(icon_type));
}
// If Cellular is connecting, use the active non cellular network.
return GetDefaultImageImpl(active_non_cellular_, icon_type, animating);
}
return GetDefaultImageImpl(default_network_, icon_type, animating);
}
gfx::ImageSkia ActiveNetworkIcon::GetDualImageCellular(
network_icon::IconType icon_type,
bool* animating) {
if (!network_state_handler_->IsTechnologyAvailable(
NetworkTypePattern::Cellular())) {
if (animating)
*animating = false;
return gfx::ImageSkia();
}
if (cellular_uninitialized_msg_ != 0) {
if (animating)
*animating = true;
return network_icon::GetConnectingImageForNetworkType(
network_icon::NetworkType::kCellular, icon_type);
}
if (!active_cellular_) {
if (animating)
*animating = false;
return network_icon::GetDisconnectedImageForNetworkType(
network_icon::NetworkType::kCellular);
}
return network_icon::GetImageForNonVirtualNetwork(
*active_cellular_, icon_type, false /* show_vpn_badge */, animating);
}
void ActiveNetworkIcon::InitForTesting(
chromeos::NetworkStateHandler* network_state_handler) {
ShutdownNetworkStateHandler();
InitializeNetworkStateHandler(network_state_handler);
}
void ActiveNetworkIcon::InitializeNetworkStateHandler(
chromeos::NetworkStateHandler* handler) {
DCHECK(!network_state_handler_);
DCHECK(handler);
network_state_handler_ = handler;
network_state_handler_->AddObserver(this, FROM_HERE);
UpdateActiveNetworks();
}
void ActiveNetworkIcon::ShutdownNetworkStateHandler() {
if (!network_state_handler_)
return;
network_state_handler_->RemoveObserver(this, FROM_HERE);
}
gfx::ImageSkia ActiveNetworkIcon::GetDefaultImageImpl(
const base::Optional<NetworkIconState>& default_network,
network_icon::IconType icon_type,
bool* animating) {
if (!default_network) {
VLOG(1) << __func__ << ": No network";
return GetDefaultImageForNoNetwork(icon_type, animating);
}
// Don't show connected Ethernet in the tray unless a VPN is present.
if (default_network->type == network_icon::NetworkType::kEthernet &&
IsTrayIcon(icon_type) && !active_vpn_) {
if (animating)
*animating = false;
VLOG(1) << __func__ << ": Ethernet: No icon";
return gfx::ImageSkia();
}
// Connected network with a connecting VPN.
if (network_icon::IsConnected(*default_network) && active_vpn_ &&
network_icon::IsConnecting(*active_vpn_)) {
if (animating)
*animating = true;
VLOG(1) << __func__ << ": Connected with connecting VPN";
return network_icon::GetConnectedNetworkWithConnectingVpnImage(
*default_network, icon_type);
}
// Default behavior: connected or connecting network, possibly with VPN badge.
bool show_vpn_badge = !!active_vpn_;
VLOG(1) << __func__ << ": Network: " << default_network->name
<< " Strength: " << default_network->signal_strength;
return network_icon::GetImageForNonVirtualNetwork(*default_network, icon_type,
show_vpn_badge, animating);
}
gfx::ImageSkia ActiveNetworkIcon::GetDefaultImageForNoNetwork(
network_icon::IconType icon_type,
bool* animating) {
if (animating)
*animating = false;
if (network_state_handler_ &&
network_state_handler_->IsTechnologyEnabled(NetworkTypePattern::WiFi())) {
// WiFi is enabled but disconnected, show an empty wedge.
return network_icon::GetBasicImage(
icon_type, network_icon::NetworkType::kWiFi, false /* connected */);
}
// WiFi is disabled, show a full icon with a strikethrough.
return network_icon::GetImageForWiFiEnabledState(false /* not enabled*/,
icon_type);
}
void ActiveNetworkIcon::UpdateActiveNetworks() {
std::vector<const chromeos::NetworkState*> active_networks;
network_state_handler_->GetActiveNetworkListByType(
NetworkTypePattern::Default(), &active_networks);
ActiveNetworksChanged(active_networks);
}
void ActiveNetworkIcon::SetCellularUninitializedMsg() {
if (network_state_handler_->GetTechnologyState(
NetworkTypePattern::Cellular()) ==
NetworkStateHandler::TECHNOLOGY_UNINITIALIZED) {
cellular_uninitialized_msg_ = IDS_ASH_STATUS_TRAY_INITIALIZING_CELLULAR;
uninitialized_state_time_ = base::Time::Now();
return;
}
if (network_state_handler_->GetScanningByType(
NetworkTypePattern::Cellular())) {
cellular_uninitialized_msg_ = IDS_ASH_STATUS_TRAY_MOBILE_SCANNING;
uninitialized_state_time_ = base::Time::Now();
return;
}
// There can be a delay between leaving the Initializing state and when
// a Cellular device shows up, so keep showing the initializing
// animation for a bit to avoid flashing the disconnect icon.
const int kInitializingDelaySeconds = 1;
base::TimeDelta dtime = base::Time::Now() - uninitialized_state_time_;
if (dtime.InSeconds() >= kInitializingDelaySeconds)
cellular_uninitialized_msg_ = 0;
}
void ActiveNetworkIcon::DeviceListChanged() {
UpdateActiveNetworks();
}
void ActiveNetworkIcon::DevicePropertiesUpdated(
const chromeos::DeviceState* device) {
SetCellularUninitializedMsg();
}
void ActiveNetworkIcon::ActiveNetworksChanged(
const std::vector<const chromeos::NetworkState*>& active_networks) {
active_cellular_.reset();
active_vpn_.reset();
const chromeos::NetworkState* connected_network = nullptr;
const chromeos::NetworkState* connected_non_cellular = nullptr;
const chromeos::NetworkState* connecting_network = nullptr;
const chromeos::NetworkState* connecting_non_cellular = nullptr;
for (const chromeos::NetworkState* network : active_networks) {
if (network->Matches(NetworkTypePattern::VPN())) {
if (!active_vpn_)
active_vpn_ = base::make_optional<NetworkIconState>(network);
continue;
}
if (network->Matches(NetworkTypePattern::Cellular())) {
if (!active_cellular_)
active_cellular_ = base::make_optional<NetworkIconState>(network);
}
if (network->IsConnectedState()) {
if (!connected_network)
connected_network = network;
if (!connected_non_cellular &&
!network->Matches(NetworkTypePattern::Cellular())) {
connected_non_cellular = network;
}
continue;
}
// Active non connected networks are connecting.
if (network->Matches(NetworkTypePattern::Wireless())) {
if (!connecting_network)
connecting_network = network;
if (!connecting_non_cellular &&
!network->Matches(NetworkTypePattern::Cellular())) {
connecting_non_cellular = network;
}
}
}
VLOG_IF(2, connected_network)
<< __func__ << ": Connected network: " << connected_network->name()
<< " State: " << connected_network->connection_state()
<< " Strength: " << connected_network->signal_strength();
VLOG_IF(2, connecting_network)
<< __func__ << ": Connecting network: " << connecting_network->name()
<< " State: " << connecting_network->connection_state()
<< " Strength: " << connecting_network->signal_strength();
default_network_ =
GetConnectingOrConnected(connecting_network, connected_network);
VLOG_IF(2, default_network_)
<< __func__ << ": Default network: " << default_network_->name
<< " Strength: " << default_network_->signal_strength;
active_non_cellular_ =
GetConnectingOrConnected(connecting_non_cellular, connected_non_cellular);
SetCellularUninitializedMsg();
}
void ActiveNetworkIcon::OnShuttingDown() {
network_state_handler_ = nullptr;
}
} // namespace ash