blob: 07ec27bb89280a27db1796fb1c8e1a694817ef8d [file] [log] [blame]
// Copyright 2020 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/shelf/login_shelf_gesture_controller.h"
#include "ash/login/login_screen_controller.h"
#include "ash/login/ui/login_test_base.h"
#include "ash/shelf/contextual_nudge.h"
#include "ash/shelf/shelf.h"
#include "ash/shelf/shelf_widget.h"
#include "ash/shell.h"
#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
namespace ash {
class TestLoginShelfFlingHandler {
public:
TestLoginShelfFlingHandler() {
gesture_detection_active_ =
Shell::Get()->login_screen_controller()->SetLoginShelfGestureHandler(
base::ASCIIToUTF16("Test swipe"),
base::BindRepeating(&TestLoginShelfFlingHandler::OnFlingDetected,
base::Unretained(this)),
base::BindOnce(
&TestLoginShelfFlingHandler::OnGestureDetectionDisabled,
base::Unretained(this)));
}
~TestLoginShelfFlingHandler() {
if (gesture_detection_active_)
Shell::Get()->login_screen_controller()->ClearLoginShelfGestureHandler();
}
int GetAndResetDetectedFlingCount() {
int result = detected_flings_;
detected_flings_ = 0;
return result;
}
bool gesture_detection_active() const { return gesture_detection_active_; }
void OnFlingDetected() { ++detected_flings_; }
void OnGestureDetectionDisabled() {
EXPECT_TRUE(gesture_detection_active_);
gesture_detection_active_ = false;
}
private:
int detected_flings_ = 0;
bool gesture_detection_active_ = false;
};
class LoginShelfGestureControllerTest : public LoginTestBase {
public:
LoginShelfGestureControllerTest() = default;
LoginShelfGestureControllerTest(
const LoginShelfGestureControllerTest& other) = delete;
LoginShelfGestureControllerTest& operator=(
const LoginShelfGestureControllerTest& other) = delete;
~LoginShelfGestureControllerTest() override = default;
// LoginTestBase:
void SetUp() override {
set_start_session(false);
LoginTestBase::SetUp();
}
LoginShelfGestureController* GetLoginScreenGestureController() {
return GetPrimaryShelf()
->shelf_widget()
->login_shelf_gesture_controller_for_testing();
}
ContextualNudge* GetGestureContextualNudge() {
return GetLoginScreenGestureController()->nudge_for_testing();
}
void NotifySessionStateChanged(session_manager::SessionState state) {
GetSessionControllerClient()->SetSessionState(state);
GetSessionControllerClient()->FlushForTest();
}
void SwipeOnShelf(const gfx::Point& start, const gfx::Vector2d& direction) {
const gfx::Point end(start + direction);
const base::TimeDelta kTimeDelta = base::TimeDelta::FromMilliseconds(500);
const int kNumScrollSteps = 4;
GetEventGenerator()->GestureScrollSequence(start, end, kTimeDelta,
kNumScrollSteps);
}
void FlingOnShelf(const gfx::Point& start, const gfx::Vector2d& direction) {
const gfx::Point end(start + direction);
const base::TimeDelta kTimeDelta = base::TimeDelta::FromMilliseconds(10);
const int kNumScrollSteps = 4;
GetEventGenerator()->GestureScrollSequence(start, end, kTimeDelta,
kNumScrollSteps);
}
};
TEST_F(LoginShelfGestureControllerTest,
SettingGestureHandlerShowsDragHandleInOobe) {
NotifySessionStateChanged(session_manager::SessionState::OOBE);
EXPECT_FALSE(
GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
EXPECT_FALSE(GetLoginScreenGestureController());
// Login shelf gesture detection should not start if not in tablet mode.
auto fling_handler = std::make_unique<TestLoginShelfFlingHandler>();
EXPECT_FALSE(fling_handler->gesture_detection_active());
TabletModeControllerTestApi().EnterTabletMode();
// Enter tablet mode and create another scoped login shelf gesture handler,
// and verify that makes the drag handle visible.
fling_handler = std::make_unique<TestLoginShelfFlingHandler>();
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_TRUE(GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
ASSERT_TRUE(GetLoginScreenGestureController());
ASSERT_TRUE(GetPrimaryShelf()
->shelf_widget()
->login_shelf_gesture_controller_for_testing()
->nudge_for_testing());
EXPECT_TRUE(GetGestureContextualNudge()->GetWidget()->IsVisible());
// The drag handle should be removed once the user logs in.
CreateUserSessions(1);
EXPECT_FALSE(fling_handler->gesture_detection_active());
EXPECT_FALSE(
GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
EXPECT_FALSE(GetLoginScreenGestureController());
}
TEST_F(LoginShelfGestureControllerTest, DragHandleAndNudgeAnimate) {
NotifySessionStateChanged(session_manager::SessionState::OOBE);
EXPECT_FALSE(
GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
EXPECT_FALSE(GetLoginScreenGestureController());
TabletModeControllerTestApi().EnterTabletMode();
ui::ScopedAnimationDurationScaleMode test_duration_mode(
ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
// Enter tablet mode and create a scoped login shelf gesture handler,
// and verify that makes the drag handle visible.
auto fling_handler = std::make_unique<TestLoginShelfFlingHandler>();
EXPECT_TRUE(fling_handler->gesture_detection_active());
DragHandle* const drag_handle =
GetPrimaryShelf()->shelf_widget()->GetDragHandle();
EXPECT_TRUE(drag_handle->GetVisible());
ASSERT_TRUE(GetLoginScreenGestureController());
ASSERT_TRUE(GetPrimaryShelf()
->shelf_widget()
->login_shelf_gesture_controller_for_testing()
->nudge_for_testing());
views::Widget* const nudge_widget = GetGestureContextualNudge()->GetWidget();
EXPECT_TRUE(nudge_widget->IsVisible());
base::OneShotTimer* animation_timer =
GetLoginScreenGestureController()->nudge_animation_timer_for_testing();
// The nudge and drag handler should start animating with a delay.
ASSERT_TRUE(animation_timer->IsRunning());
EXPECT_FALSE(drag_handle->layer()->GetAnimator()->is_animating());
EXPECT_FALSE(nudge_widget->GetLayer()->GetAnimator()->is_animating());
animation_timer->FireNow();
EXPECT_TRUE(drag_handle->GetVisible());
EXPECT_TRUE(drag_handle->layer()->GetAnimator()->is_animating());
EXPECT_TRUE(nudge_widget->GetLayer()->GetAnimator()->is_animating());
EXPECT_EQ(drag_handle->layer()->GetTargetTransform(),
nudge_widget->GetLayer()->GetTargetTransform());
EXPECT_FALSE(animation_timer->IsRunning());
// Once the animations complete, the drag handle and the nudge should be at
// the original position, and another animation should be scheduled.
drag_handle->layer()->GetAnimator()->StopAnimating();
nudge_widget->GetLayer()->GetAnimator()->StopAnimating();
EXPECT_EQ(drag_handle->layer()->GetTargetTransform(),
nudge_widget->GetLayer()->GetTargetTransform());
EXPECT_EQ(gfx::Transform(), nudge_widget->GetLayer()->GetTargetTransform());
ASSERT_TRUE(animation_timer->IsRunning());
// Verify that another animation is scheduled once the second set of
// animations completes.
animation_timer->FireNow();
EXPECT_TRUE(drag_handle->layer()->GetAnimator()->is_animating());
EXPECT_TRUE(nudge_widget->GetLayer()->GetAnimator()->is_animating());
drag_handle->layer()->GetAnimator()->StopAnimating();
nudge_widget->GetLayer()->GetAnimator()->StopAnimating();
EXPECT_TRUE(animation_timer->IsRunning());
}
TEST_F(LoginShelfGestureControllerTest, TappingNudgeWidgetStopsAnimations) {
NotifySessionStateChanged(session_manager::SessionState::OOBE);
EXPECT_FALSE(
GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
EXPECT_FALSE(GetLoginScreenGestureController());
TabletModeControllerTestApi().EnterTabletMode();
ui::ScopedAnimationDurationScaleMode test_duration_mode(
ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
// Enter tablet mode and create a scoped login shelf gesture handler,
// and verify that makes the drag handle visible.
auto fling_handler = std::make_unique<TestLoginShelfFlingHandler>();
EXPECT_TRUE(fling_handler->gesture_detection_active());
DragHandle* const drag_handle =
GetPrimaryShelf()->shelf_widget()->GetDragHandle();
EXPECT_TRUE(drag_handle->GetVisible());
ASSERT_TRUE(GetLoginScreenGestureController());
views::Widget* const nudge_widget = GetGestureContextualNudge()->GetWidget();
EXPECT_TRUE(nudge_widget->IsVisible());
// Start the animation.
base::OneShotTimer* animation_timer =
GetLoginScreenGestureController()->nudge_animation_timer_for_testing();
ASSERT_TRUE(animation_timer->IsRunning());
animation_timer->FireNow();
EXPECT_TRUE(drag_handle->layer()->GetAnimator()->is_animating());
EXPECT_TRUE(nudge_widget->GetLayer()->GetAnimator()->is_animating());
// Tapping the contextual nudge should schedule an animation to the original
// position.
GetEventGenerator()->GestureTapAt(
nudge_widget->GetWindowBoundsInScreen().CenterPoint());
EXPECT_EQ(drag_handle->layer()->GetTargetTransform(),
nudge_widget->GetLayer()->GetTargetTransform());
EXPECT_EQ(gfx::Transform(), nudge_widget->GetLayer()->GetTargetTransform());
// Once the "stop" animation finishes, no further animation should be
// scheduled.
drag_handle->layer()->GetAnimator()->StopAnimating();
nudge_widget->GetLayer()->GetAnimator()->StopAnimating();
EXPECT_EQ(drag_handle->layer()->GetTargetTransform(),
nudge_widget->GetLayer()->GetTargetTransform());
EXPECT_EQ(gfx::Transform(), nudge_widget->GetLayer()->GetTargetTransform());
EXPECT_FALSE(animation_timer->IsRunning());
}
TEST_F(LoginShelfGestureControllerTest,
TappingNudgeWidgetCancelsInitialScheduledAnimations) {
NotifySessionStateChanged(session_manager::SessionState::OOBE);
EXPECT_FALSE(
GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
EXPECT_FALSE(GetLoginScreenGestureController());
TabletModeControllerTestApi().EnterTabletMode();
ui::ScopedAnimationDurationScaleMode test_duration_mode(
ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
// Enter tablet mode and create a scoped login shelf gesture handler,
// and verify that makes the drag handle visible.
auto fling_handler = std::make_unique<TestLoginShelfFlingHandler>();
EXPECT_TRUE(fling_handler->gesture_detection_active());
DragHandle* const drag_handle =
GetPrimaryShelf()->shelf_widget()->GetDragHandle();
EXPECT_TRUE(drag_handle->GetVisible());
ASSERT_TRUE(GetLoginScreenGestureController());
views::Widget* const nudge_widget = GetGestureContextualNudge()->GetWidget();
EXPECT_TRUE(nudge_widget->IsVisible());
base::OneShotTimer* animation_timer =
GetLoginScreenGestureController()->nudge_animation_timer_for_testing();
ASSERT_TRUE(animation_timer->IsRunning());
// Tap the contextual nudge before the nudge animation is scheduled - that
// should stop the animation timer.
GetEventGenerator()->GestureTapAt(
nudge_widget->GetWindowBoundsInScreen().CenterPoint());
EXPECT_FALSE(animation_timer->IsRunning());
// The stop nudge animation could still be run.
drag_handle->layer()->GetAnimator()->StopAnimating();
nudge_widget->GetLayer()->GetAnimator()->StopAnimating();
EXPECT_EQ(drag_handle->layer()->GetTargetTransform(),
nudge_widget->GetLayer()->GetTargetTransform());
EXPECT_EQ(gfx::Transform(), nudge_widget->GetLayer()->GetTargetTransform());
drag_handle->layer()->GetAnimator()->StopAnimating();
nudge_widget->GetLayer()->GetAnimator()->StopAnimating();
EXPECT_FALSE(animation_timer->IsRunning());
}
TEST_F(LoginShelfGestureControllerTest,
TappingNudgeWidgetCancelsSecondScheduledAnimations) {
NotifySessionStateChanged(session_manager::SessionState::OOBE);
EXPECT_FALSE(
GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
EXPECT_FALSE(GetLoginScreenGestureController());
TabletModeControllerTestApi().EnterTabletMode();
ui::ScopedAnimationDurationScaleMode test_duration_mode(
ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
// Enter tablet mode and create a scoped login shelf gesture handler,
// and verify that makes the drag handle visible.
auto fling_handler = std::make_unique<TestLoginShelfFlingHandler>();
EXPECT_TRUE(fling_handler->gesture_detection_active());
DragHandle* const drag_handle =
GetPrimaryShelf()->shelf_widget()->GetDragHandle();
EXPECT_TRUE(drag_handle->GetVisible());
ASSERT_TRUE(GetLoginScreenGestureController());
views::Widget* const nudge_widget = GetGestureContextualNudge()->GetWidget();
EXPECT_TRUE(nudge_widget->IsVisible());
// Run the first nudge animation sequence.
base::OneShotTimer* animation_timer =
GetLoginScreenGestureController()->nudge_animation_timer_for_testing();
ASSERT_TRUE(animation_timer->IsRunning());
animation_timer->FireNow();
drag_handle->layer()->GetAnimator()->StopAnimating();
nudge_widget->GetLayer()->GetAnimator()->StopAnimating();
EXPECT_TRUE(animation_timer->IsRunning());
// Tap the contextual nudge before the nudge animation is scheduled - that
// should stop the animation timer.
GetEventGenerator()->GestureTapAt(
nudge_widget->GetWindowBoundsInScreen().CenterPoint());
EXPECT_FALSE(animation_timer->IsRunning());
// The stop nudge animation could still be run.
drag_handle->layer()->GetAnimator()->StopAnimating();
nudge_widget->GetLayer()->GetAnimator()->StopAnimating();
EXPECT_EQ(drag_handle->layer()->GetTargetTransform(),
nudge_widget->GetLayer()->GetTargetTransform());
EXPECT_EQ(gfx::Transform(), nudge_widget->GetLayer()->GetTargetTransform());
drag_handle->layer()->GetAnimator()->StopAnimating();
nudge_widget->GetLayer()->GetAnimator()->StopAnimating();
EXPECT_FALSE(animation_timer->IsRunning());
}
TEST_F(LoginShelfGestureControllerTest,
SettingGestureHandlerShowsDragHandleOnLogin) {
NotifySessionStateChanged(session_manager::SessionState::LOGIN_PRIMARY);
EXPECT_FALSE(
GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
EXPECT_FALSE(GetLoginScreenGestureController());
// Login shelf gesture detection should not start if not in tablet mode.
auto fling_handler = std::make_unique<TestLoginShelfFlingHandler>();
EXPECT_FALSE(fling_handler->gesture_detection_active());
TabletModeControllerTestApi().EnterTabletMode();
// Enter tablet mode and create another scoped login shelf gesture handler,
// and verify that makes the drag handle visible.
fling_handler = std::make_unique<TestLoginShelfFlingHandler>();
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_TRUE(GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
ASSERT_TRUE(GetLoginScreenGestureController());
ASSERT_TRUE(GetGestureContextualNudge());
EXPECT_TRUE(GetGestureContextualNudge()->GetWidget()->IsVisible());
// The drag handle should be removed once the user logs in.
CreateUserSessions(1);
EXPECT_FALSE(fling_handler->gesture_detection_active());
EXPECT_FALSE(
GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
EXPECT_FALSE(GetLoginScreenGestureController());
}
TEST_F(LoginShelfGestureControllerTest, TabletModeExitResetsGestureDetection) {
NotifySessionStateChanged(session_manager::SessionState::OOBE);
EXPECT_FALSE(
GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
EXPECT_FALSE(GetLoginScreenGestureController());
// Login shelf gesture detection should not start if not in tablet mode.
auto fling_handler = std::make_unique<TestLoginShelfFlingHandler>();
EXPECT_FALSE(fling_handler->gesture_detection_active());
TabletModeControllerTestApi().EnterTabletMode();
// Enter tablet mode and create another scoped login shelf gesture handler,
// and verify that makes the drag handle visible.
fling_handler = std::make_unique<TestLoginShelfFlingHandler>();
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_TRUE(GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
ASSERT_TRUE(GetLoginScreenGestureController());
ASSERT_TRUE(GetGestureContextualNudge());
EXPECT_TRUE(GetGestureContextualNudge()->GetWidget()->IsVisible());
// The drag handle should be removed in clamshell.
TabletModeControllerTestApi().LeaveTabletMode();
EXPECT_FALSE(fling_handler->gesture_detection_active());
EXPECT_FALSE(
GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
EXPECT_FALSE(GetLoginScreenGestureController());
}
TEST_F(LoginShelfGestureControllerTest,
DragHandleHiddenIfGestureHandlerIsReset) {
NotifySessionStateChanged(session_manager::SessionState::OOBE);
TabletModeControllerTestApi().EnterTabletMode();
// Login shelf gesture detection should not start if not in tablet mode.
auto fling_handler = std::make_unique<TestLoginShelfFlingHandler>();
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_TRUE(GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
ASSERT_TRUE(GetLoginScreenGestureController());
ASSERT_TRUE(GetGestureContextualNudge());
EXPECT_TRUE(GetGestureContextualNudge()->GetWidget()->IsVisible());
fling_handler.reset();
EXPECT_FALSE(
GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
EXPECT_FALSE(GetLoginScreenGestureController());
}
TEST_F(LoginShelfGestureControllerTest,
HandlerDoesNotReceiveEventsAfterGettingNotifiedOfControllerExit) {
NotifySessionStateChanged(session_manager::SessionState::OOBE);
TabletModeControllerTestApi().EnterTabletMode();
// Login shelf gesture detection should not start if not in tablet mode.
auto fling_handler = std::make_unique<TestLoginShelfFlingHandler>();
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_TRUE(GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
ASSERT_TRUE(GetLoginScreenGestureController());
ASSERT_TRUE(GetGestureContextualNudge());
EXPECT_TRUE(GetGestureContextualNudge()->GetWidget()->IsVisible());
TabletModeControllerTestApi().LeaveTabletMode();
EXPECT_FALSE(fling_handler->gesture_detection_active());
EXPECT_FALSE(
GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
EXPECT_FALSE(GetLoginScreenGestureController());
TabletModeControllerTestApi().EnterTabletMode();
EXPECT_FALSE(
GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
EXPECT_FALSE(GetLoginScreenGestureController());
// Swipe on the shelf should not be reported given that the handler was
// notified that the gesture controller was disabled (on tablet mode exit).
const gfx::Rect shelf_bounds =
GetPrimaryShelf()->shelf_widget()->GetWindowBoundsInScreen();
FlingOnShelf(shelf_bounds.CenterPoint(), gfx::Vector2d(0, -100));
EXPECT_EQ(0, fling_handler->GetAndResetDetectedFlingCount());
}
TEST_F(LoginShelfGestureControllerTest,
RegisteringHandlerClearsThePreviousOne) {
NotifySessionStateChanged(session_manager::SessionState::OOBE);
TabletModeControllerTestApi().EnterTabletMode();
// Login shelf gesture detection should not start if not in tablet mode.
auto fling_handler_1 = std::make_unique<TestLoginShelfFlingHandler>();
EXPECT_TRUE(fling_handler_1->gesture_detection_active());
EXPECT_TRUE(GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
ASSERT_TRUE(GetLoginScreenGestureController());
ASSERT_TRUE(GetGestureContextualNudge());
EXPECT_TRUE(GetGestureContextualNudge()->GetWidget()->IsVisible());
auto fling_handler_2 = std::make_unique<TestLoginShelfFlingHandler>();
EXPECT_TRUE(fling_handler_2->gesture_detection_active());
EXPECT_TRUE(GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
ASSERT_TRUE(GetLoginScreenGestureController());
ASSERT_TRUE(GetGestureContextualNudge());
EXPECT_TRUE(GetGestureContextualNudge()->GetWidget()->IsVisible());
EXPECT_FALSE(fling_handler_1->gesture_detection_active());
// Only the second handler should be notified of a gesture.
const gfx::Rect shelf_bounds =
GetPrimaryShelf()->shelf_widget()->GetWindowBoundsInScreen();
// Fling up on shelf, and verify the gesture is detected.
FlingOnShelf(shelf_bounds.CenterPoint(), gfx::Vector2d(0, -100));
EXPECT_EQ(1, fling_handler_2->GetAndResetDetectedFlingCount());
EXPECT_EQ(0, fling_handler_1->GetAndResetDetectedFlingCount());
}
TEST_F(LoginShelfGestureControllerTest,
GracefullyHandleNudgeWidgetDestruction) {
NotifySessionStateChanged(session_manager::SessionState::OOBE);
TabletModeControllerTestApi().EnterTabletMode();
// Login shelf gesture detection should not start if not in tablet mode.
auto fling_handler = std::make_unique<TestLoginShelfFlingHandler>();
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_TRUE(GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
ASSERT_TRUE(GetLoginScreenGestureController());
ASSERT_TRUE(GetGestureContextualNudge());
EXPECT_TRUE(GetGestureContextualNudge()->GetWidget()->IsVisible());
GetGestureContextualNudge()->GetWidget()->CloseNow();
// The gestures should still lbe recorded, even if the nudge widget went away.
const gfx::Rect shelf_bounds =
GetPrimaryShelf()->shelf_widget()->GetWindowBoundsInScreen();
// Fling up on shelf, and verify the gesture is detected.
FlingOnShelf(shelf_bounds.CenterPoint(), gfx::Vector2d(0, -100));
EXPECT_EQ(1, fling_handler->GetAndResetDetectedFlingCount());
}
TEST_F(LoginShelfGestureControllerTest, FlingDetectionInOobeFromShelf) {
const gfx::Rect shelf_bounds =
GetPrimaryShelf()->shelf_widget()->GetWindowBoundsInScreen();
const std::vector<gfx::Point> starting_points = {
shelf_bounds.CenterPoint(),
shelf_bounds.left_center(),
shelf_bounds.left_center() + gfx::Vector2d(20, 0),
shelf_bounds.right_center(),
shelf_bounds.right_center() + gfx::Vector2d(-20, 0),
shelf_bounds.bottom_center(),
shelf_bounds.bottom_left() + gfx::Vector2d(20, 0),
shelf_bounds.bottom_right() + gfx::Vector2d(-20, 0),
shelf_bounds.top_center(),
shelf_bounds.origin() + gfx::Vector2d(20, 0),
shelf_bounds.top_right() + gfx::Vector2d(-20, 0),
};
NotifySessionStateChanged(session_manager::SessionState::OOBE);
TabletModeControllerTestApi().EnterTabletMode();
// Enter tablet mode and create another scoped login shelf gesture handler,
// and verify that makes the drag handle visible.
auto fling_handler = std::make_unique<TestLoginShelfFlingHandler>();
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_TRUE(GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
for (const auto& start : starting_points) {
SCOPED_TRACE(testing::Message()
<< "Starting point " << start.ToString()
<< " with shelf bounds " << shelf_bounds.ToString());
// Slow upward swipe should not trigger gesture detection.
SwipeOnShelf(start, gfx::Vector2d(0, -100));
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_EQ(0, fling_handler->GetAndResetDetectedFlingCount());
// Fling up on shelf, and verify the gesture is detected.
FlingOnShelf(start, gfx::Vector2d(0, -100));
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_EQ(1, fling_handler->GetAndResetDetectedFlingCount());
// Fling down, nor swipe down should not be detected.
SwipeOnShelf(start, gfx::Vector2d(0, 20));
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_EQ(0, fling_handler->GetAndResetDetectedFlingCount());
FlingOnShelf(start, gfx::Vector2d(0, 20));
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_EQ(0, fling_handler->GetAndResetDetectedFlingCount());
}
}
TEST_F(LoginShelfGestureControllerTest, FlingDetectionOnLoginScreenFromShelf) {
const gfx::Rect shelf_bounds =
GetPrimaryShelf()->shelf_widget()->GetWindowBoundsInScreen();
const std::vector<gfx::Point> starting_points = {
shelf_bounds.CenterPoint(),
shelf_bounds.left_center(),
shelf_bounds.left_center() + gfx::Vector2d(20, 0),
shelf_bounds.right_center(),
shelf_bounds.right_center() + gfx::Vector2d(-20, 0),
shelf_bounds.bottom_center(),
shelf_bounds.bottom_left() + gfx::Vector2d(20, 0),
shelf_bounds.bottom_right() + gfx::Vector2d(-20, 0),
shelf_bounds.top_center(),
shelf_bounds.origin() + gfx::Vector2d(20, 0),
shelf_bounds.top_right() + gfx::Vector2d(-20, 0),
};
NotifySessionStateChanged(session_manager::SessionState::LOGIN_PRIMARY);
TabletModeControllerTestApi().EnterTabletMode();
// Enter tablet mode and create another scoped login shelf gesture handler,
// and verify that makes the drag handle visible.
auto fling_handler = std::make_unique<TestLoginShelfFlingHandler>();
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_TRUE(GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
for (const auto& start : starting_points) {
SCOPED_TRACE(testing::Message()
<< "Starting point " << start.ToString()
<< " with shelf bounds " << shelf_bounds.ToString());
// Slow upward swipe should not trigger gesture detection.
SwipeOnShelf(start, gfx::Vector2d(0, -100));
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_EQ(0, fling_handler->GetAndResetDetectedFlingCount());
// Fling up on shelf, and verify the gesture is detected.
FlingOnShelf(start, gfx::Vector2d(0, -100));
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_EQ(1, fling_handler->GetAndResetDetectedFlingCount());
// Fling down, nor swipe down should not be detected.
SwipeOnShelf(start, gfx::Vector2d(0, 20));
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_EQ(0, fling_handler->GetAndResetDetectedFlingCount());
FlingOnShelf(start, gfx::Vector2d(0, 20));
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_EQ(0, fling_handler->GetAndResetDetectedFlingCount());
}
}
TEST_F(LoginShelfGestureControllerTest, FlingFromAboveTheShelf) {
NotifySessionStateChanged(session_manager::SessionState::LOGIN_PRIMARY);
TabletModeControllerTestApi().EnterTabletMode();
// Enter tablet mode and create another scoped login shelf gesture handler,
// and verify that makes the drag handle visible.
auto fling_handler = std::make_unique<TestLoginShelfFlingHandler>();
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_TRUE(GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
const gfx::Rect shelf_bounds =
GetPrimaryShelf()->shelf_widget()->GetWindowBoundsInScreen();
const std::vector<gfx::Point> starting_points = {
shelf_bounds.top_center() + gfx::Vector2d(0, -1),
shelf_bounds.origin() + gfx::Vector2d(20, -1),
shelf_bounds.top_right() + gfx::Vector2d(-20, -1),
};
for (const auto& start : starting_points) {
SCOPED_TRACE(testing::Message()
<< "Starting point " << start.ToString()
<< " with shelf bounds " << shelf_bounds.ToString());
SwipeOnShelf(start, gfx::Vector2d(0, -100));
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_EQ(0, fling_handler->GetAndResetDetectedFlingCount());
FlingOnShelf(start, gfx::Vector2d(0, -100));
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_EQ(0, fling_handler->GetAndResetDetectedFlingCount());
SwipeOnShelf(start, gfx::Vector2d(0, 20));
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_EQ(0, fling_handler->GetAndResetDetectedFlingCount());
FlingOnShelf(start, gfx::Vector2d(0, 20));
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_EQ(0, fling_handler->GetAndResetDetectedFlingCount());
}
}
TEST_F(LoginShelfGestureControllerTest, FlingDoesNotLeaveShelf) {
NotifySessionStateChanged(session_manager::SessionState::LOGIN_PRIMARY);
TabletModeControllerTestApi().EnterTabletMode();
// Enter tablet mode and create another scoped login shelf gesture handler,
// and verify that makes the drag handle visible.
auto fling_handler = std::make_unique<TestLoginShelfFlingHandler>();
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_TRUE(GetPrimaryShelf()->shelf_widget()->GetDragHandle()->GetVisible());
const gfx::Rect shelf_bounds =
GetPrimaryShelf()->shelf_widget()->GetWindowBoundsInScreen();
const std::vector<gfx::Point> starting_points = {
shelf_bounds.bottom_center(),
shelf_bounds.bottom_left(),
shelf_bounds.bottom_right(),
};
for (const auto& start : starting_points) {
SCOPED_TRACE(testing::Message()
<< "Starting point " << start.ToString()
<< " with shelf bounds " << shelf_bounds.ToString());
SwipeOnShelf(start, gfx::Vector2d(0, -20));
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_EQ(0, fling_handler->GetAndResetDetectedFlingCount());
FlingOnShelf(start, gfx::Vector2d(0, -20));
EXPECT_TRUE(fling_handler->gesture_detection_active());
EXPECT_EQ(0, fling_handler->GetAndResetDetectedFlingCount());
}
}
// Tests that shutdown is graceful if a login shelf gesture handler is still
// registered.
TEST_F(LoginShelfGestureControllerTest, HandlerExitsOnShutdown) {
NotifySessionStateChanged(session_manager::SessionState::LOGIN_PRIMARY);
TabletModeControllerTestApi().EnterTabletMode();
Shell::Get()->login_screen_controller()->SetLoginShelfGestureHandler(
base::ASCIIToUTF16("Test swipe"), base::DoNothing(), base::DoNothing());
}
} // namespace ash