From b432b7c1ef34b32400fbc2d6f9bfa4624e4ea32e Mon Sep 17 00:00:00 2001 From: Min Chen Date: Fri, 13 Apr 2018 23:11:32 +0000 Subject: [PATCH] ash: Start pre-shutdown animation if long press power button when menu is already shown. - Don't dismiss the menu if pressing power button when menu is already shown. Wait for 650ms to start the pre-shutdown animation and request focus for 'power off' item instead. - Turn screen off for convertible device / in tablet mode if "ModeSpecificPowerButton" is set when menu is not fully shown or second press before starting the pre-shutdown animation. Test=PowerButtonControllerTest* Bug: 826057 Change-Id: I1f906e2bcf5d91960180742bf558c00784fbaa1e Reviewed-on: https://chromium-review.googlesource.com/1011590 Commit-Queue: Min Chen Reviewed-by: Qiang Xu Reviewed-by: Dan Erat Cr-Commit-Position: refs/heads/master@{#550785} --- ash/system/power/power_button_controller.cc | 35 +++++++--- ash/system/power/power_button_controller.h | 7 ++ .../power/power_button_controller_unittest.cc | 66 ++++++++++++++++++- 3 files changed, 95 insertions(+), 13 deletions(-) diff --git a/ash/system/power/power_button_controller.cc b/ash/system/power/power_button_controller.cc index 750dd27b6bfd5..c78649ff7ad82 100644 --- a/ash/system/power/power_button_controller.cc +++ b/ash/system/power/power_button_controller.cc @@ -167,6 +167,14 @@ PowerButtonController::~PowerButtonController() { this); } +void PowerButtonController::OnPreShutdownTimeout() { + lock_state_controller_->StartShutdownAnimation(ShutdownReason::POWER_BUTTON); + DCHECK(menu_widget_); + static_cast(menu_widget_->GetContentsView()) + ->power_button_menu_view() + ->FocusPowerOffButton(); +} + void PowerButtonController::OnPowerButtonEvent( bool down, const base::TimeTicks& timestamp) { @@ -203,7 +211,7 @@ void PowerButtonController::OnPowerButtonEvent( } if (down) { - show_menu_animation_done_ = false; + force_off_on_button_up_ = false; if (ShouldTurnScreenOffForTap()) { force_off_on_button_up_ = true; @@ -226,8 +234,15 @@ void PowerButtonController::OnPowerButtonEvent( } screen_off_when_power_button_down_ = !display_controller_->IsScreenOn(); + menu_shown_when_power_button_down_ = show_menu_animation_done_; display_controller_->SetBacklightsForcedOff(false); + if (menu_shown_when_power_button_down_) { + pre_shutdown_timer_.Start(FROM_HERE, kStartShutdownAnimationTimeout, this, + &PowerButtonController::OnPreShutdownTimeout); + return; + } + if (!ShouldTurnScreenOffForTap()) { StartPowerMenuAnimation(); } else { @@ -247,6 +262,7 @@ void PowerButtonController::OnPowerButtonEvent( last_button_up_time_ = timestamp; const bool menu_timer_was_running = power_button_menu_timer_.IsRunning(); + const bool pre_shutdown_timer_was_running = pre_shutdown_timer_.IsRunning(); power_button_menu_timer_.Stop(); pre_shutdown_timer_.Stop(); @@ -262,8 +278,11 @@ void PowerButtonController::OnPowerButtonEvent( if (timestamp - previous_up_time <= kIgnoreRepeatedButtonUpDelay) return; - if (menu_timer_was_running && !screen_off_when_power_button_down_ && - force_off_on_button_up_) { + if (screen_off_when_power_button_down_ || !force_off_on_button_up_) + return; + + if (menu_timer_was_running || (menu_shown_when_power_button_down_ && + pre_shutdown_timer_was_running)) { display_controller_->SetBacklightsForcedOff(true); LockScreenIfRequired(); } @@ -307,6 +326,7 @@ void PowerButtonController::DismissMenu() { if (IsMenuOpened()) menu_widget_->Hide(); + show_menu_animation_done_ = false; active_window_widget_controller_.reset(); } @@ -493,13 +513,8 @@ void PowerButtonController::SetShowMenuAnimationDone() { ->power_button_menu_view() ->FocusPowerOffButton(); - pre_shutdown_timer_.Start( - FROM_HERE, kStartShutdownAnimationTimeout, - base::BindRepeating( - [](LockStateController* controller) { - controller->StartShutdownAnimation(ShutdownReason::POWER_BUTTON); - }, - lock_state_controller_)); + pre_shutdown_timer_.Start(FROM_HERE, kStartShutdownAnimationTimeout, this, + &PowerButtonController::OnPreShutdownTimeout); } void PowerButtonController::ParsePowerButtonPositionSwitch() { diff --git a/ash/system/power/power_button_controller.h b/ash/system/power/power_button_controller.h index ca15f2262a408..a518d183f6f91 100644 --- a/ash/system/power/power_button_controller.h +++ b/ash/system/power/power_button_controller.h @@ -159,6 +159,10 @@ class ASH_EXPORT PowerButtonController // button is pressed or when |power_button_menu_timer_| fires. void StartPowerMenuAnimation(); + // Called by |pre_shutdown_timer_| to start the cancellable pre-shutdown + // animation. + void OnPreShutdownTimeout(); + // Updates |button_type_| and |force_clamshell_power_button_| based on the // current command line. void ProcessCommandLine(); @@ -218,6 +222,9 @@ class ASH_EXPORT PowerButtonController // True if the screen was off when the power button was pressed. bool screen_off_when_power_button_down_ = false; + // True if power menu is already shown when pressing the power button. + bool menu_shown_when_power_button_down_ = false; + // True if the next button release event should force the display off. bool force_off_on_button_up_ = false; diff --git a/ash/system/power/power_button_controller_unittest.cc b/ash/system/power/power_button_controller_unittest.cc index 2bc0428607b10..d33f06d06600e 100644 --- a/ash/system/power/power_button_controller_unittest.cc +++ b/ash/system/power/power_button_controller_unittest.cc @@ -218,6 +218,13 @@ TEST_F(PowerButtonControllerTest, TappingPowerButtonOfClamshell) { EXPECT_FALSE(power_manager_client_->backlights_forced_off()); // Power button menu should keep opened if showing animation has finished. EXPECT_TRUE(power_button_test_api_->IsMenuOpened()); + + // Tapping power button when menu is already shown should not turn screen off. + AdvanceClockToAvoidIgnoring(); + PressPowerButton(); + ReleasePowerButton(); + EXPECT_FALSE(power_manager_client_->backlights_forced_off()); + EXPECT_TRUE(power_button_test_api_->IsMenuOpened()); } // Tests that tapping power button of a device that has tablet mode switch. @@ -240,6 +247,7 @@ TEST_F(PowerButtonControllerTest, TappingPowerButtonOfTablet) { // Showing power menu animation should start until power menu timer is // timeout. + AdvanceClockToAvoidIgnoring(); PressPowerButton(); power_button_test_api_->SetShowMenuAnimationDone(false); EXPECT_TRUE(power_button_test_api_->TriggerPowerButtonMenuTimeout()); @@ -250,8 +258,23 @@ TEST_F(PowerButtonControllerTest, TappingPowerButtonOfTablet) { // release the power button. EXPECT_TRUE(power_button_test_api_->IsMenuOpened()); + // Tapping power button when menu is already shown should still turn screen + // off and dismiss the menu. + AdvanceClockToAvoidIgnoring(); + PressPowerButton(); + EXPECT_TRUE(power_button_test_api_->PreShutdownTimerIsRunning()); + ReleasePowerButton(); + EXPECT_FALSE(power_button_test_api_->PreShutdownTimerIsRunning()); + EXPECT_TRUE(power_manager_client_->backlights_forced_off()); + EXPECT_FALSE(power_button_test_api_->IsMenuOpened()); + + // Should turn screen on if screen is off. + AdvanceClockToAvoidIgnoring(); + TappingPowerButtonWhenScreenIsIdleOff(); + // Should not turn screen off if clamshell-like power button behavior is // requested. + AdvanceClockToAvoidIgnoring(); ForceClamshellPowerButton(); SetTabletModeSwitchState(PowerManagerClient::TabletMode::ON); AdvanceClockToAvoidIgnoring(); @@ -292,6 +315,17 @@ TEST_F(PowerButtonControllerTest, ModeSpecificPowerButton) { EXPECT_TRUE(power_button_test_api_->IsMenuOpened()); ReleasePowerButton(); EXPECT_FALSE(power_manager_client_->backlights_forced_off()); + + // Tapping power button again in laptop mode when menu is opened should not + // turn the screen off. + EXPECT_TRUE(power_button_test_api_->IsMenuOpened()); + AdvanceClockToAvoidIgnoring(); + PressPowerButton(); + EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning()); + EXPECT_TRUE(power_button_test_api_->PreShutdownTimerIsRunning()); + ReleasePowerButton(); + EXPECT_FALSE(power_manager_client_->backlights_forced_off()); + EXPECT_TRUE(power_button_test_api_->IsMenuOpened()); } // Tests that release power button after menu is opened but before trigger @@ -839,11 +873,37 @@ TEST_F(PowerButtonControllerTest, MenuItemsToLoginStatus) { EXPECT_TRUE(power_button_test_api_->MenuHasSignOutItem()); } -// Repeat long press should redisplay the menu. -TEST_F(PowerButtonControllerTest, PressButtonWhenMenuIsOpened) { +// Tests long-pressing the power button when the menu is open. +TEST_F(PowerButtonControllerTest, LongPressButtonWhenMenuIsOpened) { OpenPowerButtonMenu(); AdvanceClockToAvoidIgnoring(); - OpenPowerButtonMenu(); + + // Long pressing the power button when menu is opened should not dismiss the + // menu but trigger the pre-shutdown animation instead. Menu should stay + // opened if releasing the button can cancel the animation. + PressPowerButton(); + EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning()); + ASSERT_TRUE(power_button_test_api_->TriggerPreShutdownTimeout()); + EXPECT_TRUE(lock_state_test_api_->shutdown_timer_is_running()); + ReleasePowerButton(); + EXPECT_FALSE(lock_state_test_api_->shutdown_timer_is_running()); + EXPECT_TRUE(power_button_test_api_->IsMenuOpened()); + + // Change focus to 'sign out' + PressKey(ui::VKEY_TAB); + EXPECT_TRUE(power_button_test_api_->GetPowerButtonMenuView() + ->sign_out_item_for_test() + ->HasFocus()); + + // Long press when menu is opened with focus on 'sign out' item will change + // the focus to 'power off' after starting the pre-shutdown animation. + PressPowerButton(); + ASSERT_TRUE(power_button_test_api_->TriggerPreShutdownTimeout()); + EXPECT_TRUE(lock_state_test_api_->shutdown_timer_is_running()); + EXPECT_TRUE(power_button_test_api_->GetPowerButtonMenuView() + ->power_off_item_for_test() + ->HasFocus()); + ReleasePowerButton(); } // Tests that switches between laptop mode and tablet mode should dismiss the