Commit a652de4c authored by Mohsen Izadi's avatar Mohsen Izadi Committed by Commit Bot

Add elasticity to simple gesture nav

This CL adds elasticity to the simple gesture nav UI. After it reaches
the activation threshold, the affordance would be in its final shape
(full opacity, centered arrow, full ripple size), however it would still
move with further drags with diminishing speed until it completely
stops. Further drags would be ignored.

BUG=668296
TEST=manual

Change-Id: I7423e441bf90c04b84fda2cf9ddde44745bc945e
Reviewed-on: https://chromium-review.googlesource.com/559592
Commit-Queue: Mohsen Izadi <mohsen@chromium.org>
Reviewed-by: default avatarSadrul Chowdhury <sadrul@chromium.org>
Cr-Commit-Position: refs/heads/master@{#488840}
parent 6f044e1b
...@@ -367,6 +367,7 @@ bool OverscrollController::ProcessOverscroll(float delta_x, ...@@ -367,6 +367,7 @@ bool OverscrollController::ProcessOverscroll(float delta_x,
if (delegate_) { if (delegate_) {
base::Optional<float> cap = delegate_->GetMaxOverscrollDelta(); base::Optional<float> cap = delegate_->GetMaxOverscrollDelta();
if (cap) { if (cap) {
DCHECK_LE(0.f, cap.value());
switch (overscroll_mode_) { switch (overscroll_mode_) {
case OVERSCROLL_WEST: case OVERSCROLL_WEST:
case OVERSCROLL_EAST: case OVERSCROLL_EAST:
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <utility> #include <utility>
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "cc/paint/paint_flags.h" #include "cc/paint/paint_flags.h"
#include "components/vector_icons/vector_icons.h" #include "components/vector_icons/vector_icons.h"
#include "content/browser/frame_host/navigation_controller_impl.h" #include "content/browser/frame_host/navigation_controller_impl.h"
...@@ -60,10 +61,19 @@ const gfx::Tween::Type kBurstAnimationTweenType = gfx::Tween::EASE_IN; ...@@ -60,10 +61,19 @@ const gfx::Tween::Type kBurstAnimationTweenType = gfx::Tween::EASE_IN;
constexpr auto kRippleBurstAnimationDuration = constexpr auto kRippleBurstAnimationDuration =
base::TimeDelta::FromMilliseconds(160); base::TimeDelta::FromMilliseconds(160);
// Offset of the affordance when it is at the maximum distance with content // Offset of the affordance when it is at the activation threshold. Since the
// border. Since the affordance is initially out of content bounds, this is the // affordance is initially out of content bounds, this is the offset of the
// offset of the farther side of the affordance (which equals 128 + 18). // farther side of the affordance (which equals 128 + 18).
const int kMaxAffordanceOffset = 146; const int kAffordanceActivationOffset = 146;
// Extra offset of the affordance when it is dragged past the activation
// threshold.
const int kAffordanceExtraOffset = 72;
const gfx::Tween::Type kExtraDragTweenType = gfx::Tween::Type::EASE_OUT;
constexpr float kExtraAffordanceRatio =
static_cast<float>(kAffordanceExtraOffset) /
static_cast<float>(kAffordanceActivationOffset);
// Parameters defining animation when the affordance is aborted. // Parameters defining animation when the affordance is aborted.
const gfx::Tween::Type kAbortAnimationTweenType = gfx::Tween::EASE_IN; const gfx::Tween::Type kAbortAnimationTweenType = gfx::Tween::EASE_IN;
...@@ -89,10 +99,13 @@ class Affordance : public ui::LayerDelegate, public gfx::AnimationDelegate { ...@@ -89,10 +99,13 @@ class Affordance : public ui::LayerDelegate, public gfx::AnimationDelegate {
public: public:
Affordance(GestureNavSimple* owner, Affordance(GestureNavSimple* owner,
OverscrollMode mode, OverscrollMode mode,
const gfx::Rect& content_bounds); const gfx::Rect& content_bounds,
float max_drag_progress);
~Affordance() override; ~Affordance() override;
// Sets progress of affordance drag as a value between 0 and 1. // Sets drag progress. 0 means no progress. 1 means full progress. Values more
// than 1 are also allowed for when the user drags beyond the completion
// threshold.
void SetDragProgress(float progress); void SetDragProgress(float progress);
// Aborts the affordance and animates it back. This will delete |this| // Aborts the affordance and animates it back. This will delete |this|
...@@ -117,6 +130,11 @@ class Affordance : public ui::LayerDelegate, public gfx::AnimationDelegate { ...@@ -117,6 +130,11 @@ class Affordance : public ui::LayerDelegate, public gfx::AnimationDelegate {
void SetAbortProgress(float progress); void SetAbortProgress(float progress);
void SetCompleteProgress(float progress); void SetCompleteProgress(float progress);
// Helper function that returns the affordance progress according to the
// current values of different progress values (drag progress and abort
// progress). 1 means the affordance is at the activation threshold.
float GetAffordanceProgress() const;
// ui::LayerDelegate: // ui::LayerDelegate:
void OnPaintLayer(const ui::PaintContext& context) override; void OnPaintLayer(const ui::PaintContext& context) override;
void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override; void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override;
...@@ -131,6 +149,10 @@ class Affordance : public ui::LayerDelegate, public gfx::AnimationDelegate { ...@@ -131,6 +149,10 @@ class Affordance : public ui::LayerDelegate, public gfx::AnimationDelegate {
const OverscrollMode mode_; const OverscrollMode mode_;
// Maximum value for drag progress that can be reached if the user drags
// entire width of the page/screen.
const float max_drag_progress_;
// Root layer of the affordance. This is used to clip the affordance to the // Root layer of the affordance. This is used to clip the affordance to the
// content bounds. // content bounds.
std::unique_ptr<ui::Layer> root_layer_; std::unique_ptr<ui::Layer> root_layer_;
...@@ -154,9 +176,11 @@ class Affordance : public ui::LayerDelegate, public gfx::AnimationDelegate { ...@@ -154,9 +176,11 @@ class Affordance : public ui::LayerDelegate, public gfx::AnimationDelegate {
Affordance::Affordance(GestureNavSimple* owner, Affordance::Affordance(GestureNavSimple* owner,
OverscrollMode mode, OverscrollMode mode,
const gfx::Rect& content_bounds) const gfx::Rect& content_bounds,
float max_drag_progress)
: owner_(owner), : owner_(owner),
mode_(mode), mode_(mode),
max_drag_progress_(max_drag_progress),
root_layer_(base::MakeUnique<ui::Layer>(ui::LAYER_NOT_DRAWN)), root_layer_(base::MakeUnique<ui::Layer>(ui::LAYER_NOT_DRAWN)),
painted_layer_(base::MakeUnique<ui::Layer>(ui::LAYER_TEXTURED)), painted_layer_(base::MakeUnique<ui::Layer>(ui::LAYER_TEXTURED)),
image_(gfx::CreateVectorIcon(mode == OVERSCROLL_EAST image_(gfx::CreateVectorIcon(mode == OVERSCROLL_EAST
...@@ -188,7 +212,6 @@ Affordance::~Affordance() {} ...@@ -188,7 +212,6 @@ Affordance::~Affordance() {}
void Affordance::SetDragProgress(float progress) { void Affordance::SetDragProgress(float progress) {
DCHECK_EQ(State::DRAGGING, state_); DCHECK_EQ(State::DRAGGING, state_);
DCHECK_LE(0.f, progress); DCHECK_LE(0.f, progress);
DCHECK_GE(1.f, progress);
if (drag_progress_ == progress) if (drag_progress_ == progress)
return; return;
...@@ -203,26 +226,26 @@ void Affordance::Abort() { ...@@ -203,26 +226,26 @@ void Affordance::Abort() {
state_ = State::ABORTING; state_ = State::ABORTING;
animation_.reset( animation_ = base::MakeUnique<gfx::LinearAnimation>(
new gfx::LinearAnimation(drag_progress_ * kAbortAnimationDuration, GetAffordanceProgress() * kAbortAnimationDuration,
gfx::LinearAnimation::kDefaultFrameRate, this)); gfx::LinearAnimation::kDefaultFrameRate, this);
animation_->Start(); animation_->Start();
} }
void Affordance::Complete() { void Affordance::Complete() {
DCHECK_EQ(State::DRAGGING, state_); DCHECK_EQ(State::DRAGGING, state_);
DCHECK_EQ(1.f, drag_progress_); DCHECK_LE(1.f, drag_progress_);
state_ = State::COMPLETING; state_ = State::COMPLETING;
animation_.reset( animation_ = base::MakeUnique<gfx::LinearAnimation>(
new gfx::LinearAnimation(kRippleBurstAnimationDuration, kRippleBurstAnimationDuration, gfx::LinearAnimation::kDefaultFrameRate,
gfx::LinearAnimation::kDefaultFrameRate, this)); this);
animation_->Start(); animation_->Start();
} }
void Affordance::UpdateTransform() { void Affordance::UpdateTransform() {
float offset = (1 - abort_progress_) * drag_progress_ * kMaxAffordanceOffset; float offset = GetAffordanceProgress() * kAffordanceActivationOffset;
gfx::Transform transform; gfx::Transform transform;
transform.Translate(mode_ == OVERSCROLL_EAST ? offset : -offset, 0); transform.Translate(mode_ == OVERSCROLL_EAST ? offset : -offset, 0);
painted_layer_->SetTransform(transform); painted_layer_->SetTransform(transform);
...@@ -254,12 +277,33 @@ void Affordance::SetCompleteProgress(float progress) { ...@@ -254,12 +277,33 @@ void Affordance::SetCompleteProgress(float progress) {
return; return;
complete_progress_ = progress; complete_progress_ = progress;
painted_layer_->SetOpacity(1 - complete_progress_); painted_layer_->SetOpacity(gfx::Tween::CalculateValue(
kBurstAnimationTweenType, 1 - complete_progress_));
SchedulePaint(); SchedulePaint();
} }
float Affordance::GetAffordanceProgress() const {
// Apply tween on the drag progress.
float affordance_progress = drag_progress_;
if (drag_progress_ >= 1.f) {
float extra_progress = max_drag_progress_ == 1.f
? 1.f
: std::min(1.f, (drag_progress_ - 1.f) /
(max_drag_progress_ - 1.f));
affordance_progress =
1 + gfx::Tween::CalculateValue(kExtraDragTweenType, extra_progress) *
kExtraAffordanceRatio;
}
// Apply abort progress, if any.
affordance_progress *=
1 - gfx::Tween::CalculateValue(kAbortAnimationTweenType, abort_progress_);
return affordance_progress;
}
void Affordance::OnPaintLayer(const ui::PaintContext& context) { void Affordance::OnPaintLayer(const ui::PaintContext& context) {
DCHECK(drag_progress_ == 1.f || state_ != State::COMPLETING); DCHECK(drag_progress_ >= 1.f || state_ != State::COMPLETING);
DCHECK(abort_progress_ == 0.f || state_ == State::ABORTING); DCHECK(abort_progress_ == 0.f || state_ == State::ABORTING);
DCHECK(complete_progress_ == 0.f || state_ == State::COMPLETING); DCHECK(complete_progress_ == 0.f || state_ == State::COMPLETING);
...@@ -267,7 +311,7 @@ void Affordance::OnPaintLayer(const ui::PaintContext& context) { ...@@ -267,7 +311,7 @@ void Affordance::OnPaintLayer(const ui::PaintContext& context) {
gfx::Canvas* canvas = recorder.canvas(); gfx::Canvas* canvas = recorder.canvas();
gfx::PointF center_point(kMaxRippleBurstRadius, kMaxRippleBurstRadius); gfx::PointF center_point(kMaxRippleBurstRadius, kMaxRippleBurstRadius);
float progress = (1 - abort_progress_) * drag_progress_; float progress = std::min(1.f, GetAffordanceProgress());
// Draw the ripple. // Draw the ripple.
cc::PaintFlags ripple_flags; cc::PaintFlags ripple_flags;
...@@ -276,9 +320,10 @@ void Affordance::OnPaintLayer(const ui::PaintContext& context) { ...@@ -276,9 +320,10 @@ void Affordance::OnPaintLayer(const ui::PaintContext& context) {
ripple_flags.setColor(kRippleColor); ripple_flags.setColor(kRippleColor);
float ripple_radius; float ripple_radius;
if (state_ == State::COMPLETING) { if (state_ == State::COMPLETING) {
ripple_radius = const float burst_progress = gfx::Tween::CalculateValue(
kMaxRippleRadius + kBurstAnimationTweenType, complete_progress_);
complete_progress_ * (kMaxRippleBurstRadius - kMaxRippleRadius); ripple_radius = kMaxRippleRadius +
burst_progress * (kMaxRippleBurstRadius - kMaxRippleRadius);
} else { } else {
ripple_radius = ripple_radius =
kBackgroundRadius + progress * (kMaxRippleRadius - kBackgroundRadius); kBackgroundRadius + progress * (kMaxRippleRadius - kBackgroundRadius);
...@@ -333,12 +378,10 @@ void Affordance::AnimationProgressed(const gfx::Animation* animation) { ...@@ -333,12 +378,10 @@ void Affordance::AnimationProgressed(const gfx::Animation* animation) {
NOTREACHED(); NOTREACHED();
break; break;
case State::ABORTING: case State::ABORTING:
SetAbortProgress(gfx::Tween::CalculateValue( SetAbortProgress(animation->GetCurrentValue());
kAbortAnimationTweenType, animation->GetCurrentValue()));
break; break;
case State::COMPLETING: case State::COMPLETING:
SetCompleteProgress(gfx::Tween::CalculateValue( SetCompleteProgress(animation->GetCurrentValue());
kBurstAnimationTweenType, animation->GetCurrentValue()));
break; break;
} }
} }
...@@ -349,7 +392,8 @@ void Affordance::AnimationCanceled(const gfx::Animation* animation) { ...@@ -349,7 +392,8 @@ void Affordance::AnimationCanceled(const gfx::Animation* animation) {
GestureNavSimple::GestureNavSimple(WebContentsImpl* web_contents) GestureNavSimple::GestureNavSimple(WebContentsImpl* web_contents)
: web_contents_(web_contents), : web_contents_(web_contents),
completion_threshold_(0.f) {} completion_threshold_(0.f),
max_delta_(0.f) {}
GestureNavSimple::~GestureNavSimple() {} GestureNavSimple::~GestureNavSimple() {}
...@@ -364,7 +408,7 @@ void GestureNavSimple::CompleteGestureAnimation() { ...@@ -364,7 +408,7 @@ void GestureNavSimple::CompleteGestureAnimation() {
} }
void GestureNavSimple::OnAffordanceAnimationEnded() { void GestureNavSimple::OnAffordanceAnimationEnded() {
affordance_.reset(); affordance_ = nullptr;
} }
gfx::Size GestureNavSimple::GetDisplaySize() const { gfx::Size GestureNavSimple::GetDisplaySize() const {
...@@ -376,8 +420,9 @@ gfx::Size GestureNavSimple::GetDisplaySize() const { ...@@ -376,8 +420,9 @@ gfx::Size GestureNavSimple::GetDisplaySize() const {
bool GestureNavSimple::OnOverscrollUpdate(float delta_x, float delta_y) { bool GestureNavSimple::OnOverscrollUpdate(float delta_x, float delta_y) {
if (!affordance_ || affordance_->IsFinishing()) if (!affordance_ || affordance_->IsFinishing())
return false; return false;
affordance_->SetDragProgress( float delta = std::abs(delta_x);
std::min(1.f, std::abs(delta_x) / completion_threshold_)); DCHECK_LE(delta, max_delta_);
affordance_->SetDragProgress(delta / completion_threshold_);
return true; return true;
} }
...@@ -413,9 +458,14 @@ void GestureNavSimple::OnOverscrollModeChange(OverscrollMode old_mode, ...@@ -413,9 +458,14 @@ void GestureNavSimple::OnOverscrollModeChange(OverscrollMode old_mode,
completion_threshold_ = completion_threshold_ =
width * GetOverscrollConfig(OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE) - width * GetOverscrollConfig(OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE) -
start_threshold; start_threshold;
DCHECK_LE(0, completion_threshold_);
max_delta_ = width - start_threshold;
DCHECK_LE(0, max_delta_);
aura::Window* window = web_contents_->GetNativeView(); aura::Window* window = web_contents_->GetNativeView();
affordance_ = base::MakeUnique<Affordance>(this, new_mode, window->bounds()); affordance_ = base::MakeUnique<Affordance>(
this, new_mode, window->bounds(), max_delta_ / completion_threshold_);
// Adding the affordance as a child of the content window is not sufficient, // Adding the affordance as a child of the content window is not sufficient,
// because it is possible for a new layer to be parented on top of the // because it is possible for a new layer to be parented on top of the
...@@ -430,7 +480,7 @@ void GestureNavSimple::OnOverscrollModeChange(OverscrollMode old_mode, ...@@ -430,7 +480,7 @@ void GestureNavSimple::OnOverscrollModeChange(OverscrollMode old_mode,
base::Optional<float> GestureNavSimple::GetMaxOverscrollDelta() const { base::Optional<float> GestureNavSimple::GetMaxOverscrollDelta() const {
if (affordance_) if (affordance_)
return completion_threshold_; return max_delta_;
return base::nullopt; return base::nullopt;
} }
......
...@@ -43,6 +43,10 @@ class GestureNavSimple : public OverscrollControllerDelegate { ...@@ -43,6 +43,10 @@ class GestureNavSimple : public OverscrollControllerDelegate {
std::unique_ptr<Affordance> affordance_; std::unique_ptr<Affordance> affordance_;
float completion_threshold_; float completion_threshold_;
// When an overscroll is active, represents the maximum overscroll delta we
// expect in OnOverscrollUpdate().
float max_delta_;
DISALLOW_COPY_AND_ASSIGN(GestureNavSimple); DISALLOW_COPY_AND_ASSIGN(GestureNavSimple);
}; };
......
...@@ -21,6 +21,8 @@ static base::TimeDelta CalculateInterval(int frame_rate) { ...@@ -21,6 +21,8 @@ static base::TimeDelta CalculateInterval(int frame_rate) {
return base::TimeDelta::FromMicroseconds(timer_interval); return base::TimeDelta::FromMicroseconds(timer_interval);
} }
const int LinearAnimation::kDefaultFrameRate = 60;
LinearAnimation::LinearAnimation(AnimationDelegate* delegate, int frame_rate) LinearAnimation::LinearAnimation(AnimationDelegate* delegate, int frame_rate)
: LinearAnimation({}, frame_rate, delegate) {} : LinearAnimation({}, frame_rate, delegate) {}
......
...@@ -18,7 +18,7 @@ class AnimationDelegate; ...@@ -18,7 +18,7 @@ class AnimationDelegate;
class ANIMATION_EXPORT LinearAnimation : public Animation { class ANIMATION_EXPORT LinearAnimation : public Animation {
public: public:
// Default frame rate (hz). // Default frame rate (hz).
static const int kDefaultFrameRate = 60; static const int kDefaultFrameRate;
// Initializes everything except the duration. // Initializes everything except the duration.
// //
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment