blob: a406bfac0cbc791d208b7d8c10c3de17594ef5e7 [file] [log] [blame]
// Copyright (c) 2013 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 "content/browser/web_contents/aura/window_slider.h"
#include "base/bind.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/window.h"
#include "ui/base/hit_test.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/compositor/test/layer_animator_test_controller.h"
#include "ui/events/event_processor.h"
#include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h"
#include "ui/gfx/frame_time.h"
namespace content {
void DispatchEventDuringScrollCallback(ui::EventProcessor* dispatcher,
ui::Event* event,
ui::EventType type,
const gfx::Vector2dF& delta) {
if (type != ui::ET_GESTURE_SCROLL_UPDATE)
return;
ui::EventDispatchDetails details = dispatcher->OnEventFromSource(event);
CHECK(!details.dispatcher_destroyed);
}
void ChangeSliderOwnerDuringScrollCallback(scoped_ptr<aura::Window>* window,
WindowSlider* slider,
ui::EventType type,
const gfx::Vector2dF& delta) {
if (type != ui::ET_GESTURE_SCROLL_UPDATE)
return;
aura::Window* new_window = new aura::Window(NULL);
new_window->Init(aura::WINDOW_LAYER_TEXTURED);
new_window->Show();
slider->ChangeOwner(new_window);
(*window)->parent()->AddChild(new_window);
window->reset(new_window);
}
void ConfirmSlideDuringScrollCallback(WindowSlider* slider,
ui::EventType type,
const gfx::Vector2dF& delta) {
static float total_delta_x = 0;
if (type == ui::ET_GESTURE_SCROLL_BEGIN)
total_delta_x = 0;
if (type == ui::ET_GESTURE_SCROLL_UPDATE) {
total_delta_x += delta.x();
if (total_delta_x >= 70)
EXPECT_TRUE(slider->IsSlideInProgress());
} else {
EXPECT_FALSE(slider->IsSlideInProgress());
}
}
void ConfirmNoSlideDuringScrollCallback(WindowSlider* slider,
ui::EventType type,
const gfx::Vector2dF& delta) {
EXPECT_FALSE(slider->IsSlideInProgress());
}
// The window delegate does not receive any events.
class NoEventWindowDelegate : public aura::test::TestWindowDelegate {
public:
NoEventWindowDelegate() {
}
virtual ~NoEventWindowDelegate() {}
private:
// Overridden from aura::WindowDelegate:
virtual bool HasHitTestMask() const override { return true; }
DISALLOW_COPY_AND_ASSIGN(NoEventWindowDelegate);
};
class WindowSliderDelegateTest : public WindowSlider::Delegate {
public:
WindowSliderDelegateTest()
: can_create_layer_(true),
created_back_layer_(false),
created_front_layer_(false),
slide_completing_(false),
slide_completed_(false),
slide_aborted_(false),
slider_destroyed_(false) {
}
virtual ~WindowSliderDelegateTest() {
// Make sure slide_completed() gets called if slide_completing() was called.
CHECK(!slide_completing_ || slide_completed_);
}
void Reset() {
can_create_layer_ = true;
created_back_layer_ = false;
created_front_layer_ = false;
slide_completing_ = false;
slide_completed_ = false;
slide_aborted_ = false;
slider_destroyed_ = false;
}
void SetCanCreateLayer(bool can_create_layer) {
can_create_layer_ = can_create_layer;
}
bool created_back_layer() const { return created_back_layer_; }
bool created_front_layer() const { return created_front_layer_; }
bool slide_completing() const { return slide_completing_; }
bool slide_completed() const { return slide_completed_; }
bool slide_aborted() const { return slide_aborted_; }
bool slider_destroyed() const { return slider_destroyed_; }
protected:
ui::Layer* CreateLayerForTest() {
CHECK(can_create_layer_);
ui::Layer* layer = new ui::Layer(ui::LAYER_SOLID_COLOR);
layer->SetColor(SK_ColorRED);
return layer;
}
// Overridden from WindowSlider::Delegate:
virtual ui::Layer* CreateBackLayer() override {
if (!can_create_layer_)
return NULL;
created_back_layer_ = true;
return CreateLayerForTest();
}
virtual ui::Layer* CreateFrontLayer() override {
if (!can_create_layer_)
return NULL;
created_front_layer_ = true;
return CreateLayerForTest();
}
virtual void OnWindowSlideCompleted(scoped_ptr<ui::Layer> layer) override {
slide_completed_ = true;
}
virtual void OnWindowSlideCompleting() override {
slide_completing_ = true;
}
virtual void OnWindowSlideAborted() override {
slide_aborted_ = true;
}
virtual void OnWindowSliderDestroyed() override {
slider_destroyed_ = true;
}
private:
bool can_create_layer_;
bool created_back_layer_;
bool created_front_layer_;
bool slide_completing_;
bool slide_completed_;
bool slide_aborted_;
bool slider_destroyed_;
DISALLOW_COPY_AND_ASSIGN(WindowSliderDelegateTest);
};
// This delegate destroys the owner window when the slider is destroyed.
class WindowSliderDeleteOwnerOnDestroy : public WindowSliderDelegateTest {
public:
explicit WindowSliderDeleteOwnerOnDestroy(aura::Window* owner)
: owner_(owner) {
}
virtual ~WindowSliderDeleteOwnerOnDestroy() {}
private:
// Overridden from WindowSlider::Delegate:
virtual void OnWindowSliderDestroyed() override {
WindowSliderDelegateTest::OnWindowSliderDestroyed();
delete owner_;
}
aura::Window* owner_;
DISALLOW_COPY_AND_ASSIGN(WindowSliderDeleteOwnerOnDestroy);
};
// This delegate destroyes the owner window when a slide is completed.
class WindowSliderDeleteOwnerOnComplete : public WindowSliderDelegateTest {
public:
explicit WindowSliderDeleteOwnerOnComplete(aura::Window* owner)
: owner_(owner) {
}
virtual ~WindowSliderDeleteOwnerOnComplete() {}
private:
// Overridden from WindowSlider::Delegate:
virtual void OnWindowSlideCompleted(scoped_ptr<ui::Layer> layer) override {
WindowSliderDelegateTest::OnWindowSlideCompleted(layer.Pass());
delete owner_;
}
aura::Window* owner_;
DISALLOW_COPY_AND_ASSIGN(WindowSliderDeleteOwnerOnComplete);
};
typedef aura::test::AuraTestBase WindowSliderTest;
TEST_F(WindowSliderTest, WindowSlideUsingGesture) {
scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
window->SetBounds(gfx::Rect(0, 0, 400, 400));
WindowSliderDelegateTest slider_delegate;
ui::test::EventGenerator generator(root_window());
// Generate a horizontal overscroll.
WindowSlider* slider =
new WindowSlider(&slider_delegate, root_window(), window.get());
generator.GestureScrollSequenceWithCallback(
gfx::Point(10, 10),
gfx::Point(180, 10),
base::TimeDelta::FromMilliseconds(10),
10,
base::Bind(&ConfirmSlideDuringScrollCallback, slider));
EXPECT_TRUE(slider_delegate.created_back_layer());
EXPECT_TRUE(slider_delegate.slide_completing());
EXPECT_TRUE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.created_front_layer());
EXPECT_FALSE(slider_delegate.slide_aborted());
EXPECT_FALSE(slider_delegate.slider_destroyed());
EXPECT_FALSE(slider->IsSlideInProgress());
slider_delegate.Reset();
window->SetTransform(gfx::Transform());
// Generate a horizontal overscroll in the reverse direction.
generator.GestureScrollSequenceWithCallback(
gfx::Point(180, 10),
gfx::Point(10, 10),
base::TimeDelta::FromMilliseconds(10),
10,
base::Bind(&ConfirmSlideDuringScrollCallback, slider));
EXPECT_TRUE(slider_delegate.created_front_layer());
EXPECT_TRUE(slider_delegate.slide_completing());
EXPECT_TRUE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.created_back_layer());
EXPECT_FALSE(slider_delegate.slide_aborted());
EXPECT_FALSE(slider_delegate.slider_destroyed());
EXPECT_FALSE(slider->IsSlideInProgress());
slider_delegate.Reset();
// Generate a vertical overscroll.
generator.GestureScrollSequenceWithCallback(
gfx::Point(10, 10),
gfx::Point(10, 80),
base::TimeDelta::FromMilliseconds(10),
10,
base::Bind(&ConfirmNoSlideDuringScrollCallback, slider));
EXPECT_FALSE(slider_delegate.created_back_layer());
EXPECT_FALSE(slider_delegate.slide_completing());
EXPECT_FALSE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.created_front_layer());
EXPECT_FALSE(slider_delegate.slide_aborted());
EXPECT_FALSE(slider->IsSlideInProgress());
slider_delegate.Reset();
// Generate a horizontal scroll that starts overscroll, but doesn't scroll
// enough to complete it.
generator.GestureScrollSequenceWithCallback(
gfx::Point(10, 10),
gfx::Point(80, 10),
base::TimeDelta::FromMilliseconds(10),
10,
base::Bind(&ConfirmSlideDuringScrollCallback, slider));
EXPECT_TRUE(slider_delegate.created_back_layer());
EXPECT_TRUE(slider_delegate.slide_aborted());
EXPECT_FALSE(slider_delegate.created_front_layer());
EXPECT_FALSE(slider_delegate.slide_completing());
EXPECT_FALSE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.slider_destroyed());
EXPECT_FALSE(slider->IsSlideInProgress());
slider_delegate.Reset();
// Destroy the window. This should destroy the slider.
window.reset();
EXPECT_TRUE(slider_delegate.slider_destroyed());
}
// Tests that the window slide is interrupted when a different type of event
// happens.
TEST_F(WindowSliderTest, WindowSlideIsCancelledOnEvent) {
scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
window->SetBounds(gfx::Rect(0, 0, 400, 400));
WindowSliderDelegateTest slider_delegate;
ui::Event* events[] = {
new ui::MouseEvent(ui::ET_MOUSE_MOVED,
gfx::Point(55, 10),
gfx::Point(55, 10),
0, 0),
new ui::KeyEvent('a', ui::VKEY_A, ui::EF_NONE),
NULL
};
new WindowSlider(&slider_delegate, root_window(), window.get());
for (int i = 0; events[i]; ++i) {
// Generate a horizontal overscroll.
ui::test::EventGenerator generator(root_window());
generator.GestureScrollSequenceWithCallback(
gfx::Point(10, 10),
gfx::Point(80, 10),
base::TimeDelta::FromMilliseconds(10),
1,
base::Bind(&DispatchEventDuringScrollCallback,
root_window()->GetHost()->event_processor(),
base::Owned(events[i])));
EXPECT_TRUE(slider_delegate.created_back_layer());
EXPECT_TRUE(slider_delegate.slide_aborted());
EXPECT_FALSE(slider_delegate.created_front_layer());
EXPECT_FALSE(slider_delegate.slide_completing());
EXPECT_FALSE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.slider_destroyed());
slider_delegate.Reset();
}
window.reset();
EXPECT_TRUE(slider_delegate.slider_destroyed());
}
// Tests that the window slide can continue after it is interrupted by another
// event if the user continues scrolling.
TEST_F(WindowSliderTest, WindowSlideInterruptedThenContinues) {
scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
window->SetBounds(gfx::Rect(0, 0, 400, 400));
WindowSliderDelegateTest slider_delegate;
ui::ScopedAnimationDurationScaleMode normal_duration_(
ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
ui::LayerAnimator* animator = window->layer()->GetAnimator();
animator->set_disable_timer_for_test(true);
ui::LayerAnimatorTestController test_controller(animator);
WindowSlider* slider =
new WindowSlider(&slider_delegate, root_window(), window.get());
ui::MouseEvent interrupt_event(ui::ET_MOUSE_MOVED,
gfx::Point(55, 10),
gfx::Point(55, 10),
0, 0);
ui::test::EventGenerator generator(root_window());
// Start the scroll sequence. Scroll forward so that |window|'s layer is the
// one animating.
const int kTouchId = 5;
ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
gfx::Point(10, 10),
kTouchId,
ui::EventTimeForNow());
generator.Dispatch(&press);
// First scroll event of the sequence.
ui::TouchEvent move1(ui::ET_TOUCH_MOVED,
gfx::Point(100, 10),
kTouchId,
ui::EventTimeForNow());
generator.Dispatch(&move1);
EXPECT_TRUE(slider->IsSlideInProgress());
EXPECT_FALSE(animator->is_animating());
// Dispatch the event after the first scroll and confirm it interrupts the
// scroll and starts the "reset slide" animation.
generator.Dispatch(&interrupt_event);
EXPECT_TRUE(slider->IsSlideInProgress());
EXPECT_TRUE(animator->is_animating());
EXPECT_TRUE(slider_delegate.created_back_layer());
// slide_aborted() should be false because the 'reset slide' animation
// hasn't completed yet.
EXPECT_FALSE(slider_delegate.slide_aborted());
EXPECT_FALSE(slider_delegate.created_front_layer());
EXPECT_FALSE(slider_delegate.slide_completing());
EXPECT_FALSE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.slider_destroyed());
slider_delegate.Reset();
// Second scroll event of the sequence.
ui::TouchEvent move2(ui::ET_TOUCH_MOVED,
gfx::Point(200, 10),
kTouchId,
ui::EventTimeForNow());
generator.Dispatch(&move2);
// The second scroll should instantly cause the animation to complete.
EXPECT_FALSE(animator->is_animating());
EXPECT_FALSE(slider_delegate.created_back_layer());
// The ResetScroll() animation was completed, so now slide_aborted()
// should be true.
EXPECT_TRUE(slider_delegate.slide_aborted());
// Third scroll event of the sequence.
ui::TouchEvent move3(ui::ET_TOUCH_MOVED,
gfx::Point(300, 10),
kTouchId,
ui::EventTimeForNow());
generator.Dispatch(&move3);
// The third scroll should re-start the sliding.
EXPECT_TRUE(slider->IsSlideInProgress());
EXPECT_TRUE(slider_delegate.created_back_layer());
// Generate the release event, finishing the scroll sequence.
ui::TouchEvent release(ui::ET_TOUCH_RELEASED,
gfx::Point(300, 10),
kTouchId,
ui::EventTimeForNow());
generator.Dispatch(&release);
// When the scroll gesture ends, the slide animation should start.
EXPECT_TRUE(slider->IsSlideInProgress());
EXPECT_TRUE(animator->is_animating());
EXPECT_TRUE(slider_delegate.slide_completing());
EXPECT_FALSE(slider_delegate.created_front_layer());
EXPECT_FALSE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.slider_destroyed());
// Progress the animator to complete the slide animation.
ui::ScopedLayerAnimationSettings settings(animator);
base::TimeDelta duration = settings.GetTransitionDuration();
test_controller.StartThreadedAnimationsIfNeeded();
animator->Step(gfx::FrameTime::Now() + duration);
EXPECT_TRUE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.slider_destroyed());
window.reset();
EXPECT_TRUE(slider_delegate.slider_destroyed());
}
// Tests that the slide works correctly when the owner of the window changes
// during the duration of the slide.
TEST_F(WindowSliderTest, OwnerWindowChangesDuringWindowSlide) {
scoped_ptr<aura::Window> parent(CreateNormalWindow(0, root_window(), NULL));
NoEventWindowDelegate window_delegate;
window_delegate.set_window_component(HTNOWHERE);
scoped_ptr<aura::Window> window(CreateNormalWindow(1, parent.get(),
&window_delegate));
WindowSliderDelegateTest slider_delegate;
scoped_ptr<WindowSlider> slider(
new WindowSlider(&slider_delegate, parent.get(), window.get()));
// Generate a horizontal scroll, and change the owner in the middle of the
// scroll.
ui::test::EventGenerator generator(root_window());
aura::Window* old_window = window.get();
generator.GestureScrollSequenceWithCallback(
gfx::Point(10, 10),
gfx::Point(80, 10),
base::TimeDelta::FromMilliseconds(10),
1,
base::Bind(&ChangeSliderOwnerDuringScrollCallback,
base::Unretained(&window),
slider.get()));
aura::Window* new_window = window.get();
EXPECT_NE(old_window, new_window);
EXPECT_TRUE(slider_delegate.created_back_layer());
EXPECT_TRUE(slider_delegate.slide_completing());
EXPECT_TRUE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.created_front_layer());
EXPECT_FALSE(slider_delegate.slide_aborted());
EXPECT_FALSE(slider_delegate.slider_destroyed());
}
// If the delegate doesn't create the layer to show while sliding, WindowSlider
// shouldn't start the slide or change delegate's state in any way in response
// to user input.
TEST_F(WindowSliderTest, NoSlideWhenLayerCantBeCreated) {
scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
window->SetBounds(gfx::Rect(0, 0, 400, 400));
WindowSliderDelegateTest slider_delegate;
slider_delegate.SetCanCreateLayer(false);
WindowSlider* slider =
new WindowSlider(&slider_delegate, root_window(), window.get());
ui::test::EventGenerator generator(root_window());
// No slide in progress should be reported during scroll since the layer
// wasn't created.
generator.GestureScrollSequenceWithCallback(
gfx::Point(10, 10),
gfx::Point(180, 10),
base::TimeDelta::FromMilliseconds(10),
1,
base::Bind(&ConfirmNoSlideDuringScrollCallback, slider));
EXPECT_FALSE(slider_delegate.created_back_layer());
EXPECT_FALSE(slider_delegate.slide_completing());
EXPECT_FALSE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.created_front_layer());
EXPECT_FALSE(slider_delegate.slide_aborted());
EXPECT_FALSE(slider_delegate.slider_destroyed());
window->SetTransform(gfx::Transform());
slider_delegate.SetCanCreateLayer(true);
generator.GestureScrollSequenceWithCallback(
gfx::Point(10, 10),
gfx::Point(180, 10),
base::TimeDelta::FromMilliseconds(10),
10,
base::Bind(&ConfirmSlideDuringScrollCallback, slider));
EXPECT_TRUE(slider_delegate.created_back_layer());
EXPECT_TRUE(slider_delegate.slide_completing());
EXPECT_TRUE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.created_front_layer());
EXPECT_FALSE(slider_delegate.slide_aborted());
EXPECT_FALSE(slider_delegate.slider_destroyed());
window.reset();
EXPECT_TRUE(slider_delegate.slider_destroyed());
}
// Tests that the owner window can be destroyed from |OnWindowSliderDestroyed()|
// delegate callback without causing a crash.
TEST_F(WindowSliderTest, OwnerIsDestroyedOnSliderDestroy) {
size_t child_windows = root_window()->children().size();
aura::Window* window = CreateNormalWindow(0, root_window(), NULL);
window->SetBounds(gfx::Rect(0, 0, 400, 400));
EXPECT_EQ(child_windows + 1, root_window()->children().size());
WindowSliderDeleteOwnerOnDestroy slider_delegate(window);
ui::test::EventGenerator generator(root_window());
// Generate a horizontal overscroll.
scoped_ptr<WindowSlider> slider(
new WindowSlider(&slider_delegate, root_window(), window));
generator.GestureScrollSequence(gfx::Point(10, 10),
gfx::Point(180, 10),
base::TimeDelta::FromMilliseconds(10),
10);
EXPECT_TRUE(slider_delegate.created_back_layer());
EXPECT_TRUE(slider_delegate.slide_completing());
EXPECT_TRUE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.created_front_layer());
EXPECT_FALSE(slider_delegate.slide_aborted());
EXPECT_FALSE(slider_delegate.slider_destroyed());
slider.reset();
// Destroying the slider would have destroyed |window| too. So |window| should
// not need to be destroyed here.
EXPECT_EQ(child_windows, root_window()->children().size());
}
// Tests that the owner window can be destroyed from |OnWindowSlideComplete()|
// delegate callback without causing a crash.
TEST_F(WindowSliderTest, OwnerIsDestroyedOnSlideComplete) {
size_t child_windows = root_window()->children().size();
aura::Window* window = CreateNormalWindow(0, root_window(), NULL);
window->SetBounds(gfx::Rect(0, 0, 400, 400));
EXPECT_EQ(child_windows + 1, root_window()->children().size());
WindowSliderDeleteOwnerOnComplete slider_delegate(window);
ui::test::EventGenerator generator(root_window());
// Generate a horizontal overscroll.
new WindowSlider(&slider_delegate, root_window(), window);
generator.GestureScrollSequence(gfx::Point(10, 10),
gfx::Point(180, 10),
base::TimeDelta::FromMilliseconds(10),
10);
EXPECT_TRUE(slider_delegate.created_back_layer());
EXPECT_TRUE(slider_delegate.slide_completing());
EXPECT_TRUE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.created_front_layer());
EXPECT_FALSE(slider_delegate.slide_aborted());
EXPECT_TRUE(slider_delegate.slider_destroyed());
// Destroying the slider would have destroyed |window| too. So |window| should
// not need to be destroyed here.
EXPECT_EQ(child_windows, root_window()->children().size());
}
// Test the scenario when two swipe gesture occur quickly one after another so
// that the second swipe occurs while the transition animation triggered by the
// first swipe is in progress.
// The second swipe is supposed to instantly complete the animation caused by
// the first swipe, ask the delegate to create a new layer, and animate it.
TEST_F(WindowSliderTest, SwipeDuringSwipeAnimation) {
scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
window->SetBounds(gfx::Rect(0, 0, 400, 400));
WindowSliderDelegateTest slider_delegate;
new WindowSlider(&slider_delegate, root_window(), window.get());
// This test uses explicit durations so needs a normal duration.
ui::ScopedAnimationDurationScaleMode normal_duration(
ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
ui::LayerAnimator* animator = window->layer()->GetAnimator();
animator->set_disable_timer_for_test(true);
ui::LayerAnimatorTestController test_controller(animator);
ui::test::EventGenerator generator(root_window());
// Swipe forward so that |window|'s layer is the one animating.
generator.GestureScrollSequence(
gfx::Point(10, 10),
gfx::Point(180, 10),
base::TimeDelta::FromMilliseconds(10),
2);
EXPECT_TRUE(slider_delegate.created_back_layer());
EXPECT_FALSE(slider_delegate.slide_aborted());
EXPECT_FALSE(slider_delegate.created_front_layer());
EXPECT_TRUE(slider_delegate.slide_completing());
EXPECT_FALSE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.slider_destroyed());
ui::ScopedLayerAnimationSettings settings(animator);
base::TimeDelta duration = settings.GetTransitionDuration();
test_controller.StartThreadedAnimationsIfNeeded();
base::TimeTicks start_time1 = gfx::FrameTime::Now();
animator->Step(start_time1 + duration / 2);
EXPECT_FALSE(slider_delegate.slide_completed());
slider_delegate.Reset();
// Generate another horizontal swipe while the animation from the previous
// swipe is in progress.
generator.GestureScrollSequence(
gfx::Point(10, 10),
gfx::Point(180, 10),
base::TimeDelta::FromMilliseconds(10),
2);
// Performing the second swipe should instantly complete the slide started
// by the first swipe and create a new layer.
EXPECT_TRUE(slider_delegate.created_back_layer());
EXPECT_FALSE(slider_delegate.slide_aborted());
EXPECT_FALSE(slider_delegate.created_front_layer());
EXPECT_TRUE(slider_delegate.slide_completing());
EXPECT_TRUE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.slider_destroyed());
test_controller.StartThreadedAnimationsIfNeeded();
base::TimeTicks start_time2 = gfx::FrameTime::Now();
slider_delegate.Reset();
animator->Step(start_time2 + duration);
// The animation for the second slide should now be completed.
EXPECT_TRUE(slider_delegate.slide_completed());
slider_delegate.Reset();
window.reset();
EXPECT_TRUE(slider_delegate.slider_destroyed());
}
} // namespace content