haptics_util_unittest.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/utility/haptics_util.h"
  5. #include <vector>
  6. #include "ash/shell.h"
  7. #include "ash/test/ash_test_base.h"
  8. #include "ash/utility/haptics_tracking_test_input_controller.h"
  9. #include "ash/wm/desks/desk_animation_impl.h"
  10. #include "ash/wm/desks/desk_mini_view.h"
  11. #include "ash/wm/desks/desks_bar_view.h"
  12. #include "ash/wm/desks/desks_constants.h"
  13. #include "ash/wm/desks/desks_controller.h"
  14. #include "ash/wm/desks/desks_histogram_enums.h"
  15. #include "ash/wm/desks/desks_test_util.h"
  16. #include "ash/wm/desks/root_window_desk_switch_animator_test_api.h"
  17. #include "ash/wm/gestures/wm_gesture_handler.h"
  18. #include "ash/wm/overview/overview_controller.h"
  19. #include "ash/wm/overview/overview_grid.h"
  20. #include "ash/wm/overview/overview_item.h"
  21. #include "ash/wm/overview/overview_session.h"
  22. #include "ash/wm/workspace/workspace_window_resizer.h"
  23. #include "ui/aura/window.h"
  24. #include "ui/events/devices/haptic_touchpad_effects.h"
  25. #include "ui/gfx/geometry/rect.h"
  26. #include "ui/gfx/geometry/rect_f.h"
  27. namespace ash {
  28. using ui::HapticTouchpadEffect;
  29. using ui::HapticTouchpadEffectStrength;
  30. using HapticsUtilTest = AshTestBase;
  31. // Test haptic feedback with all effect/strength combinations.
  32. TEST_F(HapticsUtilTest, HapticFeedbackBasic) {
  33. auto input_controller =
  34. std::make_unique<HapticsTrackingTestInputController>();
  35. std::vector<HapticTouchpadEffect> effects = {
  36. HapticTouchpadEffect::kSnap, HapticTouchpadEffect::kKnock,
  37. HapticTouchpadEffect::kTick, HapticTouchpadEffect::kPress,
  38. HapticTouchpadEffect::kRelease,
  39. };
  40. std::vector<HapticTouchpadEffectStrength> strengths = {
  41. HapticTouchpadEffectStrength::kLow,
  42. HapticTouchpadEffectStrength::kMedium,
  43. HapticTouchpadEffectStrength::kHigh,
  44. };
  45. for (HapticTouchpadEffect effect : effects) {
  46. for (HapticTouchpadEffectStrength strength : strengths) {
  47. for (int count = 0; count < 16; count++) {
  48. haptics_util::PlayHapticTouchpadEffect(effect, strength);
  49. EXPECT_EQ(count + 1,
  50. input_controller->GetSentHapticCount(effect, strength));
  51. }
  52. }
  53. }
  54. }
  55. // Test haptic feedback for normal window snapping. This covers drag to snap
  56. // primary/secondary/maximize.
  57. TEST_F(HapticsUtilTest, HapticFeedbackForNormalWindowSnap) {
  58. auto input_controller =
  59. std::make_unique<HapticsTrackingTestInputController>();
  60. UpdateDisplay("800x600");
  61. gfx::Rect bounds(200, 200, 300, 300);
  62. std::unique_ptr<aura::Window> window = CreateTestWindow(bounds);
  63. ui::test::EventGenerator* event_generator = GetEventGenerator();
  64. // Each element in the vector represents a test case. The first in the pair is
  65. // the drag target point, which is used to trigger window snapping, and the
  66. // second is the expected window bounds after drag.
  67. std::vector<std::pair<gfx::Point, gfx::Rect>> test_cases = {
  68. {{0, 220}, {0, 0, 400, 552}},
  69. {{800, 220}, {400, 0, 400, 552}},
  70. {{350, 0}, {0, 0, 800, 552}},
  71. };
  72. // Drag by touch should not trigger haptic feedback.
  73. for (size_t i = 0; i < test_cases.size(); i++) {
  74. std::pair<gfx::Point, gfx::Rect> test_case = test_cases[i];
  75. window->SetBounds(bounds);
  76. gfx::Point start =
  77. window->GetBoundsInScreen().top_center() + gfx::Vector2d(0, 20);
  78. event_generator->set_current_screen_location(start);
  79. event_generator->PressTouch();
  80. event_generator->MoveTouch(test_case.first);
  81. EXPECT_EQ(0, input_controller->GetSentHapticCount(
  82. HapticTouchpadEffect::kSnap,
  83. HapticTouchpadEffectStrength::kMedium));
  84. event_generator->ReleaseTouch();
  85. EXPECT_EQ(test_case.second, window->GetBoundsInScreen());
  86. }
  87. // Drag by touchpad/mouse should trigger haptic feedback.
  88. for (size_t i = 0; i < test_cases.size(); i++) {
  89. std::pair<gfx::Point, gfx::Rect> test_case = test_cases[i];
  90. window->SetBounds(bounds);
  91. gfx::Point start =
  92. window->GetBoundsInScreen().top_center() + gfx::Vector2d(0, 20);
  93. event_generator->set_current_screen_location(start);
  94. event_generator->PressLeftButton();
  95. event_generator->MoveMouseTo(test_case.first);
  96. WorkspaceWindowResizer* workspace_resizer =
  97. WorkspaceWindowResizer::GetInstanceForTest();
  98. if (workspace_resizer->dwell_countdown_timer_.IsRunning())
  99. workspace_resizer->dwell_countdown_timer_.FireNow();
  100. EXPECT_EQ((int)i + 1, input_controller->GetSentHapticCount(
  101. HapticTouchpadEffect::kSnap,
  102. HapticTouchpadEffectStrength::kMedium));
  103. event_generator->ReleaseLeftButton();
  104. EXPECT_EQ(test_case.second, window->GetBoundsInScreen());
  105. }
  106. }
  107. // Test haptic feedback for overview window snapping. This covers drag to split
  108. // in overview.
  109. TEST_F(HapticsUtilTest, HapticFeedbackForOverviewWindowSnap) {
  110. auto input_controller =
  111. std::make_unique<HapticsTrackingTestInputController>();
  112. OverviewController* overview_controller = Shell::Get()->overview_controller();
  113. UpdateDisplay("800x600");
  114. std::unique_ptr<aura::Window> window =
  115. CreateTestWindow(gfx::Rect(200, 200, 300, 300));
  116. ui::test::EventGenerator* event_generator = GetEventGenerator();
  117. // Each element in the vector represents a test case. The first in the pair is
  118. // the drag target point, which is used to trigger window snapping, and the
  119. // second is the expected window bounds after drag.
  120. std::vector<std::pair<gfx::Point, gfx::Rect>> test_cases = {
  121. {{0, 300}, {0, 0, 400, 552}},
  122. {{800, 300}, {400, 0, 400, 552}},
  123. };
  124. // Drag by touch should not trigger haptic feedback.
  125. for (size_t i = 0; i < test_cases.size(); i++) {
  126. std::pair<gfx::Point, gfx::Rect> test_case = test_cases[i];
  127. EnterOverview();
  128. OverviewItem* overview_item =
  129. overview_controller->overview_session()->GetOverviewItemForWindow(
  130. window.get());
  131. event_generator->set_current_screen_location(
  132. gfx::ToRoundedPoint(overview_item->target_bounds().CenterPoint()));
  133. event_generator->PressTouch();
  134. event_generator->MoveTouch(test_case.first);
  135. EXPECT_TRUE(overview_controller->InOverviewSession());
  136. EXPECT_EQ(0, input_controller->GetSentHapticCount(
  137. HapticTouchpadEffect::kSnap,
  138. HapticTouchpadEffectStrength::kMedium));
  139. event_generator->ReleaseTouch();
  140. EXPECT_FALSE(overview_controller->InOverviewSession());
  141. EXPECT_EQ(test_case.second, window->GetBoundsInScreen());
  142. }
  143. // Drag by touchpad/mouse should trigger haptic feedback.
  144. for (size_t i = 0; i < test_cases.size(); i++) {
  145. std::pair<gfx::Point, gfx::Rect> test_case = test_cases[i];
  146. EnterOverview();
  147. OverviewItem* overview_item =
  148. overview_controller->overview_session()->GetOverviewItemForWindow(
  149. window.get());
  150. event_generator->set_current_screen_location(
  151. gfx::ToRoundedPoint(overview_item->target_bounds().CenterPoint()));
  152. event_generator->PressLeftButton();
  153. event_generator->MoveMouseTo(test_case.first);
  154. EXPECT_TRUE(overview_controller->InOverviewSession());
  155. EXPECT_EQ((int)i + 1, input_controller->GetSentHapticCount(
  156. HapticTouchpadEffect::kSnap,
  157. HapticTouchpadEffectStrength::kMedium));
  158. event_generator->ReleaseLeftButton();
  159. EXPECT_FALSE(overview_controller->InOverviewSession());
  160. EXPECT_EQ(test_case.second, window->GetBoundsInScreen());
  161. }
  162. }
  163. // Test haptic feedback for off limits desk switching, e.g. swiping left from
  164. // the first desk and swiping right from the last desk.
  165. TEST_F(HapticsUtilTest, HapticFeedbackForDeskSwitchingOffLimits) {
  166. auto input_controller =
  167. std::make_unique<HapticsTrackingTestInputController>();
  168. auto* desk_controller = DesksController::Get();
  169. // Make sure to start with two desks.
  170. NewDesk();
  171. EXPECT_EQ(2u, desk_controller->desks().size());
  172. EXPECT_EQ(0, desk_controller->GetActiveDeskIndex());
  173. EXPECT_EQ(
  174. input_controller->GetSentHapticCount(
  175. HapticTouchpadEffect::kKnock, HapticTouchpadEffectStrength::kMedium),
  176. 0);
  177. // Swipe from `desk 0` to `desk 1` should not trigger `kKnock` effect.
  178. ScrollToSwitchDesks(/*scroll_left=*/false, GetEventGenerator());
  179. EXPECT_EQ(1, desk_controller->GetActiveDeskIndex());
  180. EXPECT_EQ(0, input_controller->GetSentHapticCount(
  181. HapticTouchpadEffect::kKnock,
  182. HapticTouchpadEffectStrength::kMedium));
  183. // Swipe from `desk 1` to right should trigger `kKnock` effect.
  184. ScrollToSwitchDesks(/*scroll_left=*/false,
  185. /*event_generator=*/GetEventGenerator());
  186. EXPECT_EQ(1, desk_controller->GetActiveDeskIndex());
  187. EXPECT_EQ(1, input_controller->GetSentHapticCount(
  188. HapticTouchpadEffect::kKnock,
  189. HapticTouchpadEffectStrength::kMedium));
  190. }
  191. // Tests that haptics are sent when doing a continuous touchpad gesture to
  192. // switch desks. They are expected to be sent if we hit the edge, or when the
  193. // visible desk changes.
  194. TEST_F(HapticsUtilTest, HapticFeedbackForContinuousDesksSwitching) {
  195. auto input_controller =
  196. std::make_unique<HapticsTrackingTestInputController>();
  197. // Add three desks for a total of four.
  198. auto* desks_controller = DesksController::Get();
  199. desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
  200. desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
  201. desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
  202. // Create a standalone animation object. This is the same object that gets
  203. // created when swiping with 4 fingers, but mocking 4 fingers swipes is harder
  204. // to control in a test with all the async operations and touchpad unit
  205. // conversions.
  206. DeskActivationAnimation animation(desks_controller, 0, 1,
  207. DesksSwitchSource::kDeskSwitchTouchpad,
  208. /*update_window_activation=*/false);
  209. animation.set_skip_notify_controller_on_animation_finished_for_testing(true);
  210. animation.Launch();
  211. // Wait for the ending screenshot to be taken.
  212. WaitUntilEndingScreenshotTaken(&animation);
  213. EXPECT_EQ(0, input_controller->GetSentHapticCount(
  214. HapticTouchpadEffect::kKnock,
  215. HapticTouchpadEffectStrength::kMedium));
  216. EXPECT_EQ(0, input_controller->GetSentHapticCount(
  217. HapticTouchpadEffect::kTick,
  218. HapticTouchpadEffectStrength::kMedium));
  219. // Swipe enough so that our third and fourth desk screenshots are taken, and
  220. // then swipe so that the fourth desk is fully shown. There should be 3
  221. // visible desk changes in total, which means 3 tick haptic events sent.
  222. animation.UpdateSwipeAnimation(-kTouchpadSwipeLengthForDeskChange);
  223. WaitUntilEndingScreenshotTaken(&animation);
  224. animation.UpdateSwipeAnimation(-kTouchpadSwipeLengthForDeskChange);
  225. WaitUntilEndingScreenshotTaken(&animation);
  226. animation.UpdateSwipeAnimation(-kTouchpadSwipeLengthForDeskChange);
  227. EXPECT_EQ(3, input_controller->GetSentHapticCount(
  228. HapticTouchpadEffect::kTick,
  229. HapticTouchpadEffectStrength::kMedium));
  230. // Try doing a full swipe to the right. Test that a knock haptic event is sent
  231. // because we are at the edge.
  232. animation.UpdateSwipeAnimation(-kTouchpadSwipeLengthForDeskChange);
  233. EXPECT_EQ(1, input_controller->GetSentHapticCount(
  234. HapticTouchpadEffect::kKnock,
  235. HapticTouchpadEffectStrength::kMedium));
  236. // Swipe 3 times to the left. We move from the fourth desk as the visible desk
  237. // to the first desk, so there should be three more tick haptic events.
  238. animation.UpdateSwipeAnimation(kTouchpadSwipeLengthForDeskChange);
  239. animation.UpdateSwipeAnimation(kTouchpadSwipeLengthForDeskChange);
  240. animation.UpdateSwipeAnimation(kTouchpadSwipeLengthForDeskChange);
  241. EXPECT_EQ(6, input_controller->GetSentHapticCount(
  242. HapticTouchpadEffect::kTick,
  243. HapticTouchpadEffectStrength::kMedium));
  244. // Swipe to the left while at the first desk. Tests that another haptic event
  245. // is sent because we are at the edge.
  246. animation.UpdateSwipeAnimation(kTouchpadSwipeLengthForDeskChange);
  247. EXPECT_EQ(2, input_controller->GetSentHapticCount(
  248. HapticTouchpadEffect::kKnock,
  249. HapticTouchpadEffectStrength::kMedium));
  250. }
  251. // Tests that haptics are sent when dragging a window/desk in overview.
  252. TEST_F(HapticsUtilTest, HapticFeedbackForDragAndDrop) {
  253. auto input_controller =
  254. std::make_unique<HapticsTrackingTestInputController>();
  255. OverviewController* overview_controller = Shell::Get()->overview_controller();
  256. std::unique_ptr<aura::Window> window = CreateTestWindow();
  257. ui::test::EventGenerator* event_generator = GetEventGenerator();
  258. // Add three desks for a total of two.
  259. auto* desks_controller = DesksController::Get();
  260. desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
  261. // Drag a window in overview. Test that kTick feedback is sent.
  262. EnterOverview();
  263. OverviewItem* overview_item =
  264. overview_controller->overview_session()->GetOverviewItemForWindow(
  265. window.get());
  266. const gfx::RectF bounds_f = overview_item->target_bounds();
  267. event_generator->set_current_screen_location(
  268. gfx::ToRoundedPoint(bounds_f.CenterPoint()));
  269. event_generator->PressLeftButton();
  270. event_generator->MoveMouseTo(gfx::ToRoundedPoint(bounds_f.right_center()));
  271. EXPECT_EQ(1, input_controller->GetSentHapticCount(
  272. HapticTouchpadEffect::kTick,
  273. HapticTouchpadEffectStrength::kMedium));
  274. event_generator->ReleaseLeftButton();
  275. EXPECT_TRUE(overview_controller->InOverviewSession());
  276. // Drag a desk in overview. Test that kTick feedback is sent.
  277. const gfx::Rect bounds = overview_controller->overview_session()
  278. ->grid_list()
  279. .front()
  280. ->desks_bar_view()
  281. ->mini_views()
  282. .front()
  283. ->bounds();
  284. event_generator->set_current_screen_location(bounds.CenterPoint());
  285. event_generator->PressLeftButton();
  286. event_generator->MoveMouseTo(bounds.right_center());
  287. EXPECT_EQ(2, input_controller->GetSentHapticCount(
  288. HapticTouchpadEffect::kTick,
  289. HapticTouchpadEffectStrength::kMedium));
  290. event_generator->ReleaseLeftButton();
  291. EXPECT_TRUE(overview_controller->InOverviewSession());
  292. ExitOverview();
  293. }
  294. } // namespace ash