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

Commit 97f04fe7 authored by George Mount's avatar George Mount
Browse files

ScrollView and HorizontalScrollView stretch overscroll

Bug: 178807038

Modify ScrollView and HorizontalScrollView to support
stretch overscroll.

Test: I18820794f2511ff4b7df1c5c6a9d7a2d5fafeaa0
Change-Id: I1370b702ce7331269744033c6acb61b84519c853
parent f1de89b1
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -22164,6 +22164,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     * and hardware acceleration.
     */
    boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
        // Clear the overscroll effect:
        // TODO: Use internal API instead of overriding the existing RenderEffect
        setRenderEffect(null);
        final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated();
        /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList.
         *
+35 −10
Original line number Diff line number Diff line
@@ -89,7 +89,7 @@ public class HorizontalScrollView extends FrameLayout {
     */
    @NonNull
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124053130)
    private EdgeEffect mEdgeGlowLeft = new EdgeEffect(getContext());
    private EdgeEffect mEdgeGlowLeft;

    /**
     * Tracks the state of the bottom edge glow.
@@ -98,7 +98,7 @@ public class HorizontalScrollView extends FrameLayout {
     * setting it via reflection and they need to keep working until they target Q.
     */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124052619)
    private EdgeEffect mEdgeGlowRight = new EdgeEffect(getContext());
    private EdgeEffect mEdgeGlowRight;

    /**
     * Position of the last motion event.
@@ -186,6 +186,8 @@ public class HorizontalScrollView extends FrameLayout {
    public HorizontalScrollView(
            Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        mEdgeGlowLeft = new EdgeEffect(context, attrs);
        mEdgeGlowRight = new EdgeEffect(context, attrs);
        initScrollView();

        final TypedArray a = context.obtainStyledAttributes(
@@ -631,7 +633,15 @@ public class HorizontalScrollView extends FrameLayout {
                * otherwise don't.  mScroller.isFinished should be false when
                * being flinged.
                */
                mIsBeingDragged = !mScroller.isFinished();
                mIsBeingDragged = !mScroller.isFinished() || !mEdgeGlowLeft.isFinished()
                        || !mEdgeGlowRight.isFinished();
                // Catch the edge effect if it is active.
                if (!mEdgeGlowLeft.isFinished()) {
                    mEdgeGlowLeft.onPullDistance(0f, 1f - ev.getY() / getHeight());
                }
                if (!mEdgeGlowRight.isFinished()) {
                    mEdgeGlowRight.onPullDistance(0f, ev.getY() / getHeight());
                }
                break;
            }

@@ -675,7 +685,8 @@ public class HorizontalScrollView extends FrameLayout {
                if (getChildCount() == 0) {
                    return false;
                }
                if ((mIsBeingDragged = !mScroller.isFinished())) {
                if ((mIsBeingDragged = !mScroller.isFinished() || !mEdgeGlowRight.isFinished()
                        || !mEdgeGlowLeft.isFinished())) {
                    final ViewParent parent = getParent();
                    if (parent != null) {
                        parent.requestDisallowInterceptTouchEvent(true);
@@ -721,12 +732,26 @@ public class HorizontalScrollView extends FrameLayout {
                    mLastMotionX = x;

                    final int oldX = mScrollX;
                    final int oldY = mScrollY;
                    final int range = getScrollRange();
                    final int overscrollMode = getOverScrollMode();
                    final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
                            (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);

                    final float displacement = ev.getY(activePointerIndex) / getHeight();
                    if (canOverscroll) {
                        int consumed = 0;
                        if (deltaX < 0 && mEdgeGlowRight.getDistance() != 0f) {
                            consumed = Math.round(getHeight()
                                    * mEdgeGlowRight.onPullDistance((float) deltaX / getWidth(),
                                    displacement));
                        } else if (deltaX > 0 && mEdgeGlowLeft.getDistance() != 0f) {
                            consumed = Math.round(-getHeight()
                                    * mEdgeGlowLeft.onPullDistance((float) -deltaX / getWidth(),
                                    1 - displacement));
                        }
                        deltaX -= consumed;
                    }

                    // Calling overScrollBy will call onOverScrolled, which
                    // calls onScrollChanged if applicable.
                    if (overScrollBy(deltaX, 0, mScrollX, 0, range, 0,
@@ -735,17 +760,17 @@ public class HorizontalScrollView extends FrameLayout {
                        mVelocityTracker.clear();
                    }

                    if (canOverscroll) {
                    if (canOverscroll && deltaX != 0f) {
                        final int pulledToX = oldX + deltaX;
                        if (pulledToX < 0) {
                            mEdgeGlowLeft.onPull((float) deltaX / getWidth(),
                                    1.f - ev.getY(activePointerIndex) / getHeight());
                            mEdgeGlowLeft.onPullDistance((float) -deltaX / getWidth(),
                                    1.f - displacement);
                            if (!mEdgeGlowRight.isFinished()) {
                                mEdgeGlowRight.onRelease();
                            }
                        } else if (pulledToX > range) {
                            mEdgeGlowRight.onPull((float) deltaX / getWidth(),
                                    ev.getY(activePointerIndex) / getHeight());
                            mEdgeGlowRight.onPullDistance((float) deltaX / getWidth(),
                                    displacement);
                            if (!mEdgeGlowLeft.isFinished()) {
                                mEdgeGlowLeft.onRelease();
                            }
+35 −9
Original line number Diff line number Diff line
@@ -98,7 +98,7 @@ public class ScrollView extends FrameLayout {
     */
    @NonNull
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768600)
    private EdgeEffect mEdgeGlowTop = new EdgeEffect(getContext());
    private EdgeEffect mEdgeGlowTop;

    /**
     * Tracks the state of the bottom edge glow.
@@ -108,7 +108,7 @@ public class ScrollView extends FrameLayout {
     */
    @NonNull
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769386)
    private EdgeEffect mEdgeGlowBottom = new EdgeEffect(getContext());
    private EdgeEffect mEdgeGlowBottom;

    /**
     * Position of the last motion event.
@@ -213,6 +213,8 @@ public class ScrollView extends FrameLayout {

    public ScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        mEdgeGlowTop = new EdgeEffect(context, attrs);
        mEdgeGlowBottom = new EdgeEffect(context, attrs);
        initScrollView();

        final TypedArray a = context.obtainStyledAttributes(
@@ -679,7 +681,15 @@ public class ScrollView extends FrameLayout {
                 * isFinished() is correct.
                */
                mScroller.computeScrollOffset();
                mIsBeingDragged = !mScroller.isFinished();
                mIsBeingDragged = !mScroller.isFinished() || !mEdgeGlowBottom.isFinished()
                    || !mEdgeGlowTop.isFinished();
                // Catch the edge effect if it is active.
                if (!mEdgeGlowTop.isFinished()) {
                    mEdgeGlowTop.onPullDistance(0f, ev.getX() / getWidth());
                }
                if (!mEdgeGlowBottom.isFinished()) {
                    mEdgeGlowBottom.onPullDistance(0f, 1f - ev.getX() / getWidth());
                }
                if (mIsBeingDragged && mScrollStrictSpan == null) {
                    mScrollStrictSpan = StrictMode.enterCriticalSpan("ScrollView-scroll");
                }
@@ -732,7 +742,8 @@ public class ScrollView extends FrameLayout {
                if (getChildCount() == 0) {
                    return false;
                }
                if ((mIsBeingDragged = !mScroller.isFinished())) {
                if ((mIsBeingDragged = !mScroller.isFinished() || !mEdgeGlowTop.isFinished()
                        || !mEdgeGlowBottom.isFinished())) {
                    final ViewParent parent = getParent();
                    if (parent != null) {
                        parent.requestDisallowInterceptTouchEvent(true);
@@ -793,6 +804,21 @@ public class ScrollView extends FrameLayout {
                    boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
                            (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);

                    final float displacement = ev.getX(activePointerIndex) / getWidth();
                    if (canOverscroll) {
                        int consumed = 0;
                        if (deltaY < 0 && mEdgeGlowBottom.getDistance() != 0f) {
                            consumed = Math.round(getHeight()
                                    * mEdgeGlowBottom.onPullDistance((float) deltaY / getHeight(),
                                    1 - displacement));
                        } else if (deltaY > 0 && mEdgeGlowTop.getDistance() != 0f) {
                            consumed = Math.round(-getHeight()
                                    * mEdgeGlowTop.onPullDistance((float) -deltaY / getHeight(),
                                    displacement));
                        }
                        deltaY -= consumed;
                    }

                    // Calling overScrollBy will call onOverScrolled, which
                    // calls onScrollChanged if applicable.
                    if (overScrollBy(0, deltaY, 0, mScrollY, 0, range, 0, mOverscrollDistance, true)
@@ -807,17 +833,17 @@ public class ScrollView extends FrameLayout {
                        mLastMotionY -= mScrollOffset[1];
                        vtev.offsetLocation(0, mScrollOffset[1]);
                        mNestedYOffset += mScrollOffset[1];
                    } else if (canOverscroll) {
                    } else if (canOverscroll && deltaY != 0f) {
                        final int pulledToY = oldY + deltaY;
                        if (pulledToY < 0) {
                            mEdgeGlowTop.onPull((float) deltaY / getHeight(),
                                    ev.getX(activePointerIndex) / getWidth());
                            mEdgeGlowTop.onPullDistance((float) -deltaY / getHeight(),
                                    displacement);
                            if (!mEdgeGlowBottom.isFinished()) {
                                mEdgeGlowBottom.onRelease();
                            }
                        } else if (pulledToY > range) {
                            mEdgeGlowBottom.onPull((float) deltaY / getHeight(),
                                    1.f - ev.getX(activePointerIndex) / getWidth());
                            mEdgeGlowBottom.onPullDistance((float) deltaY / getHeight(),
                                    1.f - displacement);
                            if (!mEdgeGlowTop.isFinished()) {
                                mEdgeGlowTop.onRelease();
                            }