Merge "Handle DOWN/MOVE/UP gestures with fling. Bug: 5265814"
This commit is contained in:
@@ -2771,15 +2771,21 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
}
|
||||
}
|
||||
|
||||
private boolean startScrollIfNeeded(int deltaY) {
|
||||
private boolean startScrollIfNeeded(int y) {
|
||||
// Check if we have moved far enough that it looks more like a
|
||||
// scroll than a tap
|
||||
final int deltaY = y - mMotionY;
|
||||
final int distance = Math.abs(deltaY);
|
||||
final boolean overscroll = mScrollY != 0;
|
||||
if (overscroll || distance > mTouchSlop) {
|
||||
createScrollingCache();
|
||||
mTouchMode = overscroll ? TOUCH_MODE_OVERSCROLL : TOUCH_MODE_SCROLL;
|
||||
mMotionCorrection = deltaY;
|
||||
if (overscroll) {
|
||||
mTouchMode = TOUCH_MODE_OVERSCROLL;
|
||||
mMotionCorrection = 0;
|
||||
} else {
|
||||
mTouchMode = TOUCH_MODE_SCROLL;
|
||||
mMotionCorrection = deltaY > 0 ? mTouchSlop : -mTouchSlop;
|
||||
}
|
||||
final Handler handler = getHandler();
|
||||
// Handler should not be null unless the AbsListView is not attached to a
|
||||
// window, which would make it very hard to scroll it... but the monkeys
|
||||
@@ -2799,12 +2805,176 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
if (parent != null) {
|
||||
parent.requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
scrollIfNeeded(y);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void scrollIfNeeded(int y) {
|
||||
final int rawDeltaY = y - mMotionY;
|
||||
final int deltaY = rawDeltaY - mMotionCorrection;
|
||||
int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;
|
||||
|
||||
if (mTouchMode == TOUCH_MODE_SCROLL) {
|
||||
if (PROFILE_SCROLLING) {
|
||||
if (!mScrollProfilingStarted) {
|
||||
Debug.startMethodTracing("AbsListViewScroll");
|
||||
mScrollProfilingStarted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mScrollStrictSpan == null) {
|
||||
// If it's non-null, we're already in a scroll.
|
||||
mScrollStrictSpan = StrictMode.enterCriticalSpan("AbsListView-scroll");
|
||||
}
|
||||
|
||||
if (y != mLastY) {
|
||||
// We may be here after stopping a fling and continuing to scroll.
|
||||
// If so, we haven't disallowed intercepting touch events yet.
|
||||
// Make sure that we do so in case we're in a parent that can intercept.
|
||||
if ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) == 0 &&
|
||||
Math.abs(rawDeltaY) > mTouchSlop) {
|
||||
final ViewParent parent = getParent();
|
||||
if (parent != null) {
|
||||
parent.requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
}
|
||||
|
||||
final int motionIndex;
|
||||
if (mMotionPosition >= 0) {
|
||||
motionIndex = mMotionPosition - mFirstPosition;
|
||||
} else {
|
||||
// If we don't have a motion position that we can reliably track,
|
||||
// pick something in the middle to make a best guess at things below.
|
||||
motionIndex = getChildCount() / 2;
|
||||
}
|
||||
|
||||
int motionViewPrevTop = 0;
|
||||
View motionView = this.getChildAt(motionIndex);
|
||||
if (motionView != null) {
|
||||
motionViewPrevTop = motionView.getTop();
|
||||
}
|
||||
|
||||
// No need to do all this work if we're not going to move anyway
|
||||
boolean atEdge = false;
|
||||
if (incrementalDeltaY != 0) {
|
||||
atEdge = trackMotionScroll(deltaY, incrementalDeltaY);
|
||||
}
|
||||
|
||||
// Check to see if we have bumped into the scroll limit
|
||||
motionView = this.getChildAt(motionIndex);
|
||||
if (motionView != null) {
|
||||
// Check if the top of the motion view is where it is
|
||||
// supposed to be
|
||||
final int motionViewRealTop = motionView.getTop();
|
||||
if (atEdge) {
|
||||
// Apply overscroll
|
||||
|
||||
int overscroll = -incrementalDeltaY -
|
||||
(motionViewRealTop - motionViewPrevTop);
|
||||
overScrollBy(0, overscroll, 0, mScrollY, 0, 0,
|
||||
0, mOverscrollDistance, true);
|
||||
if (Math.abs(mOverscrollDistance) == Math.abs(mScrollY)) {
|
||||
// Don't allow overfling if we're at the edge.
|
||||
if (mVelocityTracker != null) {
|
||||
mVelocityTracker.clear();
|
||||
}
|
||||
}
|
||||
|
||||
final int overscrollMode = getOverScrollMode();
|
||||
if (overscrollMode == OVER_SCROLL_ALWAYS ||
|
||||
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
|
||||
!contentFits())) {
|
||||
mDirection = 0; // Reset when entering overscroll.
|
||||
mTouchMode = TOUCH_MODE_OVERSCROLL;
|
||||
if (rawDeltaY > 0) {
|
||||
mEdgeGlowTop.onPull((float) overscroll / getHeight());
|
||||
if (!mEdgeGlowBottom.isFinished()) {
|
||||
mEdgeGlowBottom.onRelease();
|
||||
}
|
||||
} else if (rawDeltaY < 0) {
|
||||
mEdgeGlowBottom.onPull((float) overscroll / getHeight());
|
||||
if (!mEdgeGlowTop.isFinished()) {
|
||||
mEdgeGlowTop.onRelease();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mMotionY = y;
|
||||
invalidate();
|
||||
}
|
||||
mLastY = y;
|
||||
}
|
||||
} else if (mTouchMode == TOUCH_MODE_OVERSCROLL) {
|
||||
if (y != mLastY) {
|
||||
final int oldScroll = mScrollY;
|
||||
final int newScroll = oldScroll - incrementalDeltaY;
|
||||
int newDirection = y > mLastY ? 1 : -1;
|
||||
|
||||
if (mDirection == 0) {
|
||||
mDirection = newDirection;
|
||||
}
|
||||
|
||||
int overScrollDistance = -incrementalDeltaY;
|
||||
if ((newScroll < 0 && oldScroll >= 0) || (newScroll > 0 && oldScroll <= 0)) {
|
||||
overScrollDistance = -oldScroll;
|
||||
incrementalDeltaY += overScrollDistance;
|
||||
} else {
|
||||
incrementalDeltaY = 0;
|
||||
}
|
||||
|
||||
if (overScrollDistance != 0) {
|
||||
overScrollBy(0, overScrollDistance, 0, mScrollY, 0, 0,
|
||||
0, mOverscrollDistance, true);
|
||||
final int overscrollMode = getOverScrollMode();
|
||||
if (overscrollMode == OVER_SCROLL_ALWAYS ||
|
||||
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
|
||||
!contentFits())) {
|
||||
if (rawDeltaY > 0) {
|
||||
mEdgeGlowTop.onPull((float) overScrollDistance / getHeight());
|
||||
if (!mEdgeGlowBottom.isFinished()) {
|
||||
mEdgeGlowBottom.onRelease();
|
||||
}
|
||||
} else if (rawDeltaY < 0) {
|
||||
mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight());
|
||||
if (!mEdgeGlowTop.isFinished()) {
|
||||
mEdgeGlowTop.onRelease();
|
||||
}
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
if (incrementalDeltaY != 0) {
|
||||
// Coming back to 'real' list scrolling
|
||||
mScrollY = 0;
|
||||
invalidateParentIfNeeded();
|
||||
|
||||
// No need to do all this work if we're not going to move anyway
|
||||
if (incrementalDeltaY != 0) {
|
||||
trackMotionScroll(incrementalDeltaY, incrementalDeltaY);
|
||||
}
|
||||
|
||||
mTouchMode = TOUCH_MODE_SCROLL;
|
||||
|
||||
// We did not scroll the full amount. Treat this essentially like the
|
||||
// start of a new touch scroll
|
||||
final int motionPosition = findClosestMotionRow(y);
|
||||
|
||||
mMotionCorrection = 0;
|
||||
View motionView = getChildAt(motionPosition - mFirstPosition);
|
||||
mMotionViewOriginalTop = motionView != null ? motionView.getTop() : 0;
|
||||
mMotionY = y;
|
||||
mMotionPosition = motionPosition;
|
||||
}
|
||||
mLastY = y;
|
||||
mDirection = newDirection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onTouchModeChanged(boolean isInTouchMode) {
|
||||
if (isInTouchMode) {
|
||||
// Get rid of the selection when we enter touch mode
|
||||
@@ -2856,7 +3026,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
final int action = ev.getAction();
|
||||
|
||||
View v;
|
||||
int deltaY;
|
||||
|
||||
initVelocityTrackerIfNotExists();
|
||||
mVelocityTracker.addMovement(ev);
|
||||
@@ -2935,183 +3104,19 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
mActivePointerId = ev.getPointerId(pointerIndex);
|
||||
}
|
||||
final int y = (int) ev.getY(pointerIndex);
|
||||
deltaY = y - mMotionY;
|
||||
switch (mTouchMode) {
|
||||
case TOUCH_MODE_DOWN:
|
||||
case TOUCH_MODE_TAP:
|
||||
case TOUCH_MODE_DONE_WAITING:
|
||||
// Check if we have moved far enough that it looks more like a
|
||||
// scroll than a tap
|
||||
startScrollIfNeeded(deltaY);
|
||||
startScrollIfNeeded(y);
|
||||
break;
|
||||
case TOUCH_MODE_SCROLL:
|
||||
if (PROFILE_SCROLLING) {
|
||||
if (!mScrollProfilingStarted) {
|
||||
Debug.startMethodTracing("AbsListViewScroll");
|
||||
mScrollProfilingStarted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mScrollStrictSpan == null) {
|
||||
// If it's non-null, we're already in a scroll.
|
||||
mScrollStrictSpan = StrictMode.enterCriticalSpan("AbsListView-scroll");
|
||||
}
|
||||
|
||||
if (y != mLastY) {
|
||||
// We may be here after stopping a fling and continuing to scroll.
|
||||
// If so, we haven't disallowed intercepting touch events yet.
|
||||
// Make sure that we do so in case we're in a parent that can intercept.
|
||||
if ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) == 0 &&
|
||||
Math.abs(deltaY) > mTouchSlop) {
|
||||
final ViewParent parent = getParent();
|
||||
if (parent != null) {
|
||||
parent.requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
}
|
||||
|
||||
final int rawDeltaY = deltaY;
|
||||
deltaY -= mMotionCorrection;
|
||||
int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;
|
||||
|
||||
final int motionIndex;
|
||||
if (mMotionPosition >= 0) {
|
||||
motionIndex = mMotionPosition - mFirstPosition;
|
||||
} else {
|
||||
// If we don't have a motion position that we can reliably track,
|
||||
// pick something in the middle to make a best guess at things below.
|
||||
motionIndex = getChildCount() / 2;
|
||||
}
|
||||
|
||||
int motionViewPrevTop = 0;
|
||||
View motionView = this.getChildAt(motionIndex);
|
||||
if (motionView != null) {
|
||||
motionViewPrevTop = motionView.getTop();
|
||||
}
|
||||
|
||||
// No need to do all this work if we're not going to move anyway
|
||||
boolean atEdge = false;
|
||||
if (incrementalDeltaY != 0) {
|
||||
atEdge = trackMotionScroll(deltaY, incrementalDeltaY);
|
||||
}
|
||||
|
||||
// Check to see if we have bumped into the scroll limit
|
||||
motionView = this.getChildAt(motionIndex);
|
||||
if (motionView != null) {
|
||||
// Check if the top of the motion view is where it is
|
||||
// supposed to be
|
||||
final int motionViewRealTop = motionView.getTop();
|
||||
if (atEdge) {
|
||||
// Apply overscroll
|
||||
|
||||
int overscroll = -incrementalDeltaY -
|
||||
(motionViewRealTop - motionViewPrevTop);
|
||||
overScrollBy(0, overscroll, 0, mScrollY, 0, 0,
|
||||
0, mOverscrollDistance, true);
|
||||
if (Math.abs(mOverscrollDistance) == Math.abs(mScrollY)) {
|
||||
// Don't allow overfling if we're at the edge.
|
||||
if (mVelocityTracker != null) {
|
||||
mVelocityTracker.clear();
|
||||
}
|
||||
}
|
||||
|
||||
final int overscrollMode = getOverScrollMode();
|
||||
if (overscrollMode == OVER_SCROLL_ALWAYS ||
|
||||
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
|
||||
!contentFits())) {
|
||||
mDirection = 0; // Reset when entering overscroll.
|
||||
mTouchMode = TOUCH_MODE_OVERSCROLL;
|
||||
if (rawDeltaY > 0) {
|
||||
mEdgeGlowTop.onPull((float) overscroll / getHeight());
|
||||
if (!mEdgeGlowBottom.isFinished()) {
|
||||
mEdgeGlowBottom.onRelease();
|
||||
}
|
||||
} else if (rawDeltaY < 0) {
|
||||
mEdgeGlowBottom.onPull((float) overscroll / getHeight());
|
||||
if (!mEdgeGlowTop.isFinished()) {
|
||||
mEdgeGlowTop.onRelease();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mMotionY = y;
|
||||
invalidate();
|
||||
}
|
||||
mLastY = y;
|
||||
}
|
||||
break;
|
||||
|
||||
case TOUCH_MODE_OVERSCROLL:
|
||||
if (y != mLastY) {
|
||||
final int rawDeltaY = deltaY;
|
||||
deltaY -= mMotionCorrection;
|
||||
int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;
|
||||
|
||||
final int oldScroll = mScrollY;
|
||||
final int newScroll = oldScroll - incrementalDeltaY;
|
||||
int newDirection = y > mLastY ? 1 : -1;
|
||||
|
||||
if (mDirection == 0) {
|
||||
mDirection = newDirection;
|
||||
}
|
||||
|
||||
int overScrollDistance = -incrementalDeltaY;
|
||||
if ((newScroll < 0 && oldScroll >= 0) || (newScroll > 0 && oldScroll <= 0)) {
|
||||
overScrollDistance = -oldScroll;
|
||||
incrementalDeltaY += overScrollDistance;
|
||||
} else {
|
||||
incrementalDeltaY = 0;
|
||||
}
|
||||
|
||||
if (overScrollDistance != 0) {
|
||||
overScrollBy(0, overScrollDistance, 0, mScrollY, 0, 0,
|
||||
0, mOverscrollDistance, true);
|
||||
final int overscrollMode = getOverScrollMode();
|
||||
if (overscrollMode == OVER_SCROLL_ALWAYS ||
|
||||
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
|
||||
!contentFits())) {
|
||||
if (rawDeltaY > 0) {
|
||||
mEdgeGlowTop.onPull((float) overScrollDistance / getHeight());
|
||||
if (!mEdgeGlowBottom.isFinished()) {
|
||||
mEdgeGlowBottom.onRelease();
|
||||
}
|
||||
} else if (rawDeltaY < 0) {
|
||||
mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight());
|
||||
if (!mEdgeGlowTop.isFinished()) {
|
||||
mEdgeGlowTop.onRelease();
|
||||
}
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
if (incrementalDeltaY != 0) {
|
||||
// Coming back to 'real' list scrolling
|
||||
mScrollY = 0;
|
||||
invalidateParentIfNeeded();
|
||||
|
||||
// No need to do all this work if we're not going to move anyway
|
||||
if (incrementalDeltaY != 0) {
|
||||
trackMotionScroll(incrementalDeltaY, incrementalDeltaY);
|
||||
}
|
||||
|
||||
mTouchMode = TOUCH_MODE_SCROLL;
|
||||
|
||||
// We did not scroll the full amount. Treat this essentially like the
|
||||
// start of a new touch scroll
|
||||
final int motionPosition = findClosestMotionRow(y);
|
||||
|
||||
mMotionCorrection = 0;
|
||||
View motionView = getChildAt(motionPosition - mFirstPosition);
|
||||
mMotionViewOriginalTop = motionView != null ? motionView.getTop() : 0;
|
||||
mMotionY = y;
|
||||
mMotionPosition = motionPosition;
|
||||
}
|
||||
mLastY = y;
|
||||
mDirection = newDirection;
|
||||
}
|
||||
scrollIfNeeded(y);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3542,7 +3547,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
final int y = (int) ev.getY(pointerIndex);
|
||||
initVelocityTrackerIfNotExists();
|
||||
mVelocityTracker.addMovement(ev);
|
||||
if (startScrollIfNeeded(y - mMotionY)) {
|
||||
if (startScrollIfNeeded(y)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user