123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- // Copyright 2021 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/utility/haptics_util.h"
- #include <vector>
- #include "ash/shell.h"
- #include "ash/test/ash_test_base.h"
- #include "ash/utility/haptics_tracking_test_input_controller.h"
- #include "ash/wm/desks/desk_animation_impl.h"
- #include "ash/wm/desks/desk_mini_view.h"
- #include "ash/wm/desks/desks_bar_view.h"
- #include "ash/wm/desks/desks_constants.h"
- #include "ash/wm/desks/desks_controller.h"
- #include "ash/wm/desks/desks_histogram_enums.h"
- #include "ash/wm/desks/desks_test_util.h"
- #include "ash/wm/desks/root_window_desk_switch_animator_test_api.h"
- #include "ash/wm/gestures/wm_gesture_handler.h"
- #include "ash/wm/overview/overview_controller.h"
- #include "ash/wm/overview/overview_grid.h"
- #include "ash/wm/overview/overview_item.h"
- #include "ash/wm/overview/overview_session.h"
- #include "ash/wm/workspace/workspace_window_resizer.h"
- #include "ui/aura/window.h"
- #include "ui/events/devices/haptic_touchpad_effects.h"
- #include "ui/gfx/geometry/rect.h"
- #include "ui/gfx/geometry/rect_f.h"
- namespace ash {
- using ui::HapticTouchpadEffect;
- using ui::HapticTouchpadEffectStrength;
- using HapticsUtilTest = AshTestBase;
- // Test haptic feedback with all effect/strength combinations.
- TEST_F(HapticsUtilTest, HapticFeedbackBasic) {
- auto input_controller =
- std::make_unique<HapticsTrackingTestInputController>();
- std::vector<HapticTouchpadEffect> effects = {
- HapticTouchpadEffect::kSnap, HapticTouchpadEffect::kKnock,
- HapticTouchpadEffect::kTick, HapticTouchpadEffect::kPress,
- HapticTouchpadEffect::kRelease,
- };
- std::vector<HapticTouchpadEffectStrength> strengths = {
- HapticTouchpadEffectStrength::kLow,
- HapticTouchpadEffectStrength::kMedium,
- HapticTouchpadEffectStrength::kHigh,
- };
- for (HapticTouchpadEffect effect : effects) {
- for (HapticTouchpadEffectStrength strength : strengths) {
- for (int count = 0; count < 16; count++) {
- haptics_util::PlayHapticTouchpadEffect(effect, strength);
- EXPECT_EQ(count + 1,
- input_controller->GetSentHapticCount(effect, strength));
- }
- }
- }
- }
- // Test haptic feedback for normal window snapping. This covers drag to snap
- // primary/secondary/maximize.
- TEST_F(HapticsUtilTest, HapticFeedbackForNormalWindowSnap) {
- auto input_controller =
- std::make_unique<HapticsTrackingTestInputController>();
- UpdateDisplay("800x600");
- gfx::Rect bounds(200, 200, 300, 300);
- std::unique_ptr<aura::Window> window = CreateTestWindow(bounds);
- ui::test::EventGenerator* event_generator = GetEventGenerator();
- // Each element in the vector represents a test case. The first in the pair is
- // the drag target point, which is used to trigger window snapping, and the
- // second is the expected window bounds after drag.
- std::vector<std::pair<gfx::Point, gfx::Rect>> test_cases = {
- {{0, 220}, {0, 0, 400, 552}},
- {{800, 220}, {400, 0, 400, 552}},
- {{350, 0}, {0, 0, 800, 552}},
- };
- // Drag by touch should not trigger haptic feedback.
- for (size_t i = 0; i < test_cases.size(); i++) {
- std::pair<gfx::Point, gfx::Rect> test_case = test_cases[i];
- window->SetBounds(bounds);
- gfx::Point start =
- window->GetBoundsInScreen().top_center() + gfx::Vector2d(0, 20);
- event_generator->set_current_screen_location(start);
- event_generator->PressTouch();
- event_generator->MoveTouch(test_case.first);
- EXPECT_EQ(0, input_controller->GetSentHapticCount(
- HapticTouchpadEffect::kSnap,
- HapticTouchpadEffectStrength::kMedium));
- event_generator->ReleaseTouch();
- EXPECT_EQ(test_case.second, window->GetBoundsInScreen());
- }
- // Drag by touchpad/mouse should trigger haptic feedback.
- for (size_t i = 0; i < test_cases.size(); i++) {
- std::pair<gfx::Point, gfx::Rect> test_case = test_cases[i];
- window->SetBounds(bounds);
- gfx::Point start =
- window->GetBoundsInScreen().top_center() + gfx::Vector2d(0, 20);
- event_generator->set_current_screen_location(start);
- event_generator->PressLeftButton();
- event_generator->MoveMouseTo(test_case.first);
- WorkspaceWindowResizer* workspace_resizer =
- WorkspaceWindowResizer::GetInstanceForTest();
- if (workspace_resizer->dwell_countdown_timer_.IsRunning())
- workspace_resizer->dwell_countdown_timer_.FireNow();
- EXPECT_EQ((int)i + 1, input_controller->GetSentHapticCount(
- HapticTouchpadEffect::kSnap,
- HapticTouchpadEffectStrength::kMedium));
- event_generator->ReleaseLeftButton();
- EXPECT_EQ(test_case.second, window->GetBoundsInScreen());
- }
- }
- // Test haptic feedback for overview window snapping. This covers drag to split
- // in overview.
- TEST_F(HapticsUtilTest, HapticFeedbackForOverviewWindowSnap) {
- auto input_controller =
- std::make_unique<HapticsTrackingTestInputController>();
- OverviewController* overview_controller = Shell::Get()->overview_controller();
- UpdateDisplay("800x600");
- std::unique_ptr<aura::Window> window =
- CreateTestWindow(gfx::Rect(200, 200, 300, 300));
- ui::test::EventGenerator* event_generator = GetEventGenerator();
- // Each element in the vector represents a test case. The first in the pair is
- // the drag target point, which is used to trigger window snapping, and the
- // second is the expected window bounds after drag.
- std::vector<std::pair<gfx::Point, gfx::Rect>> test_cases = {
- {{0, 300}, {0, 0, 400, 552}},
- {{800, 300}, {400, 0, 400, 552}},
- };
- // Drag by touch should not trigger haptic feedback.
- for (size_t i = 0; i < test_cases.size(); i++) {
- std::pair<gfx::Point, gfx::Rect> test_case = test_cases[i];
- EnterOverview();
- OverviewItem* overview_item =
- overview_controller->overview_session()->GetOverviewItemForWindow(
- window.get());
- event_generator->set_current_screen_location(
- gfx::ToRoundedPoint(overview_item->target_bounds().CenterPoint()));
- event_generator->PressTouch();
- event_generator->MoveTouch(test_case.first);
- EXPECT_TRUE(overview_controller->InOverviewSession());
- EXPECT_EQ(0, input_controller->GetSentHapticCount(
- HapticTouchpadEffect::kSnap,
- HapticTouchpadEffectStrength::kMedium));
- event_generator->ReleaseTouch();
- EXPECT_FALSE(overview_controller->InOverviewSession());
- EXPECT_EQ(test_case.second, window->GetBoundsInScreen());
- }
- // Drag by touchpad/mouse should trigger haptic feedback.
- for (size_t i = 0; i < test_cases.size(); i++) {
- std::pair<gfx::Point, gfx::Rect> test_case = test_cases[i];
- EnterOverview();
- OverviewItem* overview_item =
- overview_controller->overview_session()->GetOverviewItemForWindow(
- window.get());
- event_generator->set_current_screen_location(
- gfx::ToRoundedPoint(overview_item->target_bounds().CenterPoint()));
- event_generator->PressLeftButton();
- event_generator->MoveMouseTo(test_case.first);
- EXPECT_TRUE(overview_controller->InOverviewSession());
- EXPECT_EQ((int)i + 1, input_controller->GetSentHapticCount(
- HapticTouchpadEffect::kSnap,
- HapticTouchpadEffectStrength::kMedium));
- event_generator->ReleaseLeftButton();
- EXPECT_FALSE(overview_controller->InOverviewSession());
- EXPECT_EQ(test_case.second, window->GetBoundsInScreen());
- }
- }
- // Test haptic feedback for off limits desk switching, e.g. swiping left from
- // the first desk and swiping right from the last desk.
- TEST_F(HapticsUtilTest, HapticFeedbackForDeskSwitchingOffLimits) {
- auto input_controller =
- std::make_unique<HapticsTrackingTestInputController>();
- auto* desk_controller = DesksController::Get();
- // Make sure to start with two desks.
- NewDesk();
- EXPECT_EQ(2u, desk_controller->desks().size());
- EXPECT_EQ(0, desk_controller->GetActiveDeskIndex());
- EXPECT_EQ(
- input_controller->GetSentHapticCount(
- HapticTouchpadEffect::kKnock, HapticTouchpadEffectStrength::kMedium),
- 0);
- // Swipe from `desk 0` to `desk 1` should not trigger `kKnock` effect.
- ScrollToSwitchDesks(/*scroll_left=*/false, GetEventGenerator());
- EXPECT_EQ(1, desk_controller->GetActiveDeskIndex());
- EXPECT_EQ(0, input_controller->GetSentHapticCount(
- HapticTouchpadEffect::kKnock,
- HapticTouchpadEffectStrength::kMedium));
- // Swipe from `desk 1` to right should trigger `kKnock` effect.
- ScrollToSwitchDesks(/*scroll_left=*/false,
- /*event_generator=*/GetEventGenerator());
- EXPECT_EQ(1, desk_controller->GetActiveDeskIndex());
- EXPECT_EQ(1, input_controller->GetSentHapticCount(
- HapticTouchpadEffect::kKnock,
- HapticTouchpadEffectStrength::kMedium));
- }
- // Tests that haptics are sent when doing a continuous touchpad gesture to
- // switch desks. They are expected to be sent if we hit the edge, or when the
- // visible desk changes.
- TEST_F(HapticsUtilTest, HapticFeedbackForContinuousDesksSwitching) {
- auto input_controller =
- std::make_unique<HapticsTrackingTestInputController>();
- // Add three desks for a total of four.
- auto* desks_controller = DesksController::Get();
- desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
- desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
- desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
- // Create a standalone animation object. This is the same object that gets
- // created when swiping with 4 fingers, but mocking 4 fingers swipes is harder
- // to control in a test with all the async operations and touchpad unit
- // conversions.
- DeskActivationAnimation animation(desks_controller, 0, 1,
- DesksSwitchSource::kDeskSwitchTouchpad,
- /*update_window_activation=*/false);
- animation.set_skip_notify_controller_on_animation_finished_for_testing(true);
- animation.Launch();
- // Wait for the ending screenshot to be taken.
- WaitUntilEndingScreenshotTaken(&animation);
- EXPECT_EQ(0, input_controller->GetSentHapticCount(
- HapticTouchpadEffect::kKnock,
- HapticTouchpadEffectStrength::kMedium));
- EXPECT_EQ(0, input_controller->GetSentHapticCount(
- HapticTouchpadEffect::kTick,
- HapticTouchpadEffectStrength::kMedium));
- // Swipe enough so that our third and fourth desk screenshots are taken, and
- // then swipe so that the fourth desk is fully shown. There should be 3
- // visible desk changes in total, which means 3 tick haptic events sent.
- animation.UpdateSwipeAnimation(-kTouchpadSwipeLengthForDeskChange);
- WaitUntilEndingScreenshotTaken(&animation);
- animation.UpdateSwipeAnimation(-kTouchpadSwipeLengthForDeskChange);
- WaitUntilEndingScreenshotTaken(&animation);
- animation.UpdateSwipeAnimation(-kTouchpadSwipeLengthForDeskChange);
- EXPECT_EQ(3, input_controller->GetSentHapticCount(
- HapticTouchpadEffect::kTick,
- HapticTouchpadEffectStrength::kMedium));
- // Try doing a full swipe to the right. Test that a knock haptic event is sent
- // because we are at the edge.
- animation.UpdateSwipeAnimation(-kTouchpadSwipeLengthForDeskChange);
- EXPECT_EQ(1, input_controller->GetSentHapticCount(
- HapticTouchpadEffect::kKnock,
- HapticTouchpadEffectStrength::kMedium));
- // Swipe 3 times to the left. We move from the fourth desk as the visible desk
- // to the first desk, so there should be three more tick haptic events.
- animation.UpdateSwipeAnimation(kTouchpadSwipeLengthForDeskChange);
- animation.UpdateSwipeAnimation(kTouchpadSwipeLengthForDeskChange);
- animation.UpdateSwipeAnimation(kTouchpadSwipeLengthForDeskChange);
- EXPECT_EQ(6, input_controller->GetSentHapticCount(
- HapticTouchpadEffect::kTick,
- HapticTouchpadEffectStrength::kMedium));
- // Swipe to the left while at the first desk. Tests that another haptic event
- // is sent because we are at the edge.
- animation.UpdateSwipeAnimation(kTouchpadSwipeLengthForDeskChange);
- EXPECT_EQ(2, input_controller->GetSentHapticCount(
- HapticTouchpadEffect::kKnock,
- HapticTouchpadEffectStrength::kMedium));
- }
- // Tests that haptics are sent when dragging a window/desk in overview.
- TEST_F(HapticsUtilTest, HapticFeedbackForDragAndDrop) {
- auto input_controller =
- std::make_unique<HapticsTrackingTestInputController>();
- OverviewController* overview_controller = Shell::Get()->overview_controller();
- std::unique_ptr<aura::Window> window = CreateTestWindow();
- ui::test::EventGenerator* event_generator = GetEventGenerator();
- // Add three desks for a total of two.
- auto* desks_controller = DesksController::Get();
- desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
- // Drag a window in overview. Test that kTick feedback is sent.
- EnterOverview();
- OverviewItem* overview_item =
- overview_controller->overview_session()->GetOverviewItemForWindow(
- window.get());
- const gfx::RectF bounds_f = overview_item->target_bounds();
- event_generator->set_current_screen_location(
- gfx::ToRoundedPoint(bounds_f.CenterPoint()));
- event_generator->PressLeftButton();
- event_generator->MoveMouseTo(gfx::ToRoundedPoint(bounds_f.right_center()));
- EXPECT_EQ(1, input_controller->GetSentHapticCount(
- HapticTouchpadEffect::kTick,
- HapticTouchpadEffectStrength::kMedium));
- event_generator->ReleaseLeftButton();
- EXPECT_TRUE(overview_controller->InOverviewSession());
- // Drag a desk in overview. Test that kTick feedback is sent.
- const gfx::Rect bounds = overview_controller->overview_session()
- ->grid_list()
- .front()
- ->desks_bar_view()
- ->mini_views()
- .front()
- ->bounds();
- event_generator->set_current_screen_location(bounds.CenterPoint());
- event_generator->PressLeftButton();
- event_generator->MoveMouseTo(bounds.right_center());
- EXPECT_EQ(2, input_controller->GetSentHapticCount(
- HapticTouchpadEffect::kTick,
- HapticTouchpadEffectStrength::kMedium));
- event_generator->ReleaseLeftButton();
- EXPECT_TRUE(overview_controller->InOverviewSession());
- ExitOverview();
- }
- } // namespace ash
|