overscroll_refresh.cc 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/android/overscroll_refresh.h"
  5. #include "base/check.h"
  6. #include "base/notreached.h"
  7. #include "cc/input/overscroll_behavior.h"
  8. #include "ui/android/overscroll_refresh_handler.h"
  9. #include "ui/gfx/geometry/point_f.h"
  10. namespace ui {
  11. namespace {
  12. // Experimentally determined constant used to allow activation even if touch
  13. // release results in a small upward fling (quite common during a slow scroll).
  14. const float kMinFlingVelocityForActivation = -500.f;
  15. // Weighted value used to determine whether a scroll should trigger vertical
  16. // scroll or horizontal navigation.
  17. const float kWeightAngle30 = 1.73f;
  18. } // namespace
  19. OverscrollRefresh::OverscrollRefresh(OverscrollRefreshHandler* handler,
  20. float edge_width)
  21. : scrolled_to_top_(true),
  22. top_at_scroll_start_(true),
  23. overflow_y_hidden_(false),
  24. scroll_consumption_state_(DISABLED),
  25. edge_width_(edge_width),
  26. handler_(handler) {
  27. DCHECK(handler);
  28. }
  29. OverscrollRefresh::OverscrollRefresh()
  30. : scrolled_to_top_(true),
  31. overflow_y_hidden_(false),
  32. scroll_consumption_state_(DISABLED),
  33. edge_width_(kDefaultNavigationEdgeWidth * 1.f),
  34. handler_(nullptr) {}
  35. OverscrollRefresh::~OverscrollRefresh() {
  36. }
  37. void OverscrollRefresh::Reset() {
  38. scroll_consumption_state_ = DISABLED;
  39. cumulative_scroll_.set_x(0);
  40. cumulative_scroll_.set_y(0);
  41. handler_->PullReset();
  42. }
  43. void OverscrollRefresh::OnScrollBegin(const gfx::PointF& pos) {
  44. scroll_begin_x_ = pos.x();
  45. scroll_begin_y_ = pos.y();
  46. top_at_scroll_start_ = scrolled_to_top_;
  47. ReleaseWithoutActivation();
  48. scroll_consumption_state_ = AWAITING_SCROLL_UPDATE_ACK;
  49. }
  50. void OverscrollRefresh::OnScrollEnd(const gfx::Vector2dF& scroll_velocity) {
  51. bool allow_activation = scroll_velocity.y() > kMinFlingVelocityForActivation;
  52. Release(allow_activation);
  53. }
  54. void OverscrollRefresh::OnOverscrolled(const cc::OverscrollBehavior& behavior) {
  55. if (scroll_consumption_state_ != AWAITING_SCROLL_UPDATE_ACK)
  56. return;
  57. float ydelta = cumulative_scroll_.y();
  58. float xdelta = cumulative_scroll_.x();
  59. bool in_y_direction = std::abs(ydelta) > std::abs(xdelta);
  60. bool in_x_direction = std::abs(ydelta) * kWeightAngle30 < std::abs(xdelta);
  61. OverscrollAction type = OverscrollAction::NONE;
  62. bool navigate_forward = false;
  63. if (ydelta > 0 && in_y_direction) {
  64. // Pull-to-refresh. Check overscroll-behavior-y
  65. if (behavior.y != cc::OverscrollBehavior::Type::kAuto) {
  66. Reset();
  67. return;
  68. }
  69. type = OverscrollAction::PULL_TO_REFRESH;
  70. } else if (in_x_direction &&
  71. (scroll_begin_x_ < edge_width_ ||
  72. viewport_width_ - scroll_begin_x_ < edge_width_)) {
  73. // Swipe-to-navigate. Check overscroll-behavior-x
  74. if (behavior.x != cc::OverscrollBehavior::Type::kAuto) {
  75. Reset();
  76. return;
  77. }
  78. type = OverscrollAction::HISTORY_NAVIGATION;
  79. navigate_forward = xdelta < 0;
  80. }
  81. if (type != OverscrollAction::NONE) {
  82. scroll_consumption_state_ =
  83. handler_->PullStart(type, scroll_begin_x_, scroll_begin_y_,
  84. navigate_forward)
  85. ? ENABLED
  86. : DISABLED;
  87. }
  88. }
  89. bool OverscrollRefresh::WillHandleScrollUpdate(
  90. const gfx::Vector2dF& scroll_delta) {
  91. switch (scroll_consumption_state_) {
  92. case DISABLED:
  93. return false;
  94. case AWAITING_SCROLL_UPDATE_ACK:
  95. // Check applies for the pull-to-refresh condition only.
  96. if (std::abs(scroll_delta.y()) > std::abs(scroll_delta.x())) {
  97. // If the initial scroll motion is downward, or we're in other cases
  98. // where activation shouldn't have happened, stop here.
  99. if (scroll_delta.y() <= 0 || !top_at_scroll_start_ ||
  100. overflow_y_hidden_) {
  101. scroll_consumption_state_ = DISABLED;
  102. return false;
  103. }
  104. }
  105. cumulative_scroll_.Add(scroll_delta);
  106. return false;
  107. case ENABLED:
  108. handler_->PullUpdate(scroll_delta.x(), scroll_delta.y());
  109. return true;
  110. }
  111. NOTREACHED() << "Invalid overscroll state: " << scroll_consumption_state_;
  112. return false;
  113. }
  114. void OverscrollRefresh::ReleaseWithoutActivation() {
  115. bool allow_activation = false;
  116. Release(allow_activation);
  117. }
  118. bool OverscrollRefresh::IsActive() const {
  119. return scroll_consumption_state_ == ENABLED;
  120. }
  121. bool OverscrollRefresh::IsAwaitingScrollUpdateAck() const {
  122. return scroll_consumption_state_ == AWAITING_SCROLL_UPDATE_ACK;
  123. }
  124. void OverscrollRefresh::OnFrameUpdated(const gfx::SizeF& viewport_size,
  125. const gfx::PointF& content_scroll_offset,
  126. bool root_overflow_y_hidden) {
  127. viewport_width_ = viewport_size.width();
  128. scrolled_to_top_ = content_scroll_offset.y() == 0;
  129. overflow_y_hidden_ = root_overflow_y_hidden;
  130. }
  131. void OverscrollRefresh::Release(bool allow_refresh) {
  132. if (scroll_consumption_state_ == ENABLED)
  133. handler_->PullRelease(allow_refresh);
  134. scroll_consumption_state_ = DISABLED;
  135. cumulative_scroll_.set_x(0);
  136. cumulative_scroll_.set_y(0);
  137. }
  138. } // namespace ui