0

athena: Add support for fling-scroll in overview mode.

Install an animation-observer in the compositor when a fling happens, and use a
FlingCurve (which implements the same fling-curve used for fling-scrolling
web-pages) to progress the fling at each animation step in the compositor.

BUG=398117
R=mukai@chromium.org, sky@chromium.org

Review URL: https://codereview.chromium.org/436213002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@287783 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
sadrul@chromium.org
2014-08-06 16:38:37 +00:00
parent c31d8046b7
commit 4aeb08043a
6 changed files with 210 additions and 2 deletions

@ -15,6 +15,7 @@
'../ui/accessibility/accessibility.gyp:ax_gen',
'../ui/app_list/app_list.gyp:app_list',
'../ui/aura/aura.gyp:aura',
'../ui/events/events.gyp:events_base',
'../ui/strings/ui_strings.gyp:ui_strings',
'../ui/views/views.gyp:views',
],

@ -14,8 +14,13 @@
#include "ui/aura/window_delegate.h"
#include "ui/aura/window_property.h"
#include "ui/aura/window_targeter.h"
#include "ui/aura/window_tree_host.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/compositor_animation_observer.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/events/event_handler.h"
#include "ui/events/gestures/fling_curve.h"
#include "ui/gfx/frame_time.h"
#include "ui/gfx/transform.h"
#include "ui/wm/core/shadow.h"
@ -93,7 +98,8 @@ class StaticWindowTargeter : public aura::WindowTargeter {
};
class WindowOverviewModeImpl : public WindowOverviewMode,
public ui::EventHandler {
public ui::EventHandler,
public ui::CompositorAnimationObserver {
public:
WindowOverviewModeImpl(aura::Window* container,
WindowOverviewModeDelegate* delegate)
@ -113,7 +119,7 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
virtual ~WindowOverviewModeImpl() {
container_->set_target_handler(container_->delegate());
RemoveAnimationObserver();
const aura::Window::Windows& windows = container_->children();
for (aura::Window::Windows::const_iterator iter = windows.begin();
iter != windows.end();
@ -287,6 +293,24 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
return container_->bounds().height() * kScrollableFraction;
}
void CreateFlingerFor(const ui::GestureEvent& event) {
gfx::Vector2dF velocity(event.details().velocity_x(),
event.details().velocity_y());
fling_.reset(new ui::FlingCurve(velocity, gfx::FrameTime::Now()));
}
void AddAnimationObserver() {
ui::Compositor* compositor = container_->GetHost()->compositor();
if (!compositor->HasAnimationObserver(this))
compositor->AddAnimationObserver(this);
}
void RemoveAnimationObserver() {
ui::Compositor* compositor = container_->GetHost()->compositor();
if (compositor->HasAnimationObserver(this))
compositor->RemoveAnimationObserver(this);
}
// ui::EventHandler:
virtual void OnMouseEvent(ui::MouseEvent* mouse) OVERRIDE {
if (mouse->type() == ui::ET_MOUSE_PRESSED) {
@ -314,12 +338,36 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
}
} else if (gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
DoScroll(gesture->details().scroll_y());
gesture->SetHandled();
} else if (gesture->type() == ui::ET_SCROLL_FLING_START) {
CreateFlingerFor(*gesture);
AddAnimationObserver();
gesture->SetHandled();
} else if (gesture->type() == ui::ET_GESTURE_TAP_DOWN && fling_) {
fling_.reset();
RemoveAnimationObserver();
gesture->SetHandled();
}
}
// ui::CompositorAnimationObserver:
virtual void OnAnimationStep(base::TimeTicks timestamp) OVERRIDE {
CHECK(fling_);
if (fling_->start_timestamp() > timestamp)
return;
gfx::Vector2dF scroll = fling_->GetScrollAmountAtTime(timestamp);
if (scroll.IsZero()) {
fling_.reset();
RemoveAnimationObserver();
} else {
DoScroll(scroll.y());
}
}
aura::Window* container_;
WindowOverviewModeDelegate* delegate_;
scoped_ptr<aura::ScopedWindowTargeter> scoped_targeter_;
scoped_ptr<ui::FlingCurve> fling_;
DISALLOW_COPY_AND_ASSIGN(WindowOverviewModeImpl);
};

@ -46,6 +46,8 @@
'events_base_export.h',
'gesture_event_details.cc',
'gesture_event_details.h',
'gestures/fling_curve.cc',
'gestures/fling_curve.h',
'gestures/gesture_configuration.cc',
'gestures/gesture_configuration.h',
'keycodes/keyboard_code_conversion.cc',
@ -316,6 +318,7 @@
'event_processor_unittest.cc',
'event_rewriter_unittest.cc',
'event_unittest.cc',
'gestures/fling_curve_unittest.cc',
'gestures/motion_event_aura_unittest.cc',
'gestures/velocity_calculator_unittest.cc',
'gesture_detection/bitset_32_unittest.cc',

@ -0,0 +1,80 @@
// Copyright 2014 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 "ui/events/gestures/fling_curve.h"
#include <algorithm>
#include <cmath>
#include "base/logging.h"
namespace {
const float kDefaultAlpha = -5.70762e+03f;
const float kDefaultBeta = 1.72e+02f;
const float kDefaultGamma = 3.7e+00f;
inline double GetPositionAtTime(double t) {
return kDefaultAlpha * exp(-kDefaultGamma * t) - kDefaultBeta * t -
kDefaultAlpha;
}
inline double GetVelocityAtTime(double t) {
return -kDefaultAlpha * kDefaultGamma * exp(-kDefaultGamma * t) -
kDefaultBeta;
}
inline double GetTimeAtVelocity(double v) {
return -log((v + kDefaultBeta) / (-kDefaultAlpha * kDefaultGamma)) /
kDefaultGamma;
}
} // namespace
namespace ui {
FlingCurve::FlingCurve(const gfx::Vector2dF& velocity,
base::TimeTicks start_timestamp)
: curve_duration_(GetTimeAtVelocity(0)),
start_timestamp_(start_timestamp),
time_offset_(0),
position_offset_(0) {
float max_start_velocity = std::max(fabs(velocity.x()), fabs(velocity.y()));
if (max_start_velocity > GetVelocityAtTime(0))
max_start_velocity = GetVelocityAtTime(0);
CHECK_GT(max_start_velocity, 0);
displacement_ratio_ = gfx::Vector2dF(velocity.x() / max_start_velocity,
velocity.y() / max_start_velocity);
time_offset_ = GetTimeAtVelocity(max_start_velocity);
position_offset_ = GetPositionAtTime(time_offset_);
last_timestamp_ = start_timestamp_ + base::TimeDelta::FromSecondsD(
curve_duration_ - time_offset_);
}
FlingCurve::~FlingCurve() {
}
gfx::Vector2dF FlingCurve::GetScrollAmountAtTime(base::TimeTicks current) {
if (current < start_timestamp_)
return gfx::Vector2dF();
float displacement = 0;
if (current < last_timestamp_) {
float time = time_offset_ + (current - start_timestamp_).InSecondsF();
CHECK_LT(time, curve_duration_);
displacement = GetPositionAtTime(time) - position_offset_;
} else {
displacement = GetPositionAtTime(curve_duration_) - position_offset_;
}
gfx::Vector2dF scroll(displacement * displacement_ratio_.x(),
displacement * displacement_ratio_.y());
gfx::Vector2dF scroll_increment(scroll.x() - cumulative_scroll_.x(),
scroll.y() - cumulative_scroll_.y());
cumulative_scroll_ = scroll;
return scroll_increment;
}
} // namespace ui

@ -0,0 +1,40 @@
// Copyright 2014 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.
#ifndef UI_EVENTS_GESTURES_FLING_CURVE_H_
#define UI_EVENTS_GESTURES_FLING_CURVE_H_
#include "base/time/time.h"
#include "ui/events/events_base_export.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/vector2d_f.h"
namespace ui {
// FlingCurve can be used to scroll a UI element suitable for touch screen-based
// flings.
class EVENTS_BASE_EXPORT FlingCurve {
public:
FlingCurve(const gfx::Vector2dF& velocity, base::TimeTicks start_timestamp);
~FlingCurve();
gfx::Vector2dF GetScrollAmountAtTime(base::TimeTicks current_timestamp);
base::TimeTicks start_timestamp() const { return start_timestamp_; }
private:
const float curve_duration_;
const base::TimeTicks start_timestamp_;
gfx::Vector2dF displacement_ratio_;
gfx::Vector2dF cumulative_scroll_;
base::TimeTicks last_timestamp_;
float time_offset_;
float position_offset_;
DISALLOW_COPY_AND_ASSIGN(FlingCurve);
};
} // namespace ui
#endif // UI_EVENTS_GESTURES_FLING_CURVE_H_

@ -0,0 +1,36 @@
// Copyright 2014 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 "ui/events/gestures/fling_curve.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/frame_time.h"
namespace ui {
TEST(FlingCurveTest, Basic) {
const gfx::Vector2dF velocity(0, 5000);
base::TimeTicks now = gfx::FrameTime::Now();
FlingCurve curve(velocity, now);
gfx::Vector2dF scroll =
curve.GetScrollAmountAtTime(now + base::TimeDelta::FromMilliseconds(20));
EXPECT_EQ(0, scroll.x());
EXPECT_NEAR(scroll.y(), 96, 1);
scroll =
curve.GetScrollAmountAtTime(now + base::TimeDelta::FromMilliseconds(250));
EXPECT_EQ(0, scroll.x());
EXPECT_NEAR(scroll.y(), 705, 1);
scroll =
curve.GetScrollAmountAtTime(now + base::TimeDelta::FromSeconds(10));
EXPECT_EQ(0, scroll.x());
EXPECT_NEAR(scroll.y(), 392, 1);
EXPECT_TRUE(curve.GetScrollAmountAtTime(
now + base::TimeDelta::FromSeconds(20)).IsZero());
}
} // namespace ui