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

Commit 79ac3395 authored by Adam Powell's avatar Adam Powell
Browse files

Overscrolling in AbsListView; visibility cleanup for FlingRunnable

parent a7bc87cb
Loading
Loading
Loading
Loading
+268 −111
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.widget;

import com.android.internal.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
@@ -30,6 +32,7 @@ import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
@@ -41,14 +44,12 @@ import android.view.ViewConfiguration;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionWrapper;
import android.view.inputmethod.InputMethodManager;
import android.view.ContextMenu.ContextMenuInfo;

import com.android.internal.R;

import java.util.ArrayList;
import java.util.List;
@@ -126,6 +127,17 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
     */
    static final int TOUCH_MODE_FLING = 4;

    /**
     * Indicates the touch gesture is an overscroll - a scroll beyond the beginning or end.
     */
    static final int TOUCH_MODE_OVERSCROLL = 5;
    
    /**
     * Indicates the view is being flung outside of normal content bounds
     * and will spring back.
     */
    static final int TOUCH_MODE_OVERFLING = 6;

    /**
     * Regular layout - usually an unsolicited layout from the view system
     */
@@ -1915,6 +1927,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                mLayoutMode = LAYOUT_NORMAL;
                layoutChildren();
            }
        } else {
            int touchMode = mTouchMode;
            if (touchMode == TOUCH_MODE_OVERSCROLL || touchMode == TOUCH_MODE_OVERFLING) {
                mScrollY = 0;
                if (mFlingRunnable != null) {
                    mFlingRunnable.endFling();
                }
            }
        }
    }

@@ -1947,6 +1967,16 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te

        switch (action) {
        case MotionEvent.ACTION_DOWN: {
            switch (mTouchMode) {
            case TOUCH_MODE_OVERFLING: {
                mFlingRunnable.endFling();
                mTouchMode = TOUCH_MODE_OVERSCROLL;
                mLastY = y;
                mMotionCorrection = 0;
                break;
            }
            
            default: {
                int motionPosition = pointToPosition(x, y);
                if (!mDataChanged) {
                    if ((mTouchMode != TOUCH_MODE_FLING) && (motionPosition >= 0)
@@ -1986,6 +2016,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                mLastY = Integer.MIN_VALUE;
                break;
            }
            }
            break;
        }

        case MotionEvent.ACTION_MOVE: {
            deltaY = y - mMotionY;
@@ -2008,17 +2041,61 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                if (y != mLastY) {
                    deltaY -= mMotionCorrection;
                    int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;
                    
                    int motionViewPrevTop = 0;
                    View motionView = this.getChildAt(mMotionPosition - mFirstPosition);
                    if (motionView != null) {
                        motionViewPrevTop = motionView.getTop();
                    }
                    // No need to do all this work if we're not going to move anyway
                    if (incrementalDeltaY != 0) {
                        trackMotionScroll(deltaY, incrementalDeltaY);
                    }

                    // Check to see if we have bumped into the scroll limit
                    View motionView = this.getChildAt(mMotionPosition - mFirstPosition);
                    motionView = this.getChildAt(mMotionPosition - mFirstPosition);
                    if (motionView != null) {
                        // Check if the top of the motion view is where it is
                        // supposed to be
                        if (motionView.getTop() != mMotionViewNewTop) {
                        final int motionViewRealTop = motionView.getTop();
                        final int motionViewNewTop = mMotionViewNewTop;
                        if (motionViewRealTop != motionViewNewTop) {
                            // Apply overscroll
                            
                            mScrollY -= incrementalDeltaY - (motionViewRealTop - motionViewPrevTop);
                            mTouchMode = TOUCH_MODE_OVERSCROLL;
                            invalidate();
                        }
                    }
                    mLastY = y;
                }
                break;
                
            case TOUCH_MODE_OVERSCROLL:
                if (y != mLastY) {
                    deltaY -= mMotionCorrection;
                    int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;
                    
                    final int oldScroll = mScrollY;
                    final int newScroll = oldScroll - incrementalDeltaY; 
                    
                    if ((oldScroll >= 0 && newScroll <= 0) ||
                            (oldScroll <= 0 && newScroll >= 0)) {
                        // Coming back to 'real' list scrolling
                        incrementalDeltaY = -newScroll;
                        mScrollY = 0;
                        
                        // No need to do all this work if we're not going to move anyway
                        if (incrementalDeltaY != 0) {
                            trackMotionScroll(incrementalDeltaY, incrementalDeltaY);
                        }

                        // Check to see if we are back in 
                        View motionView = this.getChildAt(mMotionPosition - mFirstPosition);
                        if (motionView != null) {
                            int topOffset = motionView.getTop() - mMotionViewNewTop;
                            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 = findMotionRow(y);
@@ -2029,6 +2106,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                            mMotionY = y;
                            mMotionPosition = motionPosition;
                        }
                    } else {
                        mScrollY -= incrementalDeltaY;
                        invalidate();
                    }
                    mLastY = y;
                }
@@ -2120,6 +2200,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                                mFlingRunnable = new FlingRunnable();
                            }
                            reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
                            
                            mFlingRunnable.start(-initialVelocity);
                        } else {
                            mTouchMode = TOUCH_MODE_REST;
@@ -2130,6 +2211,24 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                    mTouchMode = TOUCH_MODE_REST;
                    reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
                }
                break;
                
            case TOUCH_MODE_OVERSCROLL:
                if (mFlingRunnable == null) {
                    mFlingRunnable = new FlingRunnable();
                }
                final VelocityTracker velocityTracker = mVelocityTracker;
                velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                final int initialVelocity = (int) velocityTracker.getYVelocity();

                reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
                if (Math.abs(initialVelocity) > mMinimumVelocity) {
                    mFlingRunnable.startOverfling(-initialVelocity);
                } else {
                    mFlingRunnable.startSpringback();
                }

                break;
            }

            setPressed(false);
@@ -2157,6 +2256,19 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
        }

        case MotionEvent.ACTION_CANCEL: {
            switch (mTouchMode) {
            case TOUCH_MODE_OVERSCROLL:
                if (mFlingRunnable == null) {
                    mFlingRunnable = new FlingRunnable();
                }
                mFlingRunnable.startSpringback();
                break;
                
            case TOUCH_MODE_OVERFLING:
                // Do nothing - let it play out.
                break;
                
            default:
                mTouchMode = TOUCH_MODE_REST;
                setPressed(false);
                View motionView = this.getChildAt(mMotionPosition - mFirstPosition);
@@ -2175,7 +2287,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                    mVelocityTracker = null;
                }
            }

        }
        }

        return true;
@@ -2205,8 +2317,13 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te

        switch (action) {
        case MotionEvent.ACTION_DOWN: {
            int touchMode = mTouchMode;
            if (touchMode == TOUCH_MODE_OVERFLING || touchMode == TOUCH_MODE_OVERSCROLL) {
                return true;
            }
            
            int motionPosition = findMotionRow(y);
            if (mTouchMode != TOUCH_MODE_FLING && motionPosition >= 0) {
            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);
@@ -2218,7 +2335,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                clearScrollingCache();
            }
            mLastY = Integer.MIN_VALUE;
            if (mTouchMode == TOUCH_MODE_FLING) {
            if (touchMode == TOUCH_MODE_FLING) {
                return true;
            }
            break;
@@ -2293,18 +2410,18 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
        /**
         * Tracks the decay of a fling scroll
         */
        private Scroller mScroller;
        private OverScroller mScroller;

        /**
         * Y value reported by mScroller on the previous fling
         */
        private int mLastFlingY;

        public FlingRunnable() {
            mScroller = new Scroller(getContext());
        FlingRunnable() {
            mScroller = new OverScroller(getContext());
        }

        public void start(int initialVelocity) {
        void start(int initialVelocity) {
            int initialY = initialVelocity < 0 ? Integer.MAX_VALUE : 0;
            mLastFlingY = initialY;
            mScroller.fling(0, initialY, 0, initialVelocity,
@@ -2320,23 +2437,40 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
            }
        }
        
        void startSpringback() {
            if (mScroller.springback(0, mScrollY, 0, 0, 0, 0)) {
                mTouchMode = TOUCH_MODE_OVERFLING;
                invalidate();
                post(this);
            }
        }
        
        void startOverfling(int initialVelocity) {
            mScroller.fling(0, mScrollY, 0, initialVelocity, 0, 0, 0, 0, 0, getHeight());
            mTouchMode = TOUCH_MODE_OVERFLING;
            invalidate();
            post(this);
        }
        
        private void endFling() {
            mTouchMode = TOUCH_MODE_REST;
            reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
            clearScrollingCache();
            removeCallbacks(this);
        }

        public void run() {
            if (mTouchMode != TOUCH_MODE_FLING) {
            switch (mTouchMode) {
            default:
                return;
            }
                
            case TOUCH_MODE_FLING: {
                if (mItemCount == 0 || getChildCount() == 0) {
                    endFling();
                    return;
                }

            final Scroller scroller = mScroller;
                final OverScroller scroller = mScroller;
                boolean more = scroller.computeScrollOffset();
                final int y = scroller.getCurrY();

@@ -2365,6 +2499,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                    delta = Math.max(-(getHeight() - mPaddingBottom - mPaddingTop - 1), delta);
                }

                // Do something different on overscroll - offsetChildrenTopAndBottom()
                trackMotionScroll(delta, delta);

                // Check to see if we have bumped into the scroll limit
@@ -2373,7 +2508,12 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                    // Check if the top of the motion view is where it is
                    // supposed to be
                    if (motionView.getTop() != mMotionViewNewTop) {
                   more = false;
                       float vel = scroller.getCurrVelocity();
                       if (delta > 0) {
                           vel = -vel;
                       }
                       startOverfling(Math.round(vel));
                       break;
                    }
                }

@@ -2383,6 +2523,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                    post(this);
                } else {
                    endFling();
                    
                    if (PROFILE_FLINGING) {
                        if (mFlingProfilingStarted) {
                            Debug.stopMethodTracing();
@@ -2390,6 +2531,22 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                        }
                    }
                }
                break;
            }
                
            case TOUCH_MODE_OVERFLING: {
                final OverScroller scroller = mScroller;
                if (scroller.computeScrollOffset()) {
                    mScrollY = scroller.getCurrY();
                    invalidate();
                    post(this);
                } else {
                    endFling();
                }
                break;
            }
            }

        }
    }

+11 −0
Original line number Diff line number Diff line
@@ -383,4 +383,15 @@ public class OverScroller {
    public int getFinalY() {
        return mCurrScroller.getFinalY();
    }
    
    /**
     * @hide
     * Returns the current velocity.
     *
     * @return The original velocity less the deceleration. Result may be
     * negative.
     */
    public float getCurrVelocity() {
        return mCurrScroller.getCurrVelocity();
    }
}