summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/widget/AbsListView.java194
1 files changed, 129 insertions, 65 deletions
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index e740cc2b1f7a..1afa54d9717f 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -715,7 +715,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*/
@NonNull
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769408)
- private EdgeEffect mEdgeGlowTop = new EdgeEffect(mContext);
+ private EdgeEffect mEdgeGlowTop;
/**
* Tracks the state of the bottom edge glow.
@@ -725,7 +725,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*/
@NonNull
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768444)
- private EdgeEffect mEdgeGlowBottom = new EdgeEffect(mContext);
+ private EdgeEffect mEdgeGlowBottom;
/**
* An estimate of how many pixels are between the top of the list and
@@ -847,6 +847,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
public AbsListView(Context context) {
super(context);
+ mEdgeGlowBottom = new EdgeEffect(context);
+ mEdgeGlowTop = new EdgeEffect(context);
initAbsListView();
mOwnerThread = Thread.currentThread();
@@ -867,6 +869,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
public AbsListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ mEdgeGlowBottom = new EdgeEffect(context, attrs);
+ mEdgeGlowTop = new EdgeEffect(context, attrs);
initAbsListView();
mOwnerThread = Thread.currentThread();
@@ -3584,6 +3588,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mLastY != Integer.MIN_VALUE ? y - mLastY + scrollConsumedCorrection : deltaY;
int lastYCorrection = 0;
+ // First allow releasing existing overscroll effect:
+ incrementalDeltaY = releaseGlow(incrementalDeltaY, x);
+
if (mTouchMode == TOUCH_MODE_SCROLL) {
if (PROFILE_SCROLLING) {
if (!mScrollProfilingStarted) {
@@ -3666,14 +3673,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mTouchMode = TOUCH_MODE_OVERSCROLL;
}
if (incrementalDeltaY > 0) {
- mEdgeGlowTop.onPull((float) -overscroll / getHeight(),
+ mEdgeGlowTop.onPullDistance((float) -overscroll / getHeight(),
(float) x / getWidth());
if (!mEdgeGlowBottom.isFinished()) {
mEdgeGlowBottom.onRelease();
}
invalidateTopGlow();
} else if (incrementalDeltaY < 0) {
- mEdgeGlowBottom.onPull((float) overscroll / getHeight(),
+ mEdgeGlowBottom.onPullDistance((float) overscroll / getHeight(),
1.f - (float) x / getWidth());
if (!mEdgeGlowTop.isFinished()) {
mEdgeGlowTop.onRelease();
@@ -3713,14 +3720,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
!contentFits())) {
if (rawDeltaY > 0) {
- mEdgeGlowTop.onPull((float) overScrollDistance / getHeight(),
+ mEdgeGlowTop.onPullDistance((float) overScrollDistance / getHeight(),
(float) x / getWidth());
if (!mEdgeGlowBottom.isFinished()) {
mEdgeGlowBottom.onRelease();
}
invalidateTopGlow();
} else if (rawDeltaY < 0) {
- mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight(),
+ mEdgeGlowBottom.onPullDistance(
+ (float) -overScrollDistance / getHeight(),
1.f - (float) x / getWidth());
if (!mEdgeGlowTop.isFinished()) {
mEdgeGlowTop.onRelease();
@@ -3757,6 +3765,44 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
}
+ /**
+ * If the edge glow is currently active, this consumes part or all of deltaY
+ * on the edge glow.
+ *
+ * @param deltaY The pointer motion, in pixels, in the vertical direction, positive
+ * for moving down and negative for moving up.
+ * @param x The horizontal position of the pointer.
+ * @return The remainder of <code>deltaY</code> that has not been consumed by the
+ * edge glow.
+ */
+ private int releaseGlow(int deltaY, int x) {
+ // First allow releasing existing overscroll effect:
+ float consumed = 0;
+ if (mEdgeGlowTop.getDistance() != 0) {
+ consumed = mEdgeGlowTop.onPullDistance((float) deltaY / getHeight(),
+ (float) x / getWidth());
+ if (consumed != 0f) {
+ invalidateTopGlow();
+ }
+ } else if (mEdgeGlowBottom.getDistance() != 0) {
+ consumed = -mEdgeGlowBottom.onPullDistance((float) -deltaY / getHeight(),
+ 1f - (float) x / getWidth());
+ if (consumed != 0f) {
+ invalidateBottomGlow();
+ }
+ }
+ int pixelsConsumed = Math.round(consumed * getHeight());
+ return deltaY - pixelsConsumed;
+ }
+
+ /**
+ * @return <code>true</code> if either the top or bottom edge glow is currently active or
+ * <code>false</code> if it has no value to release.
+ */
+ private boolean isGlowActive() {
+ return mEdgeGlowBottom.getDistance() != 0 || mEdgeGlowTop.getDistance() != 0;
+ }
+
private void invalidateTopGlow() {
if (!shouldDisplayEdgeEffects()) {
return;
@@ -3926,7 +3972,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (mTouchMode == TOUCH_MODE_OVERFLING) {
// Stopped the fling. It is a scroll.
- mFlingRunnable.endFling();
+ if (mFlingRunnable != null) {
+ mFlingRunnable.endFling();
+ }
if (mPositionScroller != null) {
mPositionScroller.stop();
}
@@ -3936,6 +3984,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mLastY = mMotionY;
mMotionCorrection = 0;
mDirection = 0;
+ stopEdgeGlowRecede(ev.getX());
} else {
final int x = (int) ev.getX();
final int y = (int) ev.getY();
@@ -3948,7 +3997,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mTouchMode = TOUCH_MODE_SCROLL;
mMotionCorrection = 0;
motionPosition = findMotionRow(y);
- mFlingRunnable.flywheelTouch();
+ if (mFlingRunnable != null) {
+ mFlingRunnable.flywheelTouch();
+ }
+ stopEdgeGlowRecede(x);
} else if ((motionPosition >= 0) && getAdapter().isEnabled(motionPosition)) {
// User clicked on an actual view (and was not stopping a
// fling). It might be a click or a scroll. Assume it is a
@@ -3984,6 +4036,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
}
+ private void stopEdgeGlowRecede(float x) {
+ if (mEdgeGlowTop.getDistance() != 0) {
+ mEdgeGlowTop.onPullDistance(0, x / getWidth());
+ }
+ if (mEdgeGlowBottom.getDistance() != 0) {
+ mEdgeGlowBottom.onPullDistance(0, x / getWidth());
+ }
+ }
+
private void onTouchMove(MotionEvent ev, MotionEvent vtev) {
if (mHasPerformedLongPress) {
// Consume all move events following a successful long press.
@@ -4489,73 +4550,76 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
switch (actionMasked) {
- case MotionEvent.ACTION_DOWN: {
- int touchMode = mTouchMode;
- if (touchMode == TOUCH_MODE_OVERFLING || touchMode == TOUCH_MODE_OVERSCROLL) {
- mMotionCorrection = 0;
- return true;
- }
-
- final int x = (int) ev.getX();
- final int y = (int) ev.getY();
- mActivePointerId = ev.getPointerId(0);
+ case MotionEvent.ACTION_DOWN: {
+ int touchMode = mTouchMode;
+ if (touchMode == TOUCH_MODE_OVERFLING || touchMode == TOUCH_MODE_OVERSCROLL) {
+ mMotionCorrection = 0;
+ return true;
+ }
- int motionPosition = findMotionRow(y);
- if (touchMode != TOUCH_MODE_FLING && motionPosition >= 0) {
- // User clicked on an actual view (and was not stopping a fling).
- // Remember where the motion event started
- v = getChildAt(motionPosition - mFirstPosition);
- mMotionViewOriginalTop = v.getTop();
- mMotionX = x;
- mMotionY = y;
- mMotionPosition = motionPosition;
- mTouchMode = TOUCH_MODE_DOWN;
- clearScrollingCache();
- }
- mLastY = Integer.MIN_VALUE;
- initOrResetVelocityTracker();
- mVelocityTracker.addMovement(ev);
- mNestedYOffset = 0;
- startNestedScroll(SCROLL_AXIS_VERTICAL);
- if (touchMode == TOUCH_MODE_FLING) {
- return true;
- }
- break;
- }
+ final int x = (int) ev.getX();
+ final int y = (int) ev.getY();
+ mActivePointerId = ev.getPointerId(0);
- case MotionEvent.ACTION_MOVE: {
- switch (mTouchMode) {
- case TOUCH_MODE_DOWN:
- int pointerIndex = ev.findPointerIndex(mActivePointerId);
- if (pointerIndex == -1) {
- pointerIndex = 0;
- mActivePointerId = ev.getPointerId(pointerIndex);
+ int motionPosition = findMotionRow(y);
+ if (isGlowActive()) {
+ // Pressed during edge effect, so this is considered the same as a fling catch.
+ mTouchMode = TOUCH_MODE_FLING;
+ } else if (touchMode != TOUCH_MODE_FLING && motionPosition >= 0) {
+ // User clicked on an actual view (and was not stopping a fling).
+ // Remember where the motion event started
+ v = getChildAt(motionPosition - mFirstPosition);
+ mMotionViewOriginalTop = v.getTop();
+ mMotionX = x;
+ mMotionY = y;
+ mMotionPosition = motionPosition;
+ mTouchMode = TOUCH_MODE_DOWN;
+ clearScrollingCache();
}
- final int y = (int) ev.getY(pointerIndex);
- initVelocityTrackerIfNotExists();
+ mLastY = Integer.MIN_VALUE;
+ initOrResetVelocityTracker();
mVelocityTracker.addMovement(ev);
- if (startScrollIfNeeded((int) ev.getX(pointerIndex), y, null)) {
+ mNestedYOffset = 0;
+ startNestedScroll(SCROLL_AXIS_VERTICAL);
+ if (touchMode == TOUCH_MODE_FLING) {
return true;
}
break;
}
- break;
- }
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP: {
- mTouchMode = TOUCH_MODE_REST;
- mActivePointerId = INVALID_POINTER;
- recycleVelocityTracker();
- reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
- stopNestedScroll();
- break;
- }
+ case MotionEvent.ACTION_MOVE: {
+ switch (mTouchMode) {
+ case TOUCH_MODE_DOWN:
+ int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ if (pointerIndex == -1) {
+ pointerIndex = 0;
+ mActivePointerId = ev.getPointerId(pointerIndex);
+ }
+ final int y = (int) ev.getY(pointerIndex);
+ initVelocityTrackerIfNotExists();
+ mVelocityTracker.addMovement(ev);
+ if (startScrollIfNeeded((int) ev.getX(pointerIndex), y, null)) {
+ return true;
+ }
+ break;
+ }
+ break;
+ }
- case MotionEvent.ACTION_POINTER_UP: {
- onSecondaryPointerUp(ev);
- break;
- }
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP: {
+ mTouchMode = TOUCH_MODE_REST;
+ mActivePointerId = INVALID_POINTER;
+ recycleVelocityTracker();
+ reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
+ stopNestedScroll();
+ break;
+ }
+
+ case MotionEvent.ACTION_POINTER_UP: {
+ onSecondaryPointerUp(ev);
+ break;
+ }
}
return false;