| Index: ui/chromeos/touch_exploration_controller_unittest.cc | 
| diff --git a/ui/chromeos/touch_exploration_controller_unittest.cc b/ui/chromeos/touch_exploration_controller_unittest.cc | 
| index 6b1f3dea84621539f4b272c9c94ed4bd714e37d3..11e9b443b6b91078b7237c15c8865edbcfdb6df1 100644 | 
| --- a/ui/chromeos/touch_exploration_controller_unittest.cc | 
| +++ b/ui/chromeos/touch_exploration_controller_unittest.cc | 
| @@ -71,6 +71,24 @@ int Factorial(int n) { | 
| return n * Factorial(n - 1); | 
| } | 
|  | 
| +class MockTouchExplorationControllerDelegate | 
| +    : public ui::TouchExplorationControllerDelegate { | 
| + public: | 
| +  virtual void const PlayVolumeAdjustSound() OVERRIDE { | 
| +    ++num_times_adjust_sound_played_; | 
| +  } | 
| +  virtual void AdjustSound(float volume) OVERRIDE { | 
| +    volume_changes_.push_back(volume); | 
| +  } | 
| + | 
| +  const std::vector<float> VolumeChanges() { return volume_changes_; } | 
| +  const int NumAdjustSounds() { return num_times_adjust_sound_played_; } | 
| + | 
| + private: | 
| +  std::vector<float> volume_changes_; | 
| +  int num_times_adjust_sound_played_ = 0; | 
| +}; | 
| + | 
| }  // namespace | 
|  | 
| class TouchExplorationTest : public aura::test::AuraTestBase { | 
| @@ -85,6 +103,7 @@ class TouchExplorationTest : public aura::test::AuraTestBase { | 
| if (gfx::GetGLImplementation() == gfx::kGLImplementationNone) | 
| gfx::GLSurface::InitializeOneOffForTests(); | 
| aura::test::AuraTestBase::SetUp(); | 
| +    delegate_ = new MockTouchExplorationControllerDelegate(); | 
| cursor_client_.reset(new aura::test::TestCursorClient(root_window())); | 
| root_window()->AddPreTargetHandler(&event_capturer_); | 
| generator_.reset(new aura::test::EventGenerator(root_window())); | 
| @@ -164,7 +183,7 @@ class TouchExplorationTest : public aura::test::AuraTestBase { | 
| touch_exploration_controller_.reset(); | 
| } else if (on && !touch_exploration_controller_.get()) { | 
| touch_exploration_controller_.reset( | 
| -          new ui::TouchExplorationController(root_window())); | 
| +          new ui::TouchExplorationController(root_window(), delegate_)); | 
| touch_exploration_controller_->SetEventHandlerForTesting( | 
| &event_capturer_); | 
| cursor_client()->ShowCursor(); | 
| @@ -207,6 +226,14 @@ class TouchExplorationTest : public aura::test::AuraTestBase { | 
| ->IsInGestureInProgressStateForTesting(); | 
| } | 
|  | 
| +  bool IsInSlideGestureState() { | 
| +    return touch_exploration_controller_->IsInSlideGestureStateForTesting(); | 
| +  } | 
| + | 
| +  gfx::Rect BoundsOfRootWindowInDIP() { | 
| +    return touch_exploration_controller_->BoundsOfRootWindowInDIPForTesting(); | 
| +  } | 
| + | 
| base::TimeDelta Now() { | 
| // This is the same as what EventTimeForNow() does, but here we do it | 
| // with our simulated clock. | 
| @@ -218,6 +245,7 @@ class TouchExplorationTest : public aura::test::AuraTestBase { | 
| ui::GestureDetector::Config gesture_detector_config_; | 
| // Owned by |generator_|. | 
| base::SimpleTestTickClock* simulated_clock_; | 
| +  MockTouchExplorationControllerDelegate* delegate_; | 
|  | 
| private: | 
| EventCapturer event_capturer_; | 
| @@ -460,6 +488,7 @@ TEST_F(TouchExplorationTest, TimerFiresLateDuringTouchExploration) { | 
| SwitchTouchExplorationMode(true); | 
|  | 
| // Send a press, then add another finger after the double-tap timeout. | 
| +  generator_->MoveTouch(gfx::Point(100, 200)); | 
| generator_->PressTouchId(1); | 
| simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); | 
| generator_->PressTouchId(2); | 
| @@ -1307,10 +1336,11 @@ TEST_F(TouchExplorationTest, FromGestureToPassthrough) { | 
| EXPECT_FALSE(IsInGestureInProgressState()); | 
|  | 
| float distance = gesture_detector_config_.touch_slop + 1; | 
| -  ui::TouchEvent first_press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 1), 0, Now()); | 
| +  ui::TouchEvent first_press( | 
| +      ui::ET_TOUCH_PRESSED, gfx::Point(100, 200), 0, Now()); | 
| generator_->Dispatch(&first_press); | 
| simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(10)); | 
| -  gfx::Point second_location(distance, 1); | 
| +  gfx::Point second_location(100 + distance, 200); | 
| generator_->MoveTouch(second_location); | 
| EXPECT_TRUE(IsInGestureInProgressState()); | 
| EXPECT_FALSE(IsInTouchToMouseMode()); | 
| @@ -1338,4 +1368,207 @@ TEST_F(TouchExplorationTest, FromGestureToPassthrough) { | 
| ASSERT_EQ(0U, captured_events.size()); | 
| } | 
|  | 
| +TEST_F(TouchExplorationTest, EnterSlideGestureState) { | 
| +  SwitchTouchExplorationMode(true); | 
| +  EXPECT_FALSE(IsInTouchToMouseMode()); | 
| +  EXPECT_FALSE(IsInGestureInProgressState()); | 
| + | 
| +  gfx::Rect window = BoundsOfRootWindowInDIP(); | 
| +  float distance = gesture_detector_config_.touch_slop + 1; | 
| +  ui::TouchEvent first_press( | 
| +      ui::ET_TOUCH_PRESSED, gfx::Point(window.right(), 1), 0, Now()); | 
| +  gfx::Point second_location(window.right(), 1 + distance / 2); | 
| +  gfx::Point third_location(window.right(), 1 + distance); | 
| + | 
| +  generator_->Dispatch(&first_press); | 
| +  simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(10)); | 
| + | 
| +  // Since we haven't moved past slop yet, we should not be in slide gesture. | 
| +  generator_->MoveTouch(second_location); | 
| +  EXPECT_FALSE(IsInTouchToMouseMode()); | 
| +  EXPECT_FALSE(IsInGestureInProgressState()); | 
| +  EXPECT_FALSE(IsInSlideGestureState()); | 
| +  simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(10)); | 
| + | 
| +  // Once we are out of slop, we should be in slide gesture since we are along | 
| +  // the edge of the screen. | 
| +  generator_->MoveTouch(third_location); | 
| +  EXPECT_FALSE(IsInGestureInProgressState()); | 
| +  EXPECT_TRUE(IsInSlideGestureState()); | 
| +  EXPECT_FALSE(IsInTouchToMouseMode()); | 
| +  const ScopedVector<ui::Event>& captured_events = GetCapturedEvents(); | 
| +  ASSERT_EQ(0U, captured_events.size()); | 
| + | 
| +  // Since we are at the right edge of the screen, but the sound timer has not | 
| +  // elapsed, there should have two sounds that fired and two volume | 
| +  // changes (one for each movement). | 
| +  int num_adjust_sounds = delegate_->NumAdjustSounds(); | 
| +  EXPECT_EQ(num_adjust_sounds, 2U); | 
| +  EXPECT_EQ(delegate_->VolumeChanges().size(), 2U); | 
| + | 
| +  // Exit out of slide gesture once touch is lifted, but not before even if the | 
| +  // grace period is over. | 
| + | 
| +  AdvanceSimulatedTimePastPotentialTapDelay(); | 
| +  ASSERT_EQ(0U, captured_events.size()); | 
| +  EXPECT_FALSE(IsInTouchToMouseMode()); | 
| +  EXPECT_FALSE(IsInGestureInProgressState()); | 
| +  EXPECT_TRUE(IsInSlideGestureState()); | 
| + | 
| +  generator_->ReleaseTouch(); | 
| +  ASSERT_EQ(0U, captured_events.size()); | 
| +  EXPECT_FALSE(IsInTouchToMouseMode()); | 
| +  EXPECT_FALSE(IsInGestureInProgressState()); | 
| +  EXPECT_FALSE(IsInSlideGestureState()); | 
| +} | 
| + | 
| +// If a press + move occurred outside the boundaries, but within the slop | 
| +// boundaries and then moved into the boundaries of an edge, there still should | 
| +// not be a slide gesture. | 
| +TEST_F(TouchExplorationTest, AvoidEnteringSlideGesture) { | 
| +  SwitchTouchExplorationMode(true); | 
| + | 
| +  // DO SOMETHING TO MAKE THESE CONSTANTS ACCESSIBLE FROM ORIGINAL FILE | 
| +  const float kMaxDistanceFromEdge = 75; | 
| +  const float kSlopDistanceFromEdge = kMaxDistanceFromEdge + 40; | 
| + | 
| +  gfx::Rect window = BoundsOfRootWindowInDIP(); | 
| +  float distance = gesture_detector_config_.touch_slop + 1; | 
| +  ui::TouchEvent first_press( | 
| +      ui::ET_TOUCH_PRESSED, | 
| +      gfx::Point(window.right() - kSlopDistanceFromEdge, 1), | 
| +      0, | 
| +      Now()); | 
| +  gfx::Point out_of_slop(window.right() - kSlopDistanceFromEdge + distance, 1); | 
| +  gfx::Point into_boundaries(window.right() - kMaxDistanceFromEdge / 2, 1); | 
| + | 
| +  generator_->Dispatch(&first_press); | 
| +  simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(10)); | 
| + | 
| +  generator_->MoveTouch(out_of_slop); | 
| +  EXPECT_FALSE(IsInTouchToMouseMode()); | 
| +  EXPECT_TRUE(IsInGestureInProgressState()); | 
| +  EXPECT_FALSE(IsInSlideGestureState()); | 
| +  simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(10)); | 
| + | 
| +  // Since we did not start moving while in the boundaries, we should not be in | 
| +  // slide gestures. | 
| +  generator_->MoveTouch(into_boundaries); | 
| +  EXPECT_TRUE(IsInGestureInProgressState()); | 
| +  EXPECT_FALSE(IsInSlideGestureState()); | 
| +  EXPECT_FALSE(IsInTouchToMouseMode()); | 
| +  const ScopedVector<ui::Event>& captured_events = GetCapturedEvents(); | 
| +  ASSERT_EQ(0U, captured_events.size()); | 
| + | 
| +  generator_->ReleaseTouch(); | 
| +} | 
| + | 
| +// If the slide gesture begins within the boundaries and then moves | 
| +// SlopDistanceFromEdge there should still be a sound change. If the finger | 
| +// moves into the center screen, there should no longer be a sound change but it | 
| +// should still be in slide gesture. If the finger moves back into the edges | 
| +// without lifting, it should start changing sound again. | 
| +TEST_F(TouchExplorationTest, TestingBoundaries) { | 
| +  SwitchTouchExplorationMode(true); | 
| + | 
| +  // DO SOMETHING TO MAKE THESE CONSTANTS ACCESSIBLE FROM ORIGINAL FILE | 
| +  const float kMaxDistanceFromEdge = 75; | 
| +  const float kSlopDistanceFromEdge = kMaxDistanceFromEdge + 40; | 
| + | 
| +  gfx::Rect window = BoundsOfRootWindowInDIP(); | 
| +  gfx::Point initial_press(window.right() - kMaxDistanceFromEdge / 2, 1); | 
| +  ui::TouchEvent first_press( | 
| +      ui::ET_TOUCH_PRESSED, | 
| +      initial_press, | 
| +      0, | 
| +      Now()); | 
| +  gfx::Point touch_move(initial_press.x() + gesture_detector_config_.touch_slop, | 
| +                        1); | 
| +  gfx::Point into_slop_boundaries(window.right() - kSlopDistanceFromEdge / 2, | 
| +                                  1); | 
| +  gfx::Point center_screen(window.right() / 2, window.bottom() / 2); | 
| + | 
| +  generator_->Dispatch(&first_press); | 
| +  simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(10)); | 
| + | 
| +  generator_->MoveTouch(touch_move); | 
| +  EXPECT_FALSE(IsInTouchToMouseMode()); | 
| +  EXPECT_FALSE(IsInGestureInProgressState()); | 
| +  EXPECT_FALSE(IsInSlideGestureState()); | 
| +  simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(10)); | 
| + | 
| +  // Move the touch into slop boundaries. It should stil be in slide gestures | 
| +  // and adjust the volume. | 
| +  generator_->MoveTouch(into_slop_boundaries); | 
| +  EXPECT_FALSE(IsInGestureInProgressState()); | 
| +  EXPECT_TRUE(IsInSlideGestureState()); | 
| +  EXPECT_FALSE(IsInTouchToMouseMode()); | 
| + | 
| +  // The sound is rate limiting so it only activates every 150ms. | 
| +  simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(200)); | 
| + | 
| +  int num_adjust_sounds = delegate_->NumAdjustSounds(); | 
| +  EXPECT_EQ(num_adjust_sounds, 2U); | 
| +  EXPECT_EQ(delegate_->VolumeChanges().size(), 2U); | 
| + | 
| +  // Move the touch into the center of the window. It should still be in slide | 
| +  // gestures, but there should not be anymore volume adjustments. | 
| +  generator_->MoveTouch(center_screen); | 
| +  EXPECT_FALSE(IsInGestureInProgressState()); | 
| +  EXPECT_TRUE(IsInSlideGestureState()); | 
| +  EXPECT_FALSE(IsInTouchToMouseMode()); | 
| + | 
| +  simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(200)); | 
| +  num_adjust_sounds = delegate_->NumAdjustSounds(); | 
| +  EXPECT_EQ(num_adjust_sounds, 2U); | 
| +  EXPECT_EQ(delegate_->VolumeChanges().size(), 2U); | 
| + | 
| +  // Move the touch back into slop edge distance and volume should be changing | 
| +  // again. | 
| +  generator_->MoveTouch(into_slop_boundaries); | 
| +  EXPECT_FALSE(IsInGestureInProgressState()); | 
| +  EXPECT_TRUE(IsInSlideGestureState()); | 
| +  EXPECT_FALSE(IsInTouchToMouseMode()); | 
| + | 
| +  generator_->MoveTouch( | 
| +      gfx::Point(into_slop_boundaries.x() + gesture_detector_config_.touch_slop, | 
| +                 into_slop_boundaries.y())); | 
| +  simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(200)); | 
| + | 
| +  num_adjust_sounds = delegate_->NumAdjustSounds(); | 
| +  EXPECT_EQ(num_adjust_sounds, 3U); | 
| +  EXPECT_EQ(delegate_->VolumeChanges().size(), 3U); | 
| + | 
| +  const ScopedVector<ui::Event>& captured_events = GetCapturedEvents(); | 
| +  ASSERT_EQ(0U, captured_events.size()); | 
| + | 
| +  generator_->ReleaseTouch(); | 
| +} | 
| + | 
| +// Even if the gesture starts within bounds, if it has not moved past slop | 
| +// within the grace period, it should go to touch exploration. | 
| +TEST_F(TouchExplorationTest, InBoundariesTouchExploration) { | 
| +  SwitchTouchExplorationMode(true); | 
| + | 
| +  // DO SOMETHING TO MAKE THESE CONSTANTS ACCESSIBLE FROM ORIGINAL FILE | 
| +  const float kMaxDistanceFromEdge = 75; | 
| + | 
| +  gfx::Rect window = BoundsOfRootWindowInDIP(); | 
| +  gfx::Point initial_press(window.right() - kMaxDistanceFromEdge / 2, 1); | 
| +  ui::TouchEvent first_press( | 
| +      ui::ET_TOUCH_PRESSED, | 
| +      initial_press, | 
| +      0, | 
| +      Now()); | 
| +  generator_->Dispatch(&first_press); | 
| +  EXPECT_FALSE(IsInGestureInProgressState()); | 
| +  EXPECT_FALSE(IsInSlideGestureState()); | 
| +  EXPECT_FALSE(IsInTouchToMouseMode()); | 
| + | 
| +  AdvanceSimulatedTimePastTapDelay(); | 
| +  EXPECT_FALSE(IsInGestureInProgressState()); | 
| +  EXPECT_FALSE(IsInSlideGestureState()); | 
| +  EXPECT_TRUE(IsInTouchToMouseMode()); | 
| +} | 
| + | 
| }  // namespace ui | 
|  |