| // Copyright 2013 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/wm/lock_state_controller.h" |
| |
| #include "ash/ash_switches.h" |
| #include "ash/session/session_state_delegate.h" |
| #include "ash/shell.h" |
| #include "ash/shell_window_ids.h" |
| #include "ash/test/ash_test_base.h" |
| #include "ash/test/test_lock_state_controller_delegate.h" |
| #include "ash/test/test_shell_delegate.h" |
| #include "ash/wm/power_button_controller.h" |
| #include "ash/wm/session_state_animator.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/test/event_generator.h" |
| #include "ui/aura/test/test_window_delegate.h" |
| #include "ui/aura/window_event_dispatcher.h" |
| #include "ui/compositor/layer_animator.h" |
| #include "ui/compositor/scoped_animation_duration_scale_mode.h" |
| #include "ui/compositor/scoped_layer_animation_settings.h" |
| #include "ui/gfx/rect.h" |
| #include "ui/gfx/size.h" |
| |
| #if defined(OS_CHROMEOS) |
| #include "ui/display/chromeos/display_configurator.h" |
| #include "ui/display/chromeos/test/test_display_snapshot.h" |
| #include "ui/display/types/display_constants.h" |
| #endif |
| |
| #if defined(OS_WIN) |
| #include "base/win/windows_version.h" |
| #endif |
| |
| namespace ash { |
| namespace test { |
| namespace { |
| |
| bool cursor_visible() { |
| return ash::Shell::GetInstance()->cursor_manager()->IsCursorVisible(); |
| } |
| |
| void CheckCalledCallback(bool* flag) { |
| if (flag) |
| (*flag) = true; |
| } |
| |
| aura::Window* GetContainer(int container ) { |
| aura::Window* root_window = Shell::GetPrimaryRootWindow(); |
| return Shell::GetContainer(root_window, container); |
| } |
| |
| bool IsBackgroundHidden() { |
| return !GetContainer(kShellWindowId_DesktopBackgroundContainer)->IsVisible(); |
| } |
| |
| void HideBackground() { |
| ui::ScopedLayerAnimationSettings settings( |
| GetContainer(kShellWindowId_DesktopBackgroundContainer) |
| ->layer() |
| ->GetAnimator()); |
| settings.SetTransitionDuration(base::TimeDelta()); |
| GetContainer(kShellWindowId_DesktopBackgroundContainer)->Hide(); |
| } |
| |
| } // namespace |
| |
| class LockStateControllerTest : public AshTestBase { |
| public: |
| LockStateControllerTest() : controller_(NULL), delegate_(NULL) {} |
| virtual ~LockStateControllerTest() {} |
| |
| virtual void SetUp() OVERRIDE { |
| AshTestBase::SetUp(); |
| |
| // We would control animations in a fine way: |
| animation_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode( |
| ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION)); |
| // TODO(antrim) : restore |
| // animator_helper_ = ui::test::CreateLayerAnimatorHelperForTest(); |
| |
| // Temporary disable animations so that observer is always called, and |
| // no leaks happen during tests. |
| animation_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode( |
| ui::ScopedAnimationDurationScaleMode::ZERO_DURATION)); |
| // TODO(antrim): once there is a way to mock time and run animations, make |
| // sure that animations are finished even in simple tests. |
| |
| delegate_ = new TestLockStateControllerDelegate; |
| controller_ = Shell::GetInstance()->power_button_controller(); |
| lock_state_controller_ = static_cast<LockStateController*>( |
| Shell::GetInstance()->lock_state_controller()); |
| lock_state_controller_->SetDelegate(delegate_); // transfers ownership |
| test_api_.reset(new LockStateController::TestApi(lock_state_controller_)); |
| animator_api_.reset( |
| new SessionStateAnimator::TestApi(lock_state_controller_-> |
| animator_.get())); |
| shell_delegate_ = reinterpret_cast<TestShellDelegate*>( |
| ash::Shell::GetInstance()->delegate()); |
| session_state_delegate_ = Shell::GetInstance()->session_state_delegate(); |
| } |
| |
| virtual void TearDown() { |
| // TODO(antrim) : restore |
| // animator_helper_->AdvanceUntilDone(); |
| window_.reset(); |
| AshTestBase::TearDown(); |
| } |
| |
| 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(); |
| } |
| |
| void Advance(SessionStateAnimator::AnimationSpeed speed) { |
| // TODO (antrim) : restore |
| // animator_helper_->Advance(SessionStateAnimator::GetDuration(speed)); |
| } |
| |
| void AdvancePartially(SessionStateAnimator::AnimationSpeed speed, |
| float factor) { |
| // TODO (antrim) : restore |
| // base::TimeDelta duration = SessionStateAnimator::GetDuration(speed); |
| // base::TimeDelta partial_duration = |
| // base::TimeDelta::FromInternalValue(duration.ToInternalValue() * factor); |
| // animator_helper_->Advance(partial_duration); |
| } |
| |
| void ExpectPreLockAnimationStarted() { |
| //TODO (antrim) : restore EXPECT_TRUE(animator_helper_->IsAnimating()); |
| EXPECT_TRUE( |
| animator_api_->ContainersAreAnimated( |
| SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, |
| SessionStateAnimator::ANIMATION_LIFT)); |
| EXPECT_TRUE( |
| animator_api_->ContainersAreAnimated( |
| SessionStateAnimator::LAUNCHER, |
| SessionStateAnimator::ANIMATION_FADE_OUT)); |
| EXPECT_TRUE( |
| animator_api_->ContainersAreAnimated( |
| SessionStateAnimator::LOCK_SCREEN_CONTAINERS, |
| SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY)); |
| EXPECT_TRUE(test_api_->is_animating_lock()); |
| } |
| |
| void ExpectPreLockAnimationCancel() { |
| EXPECT_TRUE( |
| animator_api_->ContainersAreAnimated( |
| SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, |
| SessionStateAnimator::ANIMATION_DROP)); |
| EXPECT_TRUE( |
| animator_api_->ContainersAreAnimated( |
| SessionStateAnimator::LAUNCHER, |
| SessionStateAnimator::ANIMATION_FADE_IN)); |
| } |
| |
| void ExpectPreLockAnimationFinished() { |
| //TODO (antrim) : restore EXPECT_FALSE(animator_helper_->IsAnimating()); |
| EXPECT_TRUE( |
| animator_api_->ContainersAreAnimated( |
| SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, |
| SessionStateAnimator::ANIMATION_LIFT)); |
| EXPECT_TRUE( |
| animator_api_->ContainersAreAnimated( |
| SessionStateAnimator::LAUNCHER, |
| SessionStateAnimator::ANIMATION_FADE_OUT)); |
| EXPECT_TRUE( |
| animator_api_->ContainersAreAnimated( |
| SessionStateAnimator::LOCK_SCREEN_CONTAINERS, |
| SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY)); |
| } |
| |
| void ExpectPostLockAnimationStarted() { |
| //TODO (antrim) : restore EXPECT_TRUE(animator_helper_->IsAnimating()); |
| EXPECT_TRUE( |
| animator_api_->ContainersAreAnimated( |
| SessionStateAnimator::LOCK_SCREEN_CONTAINERS, |
| SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN)); |
| } |
| |
| void ExpectPastLockAnimationFinished() { |
| //TODO (antrim) : restore EXPECT_FALSE(animator_helper_->IsAnimating()); |
| EXPECT_TRUE( |
| animator_api_->ContainersAreAnimated( |
| SessionStateAnimator::LOCK_SCREEN_CONTAINERS, |
| SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN)); |
| } |
| |
| void ExpectUnlockBeforeUIDestroyedAnimationStarted() { |
| //TODO (antrim) : restore EXPECT_TRUE(animator_helper_->IsAnimating()); |
| EXPECT_TRUE( |
| animator_api_->ContainersAreAnimated( |
| SessionStateAnimator::LOCK_SCREEN_CONTAINERS, |
| SessionStateAnimator::ANIMATION_LIFT)); |
| } |
| |
| void ExpectUnlockBeforeUIDestroyedAnimationFinished() { |
| //TODO (antrim) : restore EXPECT_FALSE(animator_helper_->IsAnimating()); |
| EXPECT_TRUE( |
| animator_api_->ContainersAreAnimated( |
| SessionStateAnimator::LOCK_SCREEN_CONTAINERS, |
| SessionStateAnimator::ANIMATION_LIFT)); |
| } |
| |
| void ExpectUnlockAfterUIDestroyedAnimationStarted() { |
| //TODO (antrim) : restore EXPECT_TRUE(animator_helper_->IsAnimating()); |
| EXPECT_TRUE( |
| animator_api_->ContainersAreAnimated( |
| SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, |
| SessionStateAnimator::ANIMATION_DROP)); |
| EXPECT_TRUE( |
| animator_api_->ContainersAreAnimated( |
| SessionStateAnimator::LAUNCHER, |
| SessionStateAnimator::ANIMATION_FADE_IN)); |
| } |
| |
| void ExpectUnlockAfterUIDestroyedAnimationFinished() { |
| //TODO (antrim) : restore EXPECT_FALSE(animator_helper_->IsAnimating()); |
| EXPECT_TRUE( |
| animator_api_->ContainersAreAnimated( |
| SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, |
| SessionStateAnimator::ANIMATION_DROP)); |
| EXPECT_TRUE( |
| animator_api_->ContainersAreAnimated( |
| SessionStateAnimator::LAUNCHER, |
| SessionStateAnimator::ANIMATION_FADE_IN)); |
| } |
| |
| void ExpectShutdownAnimationStarted() { |
| //TODO (antrim) : restore EXPECT_TRUE(animator_helper_->IsAnimating()); |
| EXPECT_TRUE( |
| animator_api_->RootWindowIsAnimated( |
| SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS)); |
| } |
| |
| void ExpectShutdownAnimationFinished() { |
| //TODO (antrim) : restore EXPECT_FALSE(animator_helper_->IsAnimating()); |
| EXPECT_TRUE( |
| animator_api_->RootWindowIsAnimated( |
| SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS)); |
| } |
| |
| void ExpectShutdownAnimationCancel() { |
| //TODO (antrim) : restore EXPECT_TRUE(animator_helper_->IsAnimating()); |
| EXPECT_TRUE( |
| animator_api_->RootWindowIsAnimated( |
| SessionStateAnimator::ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS)); |
| } |
| |
| void ExpectBackgroundIsShowing() { |
| //TODO (antrim) : restore EXPECT_TRUE(animator_helper_->IsAnimating()); |
| EXPECT_TRUE( |
| animator_api_->ContainersAreAnimated( |
| SessionStateAnimator::DESKTOP_BACKGROUND, |
| SessionStateAnimator::ANIMATION_FADE_IN)); |
| } |
| |
| void ExpectBackgroundIsHiding() { |
| //TODO (antrim) : restore EXPECT_TRUE(animator_helper_->IsAnimating()); |
| EXPECT_TRUE( |
| animator_api_->ContainersAreAnimated( |
| SessionStateAnimator::DESKTOP_BACKGROUND, |
| SessionStateAnimator::ANIMATION_FADE_OUT)); |
| } |
| |
| void ExpectUnlockedState() { |
| //TODO (antrim) : restore EXPECT_FALSE(animator_helper_->IsAnimating()); |
| EXPECT_FALSE(session_state_delegate_->IsScreenLocked()); |
| |
| aura::Window::Windows containers; |
| |
| SessionStateAnimator::GetContainers( |
| SessionStateAnimator::LAUNCHER | |
| SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, |
| &containers); |
| for (aura::Window::Windows::const_iterator it = containers.begin(); |
| it != containers.end(); ++it) { |
| aura::Window* window = *it; |
| ui::Layer* layer = window->layer(); |
| EXPECT_EQ(1.0f, layer->opacity()); |
| EXPECT_EQ(0.0f, layer->layer_brightness()); |
| EXPECT_EQ(0.0f, layer->layer_saturation()); |
| EXPECT_EQ(gfx::Transform(), layer->transform()); |
| } |
| } |
| |
| void ExpectLockedState() { |
| //TODO (antrim) : restore EXPECT_FALSE(animator_helper_->IsAnimating()); |
| EXPECT_TRUE(session_state_delegate_->IsScreenLocked()); |
| |
| aura::Window::Windows containers; |
| |
| SessionStateAnimator::GetContainers( |
| SessionStateAnimator::LOCK_SCREEN_RELATED_CONTAINERS | |
| SessionStateAnimator::LOCK_SCREEN_CONTAINERS, |
| &containers); |
| for (aura::Window::Windows::const_iterator it = containers.begin(); |
| it != containers.end(); ++it) { |
| aura::Window* window = *it; |
| ui::Layer* layer = window->layer(); |
| EXPECT_EQ(1.0f, layer->opacity()); |
| EXPECT_EQ(0.0f, layer->layer_brightness()); |
| EXPECT_EQ(0.0f, layer->layer_saturation()); |
| EXPECT_EQ(gfx::Transform(), layer->transform()); |
| } |
| } |
| |
| void PressPowerButton() { |
| controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); |
| //TODO (antrim) : restore animator_helper_->Advance(base::TimeDelta()); |
| } |
| |
| void ReleasePowerButton() { |
| controller_->OnPowerButtonEvent(false, base::TimeTicks::Now()); |
| //TODO (antrim) : restore animator_helper_->Advance(base::TimeDelta()); |
| } |
| |
| void PressLockButton() { |
| controller_->OnLockButtonEvent(true, base::TimeTicks::Now()); |
| } |
| |
| void ReleaseLockButton() { |
| controller_->OnLockButtonEvent(false, base::TimeTicks::Now()); |
| } |
| |
| void SystemLocks() { |
| lock_state_controller_->OnLockStateChanged(true); |
| session_state_delegate_->LockScreen(); |
| //TODO (antrim) : restore animator_helper_->Advance(base::TimeDelta()); |
| } |
| |
| void SuccessfulAuthentication(bool* call_flag) { |
| base::Closure closure = base::Bind(&CheckCalledCallback, call_flag); |
| lock_state_controller_->OnLockScreenHide(closure); |
| //TODO (antrim) : restore animator_helper_->Advance(base::TimeDelta()); |
| } |
| |
| void SystemUnlocks() { |
| lock_state_controller_->OnLockStateChanged(false); |
| session_state_delegate_->UnlockScreen(); |
| //TODO (antrim) : restore animator_helper_->Advance(base::TimeDelta()); |
| } |
| |
| void Initialize(bool legacy_button, user::LoginStatus status) { |
| controller_->set_has_legacy_power_button_for_test(legacy_button); |
| lock_state_controller_->OnLoginStateChanged(status); |
| SetUserLoggedIn(status != user::LOGGED_IN_NONE); |
| if (status == user::LOGGED_IN_GUEST) |
| SetCanLockScreen(false); |
| lock_state_controller_->OnLockStateChanged(false); |
| } |
| |
| void CreateWindowForLockscreen() { |
| window_.reset(new aura::Window(&window_delegate_)); |
| window_->SetBounds(gfx::Rect(0, 0, 100, 100)); |
| window_->SetType(ui::wm::WINDOW_TYPE_NORMAL); |
| window_->Init(aura::WINDOW_LAYER_TEXTURED); |
| window_->SetName("WINDOW"); |
| aura::Window* container = Shell::GetContainer( |
| Shell::GetPrimaryRootWindow(), kShellWindowId_LockScreenContainer); |
| ASSERT_TRUE(container); |
| container->AddChild(window_.get()); |
| window_->Show(); |
| } |
| |
| PowerButtonController* controller_; // not owned |
| LockStateController* lock_state_controller_; // not owned |
| TestLockStateControllerDelegate* delegate_; // not owned |
| TestShellDelegate* shell_delegate_; // not owned |
| SessionStateDelegate* session_state_delegate_; // not owned |
| |
| aura::test::TestWindowDelegate window_delegate_; |
| scoped_ptr<aura::Window> window_; |
| scoped_ptr<ui::ScopedAnimationDurationScaleMode> animation_duration_mode_; |
| scoped_ptr<LockStateController::TestApi> test_api_; |
| scoped_ptr<SessionStateAnimator::TestApi> animator_api_; |
| // TODO(antrim) : restore |
| // scoped_ptr<ui::test::AnimationContainerTestHelper> animator_helper_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(LockStateControllerTest); |
| }; |
| |
| // 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. |
| // TODO(antrim): Reenable this: http://crbug.com/167048 |
| TEST_F(LockStateControllerTest, DISABLED_LegacyLockAndShutDown) { |
| Initialize(true, user::LOGGED_IN_USER); |
| |
| ExpectUnlockedState(); |
| |
| // We should request that the screen be locked immediately after seeing the |
| // power button get pressed. |
| PressPowerButton(); |
| |
| ExpectPreLockAnimationStarted(); |
| |
| EXPECT_FALSE(test_api_->is_lock_cancellable()); |
| |
| Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); |
| |
| ExpectPreLockAnimationFinished(); |
| EXPECT_EQ(1, delegate_->num_lock_requests()); |
| |
| // Notify that we locked successfully. |
| lock_state_controller_->OnStartingLock(); |
| // We had that animation already. |
| //TODO (antrim) : restore |
| // EXPECT_FALSE(animator_helper_->IsAnimating()); |
| |
| SystemLocks(); |
| |
| ExpectPostLockAnimationStarted(); |
| Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); |
| ExpectPastLockAnimationFinished(); |
| |
| // 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()); |
| |
| ReleasePowerButton(); |
| |
| // Hold the button again and check that we start shutting down. |
| PressPowerButton(); |
| |
| ExpectShutdownAnimationStarted(); |
| |
| EXPECT_EQ(0, NumShutdownRequests()); |
| // 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(LockStateControllerTest, LegacyNotLoggedIn) { |
| Initialize(true, user::LOGGED_IN_NONE); |
| |
| PressPowerButton(); |
| ExpectShutdownAnimationStarted(); |
| |
| 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(LockStateControllerTest, LegacyGuest) { |
| Initialize(true, user::LOGGED_IN_GUEST); |
| |
| PressPowerButton(); |
| ExpectShutdownAnimationStarted(); |
| |
| 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(LockStateControllerTest, ShutdownWhenNotLoggedIn) { |
| Initialize(false, user::LOGGED_IN_NONE); |
| |
| // Press the power button and check that we start the shutdown timer. |
| PressPowerButton(); |
| EXPECT_FALSE(test_api_->is_animating_lock()); |
| EXPECT_TRUE(test_api_->shutdown_timer_is_running()); |
| ExpectShutdownAnimationStarted(); |
| |
| AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN, 0.5f); |
| |
| // Release the power button before the shutdown timer fires. |
| ReleasePowerButton(); |
| |
| EXPECT_FALSE(test_api_->shutdown_timer_is_running()); |
| ExpectShutdownAnimationCancel(); |
| |
| AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_REVERT, 0.5f); |
| |
| // Press the button again and make the shutdown timeout fire this time. |
| // Check that we start the timer for actually requesting the shutdown. |
| PressPowerButton(); |
| |
| EXPECT_TRUE(test_api_->shutdown_timer_is_running()); |
| |
| Advance(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN); |
| ExpectShutdownAnimationFinished(); |
| test_api_->trigger_shutdown_timeout(); |
| |
| EXPECT_TRUE(test_api_->real_shutdown_timer_is_running()); |
| EXPECT_EQ(0, NumShutdownRequests()); |
| |
| // 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. |
| // TODO(antrim): Reenable this: http://crbug.com/167048 |
| TEST_F(LockStateControllerTest, DISABLED_LockAndUnlock) { |
| Initialize(false, user::LOGGED_IN_USER); |
| |
| ExpectUnlockedState(); |
| |
| // Press the power button and check that the lock timer is started and that we |
| // start lifting the non-screen-locker containers. |
| PressPowerButton(); |
| |
| ExpectPreLockAnimationStarted(); |
| EXPECT_TRUE(test_api_->is_lock_cancellable()); |
| EXPECT_EQ(0, delegate_->num_lock_requests()); |
| |
| Advance(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE); |
| ExpectPreLockAnimationFinished(); |
| |
| EXPECT_EQ(1, delegate_->num_lock_requests()); |
| |
| // Notify that we locked successfully. |
| lock_state_controller_->OnStartingLock(); |
| // We had that animation already. |
| //TODO (antrim) : restore EXPECT_FALSE(animator_helper_->IsAnimating()); |
| |
| SystemLocks(); |
| |
| ExpectPostLockAnimationStarted(); |
| Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); |
| ExpectPastLockAnimationFinished(); |
| |
| // When we release the power button, the lock-to-shutdown timer should be |
| // stopped. |
| ExpectLockedState(); |
| EXPECT_TRUE(test_api_->lock_to_shutdown_timer_is_running()); |
| ReleasePowerButton(); |
| ExpectLockedState(); |
| 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. |
| bool called = false; |
| SuccessfulAuthentication(&called); |
| |
| ExpectUnlockBeforeUIDestroyedAnimationStarted(); |
| EXPECT_FALSE(called); |
| Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); |
| ExpectUnlockBeforeUIDestroyedAnimationFinished(); |
| |
| EXPECT_TRUE(called); |
| |
| SystemUnlocks(); |
| |
| ExpectUnlockAfterUIDestroyedAnimationStarted(); |
| Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); |
| ExpectUnlockAfterUIDestroyedAnimationFinished(); |
| |
| ExpectUnlockedState(); |
| } |
| |
| // Test that we deal with cancelling lock correctly. |
| // TODO(antrim): Reenable this: http://crbug.com/167048 |
| TEST_F(LockStateControllerTest, DISABLED_LockAndCancel) { |
| Initialize(false, user::LOGGED_IN_USER); |
| |
| ExpectUnlockedState(); |
| |
| // Press the power button and check that the lock timer is started and that we |
| // start lifting the non-screen-locker containers. |
| PressPowerButton(); |
| |
| ExpectPreLockAnimationStarted(); |
| EXPECT_TRUE(test_api_->is_lock_cancellable()); |
| |
| // forward only half way through |
| AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, 0.5f); |
| |
| gfx::Transform transform_before_button_released = |
| GetContainer(kShellWindowId_DefaultContainer)->layer()->transform(); |
| |
| // Release the button before the lock timer fires. |
| ReleasePowerButton(); |
| |
| ExpectPreLockAnimationCancel(); |
| |
| gfx::Transform transform_after_button_released = |
| GetContainer(kShellWindowId_DefaultContainer)->layer()->transform(); |
| // Expect no flickering, animation should proceed from mid-state. |
| EXPECT_EQ(transform_before_button_released, transform_after_button_released); |
| |
| Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); |
| ExpectUnlockedState(); |
| EXPECT_EQ(0, delegate_->num_lock_requests()); |
| } |
| |
| // Test that we deal with cancelling lock correctly. |
| // TODO(antrim): Reenable this: http://crbug.com/167048 |
| TEST_F(LockStateControllerTest, |
| DISABLED_LockAndCancelAndLockAgain) { |
| Initialize(false, user::LOGGED_IN_USER); |
| |
| ExpectUnlockedState(); |
| |
| // Press the power button and check that the lock timer is started and that we |
| // start lifting the non-screen-locker containers. |
| PressPowerButton(); |
| |
| ExpectPreLockAnimationStarted(); |
| EXPECT_TRUE(test_api_->is_lock_cancellable()); |
| |
| // forward only half way through |
| AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, 0.5f); |
| |
| // Release the button before the lock timer fires. |
| ReleasePowerButton(); |
| ExpectPreLockAnimationCancel(); |
| |
| AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, 0.5f); |
| |
| PressPowerButton(); |
| ExpectPreLockAnimationStarted(); |
| EXPECT_TRUE(test_api_->is_lock_cancellable()); |
| |
| AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, 0.6f); |
| |
| EXPECT_EQ(0, delegate_->num_lock_requests()); |
| ExpectPreLockAnimationStarted(); |
| |
| AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, 0.6f); |
| ExpectPreLockAnimationFinished(); |
| EXPECT_EQ(1, delegate_->num_lock_requests()); |
| } |
| |
| // Hold the power button down from the unlocked state to eventual shutdown. |
| // TODO(antrim): Reenable this: http://crbug.com/167048 |
| TEST_F(LockStateControllerTest, DISABLED_LockToShutdown) { |
| Initialize(false, user::LOGGED_IN_USER); |
| |
| // Hold the power button and lock the screen. |
| PressPowerButton(); |
| EXPECT_TRUE(test_api_->is_animating_lock()); |
| |
| Advance(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE); |
| SystemLocks(); |
| Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); |
| |
| // 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(); |
| |
| ExpectShutdownAnimationStarted(); |
| EXPECT_TRUE(test_api_->shutdown_timer_is_running()); |
| |
| // Fire the shutdown timeout and check that we request shutdown. |
| Advance(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN); |
| ExpectShutdownAnimationFinished(); |
| 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(LockStateControllerTest, CancelLockToShutdown) { |
| Initialize(false, user::LOGGED_IN_USER); |
| |
| PressPowerButton(); |
| |
| // Hold the power button and lock the screen. |
| EXPECT_TRUE(test_api_->is_animating_lock()); |
| |
| Advance(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE); |
| SystemLocks(); |
| AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, 0.5f); |
| |
| // Power button is released while system attempts to lock. |
| ReleasePowerButton(); |
| |
| Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); |
| |
| 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. |
| // TODO(antrim): Reenable this: http://crbug.com/167048 |
| TEST_F(LockStateControllerTest, DISABLED_Lock) { |
| // We require animations to have a duration for this test. |
| ui::ScopedAnimationDurationScaleMode normal_duration_mode( |
| ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION); |
| |
| Initialize(false, user::LOGGED_IN_USER); |
| |
| // Hold the power button and lock the screen. |
| PressPowerButton(); |
| ExpectPreLockAnimationStarted(); |
| |
| Advance(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE); |
| |
| 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 and this was animated. |
| 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(); |
| |
| ExpectUnlockAfterUIDestroyedAnimationStarted(); |
| Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); |
| ExpectUnlockAfterUIDestroyedAnimationFinished(); |
| ExpectUnlockedState(); |
| } |
| |
| // Test the basic operation of the lock button (not logged in). |
| TEST_F(LockStateControllerTest, LockButtonBasicNotLoggedIn) { |
| // The lock button shouldn't do anything if we aren't logged in. |
| Initialize(false, user::LOGGED_IN_NONE); |
| |
| PressLockButton(); |
| EXPECT_FALSE(test_api_->is_animating_lock()); |
| ReleaseLockButton(); |
| EXPECT_EQ(0, delegate_->num_lock_requests()); |
| } |
| |
| // Test the basic operation of the lock button (guest). |
| TEST_F(LockStateControllerTest, LockButtonBasicGuest) { |
| // The lock button shouldn't do anything when we're logged in as a guest. |
| Initialize(false, user::LOGGED_IN_GUEST); |
| |
| PressLockButton(); |
| EXPECT_FALSE(test_api_->is_animating_lock()); |
| ReleaseLockButton(); |
| EXPECT_EQ(0, delegate_->num_lock_requests()); |
| } |
| |
| // Test the basic operation of the lock button. |
| // TODO(antrim): Reenable this: http://crbug.com/167048 |
| TEST_F(LockStateControllerTest, DISABLED_LockButtonBasic) { |
| // If we're logged in as a regular user, we should start the lock timer and |
| // the pre-lock animation. |
| Initialize(false, user::LOGGED_IN_USER); |
| |
| PressLockButton(); |
| ExpectPreLockAnimationStarted(); |
| AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, 0.5f); |
| |
| // If the button is released immediately, we shouldn't lock the screen. |
| ReleaseLockButton(); |
| ExpectPreLockAnimationCancel(); |
| Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); |
| |
| ExpectUnlockedState(); |
| 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. |
| PressLockButton(); |
| ExpectPreLockAnimationStarted(); |
| Advance(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE); |
| EXPECT_EQ(1, delegate_->num_lock_requests()); |
| |
| // Pressing the lock button while we have a pending lock request shouldn't do |
| // anything. |
| ReleaseLockButton(); |
| PressLockButton(); |
| ExpectPreLockAnimationFinished(); |
| ReleaseLockButton(); |
| |
| // Pressing the button also shouldn't do anything after the screen is locked. |
| SystemLocks(); |
| ExpectPostLockAnimationStarted(); |
| |
| PressLockButton(); |
| ReleaseLockButton(); |
| ExpectPostLockAnimationStarted(); |
| |
| Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); |
| ExpectPastLockAnimationFinished(); |
| |
| PressLockButton(); |
| ReleaseLockButton(); |
| ExpectPastLockAnimationFinished(); |
| } |
| |
| // Test that the power button takes priority over the lock button. |
| // TODO(antrim): Reenable this: http://crbug.com/167048 |
| TEST_F(LockStateControllerTest, |
| DISABLED_PowerButtonPreemptsLockButton) { |
| Initialize(false, user::LOGGED_IN_USER); |
| |
| // While the lock button is down, hold the power button. |
| PressLockButton(); |
| ExpectPreLockAnimationStarted(); |
| PressPowerButton(); |
| ExpectPreLockAnimationStarted(); |
| |
| AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, 0.5f); |
| |
| // The lock timer shouldn't be stopped when the lock button is released. |
| ReleaseLockButton(); |
| ExpectPreLockAnimationStarted(); |
| ReleasePowerButton(); |
| ExpectPreLockAnimationCancel(); |
| |
| Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); |
| ExpectUnlockedState(); |
| |
| // Now press the power button first and then the lock button. |
| PressPowerButton(); |
| ExpectPreLockAnimationStarted(); |
| PressLockButton(); |
| ExpectPreLockAnimationStarted(); |
| |
| AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, 0.5f); |
| |
| // Releasing the power button should stop the lock timer. |
| ReleasePowerButton(); |
| ExpectPreLockAnimationCancel(); |
| ReleaseLockButton(); |
| ExpectPreLockAnimationCancel(); |
| } |
| |
| // 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(LockStateControllerTest, LockWithoutButton) { |
| Initialize(false, user::LOGGED_IN_USER); |
| lock_state_controller_->OnStartingLock(); |
| |
| ExpectPreLockAnimationStarted(); |
| EXPECT_FALSE(test_api_->is_lock_cancellable()); |
| |
| // TODO(antrim): After time-faking is fixed, let the pre-lock animation |
| // complete here and check that delegate_->num_lock_requests() is 0 to |
| // prevent http://crbug.com/172487 from regressing. |
| } |
| |
| // 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(LockStateControllerTest, ShutdownWithoutButton) { |
| Initialize(false, user::LOGGED_IN_USER); |
| lock_state_controller_->OnAppTerminating(); |
| |
| EXPECT_TRUE( |
| animator_api_->ContainersAreAnimated( |
| SessionStateAnimator::kAllContainersMask, |
| 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(LockStateControllerTest, RequestShutdownFromLoginScreen) { |
| Initialize(false, user::LOGGED_IN_NONE); |
| CreateWindowForLockscreen(); |
| |
| lock_state_controller_->RequestShutdown(); |
| |
| ExpectShutdownAnimationStarted(); |
| Advance(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN); |
| |
| 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(LockStateControllerTest, RequestShutdownFromLockScreen) { |
| Initialize(false, user::LOGGED_IN_USER); |
| |
| SystemLocks(); |
| CreateWindowForLockscreen(); |
| Advance(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN); |
| ExpectPastLockAnimationFinished(); |
| |
| lock_state_controller_->RequestShutdown(); |
| |
| ExpectShutdownAnimationStarted(); |
| Advance(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN); |
| |
| 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()); |
| } |
| |
| // TODO(antrim): Reenable this: http://crbug.com/167048 |
| TEST_F(LockStateControllerTest, |
| DISABLED_RequestAndCancelShutdownFromLockScreen) { |
| Initialize(false, user::LOGGED_IN_USER); |
| |
| SystemLocks(); |
| Advance(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN); |
| ExpectLockedState(); |
| |
| // Press the power button and check that we start the shutdown timer. |
| PressPowerButton(); |
| EXPECT_FALSE(test_api_->is_animating_lock()); |
| EXPECT_TRUE(test_api_->shutdown_timer_is_running()); |
| |
| ExpectShutdownAnimationStarted(); |
| |
| AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN, 0.5f); |
| |
| float grayscale_before_button_release = |
| Shell::GetPrimaryRootWindow()->layer()->layer_grayscale(); |
| |
| // Release the power button before the shutdown timer fires. |
| ReleasePowerButton(); |
| |
| EXPECT_FALSE(test_api_->shutdown_timer_is_running()); |
| |
| ExpectShutdownAnimationCancel(); |
| |
| float grayscale_after_button_release = |
| Shell::GetPrimaryRootWindow()->layer()->layer_grayscale(); |
| // Expect no flickering in undo animation. |
| EXPECT_EQ(grayscale_before_button_release, grayscale_after_button_release); |
| |
| Advance(SessionStateAnimator::ANIMATION_SPEED_REVERT); |
| ExpectLockedState(); |
| } |
| |
| // Test that we ignore power button presses when the screen is turned off. |
| TEST_F(LockStateControllerTest, IgnorePowerButtonIfScreenIsOff) { |
| Initialize(false, 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); |
| PressPowerButton(); |
| EXPECT_FALSE(test_api_->is_animating_lock()); |
| ReleasePowerButton(); |
| |
| // After increasing the brightness to 10%, we should start the timer like |
| // usual. |
| controller_->OnScreenBrightnessChanged(10.0); |
| PressPowerButton(); |
| EXPECT_TRUE(test_api_->is_animating_lock()); |
| ReleasePowerButton(); |
| } |
| |
| #if defined(OS_CHROMEOS) && defined(USE_X11) |
| TEST_F(LockStateControllerTest, HonorPowerButtonInDockedMode) { |
| ScopedVector<const ui::DisplayMode> modes; |
| modes.push_back(new ui::DisplayMode(gfx::Size(1, 1), false, 60.0f)); |
| |
| // Create two outputs, the first internal and the second external. |
| ui::DisplayConfigurator::DisplayStateList outputs; |
| ui::DisplayConfigurator::DisplayState internal_output; |
| ui::TestDisplaySnapshot internal_display; |
| internal_display.set_type(ui::DISPLAY_CONNECTION_TYPE_INTERNAL); |
| internal_display.set_modes(modes.get()); |
| internal_output.display = &internal_display; |
| outputs.push_back(internal_output); |
| |
| ui::DisplayConfigurator::DisplayState external_output; |
| ui::TestDisplaySnapshot external_display; |
| external_display.set_type(ui::DISPLAY_CONNECTION_TYPE_HDMI); |
| external_display.set_modes(modes.get()); |
| external_output.display = &external_display; |
| outputs.push_back(external_output); |
| |
| // When all of the displays are turned off (e.g. due to user inactivity), the |
| // power button should be ignored. |
| controller_->OnScreenBrightnessChanged(0.0); |
| static_cast<ui::TestDisplaySnapshot*>(outputs[0].display) |
| ->set_current_mode(NULL); |
| static_cast<ui::TestDisplaySnapshot*>(outputs[1].display) |
| ->set_current_mode(NULL); |
| controller_->OnDisplayModeChanged(outputs); |
| PressPowerButton(); |
| EXPECT_FALSE(test_api_->is_animating_lock()); |
| ReleasePowerButton(); |
| |
| // When the screen brightness is 0% but the external display is still turned |
| // on (indicating either docked mode or the user having manually decreased the |
| // brightness to 0%), the power button should still be handled. |
| static_cast<ui::TestDisplaySnapshot*>(outputs[1].display) |
| ->set_current_mode(modes[0]); |
| controller_->OnDisplayModeChanged(outputs); |
| PressPowerButton(); |
| EXPECT_TRUE(test_api_->is_animating_lock()); |
| ReleasePowerButton(); |
| } |
| #endif |
| |
| // Test that hidden background appears and revers correctly on lock/cancel. |
| // TODO(antrim): Reenable this: http://crbug.com/167048 |
| TEST_F(LockStateControllerTest, DISABLED_TestHiddenBackgroundLockCancel) { |
| Initialize(false, user::LOGGED_IN_USER); |
| HideBackground(); |
| |
| EXPECT_TRUE(IsBackgroundHidden()); |
| ExpectUnlockedState(); |
| PressPowerButton(); |
| |
| ExpectPreLockAnimationStarted(); |
| EXPECT_FALSE(IsBackgroundHidden()); |
| ExpectBackgroundIsShowing(); |
| |
| // Forward only half way through. |
| AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, 0.5f); |
| |
| // Release the button before the lock timer fires. |
| ReleasePowerButton(); |
| ExpectPreLockAnimationCancel(); |
| ExpectBackgroundIsHiding(); |
| EXPECT_FALSE(IsBackgroundHidden()); |
| |
| Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); |
| |
| ExpectUnlockedState(); |
| EXPECT_TRUE(IsBackgroundHidden()); |
| } |
| |
| // Test that hidden background appears and revers correctly on lock/unlock. |
| // TODO(antrim): Reenable this: http://crbug.com/167048 |
| TEST_F(LockStateControllerTest, DISABLED_TestHiddenBackgroundLockUnlock) { |
| Initialize(false, user::LOGGED_IN_USER); |
| HideBackground(); |
| |
| EXPECT_TRUE(IsBackgroundHidden()); |
| ExpectUnlockedState(); |
| |
| // Press the power button and check that the lock timer is started and that we |
| // start lifting the non-screen-locker containers. |
| PressPowerButton(); |
| |
| ExpectPreLockAnimationStarted(); |
| EXPECT_FALSE(IsBackgroundHidden()); |
| ExpectBackgroundIsShowing(); |
| |
| Advance(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE); |
| |
| ExpectPreLockAnimationFinished(); |
| |
| SystemLocks(); |
| |
| ReleasePowerButton(); |
| |
| ExpectPostLockAnimationStarted(); |
| Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); |
| ExpectPastLockAnimationFinished(); |
| |
| ExpectLockedState(); |
| |
| SuccessfulAuthentication(NULL); |
| |
| ExpectUnlockBeforeUIDestroyedAnimationStarted(); |
| Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); |
| ExpectUnlockBeforeUIDestroyedAnimationFinished(); |
| |
| SystemUnlocks(); |
| |
| ExpectUnlockAfterUIDestroyedAnimationStarted(); |
| ExpectBackgroundIsHiding(); |
| EXPECT_FALSE(IsBackgroundHidden()); |
| |
| Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); |
| ExpectUnlockAfterUIDestroyedAnimationFinished(); |
| EXPECT_TRUE(IsBackgroundHidden()); |
| |
| ExpectUnlockedState(); |
| } |
| |
| } // namespace test |
| } // namespace ash |