blob: 2b6077dce24e1400337cd05ba09e7ae01baf0274 [file] [log] [blame]
// 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/android/overscroll_refresh.h"
#include "base/logging.h"
#include "ui/android/overscroll_refresh_handler.h"
namespace ui {
namespace {
// Experimentally determined constant used to allow activation even if touch
// release results in a small upward fling (quite common during a slow scroll).
const float kMinFlingVelocityForActivation = -500.f;
} // namespace
OverscrollRefresh::OverscrollRefresh(OverscrollRefreshHandler* handler)
: scrolled_to_top_(true),
top_at_scroll_start_(true),
overflow_y_hidden_(false),
scroll_consumption_state_(DISABLED),
handler_(handler) {
DCHECK(handler);
}
OverscrollRefresh::OverscrollRefresh()
: scrolled_to_top_(true),
overflow_y_hidden_(false),
scroll_consumption_state_(DISABLED),
handler_(nullptr) {}
OverscrollRefresh::~OverscrollRefresh() {
}
void OverscrollRefresh::Reset() {
scroll_consumption_state_ = DISABLED;
cumulative_scroll_.set_x(0);
cumulative_scroll_.set_y(0);
handler_->PullReset();
}
void OverscrollRefresh::OnScrollBegin() {
top_at_scroll_start_ = scrolled_to_top_;
ReleaseWithoutActivation();
scroll_consumption_state_ = AWAITING_SCROLL_UPDATE_ACK;
}
void OverscrollRefresh::OnScrollEnd(const gfx::Vector2dF& scroll_velocity) {
bool allow_activation = scroll_velocity.y() > kMinFlingVelocityForActivation;
Release(allow_activation);
}
void OverscrollRefresh::OnOverscrolled() {
if (scroll_consumption_state_ != AWAITING_SCROLL_UPDATE_ACK)
return;
scroll_consumption_state_ =
handler_->PullStart(cumulative_scroll_.x(), cumulative_scroll_.y())
? ENABLED
: DISABLED;
}
bool OverscrollRefresh::WillHandleScrollUpdate(
const gfx::Vector2dF& scroll_delta) {
switch (scroll_consumption_state_) {
case DISABLED:
return false;
case AWAITING_SCROLL_UPDATE_ACK:
// Check applies for the pull-to-refresh condition only.
if (std::abs(scroll_delta.y()) > std::abs(scroll_delta.x())) {
// If the initial scroll motion is downward, or we're in other cases
// where activation shouldn't have happened, stop here.
if (scroll_delta.y() <= 0 || !top_at_scroll_start_ ||
overflow_y_hidden_) {
scroll_consumption_state_ = DISABLED;
return false;
}
}
cumulative_scroll_.Add(scroll_delta);
return false;
case ENABLED:
handler_->PullUpdate(scroll_delta.x(), scroll_delta.y());
return true;
}
NOTREACHED() << "Invalid overscroll state: " << scroll_consumption_state_;
return false;
}
void OverscrollRefresh::ReleaseWithoutActivation() {
bool allow_activation = false;
Release(allow_activation);
}
bool OverscrollRefresh::IsActive() const {
return scroll_consumption_state_ == ENABLED;
}
bool OverscrollRefresh::IsAwaitingScrollUpdateAck() const {
return scroll_consumption_state_ == AWAITING_SCROLL_UPDATE_ACK;
}
void OverscrollRefresh::OnFrameUpdated(
const gfx::Vector2dF& content_scroll_offset,
bool root_overflow_y_hidden) {
scrolled_to_top_ = content_scroll_offset.y() == 0;
overflow_y_hidden_ = root_overflow_y_hidden;
}
void OverscrollRefresh::Release(bool allow_refresh) {
if (scroll_consumption_state_ == ENABLED)
handler_->PullRelease(allow_refresh);
scroll_consumption_state_ = DISABLED;
cumulative_scroll_.set_x(0);
cumulative_scroll_.set_y(0);
}
} // namespace ui