0

Added curtain mode view for power button widget.

This change adds a new view for the widget displayed when the power
button is pressed and the device is in curtain mode.

Screenshot: http://screen/fLWunZ5cNQFiQJm.
Bug: b/268174075
Change-Id: I1ba0afda6717c6aa02f942adaac478df985f1b2b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4239885
Reviewed-by: Xiaoqian Dai <xdai@chromium.org>
Commit-Queue: Ashutosh Singhal <macinashutosh@google.com>
Reviewed-by: Jeroen Dhollander <jeroendh@google.com>
Cr-Commit-Position: refs/heads/main@{#1118802}
This commit is contained in:
Ashutosh Singhal
2023-03-17 19:06:32 +00:00
committed by Chromium LUCI CQ
parent 681ab80215
commit 88050756b5
13 changed files with 461 additions and 90 deletions

@ -1739,6 +1739,8 @@ component("ash") {
"system/power/power_button_controller.h",
"system/power/power_button_display_controller.cc",
"system/power/power_button_display_controller.h",
"system/power/power_button_menu_curtain_view.cc",
"system/power/power_button_menu_curtain_view.h",
"system/power/power_button_menu_item_view.cc",
"system/power/power_button_menu_item_view.h",
"system/power/power_button_menu_metrics_type.cc",
@ -1747,6 +1749,8 @@ component("ash") {
"system/power/power_button_menu_screen_view.h",
"system/power/power_button_menu_view.cc",
"system/power/power_button_menu_view.h",
"system/power/power_button_menu_view_util.cc",
"system/power/power_button_menu_view_util.h",
"system/power/power_button_screenshot_controller.cc",
"system/power/power_button_screenshot_controller.h",
"system/power/power_event_observer.cc",

@ -6373,6 +6373,16 @@ New install
<message name="IDS_ASH_PAGINATION_RIGHT_ARROW_TOOLTIP" desc="The tooltip text used for pagination right arrow button." >
Next page
</message>
</messages>
</release>
<!-- Power menu widget for security curtain -->
<message name="IDS_ASH_CURTAIN_POWER_WIDGET_TITLE" desc="Title text displayed in the dialog when the power button is pressed and the remote admin session on ChromeOs device will end.">
Shut down the device?
</message>
<message name="IDS_ASH_CURTAIN_POWER_WIDGET_DESCRIPTION" desc="Detailed description displayed to inform the user that the device will be shut down and remote admin session will be end if they press the power button again. The linebreak should NOT be removed from the string.">
Once shut down, the administrator will be logged out and won't be able to control your device.
To shut down the device, press and hold the power button on the device again.
</message>
</messages>
</release>
</grit>

@ -0,0 +1 @@
7f0989c1fd1790b3e21963c5d51b4fdf3bef1c66

@ -0,0 +1 @@
7f0989c1fd1790b3e21963c5d51b4fdf3bef1c66

@ -14,6 +14,7 @@
#include "ash/system/power/power_button_controller_test_api.h"
#include "ash/system/power/power_button_menu_item_view.h"
#include "ash/system/power/power_button_menu_view.h"
#include "ash/system/power/power_button_menu_view_util.h"
#include "ash/system/power/power_button_test_base.h"
#include "ash/test_media_client.h"
#include "ash/touch/touch_devices_controller.h"
@ -1170,7 +1171,7 @@ TEST_P(PowerButtonControllerWithPositionTest,
EXPECT_TRUE(IsMenuCentered());
TapToDismissPowerButtonMenu();
int animation_transform = PowerButtonMenuView::kMenuViewTransformDistanceDp;
int animation_transform = kPowerButtonMenuTransformDistanceDp;
EnableTabletMode(true);
EXPECT_TRUE(IsTabletMode());
OpenPowerButtonMenu();

@ -0,0 +1,190 @@
// 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.
#include "ash/system/power/power_button_menu_curtain_view.h"
#include <memory>
#include "ash/public/cpp/style/color_provider.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_id.h"
#include "ash/style/ash_color_provider.h"
#include "ash/style/system_shadow.h"
#include "ash/system/power/power_button_menu_view_util.h"
#include "base/check_deref.h"
#include "chromeos/ui/vector_icons/vector_icons.h"
#include "ui/accessibility/ax_enums.mojom-shared.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/background.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/highlight_border.h"
#include "ui/views/layout/flex_layout_types.h"
#include "ui/views/layout/flex_layout_view.h"
#include "ui/views/metadata/view_factory_internal.h"
#include "ui/views/style/typography.h"
#include "ui/views/view_class_properties.h"
namespace ash {
namespace {
using views::Builder;
using views::FlexLayoutView;
using views::ImageView;
using views::LayoutOrientation;
constexpr gfx::Size kEnterpriseIconSize(20, 20);
// Bottom margin for the enterprise icon.
constexpr int kIconBottomMargin = 30;
// Preferred width of the dialog.
constexpr int kWidth = 400;
// Inner padding for the widget.
constexpr int kHorizontalPadding = 25;
constexpr int kVerticalPadding = 20;
// Bottom margin for the widget title.
constexpr int kTitleBottomMargin = 35;
// Line height for the widget content text.
constexpr int kContentLineHeight = 12;
views::FlexSpecification FullFlex() {
return views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToMinimum,
views::MaximumFlexSizeRule::kUnbounded)
.WithWeight(1);
}
gfx::ImageSkia EnterpriseIcon(const ColorProvider& color_provider) {
return gfx::CreateVectorIcon(
chromeos::kEnterpriseIcon,
color_provider.GetContentLayerColor(
ash::AshColorProvider::ContentLayerType::kIconColorPrimary));
}
std::u16string TitleText() {
return l10n_util::GetStringUTF16(IDS_ASH_CURTAIN_POWER_WIDGET_TITLE);
}
std::u16string MessageText() {
return l10n_util::GetStringUTF16(IDS_ASH_CURTAIN_POWER_WIDGET_DESCRIPTION);
}
} // namespace
PowerButtonMenuCurtainView::PowerButtonMenuCurtainView() {
SetPaintToLayer();
SetBorder(std::make_unique<views::HighlightBorder>(
kPowerButtonMenuCornerRadius, kPowerButtonMenuBorderType,
/*use_light_colors=*/false));
SetBackground(
views::CreateThemedSolidBackground(kPowerButtonMenuBackgroundColorId));
layer()->SetFillsBoundsOpaquely(false);
layer()->SetRoundedCornerRadius(
gfx::RoundedCornersF(kPowerButtonMenuCornerRadius));
layer()->SetBackgroundBlur(kPowerButtonMenuBlurType);
GetViewAccessibility().OverrideRole(ax::mojom::Role::kDialog);
Initialize();
// Create a system shadow for current view.
shadow_ = ash::SystemShadow::CreateShadowOnNinePatchLayerForView(
this, ash::SystemShadow::Type::kElevation12);
shadow_->SetRoundedCornerRadius(kPowerButtonMenuCornerRadius);
}
PowerButtonMenuCurtainView::~PowerButtonMenuCurtainView() = default;
void PowerButtonMenuCurtainView::ScheduleShowHideAnimation(bool show) {
// Set initial state.
SetVisible(true);
// Calculate transform of menu view and shadow bounds.
gfx::Transform transform;
if (show) {
transform.Translate(0, kPowerButtonMenuTransformDistanceDp);
}
SetLayerAnimation(layer(), this, show, transform);
SetLayerAnimation(shadow_->GetLayer(), nullptr, show, transform);
}
void PowerButtonMenuCurtainView::Initialize() {
// TODO(b/272826467) Update to views::View::GetColorProvider().
const ColorProvider& color_provider = CHECK_DEREF(ColorProvider::Get());
Builder<FlexLayoutView>(this)
.SetOrientation(views::LayoutOrientation::kHorizontal)
.AddChildren(
Builder<FlexLayoutView>()
.SetOrientation(LayoutOrientation::kVertical)
.SetProperty(views::kFlexBehaviorKey, FullFlex())
.AddChildren(
// Enterprise icon
Builder<ImageView>()
.SetImage(EnterpriseIcon(color_provider))
.SetImageSize(kEnterpriseIconSize)
.SetSize(kEnterpriseIconSize)
.SetHorizontalAlignment(ImageView::Alignment::kLeading)
.SetProperty(views::kFlexBehaviorKey, FullFlex())
.SetProperty(views::kMarginsKey,
gfx::Insets::TLBR(
kVerticalPadding, kHorizontalPadding,
kIconBottomMargin, kHorizontalPadding)),
// Title
Builder<views::Label>()
.SetText(TitleText())
.SetTextStyle(views::style::STYLE_EMPHASIZED)
.SetTextContext(views::style::CONTEXT_DIALOG_TITLE)
.SetHorizontalAlignment(
gfx::HorizontalAlignment::ALIGN_LEFT)
.SetMultiLine(true)
.SetEnabledColor(color_provider.GetContentLayerColor(
ColorProvider::ContentLayerType::kTextColorPrimary))
.SetProperty(views::kFlexBehaviorKey, FullFlex())
.SetProperty(views::kMarginsKey,
gfx::Insets::TLBR(0, kHorizontalPadding,
kTitleBottomMargin,
kHorizontalPadding))
.SetMaximumWidth(kWidth),
// Description
Builder<views::Label>()
.SetText(MessageText())
.SetTextContext(views::style::CONTEXT_DIALOG_BODY_TEXT)
.SetHorizontalAlignment(
gfx::HorizontalAlignment::ALIGN_LEFT)
.SetMultiLine(true)
.SetEnabledColor(color_provider.GetContentLayerColor(
ColorProvider::ContentLayerType::kTextColorPrimary))
.SetProperty(views::kFlexBehaviorKey, FullFlex())
.SetProperty(views::kMarginsKey,
gfx::Insets::TLBR(0, kHorizontalPadding,
kVerticalPadding,
kHorizontalPadding))
.SetLineHeight(kContentLineHeight)
.SetMaximumWidth(kWidth)))
.BuildChildren();
}
void PowerButtonMenuCurtainView::OnImplicitAnimationsCompleted() {
if (layer()->opacity() == 0.f) {
SetVisible(false);
}
}
BEGIN_METADATA(PowerButtonMenuCurtainView, views::FlexLayoutView)
END_METADATA
} // namespace ash

@ -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.
#ifndef ASH_SYSTEM_POWER_POWER_BUTTON_MENU_CURTAIN_VIEW_H_
#define ASH_SYSTEM_POWER_POWER_BUTTON_MENU_CURTAIN_VIEW_H_
#include "ash/ash_export.h"
#include "ash/style/system_shadow.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/flex_layout_view.h"
namespace ash {
// PowerButtonMenuCurtainView is displayed inside the power menu popup when the
// power button is pressed while the security curtain is present.
class ASH_EXPORT PowerButtonMenuCurtainView
: public views::FlexLayoutView,
public ui::ImplicitAnimationObserver {
public:
PowerButtonMenuCurtainView();
PowerButtonMenuCurtainView(const PowerButtonMenuCurtainView&) = delete;
PowerButtonMenuCurtainView& operator=(const PowerButtonMenuCurtainView&) =
delete;
~PowerButtonMenuCurtainView() override;
void ScheduleShowHideAnimation(bool show);
METADATA_HEADER(PowerButtonMenuCurtainView);
private:
void Initialize();
// ui::ImplicitAnimationObserver:
void OnImplicitAnimationsCompleted() override;
std::unique_ptr<ash::SystemShadow> shadow_;
};
} // namespace ash
#endif // ASH_SYSTEM_POWER_POWER_BUTTON_MENU_CURTAIN_VIEW_H_

@ -6,24 +6,26 @@
#include <utility>
#include "ash/curtain/security_curtain_controller.h"
#include "ash/shell.h"
#include "ash/style/ash_color_provider.h"
#include "ash/style/default_color_constants.h"
#include "ash/style/default_colors.h"
#include "ash/system/power/power_button_menu_curtain_view.h"
#include "ash/system/power/power_button_menu_metrics_type.h"
#include "ash/system/power/power_button_menu_view.h"
#include "ash/system/power/power_button_menu_view_util.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
namespace ash {
constexpr int PowerButtonMenuView::kMenuViewTransformDistanceDp;
namespace {
// Opacity of the power button menu fullscreen background shield.
@ -46,11 +48,13 @@ gfx::Size GetPrimaryDisplayLandscapeSize() {
int AdjustMenuEdgeForDisplaySize(int actual_position,
int display_edge,
int menu_size) {
return std::min(display_edge -
PowerButtonMenuView::kMenuViewTransformDistanceDp -
menu_size,
std::max(PowerButtonMenuView::kMenuViewTransformDistanceDp,
actual_position));
return std::min(
display_edge - kPowerButtonMenuTransformDistanceDp - menu_size,
std::max(kPowerButtonMenuTransformDistanceDp, actual_position));
}
bool IsCurtainModeEnabled() {
return ash::Shell::Get()->security_curtain_controller().IsEnabled();
}
} // namespace
@ -93,8 +97,7 @@ class PowerButtonMenuScreenView::PowerButtonMenuBackgroundView
animation.AddObserver(this);
animation.SetTweenType(show ? gfx::Tween::EASE_IN_2
: gfx::Tween::FAST_OUT_LINEAR_IN);
animation.SetTransitionDuration(
PowerButtonMenuView::kMenuAnimationDuration);
animation.SetTransitionDuration(kPowerButtonMenuAnimationDuration);
animation.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
layer()->SetOpacity(show ? kPowerButtonMenuOpacity : 0.f);
@ -139,14 +142,26 @@ PowerButtonMenuScreenView::~PowerButtonMenuScreenView() = default;
void PowerButtonMenuScreenView::ScheduleShowHideAnimation(bool show) {
power_button_screen_background_shield_->ScheduleShowHideAnimation(show);
power_button_menu_view_->ScheduleShowHideAnimation(show);
if (IsCurtainModeEnabled()) {
GetOrCreateCurtainView()->ScheduleShowHideAnimation(show);
} else {
power_button_menu_view_->ScheduleShowHideAnimation(show);
}
}
void PowerButtonMenuScreenView::ResetOpacity() {
for (ui::Layer* layer : {power_button_screen_background_shield_->layer(),
power_button_menu_view_->layer()}) {
DCHECK(layer);
layer->SetOpacity(0.f);
if (IsCurtainModeEnabled()) {
for (ui::Layer* layer : {power_button_screen_background_shield_->layer(),
GetOrCreateCurtainView()->layer()}) {
DCHECK(layer);
layer->SetOpacity(0.f);
}
} else {
for (ui::Layer* layer : {power_button_screen_background_shield_->layer(),
power_button_menu_view_->layer()}) {
DCHECK(layer);
layer->SetOpacity(0.f);
}
}
}
@ -159,20 +174,38 @@ void PowerButtonMenuScreenView::OnWidgetShown(
// UpdateMenuBoundsOrigins(), since the latter relies on the
// power_button_menu_view_'s preferred size, which depends on the items added
// to the view.
power_button_menu_view_->RecreateItems();
if (!IsCurtainModeEnabled()) {
power_button_menu_view_->RecreateItems();
}
if (power_button_position_ != PowerButtonPosition::NONE) {
UpdateMenuBoundsOrigins();
}
Layout();
}
PowerButtonMenuCurtainView*
PowerButtonMenuScreenView::GetOrCreateCurtainView() {
if (!power_button_menu_curtain_view_) {
power_button_menu_curtain_view_ =
AddChildView(std::make_unique<PowerButtonMenuCurtainView>());
}
return power_button_menu_curtain_view_;
}
const char* PowerButtonMenuScreenView::GetClassName() const {
return "PowerButtonMenuScreenView";
}
void PowerButtonMenuScreenView::Layout() {
power_button_screen_background_shield_->SetBoundsRect(GetContentsBounds());
if (IsCurtainModeEnabled()) {
LayoutMenuCurtainView();
} else {
LayoutMenuView();
}
}
void PowerButtonMenuScreenView::LayoutMenuView() {
gfx::Rect menu_bounds = GetMenuBounds();
PowerButtonMenuView::TransformDisplacement transform_displacement =
power_button_menu_view_->GetTransformDisplacement();
@ -185,6 +218,12 @@ void PowerButtonMenuScreenView::Layout() {
power_button_menu_view_->SetBoundsRect(menu_bounds);
}
void PowerButtonMenuScreenView::LayoutMenuCurtainView() {
gfx::Rect menu_bounds = GetMenuBounds();
menu_bounds.set_y(menu_bounds.y() - kPowerButtonMenuTransformDistanceDp);
GetOrCreateCurtainView()->SetBoundsRect(menu_bounds);
}
bool PowerButtonMenuScreenView::OnMousePressed(const ui::MouseEvent& event) {
return true;
}
@ -223,8 +262,12 @@ void PowerButtonMenuScreenView::OnDisplayMetricsChanged(
void PowerButtonMenuScreenView::LayoutWithoutTransform() {
power_button_screen_background_shield_->SetBoundsRect(GetContentsBounds());
power_button_menu_view_->layer()->SetTransform(gfx::Transform());
power_button_menu_view_->SetBoundsRect(GetMenuBounds());
if (IsCurtainModeEnabled()) {
GetOrCreateCurtainView()->SetBoundsRect(GetMenuBounds());
} else {
power_button_menu_view_->layer()->SetTransform(gfx::Transform());
power_button_menu_view_->SetBoundsRect(GetMenuBounds());
}
}
void PowerButtonMenuScreenView::UpdateMenuBoundsOrigins() {
@ -302,20 +345,19 @@ void PowerButtonMenuScreenView::UpdateMenuBoundsOrigins() {
}
menu_bounds_origins_.clear();
const gfx::Size menu_size = power_button_menu_view_->GetPreferredSize();
const gfx::Size menu_size = GetMenuViewPreferredSize();
// Power button position offset from the left when the button is at the left
// is always zero.
menu_bounds_origins_.insert(std::make_pair(
left_screen_orientation,
gfx::Point(PowerButtonMenuView::kMenuViewTransformDistanceDp,
gfx::Point(kPowerButtonMenuTransformDistanceDp,
AdjustMenuEdgeForDisplaySize(
left_power_button_y - menu_size.height() / 2,
display_edge_for_adjust, menu_size.height()))));
menu_bounds_origins_.insert(std::make_pair(
right_screen_orientation,
gfx::Point(display_width -
PowerButtonMenuView::kMenuViewTransformDistanceDp -
gfx::Point(display_width - kPowerButtonMenuTransformDistanceDp -
menu_size.width(),
AdjustMenuEdgeForDisplaySize(
right_power_button_y - menu_size.height() / 2,
@ -323,20 +365,19 @@ void PowerButtonMenuScreenView::UpdateMenuBoundsOrigins() {
// Power button position offset from the top when the button is at the top
// is always zero.
menu_bounds_origins_.insert(std::make_pair(
top_screen_orientation,
gfx::Point(AdjustMenuEdgeForDisplaySize(
top_power_button_x - menu_size.width() / 2,
display_edge_for_adjust, menu_size.width()),
PowerButtonMenuView::kMenuViewTransformDistanceDp)));
menu_bounds_origins_.insert(
std::make_pair(top_screen_orientation,
gfx::Point(AdjustMenuEdgeForDisplaySize(
top_power_button_x - menu_size.width() / 2,
display_edge_for_adjust, menu_size.width()),
kPowerButtonMenuTransformDistanceDp)));
menu_bounds_origins_.insert(std::make_pair(
bottom_screen_orientation,
gfx::Point(AdjustMenuEdgeForDisplaySize(
bottom_power_button_x - menu_size.width() / 2,
display_edge_for_adjust, menu_size.width()),
display_width -
PowerButtonMenuView::kMenuViewTransformDistanceDp -
display_width - kPowerButtonMenuTransformDistanceDp -
menu_size.height())));
}
@ -346,16 +387,23 @@ gfx::Rect PowerButtonMenuScreenView::GetMenuBounds() {
if (power_button_position_ == PowerButtonPosition::NONE ||
!Shell::Get()->tablet_mode_controller()->InTabletMode()) {
menu_bounds = GetContentsBounds();
menu_bounds.ClampToCenteredSize(
power_button_menu_view_->GetPreferredSize());
menu_bounds.ClampToCenteredSize(GetMenuViewPreferredSize());
} else {
menu_bounds.set_origin(
menu_bounds_origins_[Shell::Get()
->screen_orientation_controller()
->GetCurrentOrientation()]);
menu_bounds.set_size(power_button_menu_view_->GetPreferredSize());
menu_bounds.set_size(GetMenuViewPreferredSize());
}
return menu_bounds;
}
gfx::Size PowerButtonMenuScreenView::GetMenuViewPreferredSize() {
if (IsCurtainModeEnabled()) {
return GetOrCreateCurtainView()->GetPreferredSize();
} else {
return power_button_menu_view_->GetPreferredSize();
}
}
} // namespace ash

@ -16,6 +16,7 @@
namespace ash {
enum class ShutdownReason;
class PowerButtonMenuView;
class PowerButtonMenuCurtainView;
// PowerButtonMenuScreenView is the top-level view of power button menu UI. It
// creates a PowerButtonMenuBackgroundView to display the fullscreen background
@ -39,6 +40,10 @@ class ASH_EXPORT PowerButtonMenuScreenView : public views::View,
return power_button_menu_view_;
}
PowerButtonMenuCurtainView* power_button_menu_curtain_view() const {
return power_button_menu_curtain_view_;
}
// Schedules an animation to show or hide the view.
void ScheduleShowHideAnimation(bool show);
@ -73,14 +78,26 @@ class ASH_EXPORT PowerButtonMenuScreenView : public views::View,
// Lays out the view without animation transform.
void LayoutWithoutTransform();
// Helper methods for Layout().
void LayoutMenuView();
void LayoutMenuCurtainView();
// Updates |menu_bounds_origins_| according to power button position info.
void UpdateMenuBoundsOrigins();
// Gets the bounds of power button menu.
gfx::Rect GetMenuBounds();
// Created by PowerButtonMenuScreenView. Owned by views hierarchy.
gfx::Size GetMenuViewPreferredSize();
PowerButtonMenuCurtainView* GetOrCreateCurtainView();
// Created by PowerButtonMenuScreenView. Owned by views hierarchy. Only
// power_button_menu_view_ or power_button_menu_curtain_view_ will be
// available at a time.
PowerButtonMenuView* power_button_menu_view_ = nullptr;
PowerButtonMenuCurtainView* power_button_menu_curtain_view_ = nullptr;
PowerButtonMenuBackgroundView* power_button_screen_background_shield_ =
nullptr;

@ -18,6 +18,7 @@
#include "ash/style/system_shadow.h"
#include "ash/system/power/power_button_menu_item_view.h"
#include "ash/system/power/power_button_menu_metrics_type.h"
#include "ash/system/power/power_button_menu_view_util.h"
#include "ash/system/user/login_status.h"
#include "ash/wm/lock_state_controller.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
@ -42,42 +43,13 @@ namespace {
constexpr int kMenuItemHorizontalPadding = 16;
constexpr int kMenuItemVerticalPadding = 16;
// The rounded corner radius of menu.
constexpr int kMenuCornerRadius = 16;
// Horizontal padding between two menu items.
constexpr int kPaddingBetweenMenuItems = 8;
// Set show/hide animation for layer.
void SetLayerAnimation(ui::Layer* layer,
ui::ImplicitAnimationObserver* observer,
bool show,
const gfx::Transform& transform) {
DCHECK(layer);
auto* animator = layer->GetAnimator();
animator->AbortAllAnimations();
ui::ScopedLayerAnimationSettings animation_settings(animator);
animation_settings.SetTweenType(show ? gfx::Tween::EASE_IN
: gfx::Tween::FAST_OUT_LINEAR_IN);
animation_settings.SetTransitionDuration(
PowerButtonMenuView::kMenuAnimationDuration);
animation_settings.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
if (observer)
animation_settings.AddObserver(observer);
layer->SetOpacity(show ? 1.0f : 0.f);
layer->SetTransform(transform);
}
} // namespace
using PowerButtonPosition = PowerButtonController::PowerButtonPosition;
constexpr base::TimeDelta PowerButtonMenuView::kMenuAnimationDuration;
PowerButtonMenuView::PowerButtonMenuView(
ShutdownReason shutdown_reason,
PowerButtonPosition power_button_position)
@ -86,13 +58,15 @@ PowerButtonMenuView::PowerButtonMenuView(
SetFocusBehavior(FocusBehavior::ALWAYS);
SetPaintToLayer();
SetBorder(std::make_unique<views::HighlightBorder>(
kMenuCornerRadius, views::HighlightBorder::Type::kHighlightBorder1,
kPowerButtonMenuCornerRadius, kPowerButtonMenuBorderType,
/*use_light_colors=*/false));
SetBackground(views::CreateThemedSolidBackground(kColorAshShieldAndBase80));
SetBackground(
views::CreateThemedSolidBackground(kPowerButtonMenuBackgroundColorId));
layer()->SetFillsBoundsOpaquely(false);
layer()->SetRoundedCornerRadius(gfx::RoundedCornersF(kMenuCornerRadius));
layer()->SetBackgroundBlur(ColorProvider::kBackgroundBlurSigma);
layer()->SetRoundedCornerRadius(
gfx::RoundedCornersF(kPowerButtonMenuCornerRadius));
layer()->SetBackgroundBlur(kPowerButtonMenuBlurType);
GetViewAccessibility().OverrideRole(ax::mojom::Role::kMenu);
GetViewAccessibility().OverrideName(
l10n_util::GetStringUTF16(IDS_ASH_POWER_BUTTON_MENU_ACCESSIBLE));
@ -101,7 +75,7 @@ PowerButtonMenuView::PowerButtonMenuView(
// Create a system shadow for current view.
shadow_ = SystemShadow::CreateShadowOnNinePatchLayerForView(
this, SystemShadow::Type::kElevation12);
shadow_->SetRoundedCornerRadius(kMenuCornerRadius);
shadow_->SetRoundedCornerRadius(kPowerButtonMenuCornerRadius);
}
PowerButtonMenuView::~PowerButtonMenuView() = default;
@ -118,10 +92,11 @@ void PowerButtonMenuView::ScheduleShowHideAnimation(bool show) {
gfx::Transform transform;
if (show) {
TransformDisplacement transform_displacement = GetTransformDisplacement();
if (transform_displacement.direction == TransformDirection::X)
if (transform_displacement.direction == TransformDirection::X) {
transform.Translate(transform_displacement.distance, 0);
else if (transform_displacement.direction == TransformDirection::Y)
} else if (transform_displacement.direction == TransformDirection::Y) {
transform.Translate(0, transform_displacement.distance);
}
}
SetLayerAnimation(layer(), this, show, transform);
@ -134,7 +109,7 @@ PowerButtonMenuView::GetTransformDisplacement() const {
if (power_button_position_ == PowerButtonPosition::NONE ||
!Shell::Get()->tablet_mode_controller()->InTabletMode()) {
transform_displacement.direction = TransformDirection::Y;
transform_displacement.distance = kMenuViewTransformDistanceDp;
transform_displacement.distance = kPowerButtonMenuTransformDistanceDp;
return transform_displacement;
}
@ -167,8 +142,8 @@ PowerButtonMenuView::GetTransformDisplacement() const {
: !is_landscape_primary_or_portrait_secondary;
}
transform_displacement.distance = positive_transform
? kMenuViewTransformDistanceDp
: -kMenuViewTransformDistanceDp;
? kPowerButtonMenuTransformDistanceDp
: -kPowerButtonMenuTransformDistanceDp;
return transform_displacement;
}
@ -182,10 +157,12 @@ void PowerButtonMenuView::RecreateItems() {
PowerButtonMenuItemView** out_item_ptr) -> void {
// If an item needs to be created and exists, or needs to be destroyed but
// does not exist, there is nothing to be done.
if (create && *out_item_ptr)
if (create && *out_item_ptr) {
return;
if (!create && !*out_item_ptr)
}
if (!create && !*out_item_ptr) {
return;
}
if (create) {
*out_item_ptr = AddChildView(std::make_unique<PowerButtonMenuItemView>(
@ -314,14 +291,17 @@ gfx::Size PowerButtonMenuView::CalculatePreferredSize() const {
const int one_item_x_offset =
PowerButtonMenuItemView::kMenuItemWidth + kPaddingBetweenMenuItems;
if (sign_out_item_) {
width += one_item_x_offset;
if (lock_screen_item_) {
width += one_item_x_offset;
if (lock_screen_item_)
width += one_item_x_offset;
}
}
if (capture_mode_item_)
if (capture_mode_item_) {
width += one_item_x_offset;
if (feedback_item_)
}
if (feedback_item_) {
width += one_item_x_offset;
}
menu_size.set_width(width);
return menu_size;
}
@ -331,11 +311,13 @@ void PowerButtonMenuView::OnThemeChanged() {
}
void PowerButtonMenuView::OnImplicitAnimationsCompleted() {
if (layer()->opacity() == 0.f)
if (layer()->opacity() == 0.f) {
SetVisible(false);
}
if (layer()->opacity() == 1.0f)
if (layer()->opacity() == 1.0f) {
RequestFocus();
}
}
void PowerButtonMenuView::ButtonPressed(PowerButtonMenuActionType action,

@ -21,13 +21,6 @@ class SystemShadow;
class ASH_EXPORT PowerButtonMenuView : public views::View,
public ui::ImplicitAnimationObserver {
public:
// The duration of showing or dismissing power button menu animation.
static constexpr base::TimeDelta kMenuAnimationDuration =
base::Milliseconds(250);
// Distance of the menu animation transform.
static constexpr int kMenuViewTransformDistanceDp = 16;
// Direction of the animation transform. X means to translate from
// x-coordinate. Y means to translate from y-coordinate.
enum class TransformDirection { NONE, X, Y };

@ -0,0 +1,34 @@
// 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.
#include "ash/system/power/power_button_menu_view_util.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
namespace ash {
void SetLayerAnimation(ui::Layer* layer,
ui::ImplicitAnimationObserver* observer,
bool show,
const gfx::Transform& transform) {
DCHECK(layer);
auto* animator = layer->GetAnimator();
animator->AbortAllAnimations();
ui::ScopedLayerAnimationSettings animation_settings(animator);
animation_settings.SetTweenType(show ? gfx::Tween::EASE_IN
: gfx::Tween::FAST_OUT_LINEAR_IN);
animation_settings.SetTransitionDuration(kPowerButtonMenuAnimationDuration);
animation_settings.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
if (observer) {
animation_settings.AddObserver(observer);
}
layer->SetOpacity(show ? 1.0f : 0.f);
layer->SetTransform(transform);
}
} // namespace ash

@ -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.
#ifndef ASH_SYSTEM_POWER_POWER_BUTTON_MENU_VIEW_UTIL_H_
#define ASH_SYSTEM_POWER_POWER_BUTTON_MENU_VIEW_UTIL_H_
#include "ash/ash_export.h"
#include "ash/public/cpp/style/color_provider.h"
#include "ash/style/ash_color_id.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/gfx/geometry/transform.h"
#include "ui/views/highlight_border.h"
namespace ash {
// The duration of showing or dismissing power button menu animation.
constexpr base::TimeDelta kPowerButtonMenuAnimationDuration =
base::Milliseconds(250);
// Distance of the menu animation transform.
constexpr int kPowerButtonMenuTransformDistanceDp = 16;
// The rounded corner radius of menu.
constexpr int kPowerButtonMenuCornerRadius = 16;
// The border highlight type for the container.
constexpr auto kPowerButtonMenuBorderType =
views::HighlightBorder::Type::kHighlightBorder1;
// The color id for widget background.
constexpr auto kPowerButtonMenuBackgroundColorId = kColorAshShieldAndBase80;
// The blur type for widget background.
constexpr auto kPowerButtonMenuBlurType = ColorProvider::kBackgroundBlurSigma;
void SetLayerAnimation(ui::Layer* layer,
ui::ImplicitAnimationObserver* observer,
bool show,
const gfx::Transform& transform);
} // namespace ash
#endif // ASH_SYSTEM_POWER_POWER_BUTTON_MENU_VIEW_UTIL_H_