123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536 |
- // Copyright 2022 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/network_list_network_item_view.h"
- #include <string>
- #include "ash/constants/ash_features.h"
- #include "ash/resources/vector_icons/vector_icons.h"
- #include "ash/session/session_controller_impl.h"
- #include "ash/shell.h"
- #include "ash/strings/grit/ash_strings.h"
- #include "ash/style/ash_color_provider.h"
- #include "ash/system/model/system_tray_model.h"
- #include "ash/system/network/network_icon.h"
- #include "ash/system/network/network_icon_animation.h"
- #include "ash/system/network/tray_network_state_model.h"
- #include "ash/system/power/power_status.h"
- #include "ash/system/tray/hover_highlight_view.h"
- #include "ash/system/tray/tray_info_label.h"
- #include "ash/system/tray/tray_popup_utils.h"
- #include "ash/system/tray/tray_utils.h"
- #include "base/i18n/number_formatting.h"
- #include "chromeos/services/network_config/public/cpp/cros_network_config_util.h"
- #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
- #include "network_list_network_item_view.h"
- #include "ui/base/l10n/l10n_util.h"
- #include "ui/base/metadata/metadata_impl_macros.h"
- #include "ui/gfx/image/image_skia.h"
- #include "ui/gfx/image/image_skia_operations.h"
- #include "ui/gfx/paint_vector_icon.h"
- #include "ui/views/accessibility/view_accessibility.h"
- #include "ui/views/controls/image_view.h"
- namespace ash {
- namespace {
- using chromeos::network_config::IsInhibited;
- using chromeos::network_config::NetworkTypeMatchesType;
- using chromeos::network_config::StateIsConnected;
- using chromeos::network_config::mojom::ActivationStateType;
- using chromeos::network_config::mojom::CellularStateProperties;
- using chromeos::network_config::mojom::ConnectionStateType;
- using chromeos::network_config::mojom::NetworkStateProperties;
- using chromeos::network_config::mojom::NetworkStatePropertiesPtr;
- using chromeos::network_config::mojom::NetworkType;
- using chromeos::network_config::mojom::OncSource;
- using chromeos::network_config::mojom::ProxyMode;
- using chromeos::network_config::mojom::SecurityType;
- const int kMobileNetworkBatteryIconSize = 20;
- const int kPowerStatusPaddingRight = 10;
- const double kAlphaValueForInhibitedIconOpacity = 0.3;
- bool IsSecondaryUser() {
- SessionControllerImpl* session_controller =
- Shell::Get()->session_controller();
- return session_controller->IsActiveUserSessionStarted() &&
- !session_controller->IsUserPrimary();
- }
- bool NetworkTypeIsConfigurable(NetworkType type) {
- switch (type) {
- case NetworkType::kVPN:
- case NetworkType::kWiFi:
- return true;
- case NetworkType::kAll:
- case NetworkType::kCellular:
- case NetworkType::kEthernet:
- case NetworkType::kMobile:
- case NetworkType::kTether:
- case NetworkType::kWireless:
- return false;
- }
- NOTREACHED();
- return false;
- }
- ActivationStateType GetNetworkActivationState(
- const NetworkStatePropertiesPtr& network_properties) {
- if (NetworkTypeMatchesType(network_properties->type,
- NetworkType::kCellular)) {
- return network_properties->type_state->get_cellular()->activation_state;
- }
- return ActivationStateType::kUnknown;
- }
- bool IsNetworkInhibited(const NetworkStatePropertiesPtr& network_properties) {
- if (!NetworkTypeMatchesType(network_properties->type,
- NetworkType::kCellular)) {
- return false;
- }
- const chromeos::network_config::mojom::DeviceStateProperties*
- cellular_device =
- Shell::Get()->system_tray_model()->network_state_model()->GetDevice(
- NetworkType::kCellular);
- return cellular_device && IsInhibited(cellular_device);
- }
- bool IsCellularNetworkSimLocked(
- const NetworkStatePropertiesPtr& network_properties) {
- DCHECK(
- NetworkTypeMatchesType(network_properties->type, NetworkType::kCellular));
- return network_properties->type_state->get_cellular()->sim_locked;
- }
- bool IsNetworkConnectable(const NetworkStatePropertiesPtr& network_properties) {
- // The network must not already be connected to be able to be connected to.
- if (network_properties->connection_state !=
- ConnectionStateType::kNotConnected) {
- return false;
- }
- if (NetworkTypeMatchesType(network_properties->type,
- NetworkType::kCellular)) {
- // Cellular networks must be activated, uninhibited, and have an unlocked
- // SIM to be able to be connected to.
- const CellularStateProperties* cellular =
- network_properties->type_state->get_cellular().get();
- if (cellular->activation_state == ActivationStateType::kNotActivated &&
- !cellular->eid.empty()) {
- return false;
- }
- if (IsNetworkInhibited(network_properties) || cellular->sim_locked) {
- return false;
- }
- if (cellular->activation_state == ActivationStateType::kActivated) {
- return true;
- }
- }
- // The network can be connected to if the network is connectable.
- if (network_properties->connectable) {
- return true;
- }
- // Network can be connected to if the active user is the primary user and the
- // network is configurable.
- if (!IsSecondaryUser() &&
- NetworkTypeIsConfigurable(network_properties->type)) {
- return true;
- }
- return false;
- }
- bool IsNetworkDisabled(const NetworkStatePropertiesPtr& network_properties) {
- if (!NetworkTypeMatchesType(network_properties->type,
- NetworkType::kCellular)) {
- return false;
- }
- const CellularStateProperties* cellular =
- network_properties->type_state->get_cellular().get();
- if (!Shell::Get()->session_controller()->IsActiveUserSessionStarted() &&
- cellular->sim_locked) {
- return true;
- }
- if (cellular->activation_state == ActivationStateType::kActivating) {
- return true;
- }
- if (IsNetworkInhibited(network_properties)) {
- return true;
- }
- return network_properties->prohibited_by_policy;
- }
- bool IsWifiNetworkSecured(const NetworkStatePropertiesPtr& network_properties) {
- DCHECK(NetworkTypeMatchesType(network_properties->type, NetworkType::kWiFi));
- return network_properties->type_state->get_wifi()->security !=
- SecurityType::kNone;
- }
- bool IsNetworkManagedByPolicy(
- const NetworkStatePropertiesPtr& network_properties) {
- return network_properties->source == OncSource::kDevicePolicy ||
- network_properties->source == OncSource::kUserPolicy;
- }
- bool ShouldShowActivateCellularNetwork(
- const NetworkStatePropertiesPtr& network_properties) {
- return GetNetworkActivationState(network_properties) ==
- ActivationStateType::kNotActivated &&
- network_properties->type_state->get_cellular()->eid.empty();
- }
- bool ShouldShowContactCarrier(
- const NetworkStatePropertiesPtr& network_properties) {
- return GetNetworkActivationState(network_properties) ==
- ActivationStateType::kNotActivated &&
- !network_properties->type_state->get_cellular()->eid.empty();
- }
- gfx::ImageSkia GetNetworkImageForNetwork(
- const NetworkStatePropertiesPtr& network_properties) {
- gfx::ImageSkia network_image;
- const gfx::ImageSkia image = network_icon::GetImageForNonVirtualNetwork(
- network_properties.get(), network_icon::ICON_TYPE_LIST,
- /*badge_vpn=*/false);
- if (NetworkTypeMatchesType(network_properties->type, NetworkType::kMobile) &&
- network_properties->connection_state ==
- ConnectionStateType::kNotConnected) {
- // Mobile icons which are not connecting or connected should display a small
- // "X" icon superimposed so that it is clear that they are disconnected.
- const SkColor icon_color = AshColorProvider::Get()->GetContentLayerColor(
- AshColorProvider::ContentLayerType::kIconColorPrimary);
- network_image = gfx::ImageSkiaOperations::CreateSuperimposedImage(
- image, gfx::CreateVectorIcon(kNetworkMobileNotConnectedXIcon,
- image.height(), icon_color));
- } else {
- network_image = image;
- }
- // When the network is disabled, its appearance should be grayed out to
- // indicate users that these networks are unavailable. We must change the
- // image before we add it to the view, and then alter the label and sub-label
- // if they exist after it is added to the view.
- if (IsNetworkDisabled(network_properties)) {
- network_image = gfx::ImageSkiaOperations::CreateTransparentImage(
- network_image, kAlphaValueForInhibitedIconOpacity);
- }
- return network_image;
- }
- int GetCellularNetworkSubText(
- const NetworkStatePropertiesPtr& network_properties) {
- if (ShouldShowActivateCellularNetwork(network_properties))
- return IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CLICK_TO_ACTIVATE;
- if (ShouldShowContactCarrier(network_properties))
- return IDS_ASH_STATUS_TRAY_NETWORK_UNAVAILABLE_SIM_NETWORK;
- if (!IsCellularNetworkSimLocked(network_properties))
- return 0;
- if (Shell::Get()->session_controller()->IsActiveUserSessionStarted()) {
- return IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CLICK_TO_UNLOCK;
- }
- return IDS_ASH_STATUS_TRAY_NETWORK_STATUS_SIGN_IN_TO_UNLOCK;
- }
- } // namespace
- NetworkListNetworkItemView::NetworkListNetworkItemView(
- ViewClickListener* listener)
- : NetworkListItemView(listener) {}
- NetworkListNetworkItemView::~NetworkListNetworkItemView() = default;
- void NetworkListNetworkItemView::UpdateViewForNetwork(
- const NetworkStatePropertiesPtr& network_properties) {
- network_properties_ = mojo::Clone(network_properties);
- Reset();
- const std::u16string label = GetLabel();
- AddIconAndLabel(GetNetworkImageForNetwork(network_properties_), label);
- if (network_properties_.get()->type == NetworkType::kCellular) {
- SetupCellularSubtext();
- } else {
- SetupNetworkSubtext();
- }
- if (IsNetworkDisabled(network_properties)) {
- UpdateDisabledTextColor();
- }
- if (network_properties_->prohibited_by_policy) {
- SetTooltipText(
- l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_PROHIBITED));
- }
- // Add an additional icon to the right of the label for networks
- // that require it (e.g. Tether, controlled by extension).
- if (network_properties_->type == NetworkType::kTether) {
- AddPowerStatusView();
- } else if (IsNetworkManagedByPolicy(network_properties)) {
- AddPolicyView();
- }
- SetAccessibleName(GenerateAccessibilityLabel(label));
- GetViewAccessibility().OverrideDescription(
- GenerateAccessibilityDescription());
- }
- void NetworkListNetworkItemView::SetupCellularSubtext() {
- int cellular_subtext_message_id =
- GetCellularNetworkSubText(network_properties_);
- if (!cellular_subtext_message_id) {
- SetupNetworkSubtext();
- return;
- }
- if (text_label()) {
- const SkColor primary_text_color =
- AshColorProvider::Get()->GetContentLayerColor(
- AshColorProvider::ContentLayerType::kTextColorPrimary);
- text_label()->SetEnabledColor(primary_text_color);
- }
- SetSubText(l10n_util::GetStringUTF16(cellular_subtext_message_id));
- const SkColor sub_text_color = AshColorProvider::Get()->GetContentLayerColor(
- AshColorProvider::ContentLayerType::kTextColorWarning);
- sub_text_label()->SetEnabledColor(sub_text_color);
- }
- void NetworkListNetworkItemView::SetupNetworkSubtext() {
- if (StateIsConnected(network_properties()->connection_state)) {
- SetupConnectedScrollListItem(this);
- } else if (network_properties_.get()->connection_state ==
- ConnectionStateType::kConnecting) {
- SetupConnectingScrollListItem(this);
- }
- }
- void NetworkListNetworkItemView::UpdateDisabledTextColor() {
- if (text_label()) {
- SkColor primary_text_color = text_label()->GetEnabledColor();
- text_label()->SetEnabledColor(
- AshColorProvider::GetDisabledColor(primary_text_color));
- }
- if (sub_text_label()) {
- SkColor sub_text_color = sub_text_label()->GetEnabledColor();
- sub_text_label()->SetEnabledColor(
- AshColorProvider::GetDisabledColor(sub_text_color));
- }
- }
- void NetworkListNetworkItemView::AddPowerStatusView() {
- auto image_icon = std::make_unique<views::ImageView>();
- const SkColor icon_color = AshColorProvider::Get()->GetContentLayerColor(
- AshColorProvider::ContentLayerType::kIconColorPrimary);
- image_icon->SetPreferredSize(gfx::Size(kMenuIconSize, kMenuIconSize));
- image_icon->SetFlipCanvasOnPaintForRTLUI(true);
- PowerStatus::BatteryImageInfo icon_info;
- int battery_percentage =
- network_properties()->type_state->get_tether()->battery_percentage;
- icon_info.charge_percent = battery_percentage;
- image_icon->SetImage(PowerStatus::GetBatteryImage(
- icon_info, kMobileNetworkBatteryIconSize,
- AshColorProvider::GetSecondToneColor(icon_color), icon_color));
- // Show the numeric battery percentage on hover.
- image_icon->SetTooltipText(base::FormatPercent(battery_percentage));
- AddRightView(image_icon.release(), views::CreateEmptyBorder(gfx::Insets::TLBR(
- 0, 0, 0, kPowerStatusPaddingRight)));
- }
- void NetworkListNetworkItemView::AddPolicyView() {
- std::unique_ptr<views::ImageView> controlled_icon(
- TrayPopupUtils::CreateMainImageView());
- const SkColor icon_color = AshColorProvider::Get()->GetContentLayerColor(
- AshColorProvider::ContentLayerType::kIconColorPrimary);
- controlled_icon->SetImage(
- gfx::CreateVectorIcon(kSystemMenuBusinessIcon, icon_color));
- AddRightView(controlled_icon.release());
- }
- std::u16string NetworkListNetworkItemView::GenerateAccessibilityLabel(
- const std::u16string& label) {
- if (IsNetworkConnectable(network_properties())) {
- return l10n_util::GetStringFUTF16(
- IDS_ASH_STATUS_TRAY_NETWORK_A11Y_LABEL_CONNECT, label);
- }
- if (ShouldShowActivateCellularNetwork(network_properties())) {
- return l10n_util::GetStringFUTF16(
- IDS_ASH_STATUS_TRAY_NETWORK_A11Y_LABEL_ACTIVATE, label);
- }
- if (ShouldShowContactCarrier(network_properties())) {
- return l10n_util::GetStringFUTF16(
- IDS_ASH_STATUS_TRAY_NETWORK_A11Y_UNAVAILABLE_SIM_NETWORK, label);
- }
- return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_A11Y_LABEL_OPEN,
- label);
- }
- std::u16string NetworkListNetworkItemView::GenerateAccessibilityDescription() {
- std::u16string connection_status;
- if (StateIsConnected(network_properties()->connection_state)) {
- connection_status =
- l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED);
- } else if (network_properties()->connection_state ==
- ConnectionStateType::kConnecting) {
- connection_status = l10n_util::GetStringUTF16(
- IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTING);
- }
- int signal_strength = chromeos::network_config::GetWirelessSignalStrength(
- network_properties().get());
- switch (network_properties()->type) {
- case NetworkType::kEthernet:
- return GenerateAccessibilityDescriptionForEthernet(connection_status);
- case NetworkType::kWiFi:
- return GenerateAccessibilityDescriptionForWifi(connection_status,
- signal_strength);
- case NetworkType::kCellular:
- return GenerateAccessibilityDescriptionForCellular(connection_status,
- signal_strength);
- case NetworkType::kTether:
- return GenerateAccessibilityDescriptionForTether(connection_status,
- signal_strength);
- default:
- return u"";
- }
- }
- std::u16string
- NetworkListNetworkItemView::GenerateAccessibilityDescriptionForEthernet(
- const std::u16string& connection_status) {
- if (!connection_status.empty()) {
- if (IsNetworkManagedByPolicy(network_properties())) {
- return l10n_util::GetStringFUTF16(
- IDS_ASH_STATUS_TRAY_ETHERNET_A11Y_DESC_MANAGED_WITH_CONNECTION_STATUS,
- connection_status);
- }
- return connection_status;
- }
- if (IsNetworkManagedByPolicy(network_properties())) {
- return l10n_util::GetStringUTF16(
- IDS_ASH_STATUS_TRAY_ETHERNET_A11Y_DESC_MANAGED);
- }
- return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ETHERNET);
- }
- std::u16string
- NetworkListNetworkItemView::GenerateAccessibilityDescriptionForWifi(
- const std::u16string& connection_status,
- int signal_strength) {
- const std::u16string security_label = l10n_util::GetStringUTF16(
- IsWifiNetworkSecured(network_properties())
- ? IDS_ASH_STATUS_TRAY_NETWORK_STATUS_SECURED
- : IDS_ASH_STATUS_TRAY_NETWORK_STATUS_UNSECURED);
- if (!connection_status.empty()) {
- if (IsNetworkManagedByPolicy(network_properties())) {
- return l10n_util::GetStringFUTF16(
- IDS_ASH_STATUS_TRAY_WIFI_NETWORK_A11Y_DESC_MANAGED_WITH_CONNECTION_STATUS,
- security_label, connection_status,
- base::FormatPercent(signal_strength));
- }
- return l10n_util::GetStringFUTF16(
- IDS_ASH_STATUS_TRAY_WIFI_NETWORK_A11Y_DESC_WITH_CONNECTION_STATUS,
- security_label, connection_status,
- base::FormatPercent(signal_strength));
- }
- if (IsNetworkManagedByPolicy(network_properties())) {
- return l10n_util::GetStringFUTF16(
- IDS_ASH_STATUS_TRAY_WIFI_NETWORK_A11Y_DESC_MANAGED, security_label,
- base::FormatPercent(signal_strength));
- }
- return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_WIFI_NETWORK_A11Y_DESC,
- security_label,
- base::FormatPercent(signal_strength));
- }
- std::u16string
- NetworkListNetworkItemView::GenerateAccessibilityDescriptionForCellular(
- const std::u16string& connection_status,
- int signal_strength) {
- if (ShouldShowActivateCellularNetwork(network_properties())) {
- return l10n_util::GetStringUTF16(
- IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CLICK_TO_ACTIVATE);
- }
- if (ShouldShowContactCarrier(network_properties())) {
- return l10n_util::GetStringUTF16(
- IDS_ASH_STATUS_TRAY_NETWORK_UNAVAILABLE_SIM_NETWORK);
- }
- if (IsCellularNetworkSimLocked(network_properties())) {
- if (Shell::Get()->session_controller()->IsActiveUserSessionStarted()) {
- return l10n_util::GetStringUTF16(
- IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CLICK_TO_UNLOCK);
- }
- return l10n_util::GetStringUTF16(
- IDS_ASH_STATUS_TRAY_NETWORK_STATUS_SIGN_IN_TO_UNLOCK);
- }
- if (!connection_status.empty()) {
- if (IsNetworkManagedByPolicy(network_properties())) {
- return l10n_util::GetStringFUTF16(
- IDS_ASH_STATUS_TRAY_CELLULAR_NETWORK_A11Y_DESC_MANAGED_WITH_CONNECTION_STATUS,
- connection_status, base::FormatPercent(signal_strength));
- }
- return l10n_util::GetStringFUTF16(
- IDS_ASH_STATUS_TRAY_CELLULAR_NETWORK_A11Y_DESC_WITH_CONNECTION_STATUS,
- connection_status, base::FormatPercent(signal_strength));
- }
- if (IsNetworkManagedByPolicy(network_properties())) {
- return l10n_util::GetStringFUTF16(
- IDS_ASH_STATUS_TRAY_CELLULAR_NETWORK_A11Y_DESC_MANAGED,
- base::FormatPercent(signal_strength));
- }
- return l10n_util::GetStringFUTF16(
- IDS_ASH_STATUS_TRAY_CELLULAR_NETWORK_A11Y_DESC,
- base::FormatPercent(signal_strength));
- }
- std::u16string
- NetworkListNetworkItemView::GenerateAccessibilityDescriptionForTether(
- const std::u16string& connection_status,
- int signal_strength) {
- int battery_percentage =
- network_properties()->type_state->get_tether()->battery_percentage;
- if (!connection_status.empty()) {
- return l10n_util::GetStringFUTF16(
- IDS_ASH_STATUS_TRAY_TETHER_NETWORK_A11Y_DESC_WITH_CONNECTION_STATUS,
- connection_status, base::FormatPercent(signal_strength),
- base::FormatPercent(battery_percentage));
- }
- return l10n_util::GetStringFUTF16(
- IDS_ASH_STATUS_TRAY_TETHER_NETWORK_A11Y_DESC,
- base::FormatPercent(signal_strength),
- base::FormatPercent(battery_percentage));
- }
- BEGIN_METADATA(NetworkListNetworkItemView, NetworkListItemView)
- END_METADATA
- } // namespace ash
|