| Index: content/browser/web_contents/aura/window_slider_unittest.cc
|
| diff --git a/content/browser/web_contents/aura/window_slider_unittest.cc b/content/browser/web_contents/aura/window_slider_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a029dd8feb2fc2fbfdfa0a4cfe27cd050a7caadc
|
| --- /dev/null
|
| +++ b/content/browser/web_contents/aura/window_slider_unittest.cc
|
| @@ -0,0 +1,639 @@
|
| +// 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(ui::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() {
|
| + }
|
| + ~NoEventWindowDelegate() override {}
|
| +
|
| + private:
|
| + // Overridden from aura::WindowDelegate:
|
| + 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) {
|
| + }
|
| + ~WindowSliderDelegateTest() override {
|
| + // 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:
|
| + ui::Layer* CreateBackLayer() override {
|
| + if (!can_create_layer_)
|
| + return NULL;
|
| + created_back_layer_ = true;
|
| + return CreateLayerForTest();
|
| + }
|
| +
|
| + ui::Layer* CreateFrontLayer() override {
|
| + if (!can_create_layer_)
|
| + return NULL;
|
| + created_front_layer_ = true;
|
| + return CreateLayerForTest();
|
| + }
|
| +
|
| + void OnWindowSlideCompleted(scoped_ptr<ui::Layer> layer) override {
|
| + slide_completed_ = true;
|
| + }
|
| +
|
| + void OnWindowSlideCompleting() override { slide_completing_ = true; }
|
| +
|
| + void OnWindowSlideAborted() override { slide_aborted_ = true; }
|
| +
|
| + 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) {
|
| + }
|
| + ~WindowSliderDeleteOwnerOnDestroy() override {}
|
| +
|
| + private:
|
| + // Overridden from WindowSlider::Delegate:
|
| + 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) {
|
| + }
|
| + ~WindowSliderDeleteOwnerOnComplete() override {}
|
| +
|
| + private:
|
| + // Overridden from WindowSlider::Delegate:
|
| + 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), ui::EventTimeForNow(), 0, 0),
|
| + new ui::KeyEvent('a', ui::VKEY_A, ui::EF_NONE),
|
| + nullptr
|
| + };
|
| +
|
| + 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), ui::EventTimeForNow(), 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
|
|
|