| 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 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 226 void ClearCapturedEvents() { | 261 void ClearCapturedEvents() { |
| 227 event_capturer_.Reset(); | 262 event_capturer_.Reset(); |
| 228 } | 263 } |
| 229 | 264 |
| 230 void AdvanceSimulatedTimePastTapDelay() { | 265 void AdvanceSimulatedTimePastTapDelay() { |
| 231 simulated_clock_->Advance(gesture_detector_config_.double_tap_timeout); | 266 simulated_clock_->Advance(gesture_detector_config_.double_tap_timeout); |
| 232 simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(1)); | 267 simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(1)); |
| 233 touch_exploration_controller_->CallTapTimerNowForTesting(); | 268 touch_exploration_controller_->CallTapTimerNowForTesting(); |
| 234 } | 269 } |
| 235 | 270 |
| 271 void AdvanceSimulatedTimePastLongPressDelay() { |
| 272 simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); |
| 273 touch_exploration_controller_->CallLongPressTimerNowForTesting(); |
| 274 } |
| 275 |
| 236 void AdvanceSimulatedTimePastPotentialTapDelay() { | 276 void AdvanceSimulatedTimePastPotentialTapDelay() { |
| 237 simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); | 277 simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); |
| 238 touch_exploration_controller_->CallTapTimerNowIfRunningForTesting(); | 278 touch_exploration_controller_->CallTapTimerNowIfRunningForTesting(); |
| 239 } | 279 } |
| 240 | 280 |
| 241 void SuppressVLOGs(bool suppress) { | 281 void SuppressVLOGs(bool suppress) { |
| 242 touch_exploration_controller_->SuppressVLOGsForTesting(suppress); | 282 touch_exploration_controller_->SuppressVLOGsForTesting(suppress); |
| 243 } | 283 } |
| 244 | 284 |
| 245 void SetTickClock() { | 285 void SetTickClock() { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 259 } | 299 } |
| 260 } | 300 } |
| 261 | 301 |
| 262 void EnterTouchExplorationModeAtLocation(gfx::Point tap_location) { | 302 void EnterTouchExplorationModeAtLocation(gfx::Point tap_location) { |
| 263 ui::TouchEvent touch_press(ui::ET_TOUCH_PRESSED, tap_location, 0, Now()); | 303 ui::TouchEvent touch_press(ui::ET_TOUCH_PRESSED, tap_location, 0, Now()); |
| 264 generator_->Dispatch(&touch_press); | 304 generator_->Dispatch(&touch_press); |
| 265 AdvanceSimulatedTimePastTapDelay(); | 305 AdvanceSimulatedTimePastTapDelay(); |
| 266 EXPECT_TRUE(IsInTouchToMouseMode()); | 306 EXPECT_TRUE(IsInTouchToMouseMode()); |
| 267 } | 307 } |
| 268 | 308 |
| 309 // Checks that Corner Passthrough is working. Assumes that corner is the |
| 310 // bottom left corner or the bottom right corner. |
| 311 void AssertCornerPassthroughWorking(gfx::Point corner) { |
| 312 ASSERT_EQ(0U, delegate_.NumPassthroughSounds()); |
| 313 |
| 314 ui::TouchEvent first_press(ui::ET_TOUCH_PRESSED, corner, 0, Now()); |
| 315 generator_->Dispatch(&first_press); |
| 316 |
| 317 AdvanceSimulatedTimePastLongPressDelay(); |
| 318 EXPECT_FALSE(IsInGestureInProgressState()); |
| 319 EXPECT_FALSE(IsInSlideGestureState()); |
| 320 EXPECT_FALSE(IsInTouchToMouseMode()); |
| 321 EXPECT_TRUE(IsInCornerPassthroughState()); |
| 322 |
| 323 gfx::Rect window = BoundsOfRootWindowInDIP(); |
| 324 // The following events should be passed through. |
| 325 gfx::Point passthrough(window.right() / 2, window.bottom() / 2); |
| 326 ui::TouchEvent passthrough_press( |
| 327 ui::ET_TOUCH_PRESSED, passthrough, 1, Now()); |
| 328 ASSERT_EQ(1U, delegate_.NumPassthroughSounds()); |
| 329 generator_->Dispatch(&passthrough_press); |
| 330 generator_->ReleaseTouchId(1); |
| 331 generator_->PressTouchId(1); |
| 332 EXPECT_FALSE(IsInGestureInProgressState()); |
| 333 EXPECT_FALSE(IsInSlideGestureState()); |
| 334 EXPECT_TRUE(IsInCornerPassthroughState()); |
| 335 |
| 336 std::vector<ui::LocatedEvent*> captured_events = GetCapturedLocatedEvents(); |
| 337 ASSERT_EQ(3U, captured_events.size()); |
| 338 EXPECT_EQ(ui::ET_TOUCH_PRESSED, captured_events[0]->type()); |
| 339 EXPECT_EQ(ui::ET_TOUCH_RELEASED, captured_events[1]->type()); |
| 340 EXPECT_EQ(ui::ET_TOUCH_PRESSED, captured_events[2]->type()); |
| 341 generator_->ReleaseTouchId(1); |
| 342 ClearCapturedEvents(); |
| 343 |
| 344 generator_->ReleaseTouchId(0); |
| 345 captured_events = GetCapturedLocatedEvents(); |
| 346 ASSERT_EQ(0U, captured_events.size()); |
| 347 EXPECT_FALSE(IsInTouchToMouseMode()); |
| 348 EXPECT_FALSE(IsInCornerPassthroughState()); |
| 349 ClearCapturedEvents(); |
| 350 } |
| 351 |
| 269 bool IsInTouchToMouseMode() { | 352 bool IsInTouchToMouseMode() { |
| 270 aura::client::CursorClient* cursor_client = | 353 aura::client::CursorClient* cursor_client = |
| 271 aura::client::GetCursorClient(root_window()); | 354 aura::client::GetCursorClient(root_window()); |
| 272 return cursor_client && | 355 return cursor_client && cursor_client->IsMouseEventsEnabled() && |
| 273 cursor_client->IsMouseEventsEnabled() && | |
| 274 !cursor_client->IsCursorVisible(); | 356 !cursor_client->IsCursorVisible(); |
| 275 } | 357 } |
| 276 | 358 |
| 277 bool IsInNoFingersDownState() { | 359 bool IsInNoFingersDownState() { |
| 278 return touch_exploration_controller_->IsInNoFingersDownStateForTesting(); | 360 return touch_exploration_controller_->IsInNoFingersDownStateForTesting(); |
| 279 } | 361 } |
| 280 | 362 |
| 281 bool IsInGestureInProgressState() { | 363 bool IsInGestureInProgressState() { |
| 282 return touch_exploration_controller_ | 364 return touch_exploration_controller_ |
| 283 ->IsInGestureInProgressStateForTesting(); | 365 ->IsInGestureInProgressStateForTesting(); |
| 284 } | 366 } |
| 285 | 367 |
| 286 bool IsInSlideGestureState() { | 368 bool IsInSlideGestureState() { |
| 287 return touch_exploration_controller_->IsInSlideGestureStateForTesting(); | 369 return touch_exploration_controller_->IsInSlideGestureStateForTesting(); |
| 288 } | 370 } |
| 289 | 371 |
| 372 bool IsInCornerPassthroughState() { |
| 373 return touch_exploration_controller_ |
| 374 ->IsInCornerPassthroughStateForTesting(); |
| 375 } |
| 376 |
| 290 gfx::Rect BoundsOfRootWindowInDIP() { | 377 gfx::Rect BoundsOfRootWindowInDIP() { |
| 291 return touch_exploration_controller_->BoundsOfRootWindowInDIPForTesting(); | 378 return touch_exploration_controller_->BoundsOfRootWindowInDIPForTesting(); |
| 292 } | 379 } |
| 293 | 380 |
| 294 float GetMaxDistanceFromEdge() const{ | 381 float GetMaxDistanceFromEdge() const { |
| 295 return touch_exploration_controller_->GetMaxDistanceFromEdge(); | 382 return touch_exploration_controller_->GetMaxDistanceFromEdge(); |
| 296 } | 383 } |
| 297 | 384 |
| 298 float GetSlopDistanceFromEdge() const{ | 385 float GetSlopDistanceFromEdge() const{ |
| 299 return touch_exploration_controller_->GetSlopDistanceFromEdge(); | 386 return touch_exploration_controller_->GetSlopDistanceFromEdge(); |
| 300 } | 387 } |
| 301 | 388 |
| 302 base::TimeDelta Now() { | 389 base::TimeDelta Now() { |
| 303 // This is the same as what EventTimeForNow() does, but here we do it | 390 // This is the same as what EventTimeForNow() does, but here we do it |
| 304 // with our simulated clock. | 391 // with our simulated clock. |
| (...skipping 1215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1520 EXPECT_FALSE(IsInGestureInProgressState()); | 1607 EXPECT_FALSE(IsInGestureInProgressState()); |
| 1521 EXPECT_FALSE(IsInSlideGestureState()); | 1608 EXPECT_FALSE(IsInSlideGestureState()); |
| 1522 EXPECT_FALSE(IsInTouchToMouseMode()); | 1609 EXPECT_FALSE(IsInTouchToMouseMode()); |
| 1523 | 1610 |
| 1524 AdvanceSimulatedTimePastTapDelay(); | 1611 AdvanceSimulatedTimePastTapDelay(); |
| 1525 EXPECT_FALSE(IsInGestureInProgressState()); | 1612 EXPECT_FALSE(IsInGestureInProgressState()); |
| 1526 EXPECT_FALSE(IsInSlideGestureState()); | 1613 EXPECT_FALSE(IsInSlideGestureState()); |
| 1527 EXPECT_TRUE(IsInTouchToMouseMode()); | 1614 EXPECT_TRUE(IsInTouchToMouseMode()); |
| 1528 } | 1615 } |
| 1529 | 1616 |
| 1617 // Corner passthrough should turn on if the user first holds down on either the |
| 1618 // right or left corner past a delay and then places a finger anywhere else on |
| 1619 // the screen. |
| 1620 TEST_F(TouchExplorationTest, ActivateLeftCornerPassthrough) { |
| 1621 SwitchTouchExplorationMode(true); |
| 1622 |
| 1623 gfx::Rect window = BoundsOfRootWindowInDIP(); |
| 1624 gfx::Point left_corner(10, window.bottom() - GetMaxDistanceFromEdge() / 2); |
| 1625 AssertCornerPassthroughWorking(left_corner); |
| 1626 } |
| 1627 |
| 1628 TEST_F(TouchExplorationTest, ActivateRightCornerPassthrough) { |
| 1629 SwitchTouchExplorationMode(true); |
| 1630 |
| 1631 gfx::Rect window = BoundsOfRootWindowInDIP(); |
| 1632 gfx::Point right_corner(window.right() - GetMaxDistanceFromEdge() / 2, |
| 1633 window.bottom() - GetMaxDistanceFromEdge() / 2); |
| 1634 AssertCornerPassthroughWorking(right_corner); |
| 1635 } |
| 1636 |
| 1637 // Earcons should play if the user slides off the screen or enters the screen |
| 1638 // from the edge. |
| 1639 TEST_F(TouchExplorationTest, EnterEarconPlays) { |
| 1640 SwitchTouchExplorationMode(true); |
| 1641 |
| 1642 gfx::Rect window = BoundsOfRootWindowInDIP(); |
| 1643 |
| 1644 gfx::Point upper_left_corner(0, 0); |
| 1645 gfx::Point upper_right_corner(window.right(), 0); |
| 1646 gfx::Point lower_left_corner(0, window.bottom()); |
| 1647 gfx::Point lower_right_corner(window.right(), window.bottom()); |
| 1648 gfx::Point left_edge(0, 30); |
| 1649 gfx::Point right_edge(window.right(), 30); |
| 1650 gfx::Point top_edge(30, 0); |
| 1651 gfx::Point bottom_edge(30, window.bottom()); |
| 1652 |
| 1653 std::vector<gfx::Point> locations; |
| 1654 locations.push_back(upper_left_corner); |
| 1655 locations.push_back(upper_right_corner); |
| 1656 locations.push_back(lower_left_corner); |
| 1657 locations.push_back(lower_right_corner); |
| 1658 locations.push_back(left_edge); |
| 1659 locations.push_back(right_edge); |
| 1660 locations.push_back(top_edge); |
| 1661 locations.push_back(bottom_edge); |
| 1662 |
| 1663 for (std::vector<gfx::Point>::const_iterator point = locations.begin(); |
| 1664 point != locations.end(); |
| 1665 ++point) { |
| 1666 ui::TouchEvent touch_event(ui::ET_TOUCH_PRESSED, *point, 1, Now()); |
| 1667 |
| 1668 generator_->Dispatch(&touch_event); |
| 1669 ASSERT_EQ(1U, delegate_.NumEnterScreenSounds()); |
| 1670 generator_->ReleaseTouchId(1); |
| 1671 delegate_.ResetCountersToZero(); |
| 1672 } |
| 1673 } |
| 1674 |
| 1675 TEST_F(TouchExplorationTest, ExitEarconPlays) { |
| 1676 SwitchTouchExplorationMode(true); |
| 1677 |
| 1678 // On the device, it cannot actually tell if the finger has left the screen or |
| 1679 // not. If the finger has left the screen, it reads it as a release that |
| 1680 // occurred very close to the edge of the screen even if the finger is still |
| 1681 // technically touching the moniter. To simulate this, a release that occurs |
| 1682 // close to the edge is dispatched. |
| 1683 gfx::Point initial_press(100, 200); |
| 1684 gfx::Rect window = BoundsOfRootWindowInDIP(); |
| 1685 |
| 1686 gfx::Point upper_left_corner(0, 0); |
| 1687 gfx::Point upper_right_corner(window.right(), 0); |
| 1688 gfx::Point lower_left_corner(0, window.bottom()); |
| 1689 gfx::Point lower_right_corner(window.right(), window.bottom()); |
| 1690 gfx::Point left_edge(0, 30); |
| 1691 gfx::Point right_edge(window.right(), 30); |
| 1692 gfx::Point top_edge(30, 0); |
| 1693 gfx::Point bottom_edge(30, window.bottom()); |
| 1694 |
| 1695 std::vector<gfx::Point> locations; |
| 1696 locations.push_back(upper_left_corner); |
| 1697 locations.push_back(upper_right_corner); |
| 1698 locations.push_back(lower_left_corner); |
| 1699 locations.push_back(lower_right_corner); |
| 1700 locations.push_back(left_edge); |
| 1701 locations.push_back(right_edge); |
| 1702 locations.push_back(top_edge); |
| 1703 locations.push_back(bottom_edge); |
| 1704 |
| 1705 for (std::vector<gfx::Point>::const_iterator point = locations.begin(); |
| 1706 point != locations.end(); |
| 1707 ++point) { |
| 1708 generator_->PressTouch(); |
| 1709 generator_->MoveTouch(initial_press); |
| 1710 generator_->MoveTouch(*point); |
| 1711 generator_->ReleaseTouch(); |
| 1712 ASSERT_EQ(1U, delegate_.NumExitScreenSounds()); |
| 1713 delegate_.ResetCountersToZero(); |
| 1714 } |
| 1715 } |
| 1716 |
| 1530 } // namespace ui | 1717 } // namespace ui |
| OLD | NEW |