123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ash/system/power/power_button_menu_view.h"
- #include <memory>
- #include "ash/capture_mode/capture_mode_controller.h"
- #include "ash/constants/ash_features.h"
- #include "ash/display/screen_orientation_controller.h"
- #include "ash/login/login_screen_controller.h"
- #include "ash/public/cpp/new_window_delegate.h"
- #include "ash/public/cpp/style/scoped_light_mode_as_default.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/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/user/login_status.h"
- #include "ash/wm/lock_state_controller.h"
- #include "ash/wm/tablet_mode/tablet_mode_controller.h"
- #include "base/bind.h"
- #include "base/callback_helpers.h"
- #include "base/time/time.h"
- #include "ui/base/l10n/l10n_util.h"
- #include "ui/compositor/layer.h"
- #include "ui/compositor/layer_animator.h"
- #include "ui/compositor/scoped_layer_animation_settings.h"
- #include "ui/compositor_extra/shadow.h"
- #include "ui/gfx/vector_icon_types.h"
- #include "ui/views/accessibility/view_accessibility.h"
- #include "ui/views/background.h"
- #include "ui/views/highlight_border.h"
- namespace ash {
- namespace {
- // Horizontal and vertical padding of the menu item view.
- 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)
- : shutdown_reason_(shutdown_reason),
- power_button_position_(power_button_position) {
- SetFocusBehavior(FocusBehavior::ALWAYS);
- SetPaintToLayer();
- if (features::IsDarkLightModeEnabled()) {
- SetBorder(std::make_unique<views::HighlightBorder>(
- kMenuCornerRadius, views::HighlightBorder::Type::kHighlightBorder1,
- /*use_light_colors=*/false));
- }
- layer()->SetFillsBoundsOpaquely(false);
- layer()->SetRoundedCornerRadius(gfx::RoundedCornersF(kMenuCornerRadius));
- layer()->SetBackgroundBlur(ColorProvider::kBackgroundBlurSigma);
- GetViewAccessibility().OverrideRole(ax::mojom::Role::kMenu);
- GetViewAccessibility().OverrideName(
- l10n_util::GetStringUTF16(IDS_ASH_POWER_BUTTON_MENU_ACCESSIBLE));
- RecreateItems();
- // Create a system shadow for current view.
- shadow_ = SystemShadow::CreateShadowOnNinePatchLayerForView(
- this, SystemShadow::Type::kElevation12);
- shadow_->SetRoundedCornerRadius(kMenuCornerRadius);
- }
- PowerButtonMenuView::~PowerButtonMenuView() = default;
- void PowerButtonMenuView::FocusPowerOffButton() {
- power_off_item_->RequestFocus();
- }
- void PowerButtonMenuView::ScheduleShowHideAnimation(bool show) {
- // Set initial state.
- SetVisible(true);
- // Calculate transform of menu view and shadow bounds.
- gfx::Transform transform;
- if (show) {
- TransformDisplacement transform_displacement = GetTransformDisplacement();
- if (transform_displacement.direction == TransformDirection::X)
- transform.Translate(transform_displacement.distance, 0);
- else if (transform_displacement.direction == TransformDirection::Y)
- transform.Translate(0, transform_displacement.distance);
- }
- SetLayerAnimation(layer(), this, show, transform);
- SetLayerAnimation(shadow_->GetLayer(), nullptr, show, transform);
- }
- PowerButtonMenuView::TransformDisplacement
- PowerButtonMenuView::GetTransformDisplacement() const {
- TransformDisplacement transform_displacement;
- if (power_button_position_ == PowerButtonPosition::NONE ||
- !Shell::Get()->tablet_mode_controller()->InTabletMode()) {
- transform_displacement.direction = TransformDirection::Y;
- transform_displacement.distance = kMenuViewTransformDistanceDp;
- return transform_displacement;
- }
- chromeos::OrientationType screen_orientation =
- Shell::Get()->screen_orientation_controller()->GetCurrentOrientation();
- bool is_left_or_right = power_button_position_ == PowerButtonPosition::LEFT ||
- power_button_position_ == PowerButtonPosition::RIGHT;
- if (chromeos::IsLandscapeOrientation(screen_orientation)) {
- transform_displacement.direction =
- is_left_or_right ? TransformDirection::X : TransformDirection::Y;
- } else {
- transform_displacement.direction =
- is_left_or_right ? TransformDirection::Y : TransformDirection::X;
- }
- bool positive_transform = false;
- if (is_left_or_right) {
- bool is_primary = chromeos::IsPrimaryOrientation(screen_orientation);
- positive_transform = power_button_position_ == PowerButtonPosition::LEFT
- ? is_primary
- : !is_primary;
- } else {
- bool is_landscape_primary_or_portrait_secondary =
- screen_orientation == chromeos::OrientationType::kLandscapePrimary ||
- screen_orientation == chromeos::OrientationType::kPortraitSecondary;
- positive_transform = power_button_position_ == PowerButtonPosition::TOP
- ? is_landscape_primary_or_portrait_secondary
- : !is_landscape_primary_or_portrait_secondary;
- }
- transform_displacement.distance = positive_transform
- ? kMenuViewTransformDistanceDp
- : -kMenuViewTransformDistanceDp;
- return transform_displacement;
- }
- void PowerButtonMenuView::RecreateItems() {
- // Helper to add or remove a menu item from |this|. Stores weak pointer to
- // |out_item_ptr|.
- auto add_remove_item =
- [this](bool create, PowerButtonMenuActionType action,
- base::RepeatingClosure callback, const gfx::VectorIcon& icon,
- const std::u16string& string,
- 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)
- return;
- if (!create && !*out_item_ptr)
- return;
- if (create) {
- *out_item_ptr = AddChildView(std::make_unique<PowerButtonMenuItemView>(
- base::BindRepeating(&PowerButtonMenuView::ButtonPressed,
- base::Unretained(this), action,
- std::move(callback)),
- icon, string));
- } else {
- std::unique_ptr<PowerButtonMenuItemView> to_delete =
- RemoveChildViewT(*out_item_ptr);
- *out_item_ptr = nullptr;
- }
- };
- const SessionControllerImpl* const session_controller =
- Shell::Get()->session_controller();
- const LoginStatus login_status = session_controller->login_status();
- const bool create_sign_out = login_status != LoginStatus::NOT_LOGGED_IN;
- const bool create_lock_screen = login_status != LoginStatus::LOCKED &&
- session_controller->CanLockScreen();
- const bool create_capture_mode =
- Shell::Get()->tablet_mode_controller()->InTabletMode() &&
- !session_controller->IsUserSessionBlocked();
- const bool create_feedback = login_status != LoginStatus::LOCKED &&
- login_status != LoginStatus::KIOSK_APP;
- add_remove_item(
- true, PowerButtonMenuActionType::kPowerOff,
- base::BindRepeating(
- &LockStateController::StartShutdownAnimation,
- base::Unretained(Shell::Get()->lock_state_controller()),
- shutdown_reason_),
- kSystemPowerButtonMenuPowerOffIcon,
- l10n_util::GetStringUTF16(IDS_ASH_POWER_BUTTON_MENU_POWER_OFF_BUTTON),
- &power_off_item_);
- add_remove_item(
- create_sign_out, PowerButtonMenuActionType::kSignOut,
- base::BindRepeating(&SessionControllerImpl::RequestSignOut,
- base::Unretained(Shell::Get()->session_controller())),
- kSystemPowerButtonMenuSignOutIcon,
- user::GetLocalizedSignOutStringForStatus(login_status, false),
- &sign_out_item_);
- add_remove_item(
- create_lock_screen, PowerButtonMenuActionType::kLockScreen,
- base::BindRepeating(&SessionControllerImpl::LockScreen,
- base::Unretained(Shell::Get()->session_controller())),
- kSystemPowerButtonMenuLockScreenIcon,
- l10n_util::GetStringUTF16(IDS_ASH_POWER_BUTTON_MENU_LOCK_SCREEN_BUTTON),
- &lock_screen_item_);
- add_remove_item(
- create_capture_mode, PowerButtonMenuActionType::kCaptureMode,
- base::BindRepeating(&CaptureModeController::Start,
- base::Unretained(CaptureModeController::Get()),
- CaptureModeEntryType::kPowerMenu),
- kCaptureModeIcon,
- l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAPTURE_MODE_BUTTON_LABEL),
- &capture_mode_item_);
- add_remove_item(
- create_feedback, PowerButtonMenuActionType::kFeedback,
- base::BindRepeating(
- [](Shell* shell) {
- if (shell->session_controller()->login_status() ==
- LoginStatus::NOT_LOGGED_IN) {
- // There is a special flow for feedback while in login screen,
- // therefore we trigger the same handler associated with the
- // feedback accelerator from the login screen to bring up the
- // feedback dialog.
- shell->login_screen_controller()->HandleAccelerator(
- LoginAcceleratorAction::kShowFeedback);
- } else {
- NewWindowDelegate::GetInstance()->OpenFeedbackPage();
- }
- },
- Shell::Get()),
- kSystemPowerButtonMenuFeedbackIcon,
- l10n_util::GetStringUTF16(IDS_ASH_POWER_BUTTON_MENU_FEEDBACK_BUTTON),
- &feedback_item_);
- }
- const char* PowerButtonMenuView::GetClassName() const {
- return "PowerButtonMenuView";
- }
- void PowerButtonMenuView::Layout() {
- gfx::Rect rect(GetContentsBounds().origin(),
- power_off_item_->GetPreferredSize());
- const int y_offset =
- kMenuItemVerticalPadding - PowerButtonMenuItemView::kItemBorderThickness;
- int x_offset = kMenuItemHorizontalPadding -
- PowerButtonMenuItemView::kItemBorderThickness;
- rect.Offset(x_offset, y_offset);
- power_off_item_->SetBoundsRect(rect);
- const int padding_between_items_with_border =
- kPaddingBetweenMenuItems -
- 2 * PowerButtonMenuItemView::kItemBorderThickness;
- x_offset = rect.width() + padding_between_items_with_border;
- if (sign_out_item_) {
- rect.Offset(x_offset, 0);
- sign_out_item_->SetBoundsRect(rect);
- if (lock_screen_item_) {
- rect.Offset(x_offset, 0);
- lock_screen_item_->SetBoundsRect(rect);
- }
- }
- if (capture_mode_item_) {
- rect.Offset(x_offset, 0);
- capture_mode_item_->SetBoundsRect(rect);
- }
- if (feedback_item_) {
- rect.Offset(x_offset, 0);
- feedback_item_->SetBoundsRect(rect);
- }
- }
- gfx::Size PowerButtonMenuView::CalculatePreferredSize() const {
- gfx::Size menu_size;
- DCHECK(power_off_item_);
- menu_size = gfx::Size(0, PowerButtonMenuItemView::kMenuItemHeight +
- 2 * kMenuItemVerticalPadding);
- int width =
- PowerButtonMenuItemView::kMenuItemWidth + 2 * kMenuItemHorizontalPadding;
- 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 (capture_mode_item_)
- width += one_item_x_offset;
- if (feedback_item_)
- width += one_item_x_offset;
- menu_size.set_width(width);
- return menu_size;
- }
- void PowerButtonMenuView::OnThemeChanged() {
- views::View::OnThemeChanged();
- ScopedLightModeAsDefault scoped_light_mode_as_default;
- SetBackground(
- views::CreateSolidBackground(AshColorProvider::Get()->GetBaseLayerColor(
- AshColorProvider::BaseLayerType::kTransparent80)));
- }
- void PowerButtonMenuView::OnImplicitAnimationsCompleted() {
- if (layer()->opacity() == 0.f)
- SetVisible(false);
- if (layer()->opacity() == 1.0f)
- RequestFocus();
- }
- void PowerButtonMenuView::ButtonPressed(PowerButtonMenuActionType action,
- base::RepeatingClosure callback) {
- RecordMenuActionHistogram(action);
- std::move(callback).Run();
- Shell::Get()->power_button_controller()->DismissMenu();
- }
- } // namespace ash
|