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

Commit 9d849a2f authored by Romain Guy's avatar Romain Guy
Browse files

Optimize invalidate calls in lists.

AbsListView was doing too many invalidates during scrolls/flings.
Some of them were also covering too large an area of the screen.

Change-Id: I68fe5dda3657bddd673996e7cf4f3c3672c66cfc
parent 390f882f
Loading
Loading
Loading
Loading
+57 −35
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
        ViewTreeObserver.OnTouchModeChangeListener,
        RemoteViewsAdapter.RemoteAdapterConnectionCallback {

    @SuppressWarnings("UnusedDeclaration")
    private static final String TAG = "AbsListView";

    /**
@@ -2429,7 +2430,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
        final ViewTreeObserver treeObserver = getViewTreeObserver();
        treeObserver.removeOnTouchModeChangeListener(this);
        if (mTextFilterEnabled && mPopup != null) {
            treeObserver.removeGlobalOnLayoutListener(this);
            treeObserver.removeOnGlobalLayoutListener(this);
            mGlobalLayoutListenerAddedFilter = false;
        }

@@ -2943,11 +2944,23 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                            mDirection = 0; // Reset when entering overscroll.
                            mTouchMode = TOUCH_MODE_OVERSCROLL;
                            if (rawDeltaY > 0) {
                                if (!mEdgeGlowTop.isIdle()) {
                                    invalidate(mEdgeGlowTop.getBounds());
                                } else {
                                    invalidate();
                                }

                                mEdgeGlowTop.onPull((float) overscroll / getHeight());
                                if (!mEdgeGlowBottom.isFinished()) {
                                    mEdgeGlowBottom.onRelease();
                                }
                            } else if (rawDeltaY < 0) {
                                if (!mEdgeGlowBottom.isIdle()) {
                                    invalidate(mEdgeGlowBottom.getBounds());
                                } else {
                                    invalidate();
                                }

                                mEdgeGlowBottom.onPull((float) overscroll / getHeight());
                                if (!mEdgeGlowTop.isFinished()) {
                                    mEdgeGlowTop.onRelease();
@@ -2956,7 +2969,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                        }
                    }
                    mMotionY = y;
                    invalidate();
                }
                mLastY = y;
            }
@@ -2990,25 +3002,25 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                            if (!mEdgeGlowBottom.isFinished()) {
                                mEdgeGlowBottom.onRelease();
                            }
                            invalidate(mEdgeGlowTop.getBounds());
                        } else if (rawDeltaY < 0) {
                            mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight());
                            if (!mEdgeGlowTop.isFinished()) {
                                mEdgeGlowTop.onRelease();
                            }
                            invalidate(mEdgeGlowBottom.getBounds());
                        }
                        invalidate();
                    }
                }

                if (incrementalDeltaY != 0) {
                    // Coming back to 'real' list scrolling
                    if (mScrollY != 0) {
                        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;

@@ -3468,11 +3480,12 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                final int rightPadding = mListPadding.right + mGlowPaddingRight;
                final int width = getWidth() - leftPadding - rightPadding;

                canvas.translate(leftPadding,
                        Math.min(0, scrollY + mFirstPositionDistanceGuess));
                int edgeY = Math.min(0, scrollY + mFirstPositionDistanceGuess);
                canvas.translate(leftPadding, edgeY);
                mEdgeGlowTop.setSize(width, getHeight());
                if (mEdgeGlowTop.draw(canvas)) {
                    invalidate();
                    mEdgeGlowTop.setPosition(leftPadding, edgeY);
                    invalidate(mEdgeGlowTop.getBounds());
                }
                canvas.restoreToCount(restoreCount);
            }
@@ -3483,12 +3496,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                final int width = getWidth() - leftPadding - rightPadding;
                final int height = getHeight();

                canvas.translate(-width + leftPadding,
                        Math.max(height, scrollY + mLastPositionDistanceGuess));
                int edgeX = -width + leftPadding;
                int edgeY = Math.max(height, scrollY + mLastPositionDistanceGuess);
                canvas.translate(edgeX, edgeY);
                canvas.rotate(180, width, 0);
                mEdgeGlowBottom.setSize(width, height);
                if (mEdgeGlowBottom.draw(canvas)) {
                    invalidate();
                    // Account for the rotation
                    mEdgeGlowBottom.setPosition(edgeX + width, edgeY - mEdgeGlowBottom.getHeight());
                    invalidate(mEdgeGlowBottom.getBounds());
                }
                canvas.restoreToCount(restoreCount);
            }
@@ -3874,7 +3890,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                }

                // Don't stop just because delta is zero (it could have been rounded)
                final boolean atEnd = trackMotionScroll(delta, delta) && (delta != 0);
                final boolean atEdge = trackMotionScroll(delta, delta);
                final boolean atEnd = atEdge && (delta != 0);
                if (atEnd) {
                    if (motionView != null) {
                        // Tweak the scroll for how far we overshot
@@ -3889,7 +3906,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                }

                if (more && !atEnd) {
                    invalidate();
                    if (atEdge) invalidate();
                    mLastFlingY = y;
                    post(this);
                } else {
@@ -4431,7 +4448,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
    }

    private void createScrollingCache() {
        if (mScrollingCacheEnabled && !mCachingStarted) {
        if (mScrollingCacheEnabled && !mCachingStarted && !isHardwareAccelerated()) {
            setChildrenDrawnWithCacheEnabled(true);
            setChildrenDrawingCacheEnabled(true);
            mCachingStarted = mCachingActive = true;
@@ -4439,6 +4456,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
    }

    private void clearScrollingCache() {
        if (!isHardwareAccelerated()) {
            if (mClearScrollingCache == null) {
                mClearScrollingCache = new Runnable() {
                    public void run() {
@@ -4457,6 +4475,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
            }
            post(mClearScrollingCache);
        }
    }

    /**
     * Track a motion scroll
@@ -4599,14 +4618,18 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
            mRecycler.removeSkippedScrap();
        }

        // invalidate before moving the children to avoid unnecessary invalidate
        // calls to bubble up from the children all the way to the top
        if (!awakenScrollBars()) {
            invalidate();
        }

        offsetChildrenTopAndBottom(incrementalDeltaY);

        if (down) {
            mFirstPosition += count;
        }

        invalidate();

        final int absIncrementalDeltaY = Math.abs(incrementalDeltaY);
        if (spaceAbove < absIncrementalDeltaY || spaceBelow < absIncrementalDeltaY) {
            fillGap(down);
@@ -4629,7 +4652,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
        mBlockLayoutRequests = false;

        invokeOnItemScrollListener();
        awakenScrollBars();

        return false;
    }
+44 −5
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.widget;

import android.graphics.Rect;
import com.android.internal.R;

import android.content.Context;
@@ -45,6 +46,7 @@ import android.view.animation.Interpolator;
 * {@link #draw(Canvas)} method.</p>
 */
public class EdgeEffect {
    @SuppressWarnings("UnusedDeclaration")
    private static final String TAG = "EdgeEffect";

    // Time it will take the effect to fully recede in ms
@@ -57,10 +59,7 @@ public class EdgeEffect {
    private static final int PULL_DECAY_TIME = 1000;

    private static final float MAX_ALPHA = 1.f;
    private static final float HELD_EDGE_ALPHA = 0.7f;
    private static final float HELD_EDGE_SCALE_Y = 0.5f;
    private static final float HELD_GLOW_ALPHA = 0.5f;
    private static final float HELD_GLOW_SCALE_Y = 0.5f;

    private static final float MAX_GLOW_HEIGHT = 4.f;

@@ -76,7 +75,9 @@ public class EdgeEffect {
    private final Drawable mGlow;
    private int mWidth;
    private int mHeight;
    private final int MIN_WIDTH = 300;
    private int mX;
    private int mY;
    private static final int MIN_WIDTH = 300;
    private final int mMinWidth;

    private float mEdgeAlpha;
@@ -120,6 +121,8 @@ public class EdgeEffect {

    private float mPullDistance;
    
    private final Rect mBounds = new Rect();

    /**
     * Construct a new EdgeEffect with a theme appropriate for the provided context.
     * @param context Context used to provide theming and resource information for the EdgeEffect
@@ -144,6 +147,29 @@ public class EdgeEffect {
        mHeight = height;
    }

    /**
     * Set the position of this edge effect in pixels. This position is
     * only used by {@link #getBounds()}.
     * 
     * @param x The position of the edge effect on the X axis
     * @param y The position of the edge effect on the Y axis
     */
    void setPosition(int x, int y) {
        mX = x;
        mY = y;
    }

    boolean isIdle() {
        return mState == STATE_IDLE;
    }

    /**
     * Returns the height of the effect itself.
     */
    int getHeight() {
        return Math.max(mGlow.getBounds().height(), mEdge.getBounds().height());
    }
    
    /**
     * Reports if this EdgeEffect's animation is finished. If this method returns false
     * after a call to {@link #draw(Canvas)} the host widget should schedule another
@@ -301,7 +327,6 @@ public class EdgeEffect {
        update();

        final int edgeHeight = mEdge.getIntrinsicHeight();
        final int edgeWidth = mEdge.getIntrinsicWidth();
        final int glowHeight = mGlow.getIntrinsicHeight();
        final int glowWidth = mGlow.getIntrinsicWidth();

@@ -334,9 +359,23 @@ public class EdgeEffect {
        }
        mEdge.draw(canvas);

        if (mState == STATE_RECEDE && glowBottom == 0 && edgeBottom == 0) {
            mState = STATE_IDLE;
        }

        return mState != STATE_IDLE;
    }

    /**
     * Returns the bounds of the edge effect.
     */
    public Rect getBounds() {
        mBounds.set(mGlow.getBounds());
        mBounds.union(mEdge.getBounds());
        mBounds.offset(mX, mY);
        return mBounds;
    }

    private void update() {
        final long time = AnimationUtils.currentAnimationTimeMillis();
        final float t = Math.min((time - mStartTime) / mDuration, 1.f);