diff options
Diffstat (limited to 'chromium/ash/wm/power_button_controller_unittest.cc')
-rw-r--r-- | chromium/ash/wm/power_button_controller_unittest.cc | 637 |
1 files changed, 637 insertions, 0 deletions
diff --git a/chromium/ash/wm/power_button_controller_unittest.cc b/chromium/ash/wm/power_button_controller_unittest.cc new file mode 100644 index 00000000000..e1ce71bbc2c --- /dev/null +++ b/chromium/ash/wm/power_button_controller_unittest.cc @@ -0,0 +1,637 @@ +// Copyright (c) 2012 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/ash_switches.h" +#include "ash/session_state_delegate.h" +#include "ash/shell.h" +#include "ash/test/ash_test_base.h" +#include "ash/test/test_shell_delegate.h" +#include "ash/wm/lock_state_controller.h" +#include "ash/wm/power_button_controller.h" +#include "ash/wm/session_state_animator.h" +#include "ash/wm/session_state_controller_impl.h" +#include "base/command_line.h" +#include "base/memory/scoped_ptr.h" +#include "base/time/time.h" +#include "ui/aura/env.h" +#include "ui/aura/root_window.h" +#include "ui/aura/test/event_generator.h" +#include "ui/compositor/scoped_animation_duration_scale_mode.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/size.h" + +namespace ash { +namespace test { +namespace { +bool cursor_visible() { + return ash::Shell::GetInstance()->cursor_manager()->IsCursorVisible(); +} +} + +// Fake implementation of PowerButtonControllerDelegate that just logs requests +// to lock the screen and shut down the device. +class TestPowerButtonControllerDelegate : + public LockStateControllerDelegate { + public: + TestPowerButtonControllerDelegate() + : num_lock_requests_(0), + num_shutdown_requests_(0) {} + + int num_lock_requests() const { return num_lock_requests_; } + int num_shutdown_requests() const { return num_shutdown_requests_; } + + // PowerButtonControllerDelegate implementation. + virtual void RequestLockScreen() OVERRIDE { + num_lock_requests_++; + } + virtual void RequestShutdown() OVERRIDE { + num_shutdown_requests_++; + } + + private: + int num_lock_requests_; + int num_shutdown_requests_; + + DISALLOW_COPY_AND_ASSIGN(TestPowerButtonControllerDelegate); +}; + +class PowerButtonControllerTest : public AshTestBase { + public: + PowerButtonControllerTest() : controller_(NULL), delegate_(NULL) {} + virtual ~PowerButtonControllerTest() {} + + virtual void SetUp() OVERRIDE { + CommandLine::ForCurrentProcess()->AppendSwitch( + ash::switches::kAshDisableNewLockAnimations); + + AshTestBase::SetUp(); + delegate_ = new TestPowerButtonControllerDelegate; + controller_ = Shell::GetInstance()->power_button_controller(); + lock_state_controller_ = static_cast<SessionStateControllerImpl*>( + Shell::GetInstance()->lock_state_controller()); + lock_state_controller_->SetDelegate(delegate_); // transfers ownership + test_api_.reset(new SessionStateControllerImpl::TestApi( + lock_state_controller_)); + animator_api_.reset(new internal::SessionStateAnimator::TestApi( + lock_state_controller_->animator_.get())); + shell_delegate_ = reinterpret_cast<TestShellDelegate*>( + ash::Shell::GetInstance()->delegate()); + state_delegate_ = Shell::GetInstance()->session_state_delegate(); + } + + protected: + void GenerateMouseMoveEvent() { + aura::test::EventGenerator generator( + Shell::GetPrimaryRootWindow()); + generator.MoveMouseTo(10, 10); + } + + int NumShutdownRequests() { + return delegate_->num_shutdown_requests() + + shell_delegate_->num_exit_requests(); + } + + PowerButtonController* controller_; // not owned + SessionStateControllerImpl* lock_state_controller_; // not owned + TestPowerButtonControllerDelegate* delegate_; // not owned + TestShellDelegate* shell_delegate_; // not owned + SessionStateDelegate* state_delegate_; // not owned + + scoped_ptr<SessionStateControllerImpl::TestApi> test_api_; + scoped_ptr<internal::SessionStateAnimator::TestApi> animator_api_; + + private: + DISALLOW_COPY_AND_ASSIGN(PowerButtonControllerTest); +}; + +// Test the lock-to-shutdown flow for non-Chrome-OS hardware that doesn't +// correctly report power button releases. We should lock immediately the first +// time the button is pressed and shut down when it's pressed from the locked +// state. +TEST_F(PowerButtonControllerTest, LegacyLockAndShutDown) { + controller_->set_has_legacy_power_button_for_test(true); + lock_state_controller_->OnLoginStateChanged(user::LOGGED_IN_USER); + lock_state_controller_->OnLockStateChanged(false); + + // We should request that the screen be locked immediately after seeing the + // power button get pressed. + controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, + internal::SessionStateAnimator::ANIMATION_PARTIAL_CLOSE)); + EXPECT_FALSE(test_api_->lock_timer_is_running()); + EXPECT_EQ(1, delegate_->num_lock_requests()); + + // Notify that we locked successfully. + lock_state_controller_->OnStartingLock(); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::LAUNCHER, + internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY)); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, + internal::SessionStateAnimator::ANIMATION_FULL_CLOSE)); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS, + internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY)); + + // Notify that the lock window is visible. We should make it fade in. + lock_state_controller_->OnLockStateChanged(true); + state_delegate_->LockScreen(); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::kAllLockScreenContainersMask, + internal::SessionStateAnimator::ANIMATION_FADE_IN)); + + // We shouldn't progress towards the shutdown state, however. + EXPECT_FALSE(test_api_->lock_to_shutdown_timer_is_running()); + EXPECT_FALSE(test_api_->shutdown_timer_is_running()); + controller_->OnPowerButtonEvent(false, base::TimeTicks::Now()); + + // Hold the button again and check that we start shutting down. + controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); + EXPECT_EQ(0, NumShutdownRequests()); + + // Previously we're checking that the all containers group was animated which + // was in fact checking that + // 1. All user session containers have transform (including wallpaper). + // They're in this state after lock. + // 2. Screen locker and related containers are in fact animating + // (as shutdown is in progress). + // With http://crbug.com/144737 we no longer animate user session wallpaper + // during lock so it makes sense only to check that screen lock and related + // containers are animated during shutdown. + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::kAllLockScreenContainersMask, + internal::SessionStateAnimator::ANIMATION_FULL_CLOSE)); + // Make sure a mouse move event won't show the cursor. + GenerateMouseMoveEvent(); + EXPECT_FALSE(cursor_visible()); + EXPECT_TRUE(test_api_->real_shutdown_timer_is_running()); + test_api_->trigger_real_shutdown_timeout(); + EXPECT_EQ(1, NumShutdownRequests()); +} + +// Test that we start shutting down immediately if the power button is pressed +// while we're not logged in on an unofficial system. +TEST_F(PowerButtonControllerTest, LegacyNotLoggedIn) { + controller_->set_has_legacy_power_button_for_test(true); + lock_state_controller_->OnLoginStateChanged(user::LOGGED_IN_NONE); + lock_state_controller_->OnLockStateChanged(false); + SetUserLoggedIn(false); + controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); + EXPECT_TRUE(test_api_->real_shutdown_timer_is_running()); +} + +// Test that we start shutting down immediately if the power button is pressed +// while we're logged in as a guest on an unofficial system. +TEST_F(PowerButtonControllerTest, LegacyGuest) { + controller_->set_has_legacy_power_button_for_test(true); + lock_state_controller_->OnLoginStateChanged(user::LOGGED_IN_GUEST); + lock_state_controller_->OnLockStateChanged(false); + SetCanLockScreen(false); + controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); + EXPECT_TRUE(test_api_->real_shutdown_timer_is_running()); +} + +// When we hold the power button while the user isn't logged in, we should shut +// down the machine directly. +TEST_F(PowerButtonControllerTest, ShutdownWhenNotLoggedIn) { + controller_->set_has_legacy_power_button_for_test(false); + lock_state_controller_->OnLoginStateChanged(user::LOGGED_IN_NONE); + lock_state_controller_->OnLockStateChanged(false); + SetUserLoggedIn(false); + + // Press the power button and check that we start the shutdown timer. + controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); + EXPECT_FALSE(test_api_->lock_timer_is_running()); + EXPECT_TRUE(test_api_->shutdown_timer_is_running()); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::kAllContainersMask, + internal::SessionStateAnimator::ANIMATION_PARTIAL_CLOSE)); + + // Release the power button before the shutdown timer fires. + controller_->OnPowerButtonEvent(false, base::TimeTicks::Now()); + EXPECT_FALSE(test_api_->shutdown_timer_is_running()); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::kAllContainersMask, + internal::SessionStateAnimator::ANIMATION_UNDO_PARTIAL_CLOSE)); + + // Press the button again and make the shutdown timeout fire this time. + // Check that we start the timer for actually requesting the shutdown. + controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); + EXPECT_TRUE(test_api_->shutdown_timer_is_running()); + test_api_->trigger_shutdown_timeout(); + EXPECT_TRUE(test_api_->real_shutdown_timer_is_running()); + EXPECT_EQ(0, NumShutdownRequests()); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::LAUNCHER | + internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, + internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY)); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::kAllLockScreenContainersMask, + internal::SessionStateAnimator::ANIMATION_FULL_CLOSE)); + + // When the timout fires, we should request a shutdown. + test_api_->trigger_real_shutdown_timeout(); + EXPECT_EQ(1, NumShutdownRequests()); +} + +// Test that we lock the screen and deal with unlocking correctly. +TEST_F(PowerButtonControllerTest, LockAndUnlock) { + controller_->set_has_legacy_power_button_for_test(false); + lock_state_controller_->OnLoginStateChanged(user::LOGGED_IN_USER); + lock_state_controller_->OnLockStateChanged(false); + + // We should initially be showing the screen locker containers, since they + // also contain login-related windows that we want to show during the + // logging-in animation. + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS, + internal::SessionStateAnimator::ANIMATION_RESTORE)); + + // Press the power button and check that the lock timer is started and that we + // start scaling the non-screen-locker containers. + controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); + EXPECT_TRUE(test_api_->lock_timer_is_running()); + EXPECT_FALSE(test_api_->shutdown_timer_is_running()); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, + internal::SessionStateAnimator::ANIMATION_PARTIAL_CLOSE)); + + // Release the button before the lock timer fires. + controller_->OnPowerButtonEvent(false, base::TimeTicks::Now()); + EXPECT_FALSE(test_api_->lock_timer_is_running()); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, + internal::SessionStateAnimator::ANIMATION_UNDO_PARTIAL_CLOSE)); + + // Press the button and fire the lock timer. We should request that the + // screen be locked, but we should still be in the slow-close animation. + controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); + EXPECT_TRUE(test_api_->lock_timer_is_running()); + EXPECT_EQ(0, delegate_->num_lock_requests()); + test_api_->trigger_lock_timeout(); + EXPECT_EQ(1, delegate_->num_lock_requests()); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, + internal::SessionStateAnimator::ANIMATION_PARTIAL_CLOSE)); + + // Notify that we locked successfully. + lock_state_controller_->OnStartingLock(); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::LAUNCHER, + internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY)); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, + internal::SessionStateAnimator::ANIMATION_FULL_CLOSE)); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS, + internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY)); + + // Notify that the lock window is visible. We should make it fade in. + lock_state_controller_->OnLockStateChanged(true); + state_delegate_->LockScreen(); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::kAllLockScreenContainersMask, + internal::SessionStateAnimator::ANIMATION_FADE_IN)); + + // When we release the power button, the lock-to-shutdown timer should be + // stopped. + EXPECT_TRUE(test_api_->lock_to_shutdown_timer_is_running()); + controller_->OnPowerButtonEvent(false, base::TimeTicks::Now()); + EXPECT_FALSE(test_api_->lock_to_shutdown_timer_is_running()); + + // Notify that the screen has been unlocked. We should show the + // non-screen-locker windows. + lock_state_controller_->OnLockStateChanged(false); + state_delegate_->UnlockScreen(); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::DESKTOP_BACKGROUND | + internal::SessionStateAnimator::LAUNCHER | + internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, + internal::SessionStateAnimator::ANIMATION_RESTORE)); +} + +// Hold the power button down from the unlocked state to eventual shutdown. +TEST_F(PowerButtonControllerTest, LockToShutdown) { + controller_->set_has_legacy_power_button_for_test(false); + lock_state_controller_->OnLoginStateChanged(user::LOGGED_IN_USER); + lock_state_controller_->OnLockStateChanged(false); + + // Hold the power button and lock the screen. + controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); + EXPECT_TRUE(test_api_->lock_timer_is_running()); + test_api_->trigger_lock_timeout(); + lock_state_controller_->OnStartingLock(); + lock_state_controller_->OnLockStateChanged(true); + state_delegate_->LockScreen(); + + // When the lock-to-shutdown timeout fires, we should start the shutdown + // timer. + EXPECT_TRUE(test_api_->lock_to_shutdown_timer_is_running()); + test_api_->trigger_lock_to_shutdown_timeout(); + EXPECT_TRUE(test_api_->shutdown_timer_is_running()); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::kAllContainersMask, + internal::SessionStateAnimator::ANIMATION_PARTIAL_CLOSE)); + + // Fire the shutdown timeout and check that we request shutdown. + test_api_->trigger_shutdown_timeout(); + EXPECT_TRUE(test_api_->real_shutdown_timer_is_running()); + EXPECT_EQ(0, NumShutdownRequests()); + test_api_->trigger_real_shutdown_timeout(); + EXPECT_EQ(1, NumShutdownRequests()); +} + + +// Hold the power button down from the unlocked state to eventual shutdown, +// then release the button while system does locking. +TEST_F(PowerButtonControllerTest, CancelLockToShutdown) { + controller_->set_has_legacy_power_button_for_test(false); + + lock_state_controller_->OnLoginStateChanged(user::LOGGED_IN_USER); + lock_state_controller_->OnLockStateChanged(false); + + // Hold the power button and lock the screen. + controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); + EXPECT_TRUE(test_api_->lock_timer_is_running()); + test_api_->trigger_lock_timeout(); + lock_state_controller_->OnStartingLock(); + + // Power button is released while system attempts to lock. + controller_->OnPowerButtonEvent(false, base::TimeTicks::Now()); + lock_state_controller_->OnLockStateChanged(true); + state_delegate_->LockScreen(); + + EXPECT_FALSE(lock_state_controller_->ShutdownRequested()); + EXPECT_FALSE(test_api_->lock_to_shutdown_timer_is_running()); + EXPECT_FALSE(test_api_->shutdown_timer_is_running()); +} + +// Test that we handle the case where lock requests are ignored. +TEST_F(PowerButtonControllerTest, LockFail) { + // We require animations to have a duration for this test. + ui::ScopedAnimationDurationScaleMode normal_duration_mode( + ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION); + + controller_->set_has_legacy_power_button_for_test(false); + lock_state_controller_->OnLoginStateChanged(user::LOGGED_IN_USER); + lock_state_controller_->OnLockStateChanged(false); + + // Hold the power button and lock the screen. + controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); + EXPECT_TRUE(test_api_->lock_timer_is_running()); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::DESKTOP_BACKGROUND | + internal::SessionStateAnimator::LAUNCHER | + internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, + internal::SessionStateAnimator::ANIMATION_RESTORE)); + test_api_->trigger_lock_timeout(); + EXPECT_EQ(1, delegate_->num_lock_requests()); + EXPECT_TRUE(test_api_->lock_fail_timer_is_running()); + + // We shouldn't start the lock-to-shutdown timer until the screen has actually + // been locked. + EXPECT_FALSE(test_api_->lock_to_shutdown_timer_is_running()); + + // Act as if the request timed out. We should restore the windows. + test_api_->trigger_lock_fail_timeout(); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, + internal::SessionStateAnimator::ANIMATION_RESTORE)); +} + +// Test the basic operation of the lock button. +TEST_F(PowerButtonControllerTest, LockButtonBasic) { + controller_->set_has_legacy_power_button_for_test(false); + // The lock button shouldn't do anything if we aren't logged in. + lock_state_controller_->OnLoginStateChanged(user::LOGGED_IN_NONE); + lock_state_controller_->OnLockStateChanged(false); + SetUserLoggedIn(false); + controller_->OnLockButtonEvent(true, base::TimeTicks::Now()); + EXPECT_FALSE(test_api_->lock_timer_is_running()); + controller_->OnLockButtonEvent(false, base::TimeTicks::Now()); + EXPECT_EQ(0, delegate_->num_lock_requests()); + + // Ditto for when we're logged in as a guest. + lock_state_controller_->OnLoginStateChanged(user::LOGGED_IN_GUEST); + SetUserLoggedIn(true); + SetCanLockScreen(false); + controller_->OnLockButtonEvent(true, base::TimeTicks::Now()); + EXPECT_FALSE(test_api_->lock_timer_is_running()); + controller_->OnLockButtonEvent(false, base::TimeTicks::Now()); + EXPECT_EQ(0, delegate_->num_lock_requests()); + + // If we're logged in as a regular user, we should start the lock timer and + // the pre-lock animation. + lock_state_controller_->OnLoginStateChanged(user::LOGGED_IN_USER); + SetCanLockScreen(true); + controller_->OnLockButtonEvent(true, base::TimeTicks::Now()); + EXPECT_TRUE(test_api_->lock_timer_is_running()); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, + internal::SessionStateAnimator::ANIMATION_PARTIAL_CLOSE)); + + // If the button is released immediately, we shouldn't lock the screen. + controller_->OnLockButtonEvent(false, base::TimeTicks::Now()); + EXPECT_FALSE(test_api_->lock_timer_is_running()); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, + internal::SessionStateAnimator::ANIMATION_UNDO_PARTIAL_CLOSE)); + EXPECT_EQ(0, delegate_->num_lock_requests()); + + // Press the button again and let the lock timeout fire. We should request + // that the screen be locked. + controller_->OnLockButtonEvent(true, base::TimeTicks::Now()); + EXPECT_TRUE(test_api_->lock_timer_is_running()); + test_api_->trigger_lock_timeout(); + EXPECT_EQ(1, delegate_->num_lock_requests()); + + // Pressing the lock button while we have a pending lock request shouldn't do + // anything. + controller_->OnLockButtonEvent(false, base::TimeTicks::Now()); + controller_->OnLockButtonEvent(true, base::TimeTicks::Now()); + EXPECT_FALSE(test_api_->lock_timer_is_running()); + controller_->OnLockButtonEvent(false, base::TimeTicks::Now()); + + // Pressing the button also shouldn't do anything after the screen is locked. + lock_state_controller_->OnStartingLock(); + lock_state_controller_->OnLockStateChanged(true); + state_delegate_->LockScreen(); + controller_->OnLockButtonEvent(true, base::TimeTicks::Now()); + EXPECT_FALSE(test_api_->lock_timer_is_running()); + controller_->OnLockButtonEvent(false, base::TimeTicks::Now()); +} + +// Test that the power button takes priority over the lock button. +TEST_F(PowerButtonControllerTest, PowerButtonPreemptsLockButton) { + controller_->set_has_legacy_power_button_for_test(false); + lock_state_controller_->OnLoginStateChanged(user::LOGGED_IN_USER); + lock_state_controller_->OnLockStateChanged(false); + + // While the lock button is down, hold the power button. + controller_->OnLockButtonEvent(true, base::TimeTicks::Now()); + EXPECT_TRUE(test_api_->lock_timer_is_running()); + controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); + EXPECT_TRUE(test_api_->lock_timer_is_running()); + + // The lock timer shouldn't be stopped when the lock button is released. + controller_->OnLockButtonEvent(false, base::TimeTicks::Now()); + EXPECT_TRUE(test_api_->lock_timer_is_running()); + controller_->OnPowerButtonEvent(false, base::TimeTicks::Now()); + EXPECT_FALSE(test_api_->lock_timer_is_running()); + + // Now press the power button first and then the lock button. + controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); + EXPECT_TRUE(test_api_->lock_timer_is_running()); + controller_->OnLockButtonEvent(true, base::TimeTicks::Now()); + EXPECT_TRUE(test_api_->lock_timer_is_running()); + + // Releasing the power button should stop the lock timer. + controller_->OnPowerButtonEvent(false, base::TimeTicks::Now()); + EXPECT_FALSE(test_api_->lock_timer_is_running()); + controller_->OnLockButtonEvent(false, base::TimeTicks::Now()); + EXPECT_FALSE(test_api_->lock_timer_is_running()); +} + +// When the screen is locked without going through the usual power-button +// slow-close path (e.g. via the wrench menu), test that we still show the +// fast-close animation. +TEST_F(PowerButtonControllerTest, LockWithoutButton) { + lock_state_controller_->OnLoginStateChanged(user::LOGGED_IN_USER); + lock_state_controller_->OnStartingLock(); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, + internal::SessionStateAnimator::ANIMATION_FULL_CLOSE)); +} + +// When we hear that the process is exiting but we haven't had a chance to +// display an animation, we should just blank the screen. +TEST_F(PowerButtonControllerTest, ShutdownWithoutButton) { + lock_state_controller_->OnLoginStateChanged(user::LOGGED_IN_USER); + lock_state_controller_->OnAppTerminating(); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::kAllContainersMask, + internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY)); + GenerateMouseMoveEvent(); + EXPECT_FALSE(cursor_visible()); +} + +// Test that we display the fast-close animation and shut down when we get an +// outside request to shut down (e.g. from the login or lock screen). +TEST_F(PowerButtonControllerTest, RequestShutdownFromLoginScreen) { + lock_state_controller_->OnLoginStateChanged(user::LOGGED_IN_NONE); + lock_state_controller_->OnLockStateChanged(false); + SetUserLoggedIn(false); + lock_state_controller_->RequestShutdown(); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, + internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY)); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::kAllLockScreenContainersMask, + internal::SessionStateAnimator::ANIMATION_FULL_CLOSE)); + GenerateMouseMoveEvent(); + EXPECT_FALSE(cursor_visible()); + + EXPECT_EQ(0, NumShutdownRequests()); + EXPECT_TRUE(test_api_->real_shutdown_timer_is_running()); + test_api_->trigger_real_shutdown_timeout(); + EXPECT_EQ(1, NumShutdownRequests()); +} + +TEST_F(PowerButtonControllerTest, RequestShutdownFromLockScreen) { + lock_state_controller_->OnLoginStateChanged(user::LOGGED_IN_USER); + lock_state_controller_->OnLockStateChanged(true); + state_delegate_->LockScreen(); + lock_state_controller_->RequestShutdown(); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, + internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY)); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::kAllLockScreenContainersMask, + internal::SessionStateAnimator::ANIMATION_FULL_CLOSE)); + GenerateMouseMoveEvent(); + EXPECT_FALSE(cursor_visible()); + + EXPECT_EQ(0, NumShutdownRequests()); + EXPECT_TRUE(test_api_->real_shutdown_timer_is_running()); + test_api_->trigger_real_shutdown_timeout(); + EXPECT_EQ(1, NumShutdownRequests()); +} + +TEST_F(PowerButtonControllerTest, RequestAndCancelShutdownFromLockScreen) { + lock_state_controller_->OnLoginStateChanged(user::LOGGED_IN_USER); + lock_state_controller_->OnLockStateChanged(true); + state_delegate_->LockScreen(); + + // Press the power button and check that we start the shutdown timer. + controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); + EXPECT_FALSE(test_api_->lock_timer_is_running()); + EXPECT_TRUE(test_api_->shutdown_timer_is_running()); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::kAllContainersMask, + internal::SessionStateAnimator::ANIMATION_PARTIAL_CLOSE)); + + // Release the power button before the shutdown timer fires. + controller_->OnPowerButtonEvent(false, base::TimeTicks::Now()); + EXPECT_FALSE(test_api_->shutdown_timer_is_running()); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::kAllLockScreenContainersMask, + internal::SessionStateAnimator::ANIMATION_UNDO_PARTIAL_CLOSE)); + EXPECT_TRUE( + animator_api_->ContainersAreAnimated( + internal::SessionStateAnimator::DESKTOP_BACKGROUND, + internal::SessionStateAnimator::ANIMATION_RESTORE)); +} + +// Test that we ignore power button presses when the screen is turned off. +TEST_F(PowerButtonControllerTest, IgnorePowerButtonIfScreenIsOff) { + lock_state_controller_->OnLoginStateChanged(user::LOGGED_IN_USER); + + // When the screen brightness is at 0%, we shouldn't do anything in response + // to power button presses. + controller_->OnScreenBrightnessChanged(0.0); + controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); + EXPECT_FALSE(test_api_->lock_timer_is_running()); + + // After increasing the brightness to 10%, we should start the timer like + // usual. + controller_->OnScreenBrightnessChanged(10.0); + controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); + EXPECT_TRUE(test_api_->lock_timer_is_running()); +} + +} // namespace test +} // namespace ash |