[FreezeCast] Add freeze button in cast subpage
In the case that a casting session may be frozen, add a button for pausing / resuming, depending on the current state of the session. Since the pause button and stop button cannot fit together on a line with the device name, put them on a separate line below the device. Ensure the stop button will be aligned with the stop buttons of devices that are not freezable. Pause: https://screenshot.googleplex.com/5PsydzGks7oh2SJ.png Resume: https://screenshot.googleplex.com/ALrYGRQBDWpkqnR.png Bug: b:284516619 Change-Id: I250723afd6c3216f0e1a203c68f6aeded62c8bef Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4571349 Reviewed-by: Takumi Fujimoto <takumif@chromium.org> Reviewed-by: Evan Stade <estade@chromium.org> Commit-Queue: Benjamin Zielinski <bzielinski@google.com> Cr-Commit-Position: refs/heads/main@{#1153372}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
c3301a2ffc
commit
2c2f718aea
ash
@ -606,9 +606,15 @@ Style notes:
|
||||
<message name="IDS_ASH_STATUS_TRAY_CAST_PAUSE" desc="Label for a button in the cast notification to pause the current cast mirroring session to a Chromecast device">
|
||||
Pause
|
||||
</message>
|
||||
<message name="IDS_ASH_STATUS_TRAY_CAST_PAUSE_CASTING" desc="Label for a button in the system tray to pause the current cast mirroring session to a Chromecast device">
|
||||
Pause casting
|
||||
</message>
|
||||
<message name="IDS_ASH_STATUS_TRAY_CAST_RESUME" desc="Label for a button in the cast notification to resume a paused cast mirroring session to a Chromecast device">
|
||||
Resume
|
||||
</message>
|
||||
<message name="IDS_ASH_STATUS_TRAY_CAST_RESUME_CASTING" desc="Label for a button in the system tray to resume a paused cast mirroring session to a Chromecast device">
|
||||
Resume casting
|
||||
</message>
|
||||
<message name="IDS_ASH_STATUS_TRAY_QUIET_MODE_TOOLTIP" desc="The tooltip text for the status area icon to tell do-not-disturb mode is currently on.">
|
||||
Do Not Disturb is on
|
||||
</message>
|
||||
|
@ -0,0 +1 @@
|
||||
c8647e60121c1b5a16205154492ba70f83d50d29
|
@ -0,0 +1 @@
|
||||
12ca3db87ee67fdfa25fd132901a7f491ef74f29
|
@ -269,6 +269,8 @@ aggregate_vector_icons("ash_vector_icons") {
|
||||
"quick_settings_a11y_sticky_keys.icon",
|
||||
"quick_settings_cast.icon",
|
||||
"quick_settings_cast_connected.icon",
|
||||
"quick_settings_circle_pause.icon",
|
||||
"quick_settings_circle_play.icon",
|
||||
"quick_settings_circle_stop.icon",
|
||||
"quick_settings_left_arrow.icon",
|
||||
"quick_settings_managed.icon",
|
||||
|
45
ash/resources/vector_icons/quick_settings_circle_pause.icon
Normal file
45
ash/resources/vector_icons/quick_settings_circle_pause.icon
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
CANVAS_DIMENSIONS, 20,
|
||||
MOVE_TO, 7.5f, 13,
|
||||
H_LINE_TO, 9,
|
||||
V_LINE_TO, 7,
|
||||
H_LINE_TO, 7.5f,
|
||||
V_LINE_TO, 13,
|
||||
CLOSE,
|
||||
MOVE_TO, 11, 13,
|
||||
H_LINE_TO, 12.5f,
|
||||
V_LINE_TO, 7,
|
||||
H_LINE_TO, 11,
|
||||
V_LINE_TO, 13,
|
||||
CLOSE,
|
||||
MOVE_TO, 10, 18,
|
||||
CUBIC_TO, 8.9f, 18, 7.87f, 17.79f, 6.9f, 17.38f,
|
||||
CUBIC_TO, 5.92f, 16.96f, 5.07f, 16.39f, 4.33f, 15.67f,
|
||||
CUBIC_TO, 3.61f, 14.93f, 3.04f, 14.08f, 2.63f, 13.1f,
|
||||
CUBIC_TO, 2.21f, 12.13f, 2, 11.1f, 2, 10,
|
||||
CUBIC_TO, 2, 8.89f, 2.21f, 7.85f, 2.63f, 6.9f,
|
||||
CUBIC_TO, 3.04f, 5.92f, 3.61f, 5.08f, 4.33f, 4.35f,
|
||||
CUBIC_TO, 5.07f, 3.62f, 5.92f, 3.04f, 6.9f, 2.63f,
|
||||
CUBIC_TO, 7.87f, 2.21f, 8.9f, 2, 10, 2,
|
||||
CUBIC_TO, 11.11f, 2, 12.15f, 2.21f, 13.1f, 2.63f,
|
||||
CUBIC_TO, 14.08f, 3.04f, 14.92f, 3.62f, 15.65f, 4.35f,
|
||||
CUBIC_TO, 16.38f, 5.08f, 16.96f, 5.92f, 17.38f, 6.9f,
|
||||
CUBIC_TO, 17.79f, 7.85f, 18, 8.89f, 18, 10,
|
||||
CUBIC_TO, 18, 11.1f, 17.79f, 12.13f, 17.38f, 13.1f,
|
||||
CUBIC_TO, 16.96f, 14.08f, 16.38f, 14.93f, 15.65f, 15.67f,
|
||||
CUBIC_TO, 14.92f, 16.39f, 14.08f, 16.96f, 13.1f, 17.38f,
|
||||
CUBIC_TO, 12.15f, 17.79f, 11.11f, 18, 10, 18,
|
||||
CLOSE,
|
||||
MOVE_TO, 10, 16.5f,
|
||||
CUBIC_TO, 11.81f, 16.5f, 13.34f, 15.87f, 14.6f, 14.6f,
|
||||
CUBIC_TO, 15.87f, 13.34f, 16.5f, 11.81f, 16.5f, 10,
|
||||
CUBIC_TO, 16.5f, 8.19f, 15.87f, 6.66f, 14.6f, 5.4f,
|
||||
CUBIC_TO, 13.34f, 4.13f, 11.81f, 3.5f, 10, 3.5f,
|
||||
CUBIC_TO, 8.19f, 3.5f, 6.66f, 4.13f, 5.4f, 5.4f,
|
||||
CUBIC_TO, 4.13f, 6.66f, 3.5f, 8.19f, 3.5f, 10,
|
||||
CUBIC_TO, 3.5f, 11.81f, 4.13f, 13.34f, 5.4f, 14.6f,
|
||||
CUBIC_TO, 6.66f, 15.87f, 8.19f, 16.5f, 10, 16.5f,
|
||||
CLOSE
|
38
ash/resources/vector_icons/quick_settings_circle_play.icon
Normal file
38
ash/resources/vector_icons/quick_settings_circle_play.icon
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
CANVAS_DIMENSIONS, 20,
|
||||
MOVE_TO, 8, 13.5f,
|
||||
LINE_TO, 13.5f, 10,
|
||||
LINE_TO, 8, 6.5f,
|
||||
V_LINE_TO, 13.5f,
|
||||
CLOSE,
|
||||
MOVE_TO, 10, 18,
|
||||
CUBIC_TO, 8.9f, 18, 7.87f, 17.79f, 6.9f, 17.38f,
|
||||
CUBIC_TO, 5.92f, 16.96f, 5.07f, 16.39f, 4.33f, 15.67f,
|
||||
CUBIC_TO, 3.61f, 14.93f, 3.04f, 14.08f, 2.63f, 13.1f,
|
||||
CUBIC_TO, 2.21f, 12.13f, 2, 11.1f, 2, 10,
|
||||
CUBIC_TO, 2, 8.89f, 2.21f, 7.85f, 2.63f, 6.9f,
|
||||
CUBIC_TO, 3.04f, 5.92f, 3.61f, 5.08f, 4.33f, 4.35f,
|
||||
CUBIC_TO, 5.07f, 3.62f, 5.92f, 3.04f, 6.9f, 2.63f,
|
||||
CUBIC_TO, 7.87f, 2.21f, 8.9f, 2, 10, 2,
|
||||
CUBIC_TO, 11.11f, 2, 12.15f, 2.21f, 13.1f, 2.63f,
|
||||
CUBIC_TO, 14.08f, 3.04f, 14.92f, 3.62f, 15.65f, 4.35f,
|
||||
CUBIC_TO, 16.38f, 5.08f, 16.96f, 5.92f, 17.38f, 6.9f,
|
||||
CUBIC_TO, 17.79f, 7.85f, 18, 8.89f, 18, 10,
|
||||
CUBIC_TO, 18, 11.1f, 17.79f, 12.13f, 17.38f, 13.1f,
|
||||
CUBIC_TO, 16.96f, 14.08f, 16.38f, 14.93f, 15.65f, 15.67f,
|
||||
CUBIC_TO, 14.92f, 16.39f, 14.08f, 16.96f, 13.1f, 17.38f,
|
||||
CUBIC_TO, 12.15f, 17.79f, 11.11f, 18, 10, 18,
|
||||
CLOSE,
|
||||
MOVE_TO, 10, 16.5f,
|
||||
CUBIC_TO, 11.81f, 16.5f, 13.34f, 15.87f, 14.6f, 14.6f,
|
||||
CUBIC_TO, 15.87f, 13.34f, 16.5f, 11.81f, 16.5f, 10,
|
||||
CUBIC_TO, 16.5f, 8.19f, 15.87f, 6.66f, 14.6f, 5.4f,
|
||||
CUBIC_TO, 13.34f, 4.13f, 11.81f, 3.5f, 10, 3.5f,
|
||||
CUBIC_TO, 8.19f, 3.5f, 6.66f, 4.13f, 5.4f, 5.4f,
|
||||
CUBIC_TO, 4.13f, 6.66f, 3.5f, 8.19f, 3.5f, 10,
|
||||
CUBIC_TO, 3.5f, 11.81f, 4.13f, 13.34f, 5.4f, 14.6f,
|
||||
CUBIC_TO, 6.66f, 15.87f, 8.19f, 16.5f, 10, 16.5f,
|
||||
CLOSE
|
@ -35,11 +35,15 @@
|
||||
#include "ui/views/border.h"
|
||||
#include "ui/views/controls/scroll_view.h"
|
||||
#include "ui/views/layout/box_layout.h"
|
||||
#include "ui/views/view_class_properties.h"
|
||||
|
||||
namespace ash {
|
||||
|
||||
namespace {
|
||||
|
||||
// Extra spacing to add between cast stop buttons and the edge of the qs tray.
|
||||
constexpr int kStopButtonExtraMargin = 4;
|
||||
|
||||
// Returns the correct vector icon for |icon_type|. Some types may be different
|
||||
// for branded builds.
|
||||
const gfx::VectorIcon& SinkIconTypeToIcon(SinkIconType icon_type) {
|
||||
@ -65,6 +69,21 @@ const gfx::VectorIcon& SinkIconTypeToIcon(SinkIconType icon_type) {
|
||||
return kSystemMenuCastGenericIcon;
|
||||
}
|
||||
|
||||
std::unique_ptr<views::View> MakeButtonContainer() {
|
||||
std::unique_ptr<views::View> button_container =
|
||||
std::make_unique<views::View>();
|
||||
views::BoxLayout* manager =
|
||||
button_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
|
||||
views::BoxLayout::Orientation::kHorizontal));
|
||||
manager->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kEnd);
|
||||
manager->set_between_child_spacing(kTrayPopupLabelRightPadding);
|
||||
button_container->SetProperty(
|
||||
views::kMarginsKey,
|
||||
gfx::Insets::TLBR(0, 0, 0,
|
||||
kStopButtonExtraMargin + kQsExtraMarginsFromRightEdge));
|
||||
return button_container;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
CastDetailedView::CastDetailedView(DetailedViewDelegate* delegate)
|
||||
@ -85,40 +104,18 @@ void CastDetailedView::CreateItems() {
|
||||
|
||||
void CastDetailedView::OnDevicesUpdated(
|
||||
const std::vector<SinkAndRoute>& sinks_routes) {
|
||||
sinks_and_routes_.clear();
|
||||
// Add/update existing.
|
||||
for (const auto& device : sinks_routes)
|
||||
sinks_and_routes_.insert(std::make_pair(device.sink.id, device));
|
||||
|
||||
// Remove non-existent sinks. Removing an element invalidates all existing
|
||||
// iterators.
|
||||
auto iter = sinks_and_routes_.begin();
|
||||
while (iter != sinks_and_routes_.end()) {
|
||||
bool has_receiver = false;
|
||||
for (auto& receiver : sinks_routes) {
|
||||
if (iter->first == receiver.sink.id)
|
||||
has_receiver = true;
|
||||
}
|
||||
|
||||
if (has_receiver)
|
||||
++iter;
|
||||
else
|
||||
iter = sinks_and_routes_.erase(iter);
|
||||
}
|
||||
|
||||
// Update UI.
|
||||
UpdateReceiverListFromCachedData();
|
||||
Layout();
|
||||
}
|
||||
|
||||
void CastDetailedView::UpdateReceiverListFromCachedData() {
|
||||
// Remove all of the existing views.
|
||||
view_to_sink_map_.clear();
|
||||
scroll_content()->RemoveAllChildViews();
|
||||
add_access_code_device_ = nullptr;
|
||||
if (zero_state_view_) {
|
||||
RemoveChildViewT(zero_state_view_.get());
|
||||
zero_state_view_ = nullptr;
|
||||
}
|
||||
RemoveAllViews();
|
||||
|
||||
// QsRevamp places items in a rounded container.
|
||||
const bool is_qs_revamp_enabled = features::IsQsRevampEnabled();
|
||||
@ -130,18 +127,7 @@ void CastDetailedView::UpdateReceiverListFromCachedData() {
|
||||
// Per product requirement, access code receiver should be shown before other
|
||||
// receivers.
|
||||
if (CastConfigController::Get()->AccessCodeCastingEnabled()) {
|
||||
add_access_code_device_ = AddScrollListItem(
|
||||
item_container, vector_icons::kKeyboardIcon,
|
||||
l10n_util::GetStringUTF16(
|
||||
IDS_ASH_STATUS_TRAY_CAST_ACCESS_CODE_CAST_CONNECT));
|
||||
if (chromeos::features::IsJellyEnabled()) {
|
||||
// `views::ImageView` does not support changing the color, so set the
|
||||
// image with an updated `ui::ImageModel`.
|
||||
add_access_code_device_->icon()->SetImage(ui::ImageModel::FromVectorIcon(
|
||||
vector_icons::kKeyboardIcon, cros_tokens::kCrosSysPrimary));
|
||||
add_access_code_device_->text_label()->SetEnabledColorId(
|
||||
cros_tokens::kCrosSysPrimary);
|
||||
}
|
||||
AddAccessCodeCastButton(item_container);
|
||||
}
|
||||
|
||||
// Add a view for each receiver.
|
||||
@ -153,20 +139,10 @@ void CastDetailedView::UpdateReceiverListFromCachedData() {
|
||||
base::UTF8ToUTF16(sink.name));
|
||||
view_to_sink_map_[container] = sink.id;
|
||||
|
||||
// Add a stop casting button if this machine ("local source") is casting to
|
||||
// the device. See also CastNotificationController::OnDevicesUpdated().
|
||||
// Add receiver action buttons if this machine ("local source") is casting
|
||||
// to the device. See also CastNotificationController::OnDevicesUpdated().
|
||||
if (is_qs_revamp_enabled && !route.id.empty() && route.is_local_source) {
|
||||
auto button = std::make_unique<PillButton>(
|
||||
base::BindRepeating(&CastDetailedView::StopCasting,
|
||||
base::Unretained(this), route.id),
|
||||
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAST_STOP_CASTING),
|
||||
PillButton::kDefaultWithIconLeading, &kQuickSettingsCircleStopIcon);
|
||||
button->SetBackgroundColorId(cros_tokens::kCrosSysErrorContainer);
|
||||
button->SetIconColorId(cros_tokens::kCrosSysError);
|
||||
button->SetButtonTextColorId(cros_tokens::kCrosSysError);
|
||||
container->AddRightView(
|
||||
button.release(),
|
||||
views::CreateEmptyBorder(gfx::Insets::TLBR(0, 0, 0, 4)));
|
||||
AddReceiverActionButtons(sink, route, container, item_container);
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,6 +197,102 @@ void CastDetailedView::StopCasting(const std::string& route_id) {
|
||||
CloseBubble(); // Deletes `this`.
|
||||
}
|
||||
|
||||
void CastDetailedView::FreezePressed(const std::string& route_id,
|
||||
bool is_frozen) {
|
||||
DCHECK(features::IsQsRevampEnabled());
|
||||
if (is_frozen) {
|
||||
CastConfigController::Get()->UnfreezeRoute(route_id);
|
||||
} else {
|
||||
CastConfigController::Get()->FreezeRoute(route_id);
|
||||
CloseBubble();
|
||||
}
|
||||
}
|
||||
|
||||
void CastDetailedView::RemoveAllViews() {
|
||||
view_to_sink_map_.clear();
|
||||
sink_extra_views_map_.clear();
|
||||
scroll_content()->RemoveAllChildViews();
|
||||
add_access_code_device_ = nullptr;
|
||||
if (zero_state_view_) {
|
||||
RemoveChildViewT(zero_state_view_.get());
|
||||
zero_state_view_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CastDetailedView::AddAccessCodeCastButton(
|
||||
views::View* receiver_list_view) {
|
||||
add_access_code_device_ =
|
||||
AddScrollListItem(receiver_list_view, vector_icons::kKeyboardIcon,
|
||||
l10n_util::GetStringUTF16(
|
||||
IDS_ASH_STATUS_TRAY_CAST_ACCESS_CODE_CAST_CONNECT));
|
||||
if (chromeos::features::IsJellyEnabled()) {
|
||||
// `views::ImageView` does not support changing the color, so set the
|
||||
// image with an updated `ui::ImageModel`.
|
||||
add_access_code_device_->icon()->SetImage(ui::ImageModel::FromVectorIcon(
|
||||
vector_icons::kKeyboardIcon, cros_tokens::kCrosSysPrimary));
|
||||
add_access_code_device_->text_label()->SetEnabledColorId(
|
||||
cros_tokens::kCrosSysPrimary);
|
||||
}
|
||||
}
|
||||
|
||||
void CastDetailedView::AddReceiverActionButtons(
|
||||
const CastSink& sink,
|
||||
const CastRoute& route,
|
||||
HoverHighlightView* receiver_view,
|
||||
views::View* receiver_list_view) {
|
||||
std::unique_ptr<PillButton> stop_button = CreateStopButton(route);
|
||||
|
||||
// In the case that we want to show a pause/resume button, then we must
|
||||
// put both buttons on a row below the cast sink.
|
||||
if (route.freeze_info.can_freeze) {
|
||||
std::unique_ptr<PillButton> freeze_button = CreateFreezeButton(route);
|
||||
std::unique_ptr<views::View> button_container = MakeButtonContainer();
|
||||
std::vector<views::View*> extra_views;
|
||||
extra_views.emplace_back(
|
||||
button_container->AddChildView(std::move(freeze_button)));
|
||||
extra_views.emplace_back(
|
||||
button_container->AddChildView(std::move(stop_button)));
|
||||
sink_extra_views_map_[sink.id] = extra_views;
|
||||
|
||||
// Add the button container directly as a new row in the list of cast
|
||||
// devices. Since the associated device was just added, the buttons will
|
||||
// show up correctly below their associated device.
|
||||
receiver_list_view->AddChildView(std::move(button_container));
|
||||
} else {
|
||||
receiver_view->AddRightView(stop_button.release(),
|
||||
views::CreateEmptyBorder(gfx::Insets::TLBR(
|
||||
0, 0, 0, kStopButtonExtraMargin)));
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<PillButton> CastDetailedView::CreateStopButton(
|
||||
const CastRoute& route) {
|
||||
std::unique_ptr<PillButton> stop_button = std::make_unique<PillButton>(
|
||||
base::BindRepeating(&CastDetailedView::StopCasting,
|
||||
base::Unretained(this), route.id),
|
||||
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAST_STOP_CASTING),
|
||||
PillButton::kDefaultWithIconLeading, &kQuickSettingsCircleStopIcon);
|
||||
stop_button->SetBackgroundColorId(cros_tokens::kCrosSysErrorContainer);
|
||||
stop_button->SetIconColorId(cros_tokens::kCrosSysError);
|
||||
stop_button->SetButtonTextColorId(cros_tokens::kCrosSysError);
|
||||
return stop_button;
|
||||
}
|
||||
|
||||
std::unique_ptr<PillButton> CastDetailedView::CreateFreezeButton(
|
||||
const CastRoute& route) {
|
||||
std::unique_ptr<PillButton> freeze_button = std::make_unique<PillButton>(
|
||||
base::BindRepeating(&CastDetailedView::FreezePressed,
|
||||
base::Unretained(this), route.id,
|
||||
route.freeze_info.is_frozen),
|
||||
route.freeze_info.is_frozen
|
||||
? l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAST_RESUME_CASTING)
|
||||
: l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAST_PAUSE_CASTING),
|
||||
PillButton::kSecondaryWithIconLeading,
|
||||
route.freeze_info.is_frozen ? &kQuickSettingsCirclePlayIcon
|
||||
: &kQuickSettingsCirclePauseIcon);
|
||||
return freeze_button;
|
||||
}
|
||||
|
||||
BEGIN_METADATA(CastDetailedView, TrayDetailedView)
|
||||
END_METADATA
|
||||
|
||||
|
@ -22,6 +22,7 @@ class View;
|
||||
namespace ash {
|
||||
|
||||
class HoverHighlightView;
|
||||
class PillButton;
|
||||
|
||||
// This view displays a list of cast receivers that can be clicked on and casted
|
||||
// to. It is activated by clicking on the chevron inside of
|
||||
@ -61,12 +62,38 @@ class ASH_EXPORT CastDetailedView : public TrayDetailedView,
|
||||
// Stops casting the route identified by `route_id`.
|
||||
void StopCasting(const std::string& route_id);
|
||||
|
||||
// Pauses or resumes the route given by `route_id`.
|
||||
void FreezePressed(const std::string& route_id, bool is_frozen);
|
||||
|
||||
// Remove all child views from CastDetailedView.
|
||||
void RemoveAllViews();
|
||||
|
||||
// Adds a button which allows for adding a device using an access code.
|
||||
void AddAccessCodeCastButton(views::View* receiver_list_view);
|
||||
|
||||
// Adds buttons associated with a receiver so the user may perform route
|
||||
// actions like stopping or pausing.
|
||||
void AddReceiverActionButtons(const CastSink& sink,
|
||||
const CastRoute& route,
|
||||
HoverHighlightView* receiver_view,
|
||||
views::View* receiver_list_view);
|
||||
|
||||
// Creates a stop button which, when pressed, stops the associated `route`.
|
||||
std::unique_ptr<PillButton> CreateStopButton(const CastRoute& route);
|
||||
|
||||
// Creates a freeze button which, when pressed, pauses / resumes the
|
||||
// associated `route`.
|
||||
std::unique_ptr<PillButton> CreateFreezeButton(const CastRoute& route);
|
||||
|
||||
// A mapping from the sink id to the receiver/activity data.
|
||||
std::map<std::string, SinkAndRoute> sinks_and_routes_;
|
||||
|
||||
// A mapping from the view pointer to the associated activity sink id.
|
||||
std::map<views::View*, std::string> view_to_sink_map_;
|
||||
|
||||
// A mapping of sink id to the associated extra views.
|
||||
std::map<std::string, std::vector<views::View*>> sink_extra_views_map_;
|
||||
|
||||
// Special list item that, if clicked, launches the access code casting dialog
|
||||
raw_ptr<HoverHighlightView, ExperimentalAsh> add_access_code_device_ =
|
||||
nullptr;
|
||||
|
@ -57,6 +57,10 @@ class CastDetailedViewTest : public AshTestBase {
|
||||
return views;
|
||||
}
|
||||
|
||||
std::vector<views::View*> GetExtraViewsForSink(const std::string& sink_id) {
|
||||
return detailed_view_->sink_extra_views_map_[sink_id];
|
||||
}
|
||||
|
||||
views::View* GetZeroStateView() { return detailed_view_->zero_state_view_; }
|
||||
|
||||
// Adds two simulated cast devices.
|
||||
@ -226,4 +230,33 @@ TEST_F(CastDetailedViewTest, NoStopCastingButtonForNonLocalSource) {
|
||||
EXPECT_FALSE(row->right_view());
|
||||
}
|
||||
|
||||
TEST_F(CastDetailedViewTest, FreezeButton) {
|
||||
// Set up a fake sink and route, as if this Chromebook is casting to the
|
||||
// device. And, the route may be frozen.
|
||||
std::vector<SinkAndRoute> devices;
|
||||
SinkAndRoute device;
|
||||
device.sink.id = "fake_sink_id_1";
|
||||
device.sink.name = "Sink Name 1";
|
||||
device.sink.sink_icon_type = SinkIconType::kCast;
|
||||
device.route.id = "fake_route_id_1";
|
||||
device.route.title = "Title 1";
|
||||
// Simulate a local source (this Chromebook).
|
||||
device.route.is_local_source = true;
|
||||
device.route.freeze_info.can_freeze = true;
|
||||
devices.push_back(device);
|
||||
OnDevicesUpdated(devices);
|
||||
|
||||
std::vector<views::View*> views = GetExtraViewsForSink("fake_sink_id_1");
|
||||
ASSERT_EQ(views.size(), 2u);
|
||||
auto* freeze_button = views[0];
|
||||
EXPECT_TRUE(views::IsViewClass<PillButton>(freeze_button));
|
||||
EXPECT_EQ(freeze_button->GetTooltipText(gfx::Point()), u"Pause casting");
|
||||
|
||||
// Clicking on the button pauses casting.
|
||||
LeftClickOn(freeze_button);
|
||||
EXPECT_EQ(cast_config_.freeze_route_count(), 1u);
|
||||
EXPECT_EQ(cast_config_.freeze_route_route_id(), "fake_route_id_1");
|
||||
EXPECT_EQ(delegate_->close_bubble_call_count(), 1u);
|
||||
}
|
||||
|
||||
} // namespace ash
|
||||
|
Reference in New Issue
Block a user