0

[Instant Hotspot] Add "Set Up Your Device" button

This is one of two changes needed to implement the "Set Up Your Device"
button in Network Quick Settings

UI Deck: https://docs.google.com/presentation/d/1EDKDiBCu-KLgGGHL0Laz90S2BsEzU0HLuanbDHhpzdI/edit?resourcekey=0-HLWeff66N6-mD6ZIZFnWSg#slide=id.g21d9e5a24ff_0_0

This button is shown in the "Your Devices" section if the user has one eligible device for hotspot which is not currently enabled.

This change adds the button, if the user has a device to set up

Example: https://screenshot.googleplex.com/9xebZ3MhdNWzLap

Bug=b/321940291
Test: Added Unit Tests

Change-Id: Ic0a0759979dd10e419f8ba7f9f1928f89944c9ea
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5253708
Reviewed-by: James Cook <jamescook@chromium.org>
Commit-Queue: Joe Antonetti <joeantonetti@google.com>
Reviewed-by: Nikhil Nayunigari <nikhilcn@google.com>
Reviewed-by: Chad Duffin <chadduffin@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1268627}
This commit is contained in:
Joe Antonetti
2024-03-05 19:52:14 +00:00
committed by Chromium LUCI CQ
parent 200c86fe52
commit 5f27575331
11 changed files with 118 additions and 26 deletions

@ -76,6 +76,7 @@ include_rules = [
"+chromeos/ash/components/multidevice",
"+chromeos/ash/components/osauth/public",
"+chromeos/ash/components/peripheral_notification",
"+chromeos/ash/components/phonehub",
"+chromeos/ash/components/proximity_auth",
"+chromeos/ash/components/string_matching",
"+chromeos/ash/components/system",

@ -2901,6 +2901,9 @@ Some features are limited to increase battery life.
<message name="IDS_ASH_QUICK_SETTINGS_JOIN_WIFI_NETWORK" desc="The label used in the network detailed page for the Join Wi-Fi network entry">
Join Wi-Fi network
</message>
<message name="IDS_ASH_QUICK_SETTINGS_SET_UP_YOUR_DEVICE" desc="The label used in the network detailed page for the Set Up Your Device network entry">
Set up your device
</message>
<message name="IDS_ASH_QUICK_SETTINGS_ADD_ESIM" desc="The label used in the network detailed page for the Add eSIM network entry">
Add eSIM
</message>

@ -0,0 +1 @@
9fc5788edcfe9a0da22da17a7267b0028d903da9

@ -22,6 +22,7 @@
#include "base/metrics/histogram_functions.h"
#include "base/strings/utf_string_conversions.h"
#include "chromeos/ash/components/multidevice/logging/logging.h"
#include "chromeos/ash/components/phonehub/util/histogram_util.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/chromeos/devicetype_utils.h"
#include "ui/message_center/message_center.h"
@ -255,6 +256,9 @@ void MultiDeviceNotificationPresenter::OnNotificationClicked(
switch (notification_status_) {
case Status::kNewUserNotificationVisible:
Shell::Get()->system_tray_model()->client()->ShowMultiDeviceSetup();
phonehub::util::LogMultiDeviceSetupDialogEntryPoint(
ash::phonehub::util::MultiDeviceSetupDialogEntrypoint::
kSetupNotification);
// If user has not interacted with Phone Hub icon when the notification is
// visible, log MultiDeviceSetup.NotificationInteracted event when
// notification is clicked.

@ -60,6 +60,10 @@ enum ViewID {
VIEW_ID_MEDIA_TRAY_VIEW,
// The entry to open cross-device settings in the quick settings network
// subpage.
VIEW_ID_OPEN_CROSS_DEVICE_SETTINGS,
// Pinned notification view:
VIEW_ID_PINNED_NOTIFICATION_ICON,
VIEW_ID_PINNED_NOTIFICATION_PILL_BUTTON,

@ -42,13 +42,19 @@ constexpr auto kTopContainerBorder = gfx::Insets::TLBR(4, 0, 4, 4);
constexpr auto kBetweenContainerMargins = gfx::Insets::TLBR(6, 0, 0, 0);
// The following getter methods should only be used for
// `NetworkType::kWiFi`, `NetworkType::kMobile`, or `NetworkType::kCellular`
// types otherwise a crash will occur.
std::u16string GetLabelForWifiAndMobileNetwork(NetworkType type) {
// `NetworkType::kWiFi`, `NetworkType::kTether`, `NetworkType::kMobile`, or
// `NetworkType::kCellular` types otherwise a crash will occur.
std::u16string GetLabelForConfigureNetworkEntry(NetworkType type) {
switch (type) {
case NetworkType::kWiFi:
return l10n_util::GetStringUTF16(
IDS_ASH_QUICK_SETTINGS_JOIN_WIFI_NETWORK);
case NetworkType::kTether:
if (features::IsInstantHotspotRebrandEnabled()) {
return l10n_util::GetStringUTF16(
IDS_ASH_QUICK_SETTINGS_SET_UP_YOUR_DEVICE);
}
[[fallthrough]];
case NetworkType::kCellular:
[[fallthrough]];
case NetworkType::kMobile:
@ -58,10 +64,16 @@ std::u16string GetLabelForWifiAndMobileNetwork(NetworkType type) {
}
}
std::u16string GetTooltipForWifiAndMobileNetwork(NetworkType type) {
std::optional<std::u16string> GetTooltipForConfigureNetworkEntry(
NetworkType type) {
switch (type) {
case NetworkType::kWiFi:
return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_OTHER_WIFI);
case NetworkType::kTether:
if (features::IsInstantHotspotRebrandEnabled()) {
return std::nullopt;
}
[[fallthrough]];
case NetworkType::kCellular:
[[fallthrough]];
case NetworkType::kMobile:
@ -71,10 +83,15 @@ std::u16string GetTooltipForWifiAndMobileNetwork(NetworkType type) {
}
}
int GetViewIDForWifiAndMobileNetwork(NetworkType type) {
int GetViewIDForConfigureNetworkEntry(NetworkType type) {
switch (type) {
case NetworkType::kWiFi:
return VIEW_ID_JOIN_WIFI_NETWORK_ENTRY;
case NetworkType::kTether:
if (features::IsInstantHotspotRebrandEnabled()) {
return VIEW_ID_OPEN_CROSS_DEVICE_SETTINGS;
}
[[fallthrough]];
case NetworkType::kCellular:
[[fallthrough]];
case NetworkType::kMobile:
@ -130,17 +147,23 @@ NetworkListNetworkItemView* NetworkDetailedNetworkViewImpl::AddNetworkListItem(
HoverHighlightView* NetworkDetailedNetworkViewImpl::AddConfigureNetworkEntry(
NetworkType type) {
CHECK(type == NetworkType::kWiFi || type == NetworkType::kMobile ||
type == NetworkType::kCellular);
type == NetworkType::kCellular ||
(features::IsInstantHotspotRebrandEnabled() &&
type == NetworkType::kTether));
HoverHighlightView* entry = GetNetworkList(type)->AddChildView(
std::make_unique<HoverHighlightView>(/*listener=*/this));
entry->SetID(GetViewIDForWifiAndMobileNetwork(type));
entry->SetTooltipText(GetTooltipForWifiAndMobileNetwork(type));
entry->SetID(GetViewIDForConfigureNetworkEntry(type));
auto tooltip_text = GetTooltipForConfigureNetworkEntry(type);
if (tooltip_text.has_value()) {
entry->SetTooltipText(tooltip_text.value());
}
auto image_view = std::make_unique<views::ImageView>();
image_view->SetImage(ui::ImageModel::FromVectorIcon(
kSystemMenuPlusIcon, cros_tokens::kCrosSysPrimary));
entry->AddViewAndLabel(std::move(image_view),
GetLabelForWifiAndMobileNetwork(type));
GetLabelForConfigureNetworkEntry(type));
views::Label* label = entry->text_label();
label->SetEnabledColorId(cros_tokens::kCrosSysPrimary);
TypographyProvider::Get()->StyleLabel(ash::TypographyToken::kCrosButton2,

@ -64,6 +64,12 @@ void NetworkDetailedView::HandleViewClicked(views::View* view) {
return;
}
if (view->GetID() == VIEW_ID_OPEN_CROSS_DEVICE_SETTINGS) {
// TODO (b/323346091): Add metric for "Set Up Your Device" clicks
Shell::Get()->system_tray_model()->client()->ShowMultiDeviceSetup();
return;
}
if (view->GetID() == VIEW_ID_ADD_ESIM_ENTRY) {
base::RecordAction(base::UserMetricsAction("QS_Subpage_Network_AddESim"));
Shell::Get()->system_tray_model()->client()->ShowNetworkCreate(

@ -305,19 +305,29 @@ void NetworkListViewControllerImpl::OnGetNetworkStateList(
network_detailed_network_view()->ReorderTetherHostsTopContainer(index++);
size_t tether_item_index = 0;
tether_item_index = CreateItemViewsIfMissingAndReorder(
NetworkType::kTether, tether_item_index, networks,
&previous_network_views);
// Add tether hosts status message to NetworkDetailedNetworkView's
// `tether_hosts_network_list_view_` if it exist.
if (tether_hosts_status_message_) {
network_detailed_network_view()
->GetNetworkList(NetworkType::kTether)
->ReorderChildView(tether_hosts_status_message_,
tether_item_index++);
if (has_phone_eligible_for_setup_) {
// This does not remote tether_hosts_status_message_, as
// UpdateTetherHostsSection() ensures tether_hosts_status_message_ does
// not exist if has_phone_eligible_for_setup_ is true
tether_item_index = CreateConfigureNetworkEntry(
&set_up_cross_device_suite_entry_, NetworkType::kTether,
tether_item_index);
} else {
RemoveAndResetViewIfExists(&set_up_cross_device_suite_entry_);
tether_item_index = CreateItemViewsIfMissingAndReorder(
NetworkType::kTether, tether_item_index, networks,
&previous_network_views);
// Add tether hosts status message to NetworkDetailedNetworkView's
// `tether_hosts_network_list_view_` if it exist.
if (tether_hosts_status_message_) {
network_detailed_network_view()
->GetNetworkList(NetworkType::kTether)
->ReorderChildView(tether_hosts_status_message_,
tether_item_index);
}
}
network_detailed_network_view()->ReorderTetherHostsListView(index++);
} else {
RemoveAndResetViewIfExists(&tether_hosts_header_view_);
@ -693,20 +703,22 @@ void NetworkListViewControllerImpl::UpdateMobileSection() {
}
void NetworkListViewControllerImpl::UpdateTetherHostsSection() {
CHECK(features::IsInstantHotspotRebrandEnabled());
if (!tether_hosts_header_view_) {
return;
}
network_detailed_network_view()->UpdateTetherHostsStatus(true);
network_detailed_network_view()->UpdateTetherHostsStatus(/*enabled=*/true);
if (!IsBluetoothEnabledOrEnabling(bluetooth_system_state_)) {
if (!IsBluetoothEnabledOrEnabling(bluetooth_system_state_) &&
!has_phone_eligible_for_setup_) {
CreateInfoLabelIfMissingAndUpdate(
IDS_ASH_STATUS_TRAY_NETWORK_TETHER_NO_BLUETOOTH,
&tether_hosts_status_message_);
return;
}
if (!has_tether_networks_) {
if (!has_tether_networks_ && !has_phone_eligible_for_setup_) {
CreateInfoLabelIfMissingAndUpdate(
IDS_ASH_STATUS_TRAY_NETWORK_NO_TETHER_DEVICES_FOUND,
&tether_hosts_status_message_);

@ -279,6 +279,10 @@ class ASH_EXPORT NetworkListViewControllerImpl
// This field is not a raw_ptr<> because it was filtered by the rewriter
// for: #addr-of
RAW_PTR_EXCLUSION HoverHighlightView* add_esim_entry_ = nullptr;
// This field is not a raw_ptr<> because it was filtered by the rewriter
// for: #addr-of
RAW_PTR_EXCLUSION HoverHighlightView* set_up_cross_device_suite_entry_ =
nullptr;
bool has_cellular_networks_;
bool has_wifi_networks_;

@ -259,6 +259,11 @@ class NetworkListViewControllerTest : public AshTestBase,
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);
}
@ -882,8 +887,40 @@ TEST_P(NetworkListViewControllerTest,
// 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());
}
}

@ -717,9 +717,6 @@ void SystemTrayClientImpl::ShowNetworkSettingsHelper(
void SystemTrayClientImpl::ShowMultiDeviceSetup() {
ash::multidevice_setup::MultiDeviceSetupDialog::Show();
ash::phonehub::util::LogMultiDeviceSetupDialogEntryPoint(
ash::phonehub::util::MultiDeviceSetupDialogEntrypoint::
kSetupNotification);
}
void SystemTrayClientImpl::ShowFirmwareUpdate() {