OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/chromeos/touch_exploration_controller.h" | 5 #include "ui/chromeos/touch_exploration_controller.h" |
6 | 6 |
7 #include "base/test/simple_test_tick_clock.h" | 7 #include "base/test/simple_test_tick_clock.h" |
8 #include "base/time/time.h" | 8 #include "base/time/time.h" |
9 #include "ui/aura/client/cursor_client.h" | 9 #include "ui/aura/client/cursor_client.h" |
10 #include "ui/aura/test/aura_test_base.h" | 10 #include "ui/aura/test/aura_test_base.h" |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
68 if (n <= 0) | 68 if (n <= 0) |
69 return 0; | 69 return 0; |
70 if (n == 1) | 70 if (n == 1) |
71 return 1; | 71 return 1; |
72 return n * Factorial(n - 1); | 72 return n * Factorial(n - 1); |
73 } | 73 } |
74 | 74 |
75 class MockTouchExplorationControllerDelegate | 75 class MockTouchExplorationControllerDelegate |
76 : public ui::TouchExplorationControllerDelegate { | 76 : public ui::TouchExplorationControllerDelegate { |
77 public: | 77 public: |
78 virtual void PlayVolumeAdjustSound() OVERRIDE { | 78 virtual void SetOutputLevel(int volume) OVERRIDE { |
| 79 volume_changes_.push_back(volume); |
| 80 } |
| 81 virtual void PlayVolumeAdjustEarcon() OVERRIDE { |
79 ++num_times_adjust_sound_played_; | 82 ++num_times_adjust_sound_played_; |
80 } | 83 } |
81 virtual void SetOutputLevel(int volume) OVERRIDE { | 84 virtual void PlayPassthroughEarcon() OVERRIDE { |
82 volume_changes_.push_back(volume); | 85 ++num_times_passthrough_played_; |
| 86 } |
| 87 virtual void PlayExitScreenEarcon() OVERRIDE { |
| 88 ++num_times_exit_screen_played_; |
| 89 } |
| 90 virtual void PlayEnterScreenEarcon() OVERRIDE { |
| 91 ++num_times_enter_screen_played_; |
83 } | 92 } |
84 | 93 |
85 const std::vector<float> VolumeChanges() { return volume_changes_; } | 94 const std::vector<float> VolumeChanges() { return volume_changes_; } |
86 const size_t NumAdjustSounds() { return num_times_adjust_sound_played_; } | 95 const size_t NumAdjustSounds() { return num_times_adjust_sound_played_; } |
| 96 const size_t NumPassthroughSounds() { return num_times_passthrough_played_; } |
| 97 const size_t NumExitScreenSounds() { return num_times_exit_screen_played_; } |
| 98 const size_t NumEnterScreenSounds() { |
| 99 return num_times_enter_screen_played_; |
| 100 } |
| 101 |
| 102 void ResetCountersToZero() { |
| 103 num_times_adjust_sound_played_ = 0; |
| 104 num_times_passthrough_played_ = 0; |
| 105 num_times_exit_screen_played_ = 0; |
| 106 num_times_enter_screen_played_ = 0; |
| 107 } |
87 | 108 |
88 private: | 109 private: |
89 std::vector<float> volume_changes_; | 110 std::vector<float> volume_changes_; |
90 size_t num_times_adjust_sound_played_ = 0; | 111 size_t num_times_adjust_sound_played_ = 0; |
| 112 size_t num_times_passthrough_played_ = 0; |
| 113 size_t num_times_exit_screen_played_ = 0; |
| 114 size_t num_times_enter_screen_played_ = 0; |
91 }; | 115 }; |
92 | 116 |
93 } // namespace | 117 } // namespace |
94 | 118 |
95 class TouchExplorationControllerTestApi { | 119 class TouchExplorationControllerTestApi { |
96 public: | 120 public: |
97 TouchExplorationControllerTestApi( | 121 TouchExplorationControllerTestApi( |
98 TouchExplorationController* touch_exploration_controller) { | 122 TouchExplorationController* touch_exploration_controller) { |
99 touch_exploration_controller_.reset(touch_exploration_controller); | 123 touch_exploration_controller_.reset(touch_exploration_controller); |
100 } | 124 } |
101 | 125 |
102 void CallTapTimerNowForTesting() { | 126 void CallTapTimerNowForTesting() { |
103 DCHECK(touch_exploration_controller_->tap_timer_.IsRunning()); | 127 DCHECK(touch_exploration_controller_->tap_timer_.IsRunning()); |
104 touch_exploration_controller_->tap_timer_.Stop(); | 128 touch_exploration_controller_->tap_timer_.Stop(); |
105 touch_exploration_controller_->OnTapTimerFired(); | 129 touch_exploration_controller_->OnTapTimerFired(); |
106 } | 130 } |
107 | 131 |
| 132 void CallLongPressTimerNowForTesting() { |
| 133 DCHECK(touch_exploration_controller_->long_press_timer_.IsRunning()); |
| 134 touch_exploration_controller_->long_press_timer_.Stop(); |
| 135 touch_exploration_controller_->OnLongPressTimerFired(); |
| 136 } |
| 137 |
108 void CallTapTimerNowIfRunningForTesting() { | 138 void CallTapTimerNowIfRunningForTesting() { |
109 if (touch_exploration_controller_->tap_timer_.IsRunning()) { | 139 if (touch_exploration_controller_->tap_timer_.IsRunning()) { |
110 touch_exploration_controller_->tap_timer_.Stop(); | 140 touch_exploration_controller_->tap_timer_.Stop(); |
111 touch_exploration_controller_->OnTapTimerFired(); | 141 touch_exploration_controller_->OnTapTimerFired(); |
112 } | 142 } |
113 } | 143 } |
114 | 144 |
115 bool IsInNoFingersDownStateForTesting() const { | 145 bool IsInNoFingersDownStateForTesting() const { |
116 return touch_exploration_controller_->state_ == | 146 return touch_exploration_controller_->state_ == |
117 touch_exploration_controller_->NO_FINGERS_DOWN; | 147 touch_exploration_controller_->NO_FINGERS_DOWN; |
118 } | 148 } |
119 | 149 |
120 bool IsInGestureInProgressStateForTesting() const { | 150 bool IsInGestureInProgressStateForTesting() const { |
121 return touch_exploration_controller_->state_ == | 151 return touch_exploration_controller_->state_ == |
122 touch_exploration_controller_->GESTURE_IN_PROGRESS; | 152 touch_exploration_controller_->GESTURE_IN_PROGRESS; |
123 } | 153 } |
124 | 154 |
125 bool IsInSlideGestureStateForTesting() const { | 155 bool IsInSlideGestureStateForTesting() const { |
126 return touch_exploration_controller_->state_ == | 156 return touch_exploration_controller_->state_ == |
127 touch_exploration_controller_->SLIDE_GESTURE; | 157 touch_exploration_controller_->SLIDE_GESTURE; |
128 } | 158 } |
129 | 159 |
| 160 bool IsInCornerPassthroughStateForTesting() const { |
| 161 return touch_exploration_controller_->state_ == |
| 162 touch_exploration_controller_->CORNER_PASSTHROUGH; |
| 163 } |
| 164 |
130 gfx::Rect BoundsOfRootWindowInDIPForTesting() const { | 165 gfx::Rect BoundsOfRootWindowInDIPForTesting() const { |
131 return touch_exploration_controller_->root_window_->GetBoundsInScreen(); | 166 return touch_exploration_controller_->root_window_->GetBoundsInScreen(); |
132 } | 167 } |
133 | 168 |
134 // VLOGs should be suppressed in tests that generate a lot of logs, | 169 // VLOGs should be suppressed in tests that generate a lot of logs, |
135 // for example permutations of nine touch events. | 170 // for example permutations of nine touch events. |
136 void SuppressVLOGsForTesting(bool suppress) { | 171 void SuppressVLOGsForTesting(bool suppress) { |
137 touch_exploration_controller_->VLOG_on_ = !suppress; | 172 touch_exploration_controller_->VLOG_on_ = !suppress; |
138 } | 173 } |
139 | 174 |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
221 | 256 |
222 void ClearCapturedEvents() { | 257 void ClearCapturedEvents() { |
223 event_capturer_.Reset(); | 258 event_capturer_.Reset(); |
224 } | 259 } |
225 | 260 |
226 void AdvanceSimulatedTimePastTapDelay() { | 261 void AdvanceSimulatedTimePastTapDelay() { |
227 simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); | 262 simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); |
228 touch_exploration_controller_->CallTapTimerNowForTesting(); | 263 touch_exploration_controller_->CallTapTimerNowForTesting(); |
229 } | 264 } |
230 | 265 |
| 266 void AdvanceSimulatedTimePastLongPressDelay() { |
| 267 simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); |
| 268 touch_exploration_controller_->CallLongPressTimerNowForTesting(); |
| 269 } |
| 270 |
231 void AdvanceSimulatedTimePastPotentialTapDelay() { | 271 void AdvanceSimulatedTimePastPotentialTapDelay() { |
232 simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); | 272 simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); |
233 touch_exploration_controller_->CallTapTimerNowIfRunningForTesting(); | 273 touch_exploration_controller_->CallTapTimerNowIfRunningForTesting(); |
234 } | 274 } |
235 | 275 |
236 void SuppressVLOGs(bool suppress) { | 276 void SuppressVLOGs(bool suppress) { |
237 touch_exploration_controller_->SuppressVLOGsForTesting(suppress); | 277 touch_exploration_controller_->SuppressVLOGsForTesting(suppress); |
238 } | 278 } |
239 | 279 |
240 void SwitchTouchExplorationMode(bool on) { | 280 void SwitchTouchExplorationMode(bool on) { |
(...skipping 19 matching lines...) Expand all Loading... |
260 gfx::Point second_touch_location) { | 300 gfx::Point second_touch_location) { |
261 SwitchTouchExplorationMode(true); | 301 SwitchTouchExplorationMode(true); |
262 ui::TouchEvent first_touch_press( | 302 ui::TouchEvent first_touch_press( |
263 ui::ET_TOUCH_PRESSED, first_touch_location, 0, Now()); | 303 ui::ET_TOUCH_PRESSED, first_touch_location, 0, Now()); |
264 generator_->Dispatch(&first_touch_press); | 304 generator_->Dispatch(&first_touch_press); |
265 ui::TouchEvent second_touch_press( | 305 ui::TouchEvent second_touch_press( |
266 ui::ET_TOUCH_PRESSED, second_touch_location, 1, Now()); | 306 ui::ET_TOUCH_PRESSED, second_touch_location, 1, Now()); |
267 generator_->Dispatch(&second_touch_press); | 307 generator_->Dispatch(&second_touch_press); |
268 } | 308 } |
269 | 309 |
| 310 // Checks that Corner Passthrough is working. Assumes that corner is the |
| 311 // bottom left corner or the bottom right corner. |
| 312 void AssertCornerPassthroughWorking(gfx::Point corner) { |
| 313 ASSERT_EQ(0U, delegate_.NumPassthroughSounds()); |
| 314 |
| 315 ui::TouchEvent first_press(ui::ET_TOUCH_PRESSED, corner, 0, Now()); |
| 316 generator_->Dispatch(&first_press); |
| 317 |
| 318 AdvanceSimulatedTimePastLongPressDelay(); |
| 319 EXPECT_FALSE(IsInGestureInProgressState()); |
| 320 EXPECT_FALSE(IsInSlideGestureState()); |
| 321 EXPECT_FALSE(IsInTouchToMouseMode()); |
| 322 EXPECT_TRUE(IsInCornerPassthroughState()); |
| 323 |
| 324 gfx::Rect window = BoundsOfRootWindowInDIP(); |
| 325 // The following events should be passed through. |
| 326 gfx::Point passthrough(window.right() / 2, window.bottom() / 2); |
| 327 ui::TouchEvent passthrough_press( |
| 328 ui::ET_TOUCH_PRESSED, passthrough, 1, Now()); |
| 329 ASSERT_EQ(1U, delegate_.NumPassthroughSounds()); |
| 330 generator_->Dispatch(&passthrough_press); |
| 331 generator_->ReleaseTouchId(1); |
| 332 generator_->PressTouchId(1); |
| 333 EXPECT_FALSE(IsInGestureInProgressState()); |
| 334 EXPECT_FALSE(IsInSlideGestureState()); |
| 335 EXPECT_TRUE(IsInCornerPassthroughState()); |
| 336 |
| 337 std::vector<ui::LocatedEvent*> captured_events = GetCapturedLocatedEvents(); |
| 338 ASSERT_EQ(3U, captured_events.size()); |
| 339 EXPECT_EQ(ui::ET_TOUCH_PRESSED, captured_events[0]->type()); |
| 340 EXPECT_EQ(ui::ET_TOUCH_RELEASED, captured_events[1]->type()); |
| 341 EXPECT_EQ(ui::ET_TOUCH_PRESSED, captured_events[2]->type()); |
| 342 generator_->ReleaseTouchId(1); |
| 343 ClearCapturedEvents(); |
| 344 |
| 345 generator_->ReleaseTouchId(0); |
| 346 captured_events = GetCapturedLocatedEvents(); |
| 347 ASSERT_EQ(0U, captured_events.size()); |
| 348 EXPECT_FALSE(IsInTouchToMouseMode()); |
| 349 EXPECT_FALSE(IsInCornerPassthroughState()); |
| 350 ClearCapturedEvents(); |
| 351 } |
| 352 |
270 bool IsInTouchToMouseMode() { | 353 bool IsInTouchToMouseMode() { |
271 aura::client::CursorClient* cursor_client = | 354 aura::client::CursorClient* cursor_client = |
272 aura::client::GetCursorClient(root_window()); | 355 aura::client::GetCursorClient(root_window()); |
273 return cursor_client && | 356 return cursor_client && cursor_client->IsMouseEventsEnabled() && |
274 cursor_client->IsMouseEventsEnabled() && | |
275 !cursor_client->IsCursorVisible(); | 357 !cursor_client->IsCursorVisible(); |
276 } | 358 } |
277 | 359 |
278 bool IsInNoFingersDownState() { | 360 bool IsInNoFingersDownState() { |
279 return touch_exploration_controller_->IsInNoFingersDownStateForTesting(); | 361 return touch_exploration_controller_->IsInNoFingersDownStateForTesting(); |
280 } | 362 } |
281 | 363 |
282 bool IsInGestureInProgressState() { | 364 bool IsInGestureInProgressState() { |
283 return touch_exploration_controller_ | 365 return touch_exploration_controller_ |
284 ->IsInGestureInProgressStateForTesting(); | 366 ->IsInGestureInProgressStateForTesting(); |
285 } | 367 } |
286 | 368 |
287 bool IsInSlideGestureState() { | 369 bool IsInSlideGestureState() { |
288 return touch_exploration_controller_->IsInSlideGestureStateForTesting(); | 370 return touch_exploration_controller_->IsInSlideGestureStateForTesting(); |
289 } | 371 } |
290 | 372 |
| 373 bool IsInCornerPassthroughState() { |
| 374 return touch_exploration_controller_ |
| 375 ->IsInCornerPassthroughStateForTesting(); |
| 376 } |
| 377 |
291 gfx::Rect BoundsOfRootWindowInDIP() { | 378 gfx::Rect BoundsOfRootWindowInDIP() { |
292 return touch_exploration_controller_->BoundsOfRootWindowInDIPForTesting(); | 379 return touch_exploration_controller_->BoundsOfRootWindowInDIPForTesting(); |
293 } | 380 } |
294 | 381 |
295 float GetMaxDistanceFromEdge() const{ | 382 float GetMaxDistanceFromEdge() const { |
296 return touch_exploration_controller_->GetMaxDistanceFromEdge(); | 383 return touch_exploration_controller_->GetMaxDistanceFromEdge(); |
297 } | 384 } |
298 | 385 |
299 float GetSlopDistanceFromEdge() const{ | 386 float GetSlopDistanceFromEdge() const{ |
300 return touch_exploration_controller_->GetSlopDistanceFromEdge(); | 387 return touch_exploration_controller_->GetSlopDistanceFromEdge(); |
301 } | 388 } |
302 | 389 |
303 base::TimeDelta Now() { | 390 base::TimeDelta Now() { |
304 // This is the same as what EventTimeForNow() does, but here we do it | 391 // This is the same as what EventTimeForNow() does, but here we do it |
305 // with our simulated clock. | 392 // with our simulated clock. |
(...skipping 1327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1633 EXPECT_FALSE(IsInGestureInProgressState()); | 1720 EXPECT_FALSE(IsInGestureInProgressState()); |
1634 EXPECT_FALSE(IsInSlideGestureState()); | 1721 EXPECT_FALSE(IsInSlideGestureState()); |
1635 EXPECT_FALSE(IsInTouchToMouseMode()); | 1722 EXPECT_FALSE(IsInTouchToMouseMode()); |
1636 | 1723 |
1637 AdvanceSimulatedTimePastTapDelay(); | 1724 AdvanceSimulatedTimePastTapDelay(); |
1638 EXPECT_FALSE(IsInGestureInProgressState()); | 1725 EXPECT_FALSE(IsInGestureInProgressState()); |
1639 EXPECT_FALSE(IsInSlideGestureState()); | 1726 EXPECT_FALSE(IsInSlideGestureState()); |
1640 EXPECT_TRUE(IsInTouchToMouseMode()); | 1727 EXPECT_TRUE(IsInTouchToMouseMode()); |
1641 } | 1728 } |
1642 | 1729 |
| 1730 // Corner passthrough should turn on if the user first holds down on either the |
| 1731 // right or left corner past a delay and then places a finger anywhere else on |
| 1732 // the screen. |
| 1733 TEST_F(TouchExplorationTest, ActivateLeftCornerPassthrough) { |
| 1734 SwitchTouchExplorationMode(true); |
| 1735 |
| 1736 gfx::Rect window = BoundsOfRootWindowInDIP(); |
| 1737 gfx::Point left_corner(10, window.bottom() - GetMaxDistanceFromEdge() / 2); |
| 1738 AssertCornerPassthroughWorking(left_corner); |
| 1739 } |
| 1740 |
| 1741 TEST_F(TouchExplorationTest, ActivateRightCornerPassthrough) { |
| 1742 SwitchTouchExplorationMode(true); |
| 1743 |
| 1744 gfx::Rect window = BoundsOfRootWindowInDIP(); |
| 1745 gfx::Point right_corner(window.right() - GetMaxDistanceFromEdge() / 2, |
| 1746 window.bottom() - GetMaxDistanceFromEdge() / 2); |
| 1747 AssertCornerPassthroughWorking(right_corner); |
| 1748 } |
| 1749 |
| 1750 // Earcons should play if the user slides off the screen or enters the screen |
| 1751 // from the edge. |
| 1752 TEST_F(TouchExplorationTest, EnterEarconPlays) { |
| 1753 SwitchTouchExplorationMode(true); |
| 1754 |
| 1755 gfx::Rect window = BoundsOfRootWindowInDIP(); |
| 1756 ui::TouchEvent upper_left_corner( |
| 1757 ui::ET_TOUCH_PRESSED, gfx::Point(0, 0), 1, Now()); |
| 1758 ui::TouchEvent upper_right_corner( |
| 1759 ui::ET_TOUCH_PRESSED, gfx::Point(window.right(), 0), 1, Now()); |
| 1760 ui::TouchEvent lower_left_corner( |
| 1761 ui::ET_TOUCH_PRESSED, gfx::Point(0, window.bottom()), 1, Now()); |
| 1762 ui::TouchEvent lower_right_corner(ui::ET_TOUCH_PRESSED, |
| 1763 gfx::Point(window.right(), window.bottom()), |
| 1764 1, |
| 1765 Now()); |
| 1766 |
| 1767 generator_->Dispatch(&upper_left_corner); |
| 1768 ASSERT_EQ(1U, delegate_.NumEnterScreenSounds()); |
| 1769 generator_->ReleaseTouchId(1); |
| 1770 delegate_.ResetCountersToZero(); |
| 1771 |
| 1772 generator_->Dispatch(&upper_right_corner); |
| 1773 ASSERT_EQ(1U, delegate_.NumEnterScreenSounds()); |
| 1774 generator_->ReleaseTouchId(1); |
| 1775 delegate_.ResetCountersToZero(); |
| 1776 |
| 1777 generator_->Dispatch(&lower_left_corner); |
| 1778 ASSERT_EQ(1U, delegate_.NumEnterScreenSounds()); |
| 1779 generator_->ReleaseTouchId(1); |
| 1780 delegate_.ResetCountersToZero(); |
| 1781 |
| 1782 generator_->Dispatch(&lower_right_corner); |
| 1783 ASSERT_EQ(1U, delegate_.NumEnterScreenSounds()); |
| 1784 generator_->ReleaseTouchId(1); |
| 1785 delegate_.ResetCountersToZero(); |
| 1786 } |
| 1787 |
| 1788 TEST_F(TouchExplorationTest, ExitEarconPlays) { |
| 1789 SwitchTouchExplorationMode(true); |
| 1790 |
| 1791 // On the device, it cannot actually tell if the finger has left the screen or |
| 1792 // not. If the finger has left the screen, it reads it as a release that |
| 1793 // occurred very close to the edge of the screen even if the finger is still |
| 1794 // technically touching the moniter. To simulate this, a release that occurs |
| 1795 // close to the edge is dispatched. |
| 1796 gfx::Point initial_press(100, 200); |
| 1797 gfx::Rect window = BoundsOfRootWindowInDIP(); |
| 1798 gfx::Point upper_left_corner(0, 0); |
| 1799 gfx::Point upper_right_corner(window.right(), 0); |
| 1800 gfx::Point lower_left_corner(0, window.bottom()); |
| 1801 gfx::Point lower_right_corner(window.right(), window.bottom()); |
| 1802 |
| 1803 generator_->PressTouch(); |
| 1804 generator_->MoveTouch(initial_press); |
| 1805 generator_->MoveTouch(upper_left_corner); |
| 1806 generator_->ReleaseTouch(); |
| 1807 ASSERT_EQ(1U, delegate_.NumExitScreenSounds()); |
| 1808 delegate_.ResetCountersToZero(); |
| 1809 |
| 1810 generator_->PressTouch(); |
| 1811 generator_->MoveTouch(initial_press); |
| 1812 generator_->MoveTouch(upper_left_corner); |
| 1813 generator_->ReleaseTouch(); |
| 1814 ASSERT_EQ(1U, delegate_.NumExitScreenSounds()); |
| 1815 delegate_.ResetCountersToZero(); |
| 1816 |
| 1817 generator_->PressTouch(); |
| 1818 generator_->MoveTouch(initial_press); |
| 1819 generator_->MoveTouch(upper_right_corner); |
| 1820 generator_->ReleaseTouch(); |
| 1821 ASSERT_EQ(1U, delegate_.NumExitScreenSounds()); |
| 1822 delegate_.ResetCountersToZero(); |
| 1823 |
| 1824 generator_->PressTouch(); |
| 1825 generator_->MoveTouch(initial_press); |
| 1826 generator_->MoveTouch(lower_left_corner); |
| 1827 generator_->ReleaseTouch(); |
| 1828 ASSERT_EQ(1U, delegate_.NumExitScreenSounds()); |
| 1829 delegate_.ResetCountersToZero(); |
| 1830 |
| 1831 generator_->PressTouch(); |
| 1832 generator_->MoveTouch(initial_press); |
| 1833 generator_->MoveTouch(lower_right_corner); |
| 1834 generator_->ReleaseTouch(); |
| 1835 ASSERT_EQ(1U, delegate_.NumExitScreenSounds()); |
| 1836 delegate_.ResetCountersToZero(); |
| 1837 } |
| 1838 |
1643 } // namespace ui | 1839 } // namespace ui |
OLD | NEW |