Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 13cdf67f authored by George Mount's avatar George Mount
Browse files

Add support for stretch overscroll to internal ViewPager

Bug: 171228096

The internal ViewPager now supports stretch overscroll.

Implementation taken from androidx-platform-dev ViewPager.

Test: manual testing with share sheet

Change-Id: If3db565e64d38d8e03319311ee5d4c07bdd4eff6
parent af1e8b4e
Loading
Loading
Loading
Loading
+75 −9
Original line number Diff line number Diff line
@@ -353,8 +353,8 @@ public class ViewPager extends ViewGroup {
        mTouchSlop = configuration.getScaledPagingTouchSlop();
        mMinimumVelocity = (int) (MIN_FLING_VELOCITY * density);
        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
        mLeftEdge = new EdgeEffect(context);
        mRightEdge = new EdgeEffect(context);
        mLeftEdge = new EdgeEffect(context, attrs);
        mRightEdge = new EdgeEffect(context, attrs);

        mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density);
        mCloseEnough = (int) (CLOSE_ENOUGH * density);
@@ -386,6 +386,28 @@ public class ViewPager extends ViewGroup {
        }
    }

    /**
     * Returns the {@link EdgeEffect#getType()} for the edge effects.
     * @return the {@link EdgeEffect#getType()} for the edge effects.
     * @attr ref android.R.styleable#EdgeEffect_edgeEffectType
     */
    @EdgeEffect.EdgeEffectType
    public int getEdgeEffectType() {
        // Both left and right edge have the same edge effect type
        return mLeftEdge.getType();
    }

    /**
     * Sets the {@link EdgeEffect#setType(int)} for the edge effects.
     * @param type The edge effect type to use for the edge effects.
     * @attr ref android.R.styleable#EdgeEffect_edgeEffectType
     */
    public void setEdgeEffectType(@EdgeEffect.EdgeEffectType int type) {
        mLeftEdge.setType(type);
        mRightEdge.setType(type);
        invalidate();
    }

    /**
     * Set a PagerAdapter that will supply views for this pager as needed.
     *
@@ -1891,7 +1913,7 @@ public class ViewPager extends ViewGroup {
                }
                if (mIsBeingDragged) {
                    // Scroll to follow the motion event
                    if (performDrag(x)) {
                    if (performDrag(x, y)) {
                        postInvalidateOnAnimation();
                    }
                }
@@ -1918,6 +1940,17 @@ public class ViewPager extends ViewGroup {
                    mIsBeingDragged = true;
                    requestParentDisallowInterceptTouchEvent(true);
                    setScrollState(SCROLL_STATE_DRAGGING);
                } else if (mLeftEdge.getDistance() != 0
                        || mRightEdge.getDistance() != 0) {
                    // Caught the edge glow animation
                    mIsBeingDragged = true;
                    setScrollState(SCROLL_STATE_DRAGGING);
                    if (mLeftEdge.getDistance() != 0) {
                        mLeftEdge.onPullDistance(0f, 1 - mLastMotionY / getHeight());
                    }
                    if (mRightEdge.getDistance() != 0) {
                        mRightEdge.onPullDistance(0f, mLastMotionY / getHeight());
                    }
                } else {
                    completeScroll(false);
                    mIsBeingDragged = false;
@@ -2009,7 +2042,7 @@ public class ViewPager extends ViewGroup {
                    // Scroll to follow the motion event
                    final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
                    final float x = ev.getX(activePointerIndex);
                    needsInvalidate |= performDrag(x);
                    needsInvalidate |= performDrag(x, ev.getY(activePointerIndex));
                }
                break;
            case MotionEvent.ACTION_UP:
@@ -2080,12 +2113,43 @@ public class ViewPager extends ViewGroup {
        }
    }

    private boolean performDrag(float x) {
    /**
     * If either of the horizontal edge glows are currently active, this consumes part or all of
     * deltaX on the edge glow.
     *
     * @param deltaX The pointer motion, in pixels, in the horizontal direction, positive
     *                         for moving down and negative for moving up.
     * @param y The vertical position of the pointer.
     * @return The amount of <code>deltaX</code> that has been consumed by the
     * edge glow.
     */
    private float releaseHorizontalGlow(float deltaX, float y) {
        // First allow releasing existing overscroll effect:
        float consumed = 0;
        float displacement = y / getHeight();
        float pullDistance = (float) deltaX / getWidth();
        if (mLeftEdge.getDistance() != 0) {
            consumed = -mLeftEdge.onPullDistance(-pullDistance, 1 - displacement);
        } else if (mRightEdge.getDistance() != 0) {
            consumed = mRightEdge.onPullDistance(pullDistance, displacement);
        }
        return consumed * getWidth();
    }

    private boolean performDrag(float x, float y) {
        boolean needsInvalidate = false;

        final float dX = mLastMotionX - x;
        final int width = getPaddedWidth();
        final float deltaX = mLastMotionX - x;
        mLastMotionX = x;
        final float releaseConsumed = releaseHorizontalGlow(dX, y);
        final float deltaX = dX - releaseConsumed;
        if (releaseConsumed != 0) {
            needsInvalidate = true;
        }
        if (Math.abs(deltaX) < 0.0001f) { // ignore rounding errors from releaseHorizontalGlow()
            return needsInvalidate;
        }

        final EdgeEffect startEdge;
        final EdgeEffect endEdge;
@@ -2128,14 +2192,14 @@ public class ViewPager extends ViewGroup {
        if (scrollStart < startBound) {
            if (startAbsolute) {
                final float over = startBound - scrollStart;
                startEdge.onPull(Math.abs(over) / width);
                startEdge.onPullDistance(over / width, 1 - y / getHeight());
                needsInvalidate = true;
            }
            clampedScrollStart = startBound;
        } else if (scrollStart > endBound) {
            if (endAbsolute) {
                final float over = scrollStart - endBound;
                endEdge.onPull(Math.abs(over) / width);
                endEdge.onPullDistance(over / width, y / getHeight());
                needsInvalidate = true;
            }
            clampedScrollStart = endBound;
@@ -2228,7 +2292,9 @@ public class ViewPager extends ViewGroup {
     */
    private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) {
        int targetPage;
        if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) {
        if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity
                && mLeftEdge.getDistance() == 0 // don't fling while stretched
                && mRightEdge.getDistance() == 0) {
            targetPage = currentPage - (velocity < 0 ? mLeftIncr : 0);
        } else {
            final float truncator = currentPage >= mCurItem ? 0.4f : 0.6f;