// Copyright 2022 The Chromium Authors
// 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_view_controller_impl.h"
#include <algorithm>
#include <cstddef>
#include <memory>
#include "ash/constants/ash_features.h"
#include "ash/public/cpp/ash_view_ids.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/style/switch.h"
#include "ash/system/model/system_tray_model.h"
#include "ash/system/network/network_detailed_network_view.h"
#include "ash/system/network/network_detailed_network_view_impl.h"
#include "ash/system/network/network_utils.h"
#include "ash/system/network/tray_network_state_model.h"
#include "ash/system/tray/detailed_view_delegate.h"
#include "ash/system/tray/hover_highlight_view.h"
#include "ash/system/tray/tray_info_label.h"
#include "ash/system/tray/tri_view.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/ash_test_helper.h"
#include "ash/test_shell_delegate.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/metrics/user_action_tester.h"
#include "base/test/scoped_feature_list.h"
#include "chromeos/ash/services/bluetooth_config/fake_adapter_state_controller.h"
#include "chromeos/ash/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom.h"
#include "chromeos/ash/services/bluetooth_config/scoped_bluetooth_config_test_helper.h"
#include "chromeos/ash/services/multidevice_setup/public/cpp/fake_multidevice_setup.h"
#include "chromeos/ash/services/multidevice_setup/public/mojom/multidevice_setup.mojom-shared.h"
#include "chromeos/ash/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
#include "chromeos/ash/services/network_config/public/cpp/cros_network_config_test_helper.h"
#include "chromeos/services/network_config/public/cpp/cros_network_config_util.h"
#include "chromeos/services/network_config/public/cpp/fake_cros_network_config.h"
#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
#include "chromeos/services/network_config/public/mojom/network_types.mojom-shared.h"
#include "components/session_manager/session_manager_types.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/skia_util.h"
#include "ui/views/controls/button/toggle_button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/view.h"
namespace ash {
namespace {
using bluetooth_config::ScopedBluetoothConfigTestHelper;
using bluetooth_config::mojom::BluetoothSystemState;
using ::chromeos::network_config::FakeCrosNetworkConfig;
using ::chromeos::network_config::NetworkTypeMatchesType;
using ::chromeos::network_config::mojom::ConnectionStateType;
using ::chromeos::network_config::mojom::DeviceStatePropertiesPtr;
using ::chromeos::network_config::mojom::DeviceStateType;
using ::chromeos::network_config::mojom::GlobalPolicyPtr;
using ::chromeos::network_config::mojom::InhibitReason;
using ::chromeos::network_config::mojom::ManagedPropertiesPtr;
using ::chromeos::network_config::mojom::ManagedString;
using ::chromeos::network_config::mojom::NetworkStatePropertiesPtr;
using ::chromeos::network_config::mojom::NetworkType;
using ::chromeos::network_config::mojom::PolicySource;
using ::chromeos::network_config::mojom::SIMInfoPtr;
using ::chromeos::network_config::mojom::VpnProviderPtr;
using network_config::CrosNetworkConfigTestHelper;
using ::testing::IsNull;
using ::testing::NotNull;
const std::string kCellularName = "cellular";
const std::string kCellularName2 = "cellular_2";
const char kCellularTestIccid[] = "1234567890";
const char kTetherName[] = "tether";
const char kTetherName2[] = "tether_2";
const std::string kEthernetName = "ethernet";
const std::string kEthernetName2 = "ethernet_2";
const char kVpnName[] = "vpn";
const char kWifiName[] = "wifi";
const char kWifiName2[] = "wifi_2";
const char kTestBaseEid[] = "12345678901234567890123456789012";
constexpr char kUser1Email[] = "[email protected]";
constexpr char kNetworkListNetworkItemView[] = "NetworkListNetworkItemView";
// Delay used to simulate running process when setting device technology state.
constexpr base::TimeDelta kInteractiveDelay = base::Milliseconds(3000);
std::vector<ash::SIMInfoPtr> CellularSIMInfos(const std::string& iccid,
const std::string& eid) {
auto sim_info_mojo = chromeos::network_config::mojom::SIMInfo::New();
sim_info_mojo->iccid = iccid;
sim_info_mojo->eid = eid;
sim_info_mojo->is_primary = true;
std::vector<ash::SIMInfoPtr> sim_info_mojos;
sim_info_mojos.push_back(std::move(sim_info_mojo));
return sim_info_mojos;
}
ManagedPropertiesPtr CreateManagedPropertiesWithVPN(bool is_managed) {
auto managed_properties =
chromeos::network_config::mojom::ManagedProperties::New();
auto host = ManagedString::New();
host->active_value = "test";
host->policy_source =
is_managed ? PolicySource::kUserPolicyEnforced : PolicySource::kNone;
auto vpn = chromeos::network_config::mojom::ManagedVPNProperties::New();
vpn->host = std::move(host);
managed_properties->type_properties =
chromeos::network_config::mojom::NetworkTypeManagedProperties::NewVpn(
std::move(vpn));
managed_properties->ip_address_config_type = ManagedString::New();
managed_properties->name_servers_config_type = ManagedString::New();
managed_properties->traffic_counter_properties =
chromeos::network_config::mojom::TrafficCounterProperties::New();
return managed_properties;
}
ManagedPropertiesPtr CreateManagedPropertiesWithProxy(bool is_managed) {
auto managed_properties =
chromeos::network_config::mojom::ManagedProperties::New();
auto proxy_type = ManagedString::New();
proxy_type->active_value = "test";
proxy_type->policy_source =
is_managed ? PolicySource::kUserPolicyEnforced : PolicySource::kNone;
auto proxy_settings =
chromeos::network_config::mojom::ManagedProxySettings::New();
proxy_settings->type = std::move(proxy_type);
auto wifi = chromeos::network_config::mojom::ManagedWiFiProperties::New();
wifi->ssid = ManagedString::New();
managed_properties->type_properties =
chromeos::network_config::mojom::NetworkTypeManagedProperties::NewWifi(
std::move(wifi));
managed_properties->proxy_settings = std::move(proxy_settings);
managed_properties->ip_address_config_type = ManagedString::New();
managed_properties->name_servers_config_type = ManagedString::New();
managed_properties->traffic_counter_properties =
chromeos::network_config::mojom::TrafficCounterProperties::New();
return managed_properties;
}
// The fake delegate which is used in the `NetworkListViewControllerTest`.
class FakeNetworkDetailedNetworkViewDelegate
: public NetworkDetailedNetworkView::Delegate {
public:
FakeNetworkDetailedNetworkViewDelegate() = default;
~FakeNetworkDetailedNetworkViewDelegate() override = default;
private:
// NetworkDetailedView::Delegate:
void OnNetworkListItemSelected(
const NetworkStatePropertiesPtr& network) override {}
void OnWifiToggleClicked(bool new_state) override {}
void OnMobileToggleClicked(bool new_state) override {}
};
} // namespace
class NetworkListViewControllerTest : public AshTestBase,
public testing::WithParamInterface<bool> {
public:
NetworkListViewControllerTest()
: AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
NetworkListViewControllerTest(const NetworkListViewControllerTest&) = delete;
NetworkListViewControllerTest& operator=(
const NetworkListViewControllerTest&) = delete;
~NetworkListViewControllerTest() override = default;
void SetUp() override {
std::vector<base::test::FeatureRef> enabled_features;
std::vector<base::test::FeatureRef> disabled_features;
if (IsInstantHotspotRebrandEnabled()) {
enabled_features.push_back(features::kInstantHotspotRebrand);
} else {
disabled_features.push_back(features::kInstantHotspotRebrand);
}
feature_list_.InitWithFeatures(enabled_features, disabled_features);
fake_multidevice_setup_ =
std::make_unique<multidevice_setup::FakeMultiDeviceSetup>();
auto delegate = std::make_unique<TestShellDelegate>();
delegate->SetMultiDeviceSetupBinder(base::BindRepeating(
&multidevice_setup::MultiDeviceSetupBase::BindReceiver,
base::Unretained(fake_multidevice_setup_.get())));
AshTestBase::SetUp(std::move(delegate));
cros_network_ = std::make_unique<FakeCrosNetworkConfig>();
Shell::Get()
->system_tray_model()
->network_state_model()
->ConfigureRemoteForTesting(cros_network()->GetPendingRemote());
base::RunLoop().RunUntilIdle();
cros_network_->SetGlobalPolicy(
/*allow_only_policy_cellular_networks=*/false,
/*dns_queries_monitored=*/false,
/*report_xdr_events_enabled=*/false);
detailed_view_delegate_ =
std::make_unique<DetailedViewDelegate>(/*tray_controller=*/nullptr);
widget_ = CreateFramelessTestWidget();
widget_->SetFullscreen(true);
network_detailed_network_view_ = widget_->SetContentsView(
std::make_unique<NetworkDetailedNetworkViewImpl>(
detailed_view_delegate_.get(),
&fake_network_detailed_network_delagte_));
network_list_view_controller_impl_ =
std::make_unique<NetworkListViewControllerImpl>(
network_detailed_network_view_);
}
bool IsInstantHotspotRebrandEnabled() { return GetParam(); }
void TearDown() override {
network_list_view_controller_impl_.reset();
widget_.reset();
AshTestBase::TearDown();
}
Switch* GetMobileToggleButton() { return GetMobileSubHeader()->toggle_; }
Switch* GetWifiToggleButton() { return GetWifiSubHeader()->toggle_; }
void CheckWifiToggleButtonStatus(bool toggled_on) {
EXPECT_TRUE(GetWifiToggleButton()->GetVisible());
EXPECT_TRUE(GetWifiToggleButton()->GetEnabled());
EXPECT_EQ(GetWifiToggleButton()->GetIsOn(), toggled_on);
}
void CheckMobileToggleButtonStatus(bool enabled,
bool toggled_on,
bool visible = true) {
EXPECT_EQ(GetMobileToggleButton()->GetVisible(), visible);
EXPECT_EQ(GetMobileToggleButton()->GetEnabled(), enabled);
EXPECT_EQ(GetMobileToggleButton()->GetIsOn(), toggled_on);
}
HoverHighlightView* GetSetUpYourDeviceEntry() {
return FindViewById<HoverHighlightView*>(
VIEW_ID_OPEN_CROSS_DEVICE_SETTINGS);
}
HoverHighlightView* GetAddWifiEntry() {
return FindViewById<HoverHighlightView*>(VIEW_ID_JOIN_WIFI_NETWORK_ENTRY);
}
HoverHighlightView* GetAddESimEntry() {
return FindViewById<HoverHighlightView*>(VIEW_ID_ADD_ESIM_ENTRY);
}
NetworkListMobileHeaderView* GetMobileSubHeader() {
return network_list_view_controller_impl_->mobile_header_view_;
}
NetworkListWifiHeaderView* GetWifiSubHeader() {
return network_list_view_controller_impl_->wifi_header_view_;
}
NetworkListTetherHostsHeaderView* GetTetherHostsSubHeader() {
return network_list_view_controller_impl_->tether_hosts_header_view_;
}
TrayInfoLabel* GetMobileStatusMessage() {
return network_list_view_controller_impl_->mobile_status_message_;
}
TrayInfoLabel* GetWifiStatusMessage() {
return network_list_view_controller_impl_->wifi_status_message_;
}
TrayInfoLabel* GetTetherHostsStatusMessage() {
return network_list_view_controller_impl_->tether_hosts_status_message_;
}
TriView* GetConnectionWarning() {
return network_list_view_controller_impl_->connection_warning_;
}
views::Label* GetConnectionLabelView() {
return network_list_view_controller_impl_->connection_warning_label_;
}
views::ImageView* GetConnectionWarningIcon() {
return network_list_view_controller_impl_->connection_warning_icon_;
}
views::View* GetViewInNetworkList(std::string id) {
return network_list_view_controller_impl_->network_id_to_view_map_[id];
}
bool GetScanningBarVisibility() {
// The loading bar is the third child of the view.
return network_detailed_network_view_->children()[2]->GetVisible();
}
// Checks that network list items are in the right order. Wifi section
// is always shown.
void CheckNetworkListOrdering(int ethernet_network_count,
int wifi_network_count,
int cellular_network_count = 0,
int tether_network_count = 0) {
EXPECT_THAT(GetWifiSubHeader(), NotNull());
size_t index = 0;
// Expect that the view at `index` is a network item, and that it is an
// ethernet network.
for (int i = 0; i < ethernet_network_count; i++) {
CheckNetworkListItem(NetworkType::kEthernet, index++,
/*guid=*/std::nullopt);
}
// Expect that the view at `index` is a network item, and that it is an
// wifi network.
if (!wifi_network_count && GetWifiToggleButton()->GetIsOn()) {
// When no WiFi networks are available, status message is shown.
EXPECT_NE(nullptr, GetWifiStatusMessage());
}
index = 0;
for (int i = 0; i < wifi_network_count; i++) {
CheckNetworkListItem(NetworkType::kWiFi, 1 + index++,
/*guid=*/std::nullopt);
}
if (cellular_network_count == -1 && tether_network_count == -1) {
return;
}
index = 0;
// Expect that the view at `index` is a network item, and that it is a
// cellular network.
const NetworkType type = IsInstantHotspotRebrandEnabled()
? NetworkType::kCellular
: NetworkType::kMobile;
// const size_t count = cellular_network_count + tether_network_count;
const size_t count =
cellular_network_count +
(IsInstantHotspotRebrandEnabled() ? 0 : tether_network_count);
for (unsigned long i = 0; i < count; i++) {
CheckNetworkListItem(type, index++,
/*guid=*/std::nullopt);
}
if (IsInstantHotspotRebrandEnabled()) {
index = 0;
// Expect that the view at `index` is a network item, and that it is a
// tether network.
for (int i = 0; i < tether_network_count; i++) {
CheckNetworkListItem(NetworkType::kMobile, index++,
/*guid=*/std::nullopt);
}
}
}
void CheckNetworkListItem(NetworkType type,
size_t index,
const std::optional<std::string>& guid) {
ASSERT_GT(network_list(type)->children().size(), index);
EXPECT_STREQ(network_list(type)->children().at(index)->GetClassName(),
kNetworkListNetworkItemView);
const NetworkStatePropertiesPtr& network =
static_cast<NetworkListNetworkItemView*>(
network_list(type)->children().at(index))
->network_properties();
EXPECT_TRUE(NetworkTypeMatchesType(network->type, type));
if (guid.has_value()) {
EXPECT_EQ(network->guid, guid);
}
}
bool GetNetworkListItemIsEnabled(NetworkType type, size_t index) {
EXPECT_STREQ(network_list(type)->children().at(index)->GetClassName(),
kNetworkListNetworkItemView);
NetworkListNetworkItemView* network =
static_cast<NetworkListNetworkItemView*>(
network_list(type)->children().at(index));
return network->GetEnabled();
}
void SetBluetoothAdapterState(BluetoothSystemState system_state) {
bluetooth_config_test_helper()
->fake_adapter_state_controller()
->SetSystemState(system_state);
base::RunLoop().RunUntilIdle();
}
void LoginAsSecondaryUser() {
GetSessionControllerClient()->AddUserSession(kUser1Email);
SimulateUserLogin(kUser1Email);
GetSessionControllerClient()->SetSessionState(
session_manager::SessionState::LOGIN_SECONDARY);
base::RunLoop().RunUntilIdle();
}
bool HasScanTimerStarted() {
return network_list_view_controller_impl_->network_scan_repeating_timer_
.IsRunning();
}
NetworkDetailedNetworkView* network_detailed_network_view() {
return static_cast<NetworkDetailedNetworkView*>(
network_list_view_controller_impl_->network_detailed_network_view_);
}
views::View* network_list(NetworkType type) {
return static_cast<NetworkDetailedNetworkView*>(
network_detailed_network_view_)
->GetNetworkList(type);
}
bool IsManagedIcon(views::ImageView* icon) {
if (icon->GetID() !=
static_cast<int>(NetworkListViewControllerImpl::
NetworkListViewControllerViewChildId::
kConnectionWarningManagedIcon)) {
return false;
}
const gfx::ImageSkia managed_icon = gfx::CreateVectorIcon(
kSystemTrayManagedIcon,
AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kIconColorPrimary));
return gfx::BitmapsAreEqual(*icon->GetImage().bitmap(),
*managed_icon.bitmap());
}
bool IsSystemIcon(views::ImageView* icon) {
if (icon->GetID() !=
static_cast<int>(NetworkListViewControllerImpl::
NetworkListViewControllerViewChildId::
kConnectionWarningSystemIcon)) {
return false;
}
const gfx::ImageSkia system_icon = gfx::CreateVectorIcon(
kSystemMenuInfoIcon,
AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kIconColorPrimary));
return gfx::BitmapsAreEqual(*icon->GetImage().bitmap(),
*system_icon.bitmap());
}
FakeCrosNetworkConfig* cros_network() { return cros_network_.get(); }
std::unique_ptr<multidevice_setup::FakeMultiDeviceSetup>
fake_multidevice_setup_;
base::HistogramTester histogram_tester;
private:
template <class T>
T FindViewById(int id) {
return static_cast<T>(
network_detailed_network_view_->GetViewByID(static_cast<int>(id)));
}
ScopedBluetoothConfigTestHelper* bluetooth_config_test_helper() {
return ash_test_helper()->bluetooth_config_test_helper();
}
base::test::ScopedFeatureList feature_list_;
std::unique_ptr<FakeCrosNetworkConfig> cros_network_;
FakeNetworkDetailedNetworkViewDelegate fake_network_detailed_network_delagte_;
std::unique_ptr<DetailedViewDelegate> detailed_view_delegate_;
std::unique_ptr<views::Widget> widget_;
// Owned by `widget_`.
raw_ptr<NetworkDetailedNetworkViewImpl, DanglingUntriaged>
network_detailed_network_view_ = nullptr;
std::unique_ptr<NetworkListViewControllerImpl>
network_list_view_controller_impl_;
};
INSTANTIATE_TEST_SUITE_P(All, NetworkListViewControllerTest, testing::Bool());
TEST_P(NetworkListViewControllerTest, TetherHostsSectionIsShown) {
EXPECT_THAT(GetTetherHostsSubHeader(), IsNull());
auto properties =
chromeos::network_config::mojom::DeviceStateProperties::New();
properties->type = NetworkType::kTether;
properties->device_state = DeviceStateType::kEnabled;
cros_network()->SetDeviceProperties(properties.Clone());
// Add tether network
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kTetherName, NetworkType::kTether, ConnectionStateType::kConnected));
if (IsInstantHotspotRebrandEnabled()) {
ASSERT_THAT(GetTetherHostsSubHeader(), NotNull());
} else {
ASSERT_THAT(GetTetherHostsSubHeader(), IsNull());
return;
}
// Add cellular network
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kCellularName, NetworkType::kCellular,
ConnectionStateType::kConnected));
ASSERT_THAT(GetMobileSubHeader(), NotNull());
ASSERT_THAT(GetTetherHostsSubHeader(), NotNull());
// Tether device is prohibited.
properties->type = NetworkType::kTether;
properties->device_state = DeviceStateType::kProhibited;
cros_network()->SetDeviceProperties(properties.Clone());
EXPECT_THAT(GetMobileSubHeader(), NotNull());
EXPECT_THAT(GetTetherHostsSubHeader(), IsNull());
// Tether device is uninitialized but is primary user.
properties->device_state = DeviceStateType::kUninitialized;
cros_network()->SetDeviceProperties(properties.Clone());
ASSERT_THAT(GetMobileSubHeader(), NotNull());
EXPECT_THAT(GetTetherHostsSubHeader(), NotNull());
EXPECT_TRUE(network_list(NetworkType::kMobile)->GetVisible());
EXPECT_TRUE(network_list(NetworkType::kTether)->GetVisible());
// Tap the Tether Header - hide the Network List
LeftClickOn(GetTetherHostsSubHeader());
EXPECT_FALSE(network_list(NetworkType::kTether)->GetVisible());
// Tap it again - show the list
LeftClickOn(GetTetherHostsSubHeader());
EXPECT_TRUE(network_list(NetworkType::kTether)->GetVisible());
// Simulate login as secondary user.
LoginAsSecondaryUser();
cros_network()->ClearNetworksAndDevices();
EXPECT_THAT(GetMobileSubHeader(), IsNull());
// Add tether networks
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kTetherName, NetworkType::kTether, ConnectionStateType::kConnected));
ASSERT_THAT(GetMobileSubHeader(), IsNull());
ASSERT_THAT(GetTetherHostsSubHeader(), NotNull());
// Disable tether and ensure that the section is not shown.
properties->device_state = DeviceStateType::kDisabled;
cros_network()->SetDeviceProperties(properties.Clone());
ASSERT_THAT(GetTetherHostsSubHeader(), IsNull());
}
TEST_P(NetworkListViewControllerTest, MobileDataSectionIsShown) {
EXPECT_THAT(GetMobileSubHeader(), IsNull());
auto properties =
chromeos::network_config::mojom::DeviceStateProperties::New();
properties->type = NetworkType::kCellular;
properties->device_state = DeviceStateType::kEnabled;
cros_network()->SetDeviceProperties(properties.Clone());
ASSERT_THAT(GetMobileSubHeader(), NotNull());
// Clear device list and check if Mobile subheader is shown with just
// tether device.
cros_network()->ClearNetworksAndDevices();
EXPECT_THAT(GetMobileSubHeader(), IsNull());
if (IsInstantHotspotRebrandEnabled()) {
return;
}
// Add tether networks
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kTetherName, NetworkType::kTether, ConnectionStateType::kConnected));
ASSERT_THAT(GetMobileSubHeader(), NotNull());
// Tether device is prohibited.
properties->type = NetworkType::kTether;
properties->device_state = DeviceStateType::kProhibited;
cros_network()->SetDeviceProperties(properties.Clone());
EXPECT_THAT(GetMobileSubHeader(), IsNull());
// Tether device is uninitialized but is primary user.
properties->device_state = DeviceStateType::kUninitialized;
cros_network()->SetDeviceProperties(properties.Clone());
ASSERT_THAT(GetMobileSubHeader(), NotNull());
EXPECT_TRUE(network_list(NetworkType::kMobile)->GetVisible());
// Simulate login as secondary user.
LoginAsSecondaryUser();
cros_network()->ClearNetworksAndDevices();
EXPECT_THAT(GetMobileSubHeader(), IsNull());
// Add tether networks
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kTetherName, NetworkType::kTether, ConnectionStateType::kConnected));
ASSERT_THAT(GetMobileSubHeader(), NotNull());
}
TEST_P(NetworkListViewControllerTest, WifiSectionHeader) {
EXPECT_THAT(GetWifiSubHeader(), IsNull());
// Add an enabled wifi device.
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kWifiName, NetworkType::kWiFi, ConnectionStateType::kConnected));
ASSERT_THAT(GetWifiSubHeader(), NotNull());
CheckWifiToggleButtonStatus(/*toggled_on=*/true);
// Disable wifi device.
auto properties =
chromeos::network_config::mojom::DeviceStateProperties::New();
properties->type = NetworkType::kWiFi;
properties->device_state = DeviceStateType::kDisabled;
cros_network()->SetDeviceProperties(properties.Clone());
ASSERT_THAT(GetWifiSubHeader(), NotNull());
CheckWifiToggleButtonStatus(/*toggled_on=*/false);
}
TEST_P(NetworkListViewControllerTest, MobileSectionHeaderAddEsimButtonStates) {
EXPECT_THAT(GetMobileSubHeader(), IsNull());
EXPECT_THAT(GetMobileStatusMessage(), IsNull());
auto properties =
chromeos::network_config::mojom::DeviceStateProperties::New();
properties->type = NetworkType::kCellular;
properties->device_state = DeviceStateType::kEnabled;
cros_network()->SetDeviceProperties(properties.Clone());
// Since no Euicc was added, this means device is not eSIM capable, do not
// show add eSIM entry.
EXPECT_THAT(GetAddESimEntry(), IsNull());
cros_network()->ClearNetworksAndDevices();
properties->sim_infos = CellularSIMInfos(kCellularTestIccid, kTestBaseEid);
cros_network()->SetDeviceProperties(properties.Clone());
// If there is no network and add eSIM entry should be shown, the mobile
// status message shouldn't been shown.
EXPECT_TRUE(GetAddESimEntry()->GetVisible());
EXPECT_EQ(GetAddESimEntry()->GetTooltipText(),
l10n_util::GetStringUTF16(GetAddESimTooltipMessageId()));
ASSERT_THAT(GetMobileStatusMessage(), NotNull());
// Add eSIM button is not enabled when inhibited.
properties->inhibit_reason = InhibitReason::kResettingEuiccMemory;
cros_network()->SetDeviceProperties(properties.Clone());
EXPECT_THAT(GetAddESimEntry(), IsNull());
// Uninhibit the device.
properties->inhibit_reason = InhibitReason::kNotInhibited;
cros_network()->SetDeviceProperties(properties.Clone());
ASSERT_THAT(GetAddESimEntry(), NotNull());
EXPECT_TRUE(GetAddESimEntry()->GetVisible());
EXPECT_EQ(GetAddESimEntry()->GetTooltipText(),
l10n_util::GetStringUTF16(GetAddESimTooltipMessageId()));
// When no Mobile networks are available and eSIM policy is set to allow only
// cellular devices which means adding a new eSIM is disallowed by enterprise
// policy, add eSIM button or entry is not displayed.
cros_network()->SetGlobalPolicy(
/*allow_only_policy_cellular_networks=*/true,
/*dns_queries_monitored=*/false,
/*report_xdr_events_enabled=*/false);
EXPECT_THAT(GetAddESimEntry(), IsNull());
}
TEST_P(NetworkListViewControllerTest,
MobileSectionListAddEsimEntryNotAddedWhenLocked) {
EXPECT_THAT(GetMobileSubHeader(), IsNull());
EXPECT_THAT(GetMobileStatusMessage(), IsNull());
auto properties =
chromeos::network_config::mojom::DeviceStateProperties::New();
properties->type = NetworkType::kCellular;
properties->device_state = DeviceStateType::kEnabled;
properties->sim_infos = CellularSIMInfos(kCellularTestIccid, kTestBaseEid);
cros_network()->SetDeviceProperties(properties.Clone());
ASSERT_THAT(GetAddESimEntry(), NotNull());
EXPECT_TRUE(GetAddESimEntry()->GetVisible());
// In the locked session, the add esim entry should not be added.
GetSessionControllerClient()->SetSessionState(
session_manager::SessionState::LOCKED);
cros_network()->SetDeviceProperties(properties.Clone());
EXPECT_THAT(GetAddESimEntry(), IsNull());
}
TEST_P(NetworkListViewControllerTest, AddESimEntryUMAMetrics) {
EXPECT_THAT(GetMobileSubHeader(), IsNull());
EXPECT_THAT(GetMobileStatusMessage(), IsNull());
auto properties =
chromeos::network_config::mojom::DeviceStateProperties::New();
properties->type = NetworkType::kCellular;
properties->device_state = DeviceStateType::kEnabled;
properties->sim_infos = CellularSIMInfos(kCellularTestIccid, kTestBaseEid);
cros_network()->SetDeviceProperties(properties.Clone());
// Makes sure the add esim entry is visible.
ASSERT_THAT(GetAddESimEntry(), NotNull());
EXPECT_TRUE(GetAddESimEntry()->GetVisible());
base::UserActionTester user_action_tester;
EXPECT_EQ(0, user_action_tester.GetActionCount("QS_Subpage_Network_AddESim"));
LeftClickOn(GetAddESimEntry());
EXPECT_EQ(1, user_action_tester.GetActionCount("QS_Subpage_Network_AddESim"));
}
TEST_P(NetworkListViewControllerTest, HasCorrectMobileNetworkList) {
EXPECT_EQ(0u, network_list(NetworkType::kMobile)->children().size());
EXPECT_THAT(GetMobileSubHeader(), IsNull());
EXPECT_THAT(GetMobileStatusMessage(), IsNull());
auto properties =
chromeos::network_config::mojom::DeviceStateProperties::New();
properties->type = NetworkType::kCellular;
properties->device_state = DeviceStateType::kEnabled;
properties->sim_infos = CellularSIMInfos(kCellularTestIccid, kTestBaseEid);
cros_network()->SetDeviceProperties(properties.Clone());
properties = chromeos::network_config::mojom::DeviceStateProperties::New();
properties->type = NetworkType::kWiFi;
properties->device_state = DeviceStateType::kEnabled;
cros_network()->SetDeviceProperties(properties.Clone());
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/0,
/*cellular_network_count=*/0,
/*tether_network_count=*/0);
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kCellularName, NetworkType::kCellular,
ConnectionStateType::kConnected));
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/0,
/*cellular_network_count=*/1,
/*tether_network_count=*/0);
CheckNetworkListItem(NetworkType::kCellular, /*index=*/0u,
/*guid=*/kCellularName);
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kCellularName2, NetworkType::kCellular,
ConnectionStateType::kConnected));
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/0,
/*cellular_network_count=*/2,
/*tether_network_count=*/0);
CheckNetworkListItem(NetworkType::kCellular, /*index=*/1u,
/*guid=*/kCellularName2);
// Update a network and make sure it is still in network list.
cros_network()->SetNetworkState(kCellularName,
ConnectionStateType::kNotConnected);
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/0,
/*cellular_network_count=*/2,
/*tether_network_count=*/0);
CheckNetworkListItem(NetworkType::kCellular, /*index=*/0u,
/*guid=*/kCellularName);
CheckNetworkListItem(NetworkType::kCellular, /*index=*/1u,
/*guid=*/kCellularName2);
// Remove all networks and add Tether networks. Only one network should be in
// list.
cros_network()->ClearNetworksAndDevices();
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kTetherName, NetworkType::kTether, ConnectionStateType::kConnected));
if (IsInstantHotspotRebrandEnabled()) {
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/0);
} else {
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/0,
/*cellular_network_count=*/0,
/*tether_network_count=*/1);
}
CheckNetworkListItem(NetworkType::kTether, /*index=*/0u,
/*guid=*/kTetherName);
}
TEST_P(NetworkListViewControllerTest, HasCorrectEthernetNetworkList) {
std::vector<NetworkStatePropertiesPtr> networks;
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kEthernetName, NetworkType::kEthernet,
ConnectionStateType::kNotConnected));
CheckNetworkListOrdering(/*ethernet_network_count=*/1,
/*wifi_network_count=*/0,
/*cellular_network_count=*/-1,
/*tether_network_count=*/-1);
CheckNetworkListItem(NetworkType::kEthernet, /*index=*/0u,
/*guid=*/kEthernetName);
// Add mobile network.
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kCellularName, NetworkType::kCellular,
ConnectionStateType::kConnected));
CheckNetworkListOrdering(/*ethernet_network_count=*/1,
/*wifi_network_count=*/0,
/*cellular_network_count=*/1,
/*tether_network_count=*/0);
CheckNetworkListItem(NetworkType::kCellular, /*index=*/0u,
/*guid=*/kCellularName);
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kEthernetName2, NetworkType::kEthernet,
ConnectionStateType::kNotConnected));
CheckNetworkListOrdering(/*ethernet_network_count=*/2,
/*wifi_network_count=*/0,
/*cellular_network_count=*/1,
/*tether_network_count*/ 0);
CheckNetworkListItem(NetworkType::kCellular, /*index=*/0u,
/*guid=*/kCellularName);
}
TEST_P(NetworkListViewControllerTest,
WillShowTetherHostsNetworkListWhenHostIsAvailable) {
for (const auto& host_status :
{multidevice_setup::mojom::HostStatus::kNoEligibleHosts,
multidevice_setup::mojom::HostStatus::kHostVerified,
multidevice_setup::mojom::HostStatus::
kHostSetLocallyButWaitingForBackendConfirmation,
multidevice_setup::mojom::HostStatus::kHostSetButNotYetVerified}) {
fake_multidevice_setup_->NotifyHostStatusChanged(host_status, std::nullopt);
fake_multidevice_setup_->FlushForTesting();
base::RunLoop().RunUntilIdle();
// Since we didn't send a notification that the host is ready and not set,
// the Tether section shouldn't be shown regardless of the value of the
// feature flag.
EXPECT_THAT(GetTetherHostsSubHeader(), IsNull());
}
fake_multidevice_setup_->NotifyHostStatusChanged(
multidevice_setup::mojom::HostStatus::kEligibleHostExistsButNoHostSet,
std::nullopt);
fake_multidevice_setup_->FlushForTesting();
base::RunLoop().RunUntilIdle();
// If the rebrand is enabled, the tether section should be shown. If not, it
// shouldn't be
if (IsInstantHotspotRebrandEnabled()) {
EXPECT_THAT(GetTetherHostsSubHeader(), NotNull());
EXPECT_THAT(GetSetUpYourDeviceEntry(), NotNull());
LeftClickOn(GetSetUpYourDeviceEntry());
EXPECT_EQ(1, GetSystemTrayClient()->show_multi_device_setup_count());
} else {
EXPECT_THAT(GetTetherHostsSubHeader(), IsNull());
EXPECT_THAT(GetSetUpYourDeviceEntry(), IsNull());
}
// Add tether host.
fake_multidevice_setup_->NotifyHostStatusChanged(
multidevice_setup::mojom::HostStatus::kHostVerified, std::nullopt);
fake_multidevice_setup_->FlushForTesting();
auto properties =
chromeos::network_config::mojom::DeviceStateProperties::New();
properties->type = NetworkType::kTether;
properties->device_state = DeviceStateType::kEnabled;
cros_network()->SetDeviceProperties(properties.Clone());
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/0,
/*cellular_network_count=*/0,
/*tether_network_count=*/0);
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kTetherName, NetworkType::kTether, ConnectionStateType::kConnected));
base::RunLoop().RunUntilIdle();
if (IsInstantHotspotRebrandEnabled()) {
EXPECT_THAT(GetSetUpYourDeviceEntry(), IsNull());
EXPECT_THAT(GetTetherHostsSubHeader(), NotNull());
} else {
EXPECT_THAT(GetSetUpYourDeviceEntry(), IsNull());
EXPECT_THAT(GetTetherHostsSubHeader(), IsNull());
}
}
TEST_P(NetworkListViewControllerTest, HasCorrectTetherHostsNetworkList) {
EXPECT_EQ(0u, network_list(NetworkType::kTether)->children().size());
EXPECT_THAT(GetTetherHostsSubHeader(), IsNull());
auto properties =
chromeos::network_config::mojom::DeviceStateProperties::New();
properties->type = NetworkType::kTether;
properties->device_state = DeviceStateType::kEnabled;
cros_network()->SetDeviceProperties(properties.Clone());
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/0,
/*cellular_network_count=*/0,
/*tether_network_count=*/0);
// Add tether host.
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kTetherName, NetworkType::kTether, ConnectionStateType::kConnected));
if (IsInstantHotspotRebrandEnabled()) {
EXPECT_THAT(GetMobileSubHeader(), IsNull());
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/0,
/*cellular_network_count=*/0,
/*tether_network_count=*/1);
} else {
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/0,
/*cellular_network_count=*/0,
/*tether_network_count=*/0);
}
// Add mobile network.
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kCellularName, NetworkType::kCellular,
ConnectionStateType::kConnected));
if (features::IsInstantHotspotRebrandEnabled()) {
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/0,
/*cellular_network_count=*/1,
/*tether_network_count=*/1);
} else {
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/0,
/*cellular_network_count=*/0,
/*tether_network_count=*/0);
}
// Add another tether host.
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kTetherName2, NetworkType::kTether, ConnectionStateType::kConnected));
if (features::IsInstantHotspotRebrandEnabled()) {
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/0,
/*cellular_network_count=*/1,
/*tether_network_count=*/2);
} else {
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/0,
/*cellular_network_count=*/0,
/*tether_network_count=*/0);
}
}
TEST_P(NetworkListViewControllerTest, HasCorrectWifiNetworkList) {
// Add an enabled wifi device.
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kWifiName, NetworkType::kWiFi, ConnectionStateType::kNotConnected));
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/1,
/*cellular_network_count=*/-1,
/*tether_network_count=*/-1);
EXPECT_EQ(u"Unknown networks",
static_cast<views::Label*>(
network_list(NetworkType::kWiFi)->children()[0])
->GetText());
// Wifi list item will be at index 2 after Wifi group label.
CheckNetworkListItem(NetworkType::kWiFi, /*index=*/1u,
/*guid=*/kWifiName);
// Add mobile network.
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kCellularName, NetworkType::kCellular,
ConnectionStateType::kConnected));
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/1,
/*cellular_network_count=*/1,
/*tether_network_count=*/0);
EXPECT_EQ(u"Unknown networks",
static_cast<views::Label*>(
network_list(NetworkType::kWiFi)->children()[0])
->GetText());
CheckNetworkListItem(NetworkType::kWiFi, /*index=*/1u,
/*guid=*/kWifiName);
EXPECT_TRUE(GetAddWifiEntry()->GetVisible());
EXPECT_EQ(GetAddWifiEntry()->GetTooltipText(),
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_OTHER_WIFI));
// Add a second Wifi network.
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kWifiName2, NetworkType::kWiFi, ConnectionStateType::kNotConnected));
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/2,
/*cellular_network_count*/ 1,
/*tether_network_count*/ 0);
EXPECT_EQ(u"Unknown networks",
static_cast<views::Label*>(
network_list(NetworkType::kWiFi)->children()[0])
->GetText());
CheckNetworkListItem(NetworkType::kWiFi, /*index=*/1u,
/*guid=*/kWifiName);
CheckNetworkListItem(NetworkType::kWiFi, /*index=*/2u,
/*guid=*/kWifiName2);
base::UserActionTester user_action_tester;
EXPECT_EQ(
0, user_action_tester.GetActionCount("QS_Subpage_Network_JoinNetwork"));
LeftClickOn(GetAddWifiEntry());
EXPECT_EQ(
1, user_action_tester.GetActionCount("QS_Subpage_Network_JoinNetwork"));
}
TEST_P(NetworkListViewControllerTest,
StaysInTheSamePositionAfterUpdatingNetworks) {
// Sets a screen with a limited height to make sure it can be scrollable.
UpdateDisplay("500x200");
// Adds an enabled wifi device.
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kWifiName, NetworkType::kWiFi, ConnectionStateType::kNotConnected));
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/1,
/*cellular_network_count=*/-1,
/*tether_network_count=*/-1);
// Adds mobile network.
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kCellularName, NetworkType::kCellular,
ConnectionStateType::kConnected));
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/1,
/*cellular_network_count=*/1,
/*tether_network_count=*/0);
// Lets the network list scroll to a random number.
network_detailed_network_view()->ScrollToPosition(23);
// Adds 5 more Wifi network. The scroll position should not change after each
// time the new network is added.
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kWifiName2, NetworkType::kWiFi, ConnectionStateType::kNotConnected));
EXPECT_EQ(23, network_detailed_network_view()->GetScrollPosition());
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
"wifi_3", NetworkType::kWiFi, ConnectionStateType::kNotConnected));
EXPECT_EQ(23, network_detailed_network_view()->GetScrollPosition());
// Scrolls to another position.
network_detailed_network_view()->ScrollToPosition(37);
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
"wifi_4", NetworkType::kWiFi, ConnectionStateType::kNotConnected));
EXPECT_EQ(37, network_detailed_network_view()->GetScrollPosition());
cros_network()->RemoveNthNetworks(0);
EXPECT_EQ(37, network_detailed_network_view()->GetScrollPosition());
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
"wifi_5", NetworkType::kWiFi, ConnectionStateType::kNotConnected));
EXPECT_EQ(37, network_detailed_network_view()->GetScrollPosition());
cros_network()->RemoveNthNetworks(1);
EXPECT_EQ(37, network_detailed_network_view()->GetScrollPosition());
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
"wifi_6", NetworkType::kWiFi, ConnectionStateType::kNotConnected));
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/4,
/*cellular_network_count=*/1,
/*tether_network_count=*/0);
EXPECT_EQ(37, network_detailed_network_view()->GetScrollPosition());
}
TEST_P(NetworkListViewControllerTest,
CellularStatusMessageAndToggleButtonState) {
EXPECT_THAT(GetMobileStatusMessage(), IsNull());
// Update cellular device state to be Uninitialized.
auto properties =
chromeos::network_config::mojom::DeviceStateProperties::New();
properties->type = NetworkType::kCellular;
properties->sim_infos = CellularSIMInfos(kCellularTestIccid, kTestBaseEid);
properties->device_state = DeviceStateType::kUninitialized;
cros_network()->SetDeviceProperties(properties.Clone());
ASSERT_THAT(GetMobileStatusMessage(), NotNull());
CheckMobileToggleButtonStatus(/*enabled=*/false, /*toggled_on=*/false);
EXPECT_TRUE(network_list(NetworkType::kMobile)->GetVisible());
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_INITIALIZING_CELLULAR),
GetMobileStatusMessage()->label()->GetText());
properties->device_state = DeviceStateType::kEnabled;
cros_network()->SetDeviceProperties(properties.Clone());
ASSERT_THAT(GetMobileSubHeader(), NotNull());
ASSERT_THAT(GetMobileStatusMessage(), NotNull());
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NO_MOBILE_NETWORKS),
GetMobileStatusMessage()->label()->GetText());
CheckMobileToggleButtonStatus(/*enabled=*/true, /*toggled_on=*/true);
EXPECT_TRUE(network_list(NetworkType::kMobile)->GetVisible());
// No message is shown when there are available networks.
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kCellularName, NetworkType::kCellular,
ConnectionStateType::kConnected));
EXPECT_THAT(GetMobileStatusMessage(), IsNull());
CheckMobileToggleButtonStatus(/*enabled=*/true, /*toggled_on=*/true);
// Message shown again when list is empty.
cros_network()->ClearNetworksAndDevices();
cros_network()->SetDeviceProperties(properties.Clone());
ASSERT_THAT(GetMobileStatusMessage(), NotNull());
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NO_MOBILE_NETWORKS),
GetMobileStatusMessage()->label()->GetText());
EXPECT_TRUE(GetMobileToggleButton()->GetVisible());
EXPECT_TRUE(network_list(NetworkType::kMobile)->GetVisible());
// No message is shown when inhibited.
properties->inhibit_reason = InhibitReason::kResettingEuiccMemory;
cros_network()->SetDeviceProperties(properties.Clone());
EXPECT_THAT(GetMobileStatusMessage(), IsNull());
CheckMobileToggleButtonStatus(/*enabled=*/false, /*toggled_on=*/true);
// Uninhibit the device.
properties->inhibit_reason = InhibitReason::kNotInhibited;
cros_network()->SetDeviceProperties(properties.Clone());
// Message is shown when uninhibited.
ASSERT_THAT(GetMobileStatusMessage(), NotNull());
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NO_MOBILE_NETWORKS),
GetMobileStatusMessage()->label()->GetText());
CheckMobileToggleButtonStatus(/*enabled=*/true, /*toggled_on=*/true);
EXPECT_TRUE(network_list(NetworkType::kMobile)->GetVisible());
// When device is in disabling message is shown.
properties->device_state = DeviceStateType::kDisabling;
cros_network()->SetDeviceProperties(properties.Clone());
ASSERT_THAT(GetMobileStatusMessage(), NotNull());
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_MOBILE_DISABLING),
GetMobileStatusMessage()->label()->GetText());
CheckMobileToggleButtonStatus(/*enabled=*/false, /*toggled_on=*/false);
EXPECT_TRUE(network_list(NetworkType::kMobile)->GetVisible());
properties->device_state = DeviceStateType::kDisabled;
cros_network()->SetDeviceProperties(properties.Clone());
if (IsInstantHotspotRebrandEnabled()) {
// No mobile network list is shown when device is disabled.
EXPECT_FALSE(network_list(NetworkType::kCellular)->GetVisible());
} else {
EXPECT_FALSE(network_list(NetworkType::kMobile)->GetVisible());
}
CheckMobileToggleButtonStatus(/*enabled=*/true, /*toggled_on=*/false);
// The toggle is not enabled, the cellular device SIM is locked, and user
// cannot open the settings page.
GetSessionControllerClient()->SetSessionState(
session_manager::SessionState::LOGIN_SECONDARY);
properties->sim_lock_status =
chromeos::network_config::mojom::SIMLockStatus::New();
properties->sim_lock_status->lock_type = "lock";
cros_network()->SetDeviceProperties(properties.Clone());
EXPECT_FALSE(GetMobileToggleButton()->GetEnabled());
}
TEST_P(NetworkListViewControllerTest, HasCorrectTetherStatusMessage) {
// Mobile section is not shown if Tether network is unavailable.
if (!IsInstantHotspotRebrandEnabled()) {
EXPECT_THAT(GetMobileStatusMessage(), IsNull());
} else {
EXPECT_THAT(GetTetherHostsStatusMessage(), IsNull());
}
// Tether is enabled but no devices are added.
auto properties =
chromeos::network_config::mojom::DeviceStateProperties::New();
properties->type = NetworkType::kTether;
properties->device_state = DeviceStateType::kEnabled;
cros_network()->SetDeviceProperties(properties.Clone());
if (!IsInstantHotspotRebrandEnabled()) {
ASSERT_THAT(GetMobileStatusMessage(), NotNull());
ASSERT_THAT(GetMobileSubHeader(), NotNull());
CheckMobileToggleButtonStatus(/*enabled=*/true, /*toggled_on=*/true);
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NO_MOBILE_DEVICES_FOUND),
GetMobileStatusMessage()->label()->GetText());
EXPECT_TRUE(network_list(NetworkType::kMobile)->GetVisible());
} else {
ASSERT_THAT(GetTetherHostsStatusMessage(), NotNull());
ASSERT_THAT(GetTetherHostsSubHeader(), NotNull());
EXPECT_EQ(l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_NETWORK_NO_TETHER_DEVICES_FOUND),
GetTetherHostsStatusMessage()->label()->GetText());
EXPECT_TRUE(network_list(NetworkType::kTether)->GetVisible());
}
// Tether network is uninitialized and Bluetooth state enabling.
properties->device_state = DeviceStateType::kUninitialized;
cros_network()->SetDeviceProperties(properties.Clone());
SetBluetoothAdapterState(BluetoothSystemState::kEnabling);
if (!IsInstantHotspotRebrandEnabled()) {
CheckMobileToggleButtonStatus(/*enabled=*/false, /*toggled_on=*/true);
EXPECT_TRUE(network_list(NetworkType::kMobile)->GetVisible());
ASSERT_THAT(GetMobileStatusMessage(), NotNull());
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_INITIALIZING_CELLULAR),
GetMobileStatusMessage()->label()->GetText());
} else {
EXPECT_TRUE(network_list(NetworkType::kTether)->GetVisible());
ASSERT_THAT(GetTetherHostsStatusMessage(), NotNull());
EXPECT_EQ(l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_NETWORK_NO_TETHER_DEVICES_FOUND),
GetTetherHostsStatusMessage()->label()->GetText());
}
// Set Bluetooth device to disabling.
SetBluetoothAdapterState(BluetoothSystemState::kDisabling);
if (!IsInstantHotspotRebrandEnabled()) {
CheckMobileToggleButtonStatus(/*enabled=*/true, /*toggled_on=*/false);
ASSERT_THAT(GetMobileStatusMessage(), NotNull());
EXPECT_TRUE(network_list(NetworkType::kMobile)->GetVisible());
EXPECT_EQ(l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_ENABLING_MOBILE_ENABLES_BLUETOOTH),
GetMobileStatusMessage()->label()->GetText());
} else {
ASSERT_THAT(GetTetherHostsStatusMessage(), NotNull());
EXPECT_TRUE(network_list(NetworkType::kTether)->GetVisible());
EXPECT_EQ(l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_NETWORK_TETHER_NO_BLUETOOTH),
GetTetherHostsStatusMessage()->label()->GetText());
}
// Simulate login as secondary user and disable Bluetooth device.
LoginAsSecondaryUser();
SetBluetoothAdapterState(BluetoothSystemState::kDisabled);
if (!IsInstantHotspotRebrandEnabled()) {
CheckMobileToggleButtonStatus(/*enabled=*/false, /*toggled_on=*/false);
ASSERT_THAT(GetMobileStatusMessage(), NotNull());
EXPECT_TRUE(network_list(NetworkType::kMobile)->GetVisible());
EXPECT_EQ(l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_ENABLING_MOBILE_ENABLES_BLUETOOTH),
GetMobileStatusMessage()->label()->GetText());
} else {
ASSERT_THAT(GetTetherHostsStatusMessage(), NotNull());
EXPECT_TRUE(network_list(NetworkType::kTether)->GetVisible());
EXPECT_EQ(l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_NETWORK_TETHER_NO_BLUETOOTH),
GetTetherHostsStatusMessage()->label()->GetText());
}
// No message shown when Tether devices are added, AND Bluetooth is enabled.
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kTetherName, NetworkType::kTether, ConnectionStateType::kConnected));
SetBluetoothAdapterState(BluetoothSystemState::kEnabled);
EXPECT_THAT(GetMobileStatusMessage(), IsNull());
EXPECT_THAT(GetTetherHostsStatusMessage(), IsNull());
properties->device_state = DeviceStateType::kDisabled;
cros_network()->SetDeviceProperties(properties.Clone());
// No mobile network list is shown when device is disabled.
if (!IsInstantHotspotRebrandEnabled()) {
EXPECT_FALSE(network_list(NetworkType::kMobile)->GetVisible());
}
}
TEST_P(NetworkListViewControllerTest, HasCorrectWifiStatusMessage) {
EXPECT_THAT(GetWifiStatusMessage(), IsNull());
// Add an enabled wifi device.
auto properties =
chromeos::network_config::mojom::DeviceStateProperties::New();
properties->type = NetworkType::kWiFi;
properties->device_state = DeviceStateType::kEnabled;
cros_network()->SetDeviceProperties(properties.Clone());
// Wifi is enabled but not networks are added.
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_WIFI_ENABLED),
GetWifiStatusMessage()->label()->GetText());
// Disable wifi device.
properties->device_state = DeviceStateType::kDisabled;
cros_network()->SetDeviceProperties(properties.Clone());
EXPECT_FALSE(network_list(NetworkType::kWiFi)->GetVisible());
// Enable and add wifi network.
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kWifiName, NetworkType::kWiFi, ConnectionStateType::kConnected));
CheckNetworkListOrdering(/*ethernet_network_count=*/0,
/*wifi_network_count=*/1,
/*cellular_network_count=*/-1,
/*tether_network_count=*/-1);
}
TEST_P(NetworkListViewControllerTest, ConnectionWarningSystemIconVpn) {
EXPECT_THAT(GetConnectionWarning(), IsNull());
cros_network()->AddManagedProperties(
kVpnName, CreateManagedPropertiesWithVPN(/*is_managed=*/false));
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kVpnName, NetworkType::kVPN, ConnectionStateType::kConnected));
ASSERT_THAT(GetConnectionWarning(), NotNull());
ASSERT_THAT(GetConnectionLabelView(), NotNull());
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_MONITORED_WARNING),
GetConnectionLabelView()->GetText());
EXPECT_EQ(network_list(NetworkType::kEthernet)->children().at(0),
GetConnectionWarning());
views::ImageView* icon = GetConnectionWarningIcon();
ASSERT_THAT(icon, NotNull());
EXPECT_TRUE(IsSystemIcon(icon));
// Clear all devices and make sure warning is no longer being shown.
cros_network()->ClearNetworksAndDevices();
EXPECT_THAT(GetConnectionWarning(), IsNull());
}
TEST_P(NetworkListViewControllerTest, ConnectionWarningManagedIconVpn) {
EXPECT_THAT(GetConnectionWarning(), IsNull());
cros_network()->AddManagedProperties(
kVpnName, CreateManagedPropertiesWithVPN(/*is_managed=*/true));
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kVpnName, NetworkType::kVPN, ConnectionStateType::kConnected));
ASSERT_THAT(GetConnectionWarning(), NotNull());
ASSERT_THAT(GetConnectionLabelView(), NotNull());
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_MONITORED_WARNING),
GetConnectionLabelView()->GetText());
EXPECT_EQ(network_list(NetworkType::kEthernet)->children().at(0),
GetConnectionWarning());
views::ImageView* icon = GetConnectionWarningIcon();
ASSERT_THAT(icon, NotNull());
EXPECT_TRUE(IsManagedIcon(icon));
// Clear all devices and make sure warning is no longer being shown.
cros_network()->ClearNetworksAndDevices();
EXPECT_THAT(GetConnectionWarning(), IsNull());
}
TEST_P(NetworkListViewControllerTest, ConnectionWarningSystemIconProxy) {
EXPECT_THAT(GetConnectionWarning(), IsNull());
cros_network()->AddManagedProperties(
kWifiName, CreateManagedPropertiesWithProxy(/*is_managed=*/false));
auto network = CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kWifiName, NetworkType::kWiFi, ConnectionStateType::kConnected);
network->proxy_mode = chromeos::network_config::mojom::ProxyMode::kAutoDetect;
cros_network()->AddNetworkAndDevice(std::move(network));
ASSERT_THAT(GetConnectionWarning(), NotNull());
ASSERT_THAT(GetConnectionLabelView(), NotNull());
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_MONITORED_WARNING),
GetConnectionLabelView()->GetText());
views::ImageView* icon = GetConnectionWarningIcon();
ASSERT_THAT(icon, NotNull());
EXPECT_TRUE(IsSystemIcon(icon));
// Clear all devices and make sure warning is no longer being shown.
cros_network()->ClearNetworksAndDevices();
EXPECT_THAT(GetConnectionWarning(), IsNull());
}
TEST_P(NetworkListViewControllerTest, ConnectionWarningManagedIconProxy) {
EXPECT_THAT(GetConnectionWarning(), IsNull());
cros_network()->AddManagedProperties(
kWifiName, CreateManagedPropertiesWithProxy(/*is_managed=*/true));
auto network = CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kWifiName, NetworkType::kWiFi, ConnectionStateType::kConnected);
network->proxy_mode = chromeos::network_config::mojom::ProxyMode::kAutoDetect;
cros_network()->AddNetworkAndDevice(std::move(network));
ASSERT_THAT(GetConnectionWarning(), NotNull());
ASSERT_THAT(GetConnectionLabelView(), NotNull());
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_MANAGED_WARNING),
GetConnectionLabelView()->GetText());
views::ImageView* icon = GetConnectionWarningIcon();
ASSERT_THAT(icon, NotNull());
EXPECT_TRUE(IsManagedIcon(icon));
// Clear all devices and make sure warning is no longer being shown.
cros_network()->ClearNetworksAndDevices();
EXPECT_THAT(GetConnectionWarning(), IsNull());
}
// Disconnect and re-connect a network that shows a warning.
// Regression test for b/263803248.
TEST_P(NetworkListViewControllerTest, ConnectionWarningDisconnectReconnect) {
EXPECT_THAT(GetConnectionWarning(), IsNull());
cros_network()->AddManagedProperties(
kWifiName, CreateManagedPropertiesWithProxy(/*is_managed=*/true));
auto network = CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kWifiName, NetworkType::kWiFi, ConnectionStateType::kConnected);
network->proxy_mode = chromeos::network_config::mojom::ProxyMode::kAutoDetect;
cros_network()->AddNetworkAndDevice(std::move(network));
ASSERT_THAT(GetConnectionWarning(), NotNull());
ASSERT_THAT(GetConnectionLabelView(), NotNull());
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_MANAGED_WARNING),
GetConnectionLabelView()->GetText());
{
views::ImageView* icon = GetConnectionWarningIcon();
ASSERT_THAT(icon, NotNull());
EXPECT_TRUE(IsManagedIcon(icon));
}
// Disconnect the network and check that no warning is shown.
cros_network()->SetNetworkState(kWifiName,
ConnectionStateType::kNotConnected);
EXPECT_THAT(GetConnectionWarning(), IsNull());
// Reconnect the network. This should not crash (regression test for
// b/263803248). Afterwards, the warning should be shown again.
cros_network()->SetNetworkState(kWifiName, ConnectionStateType::kOnline);
ASSERT_THAT(GetConnectionWarning(), NotNull());
{
views::ImageView* icon = GetConnectionWarningIcon();
ASSERT_THAT(icon, NotNull());
EXPECT_TRUE(IsManagedIcon(icon));
}
}
TEST_P(NetworkListViewControllerTest,
ConnectionWarningDnsTemplateUriWithIdentifier) {
EXPECT_THAT(GetConnectionWarning(), IsNull());
auto network = CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kWifiName, NetworkType::kWiFi, ConnectionStateType::kConnected);
cros_network()->SetGlobalPolicy(
/*allow_only_policy_cellular_networks=*/false,
/*dns_queries_monitored=*/true,
/*report_xdr_events_enabled=*/false);
views::ImageView* icon = GetConnectionWarningIcon();
ASSERT_THAT(icon, NotNull());
EXPECT_TRUE(IsManagedIcon(icon));
ASSERT_THAT(GetConnectionWarning(), NotNull());
ASSERT_THAT(GetConnectionLabelView(), NotNull());
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_MANAGED_WARNING),
GetConnectionLabelView()->GetText());
}
TEST_P(NetworkListViewControllerTest, ConnectionWarningDeviceReportXDREvents) {
EXPECT_THAT(GetConnectionWarning(), IsNull());
auto network = CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kWifiName, NetworkType::kWiFi, ConnectionStateType::kConnected);
// First set XDR policy as false to check that managed warning is shown.
cros_network()->SetGlobalPolicy(
/*allow_only_policy_cellular_networks=*/false,
/*dns_queries_monitored=*/true,
/*report_xdr_events_enabled=*/false);
views::ImageView* icon = GetConnectionWarningIcon();
ASSERT_THAT(icon, NotNull());
EXPECT_TRUE(IsManagedIcon(icon));
ASSERT_THAT(GetConnectionWarning(), NotNull());
ASSERT_THAT(GetConnectionLabelView(), NotNull());
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_MANAGED_WARNING),
GetConnectionLabelView()->GetText());
// Update XDR policy to true and verify network monitored warning is shown.
cros_network()->SetGlobalPolicy(
/*allow_only_policy_cellular_networks=*/false,
/*dns_queries_monitored=*/true,
/*report_xdr_events_enabled=*/true);
icon = GetConnectionWarningIcon();
ASSERT_THAT(icon, NotNull());
EXPECT_TRUE(IsManagedIcon(icon));
ASSERT_THAT(GetConnectionWarning(), NotNull());
ASSERT_THAT(GetConnectionLabelView(), NotNull());
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_MONITORED_WARNING),
GetConnectionLabelView()->GetText());
}
TEST_P(NetworkListViewControllerTest, NetworkScanning) {
cros_network()->ClearNetworksAndDevices();
int initial_wifi_count = 0;
int initial_tether_count = 0;
// Scanning bar is not visible if WiFi is not enabled.
EXPECT_FALSE(HasScanTimerStarted());
EXPECT_FALSE(GetScanningBarVisibility());
EXPECT_EQ(initial_wifi_count + 0,
cros_network()->GetScanCount(NetworkType::kWiFi));
EXPECT_EQ(initial_wifi_count + 0,
cros_network()->GetScanCount(NetworkType::kTether));
auto wifi_properties =
chromeos::network_config::mojom::DeviceStateProperties::New();
wifi_properties->type = NetworkType::kWiFi;
wifi_properties->scanning = true;
wifi_properties->device_state = DeviceStateType::kEnabled;
cros_network()->SetDeviceProperties(wifi_properties.Clone());
auto tether_properties =
chromeos::network_config::mojom::DeviceStateProperties::New();
tether_properties->type = NetworkType::kTether;
tether_properties->scanning = true;
cros_network()->SetDeviceProperties(tether_properties.Clone());
// Add an enabled WiFi device.
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kWifiName, NetworkType::kWiFi, ConnectionStateType::kConnected));
EXPECT_TRUE(HasScanTimerStarted());
EXPECT_TRUE(GetScanningBarVisibility());
EXPECT_EQ(initial_wifi_count + 1,
cros_network()->GetScanCount(NetworkType::kWiFi));
EXPECT_EQ(initial_wifi_count + 1,
cros_network()->GetScanCount(NetworkType::kTether));
// Simulate scanning finishing.
wifi_properties->scanning = false;
cros_network()->SetDeviceProperties(wifi_properties.Clone());
tether_properties->scanning = false;
cros_network()->SetDeviceProperties(tether_properties.Clone());
// Simulate scanning finishing.
task_environment()->FastForwardBy(kInteractiveDelay);
EXPECT_FALSE(GetScanningBarVisibility());
EXPECT_TRUE(HasScanTimerStarted());
EXPECT_EQ(initial_wifi_count + 1,
cros_network()->GetScanCount(NetworkType::kWiFi));
EXPECT_EQ(initial_tether_count + 1,
cros_network()->GetScanCount(NetworkType::kTether));
// Make sure scan timer is still running.
task_environment()->FastForwardBy(kInteractiveDelay);
EXPECT_TRUE(HasScanTimerStarted());
EXPECT_FALSE(GetScanningBarVisibility());
EXPECT_EQ(initial_wifi_count + 1,
cros_network()->GetScanCount(NetworkType::kWiFi));
EXPECT_EQ(initial_tether_count + 1,
cros_network()->GetScanCount(NetworkType::kTether));
task_environment()->FastForwardBy(kInteractiveDelay);
EXPECT_TRUE(HasScanTimerStarted());
EXPECT_FALSE(GetScanningBarVisibility());
EXPECT_EQ(initial_wifi_count + 1,
cros_network()->GetScanCount(NetworkType::kWiFi));
EXPECT_EQ(initial_tether_count + 1,
cros_network()->GetScanCount(NetworkType::kTether));
// Disabling WiFi device ends scan timer.
wifi_properties->device_state = DeviceStateType::kDisabled;
cros_network()->SetDeviceProperties(wifi_properties.Clone());
EXPECT_FALSE(GetScanningBarVisibility());
EXPECT_FALSE(HasScanTimerStarted());
EXPECT_EQ(initial_wifi_count + 1,
cros_network()->GetScanCount(NetworkType::kWiFi));
EXPECT_EQ(initial_tether_count + 1,
cros_network()->GetScanCount(NetworkType::kTether));
}
TEST_P(NetworkListViewControllerTest, NetworkItemIsEnabled) {
auto properties =
chromeos::network_config::mojom::DeviceStateProperties::New();
properties->type = NetworkType::kCellular;
properties->device_state = DeviceStateType::kEnabled;
properties->sim_infos = CellularSIMInfos(kCellularTestIccid, kTestBaseEid);
cros_network()->SetDeviceProperties(properties.Clone());
ASSERT_THAT(GetMobileSubHeader(), NotNull());
EXPECT_TRUE(GetAddESimEntry()->GetVisible());
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kCellularName, NetworkType::kCellular,
ConnectionStateType::kConnected));
CheckNetworkListItem(NetworkType::kCellular, /*index=*/0u, kCellularName);
EXPECT_TRUE(GetNetworkListItemIsEnabled(NetworkType::kCellular, 0u));
// Inhibit cellular device.
properties->inhibit_reason = InhibitReason::kResettingEuiccMemory;
cros_network()->SetDeviceProperties(properties.Clone());
EXPECT_FALSE(GetNetworkListItemIsEnabled(NetworkType::kCellular, 0u));
// Uninhibit the device.
properties->inhibit_reason = InhibitReason::kNotInhibited;
cros_network()->SetDeviceProperties(properties.Clone());
EXPECT_TRUE(GetNetworkListItemIsEnabled(NetworkType::kCellular, 0u));
}
TEST_P(NetworkListViewControllerTest, NetworkItemDuringFlashing) {
auto properties =
chromeos::network_config::mojom::DeviceStateProperties::New();
properties->type = NetworkType::kCellular;
properties->device_state = DeviceStateType::kEnabled;
properties->sim_infos = CellularSIMInfos(kCellularTestIccid, kTestBaseEid);
cros_network()->SetDeviceProperties(properties.Clone());
ASSERT_THAT(GetMobileSubHeader(), NotNull());
EXPECT_TRUE(GetAddESimEntry()->GetVisible());
cros_network()->AddNetworkAndDevice(
CrosNetworkConfigTestHelper::CreateStandaloneNetworkProperties(
kCellularName, NetworkType::kCellular,
ConnectionStateType::kConnected));
CheckNetworkListItem(NetworkType::kCellular, /*index=*/0u, kCellularName);
EXPECT_TRUE(GetNetworkListItemIsEnabled(NetworkType::kCellular, 0u));
properties->is_flashing = true;
cros_network()->SetDeviceProperties(properties.Clone());
EXPECT_FALSE(GetNetworkListItemIsEnabled(NetworkType::kCellular, 0u));
ASSERT_THAT(GetMobileStatusMessage(), NotNull());
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_UPDATING),
GetMobileStatusMessage()->label()->GetText());
properties->is_flashing = false;
cros_network()->SetDeviceProperties(properties.Clone());
EXPECT_TRUE(GetNetworkListItemIsEnabled(NetworkType::kCellular, 0u));
EXPECT_THAT(GetMobileStatusMessage(), IsNull());
}
} // namespace ash