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

Commit 079e2357 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Add new fade in/out feature for drawable containers.

This is used to allow list view's pressed and activated indicators
to fade in an out, though of course it can be used elsewhere as well.

There is a lot of complexity in supporting this in list view.  The
two main things that are being dealt with:

- When recycling views, we need to make sure that the view's drawable
  state doesn't get animated from an old row's state.  The recycler
  now keeps track of which position a view was last in, and if it is
  reused at a new position there is a new View/Drawable API to tell
  it to jump to its current state instead of animating.

- For the pressed indicator to fade out, we need to keep displaying it
  after it is hidden.  There are new variables and code to keep track
  of this state, and tweaks in various places to be able to remember
  the last selected position and continue updating the drawable bounds
  as needed.

Change-Id: Ic96aa1a3c05e519665abf3098892ff2cc4f0ef2f
parent 079fd674
Loading
Loading
Loading
Loading
+134 −5
Original line number Diff line number Diff line
@@ -1905,7 +1905,7 @@
 type="int"
 transient="false"
 volatile="false"
 value="16843550"
 value="16843552"
 static="true"
 final="true"
 deprecated="not deprecated"
@@ -1916,7 +1916,7 @@
 type="int"
 transient="false"
 volatile="false"
 value="16843549"
 value="16843551"
 static="true"
 final="true"
 deprecated="not deprecated"
@@ -1927,7 +1927,7 @@
 type="int"
 transient="false"
 volatile="false"
 value="16843551"
 value="16843553"
 static="true"
 final="true"
 deprecated="not deprecated"
@@ -3804,6 +3804,17 @@
 visibility="public"
>
</field>
<field name="enterFadeDuration"
 type="int"
 transient="false"
 volatile="false"
 value="16843549"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="entries"
 type="int"
 transient="false"
@@ -3848,6 +3859,17 @@
 visibility="public"
>
</field>
<field name="exitFadeDuration"
 type="int"
 transient="false"
 volatile="false"
 value="16843550"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="expandableListPreferredChildIndicatorLeft"
 type="int"
 transient="false"
@@ -9308,7 +9330,7 @@
 type="int"
 transient="false"
 volatile="false"
 value="16843553"
 value="16843555"
 static="true"
 final="true"
 deprecated="not deprecated"
@@ -9319,7 +9341,7 @@
 type="int"
 transient="false"
 volatile="false"
 value="16843552"
 value="16843554"
 static="true"
 final="true"
 deprecated="not deprecated"
@@ -83932,6 +83954,17 @@
 visibility="public"
>
</method>
<method name="jumpToCurrentState"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="mutate"
 return="android.graphics.drawable.Drawable"
 abstract="false"
@@ -84421,6 +84454,32 @@
<parameter name="state" type="android.graphics.drawable.DrawableContainer.DrawableContainerState">
</parameter>
</method>
<method name="setEnterFadeDuration"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="ms" type="int">
</parameter>
</method>
<method name="setExitFadeDuration"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="ms" type="int">
</parameter>
</method>
<method name="unscheduleDrawable"
 return="void"
 abstract="false"
@@ -84568,6 +84627,28 @@
 visibility="public"
>
</method>
<method name="getEnterFadeDuration"
 return="int"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="getExitFadeDuration"
 return="int"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="getOpacity"
 return="int"
 abstract="false"
@@ -84629,6 +84710,32 @@
<parameter name="constant" type="boolean">
</parameter>
</method>
<method name="setEnterFadeDuration"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="duration" type="int">
</parameter>
</method>
<method name="setExitFadeDuration"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="duration" type="int">
</parameter>
</method>
<method name="setVariablePadding"
 return="void"
 abstract="false"
@@ -190423,6 +190530,17 @@
<parameter name="newSize" type="int">
</parameter>
</method>
<field name="NOTHING"
 type="int[]"
 transient="false"
 volatile="false"
 value="null"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="WILD_CARD"
 type="int[]"
 transient="false"
@@ -203765,6 +203883,17 @@
 visibility="public"
>
</method>
<method name="jumpDrawablesToCurrentState"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="layout"
 return="void"
 abstract="false"
+1 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import com.android.internal.R;
public class StateSet {

    public static final int[] WILD_CARD = new int[0];
    public static final int[] NOTHING = new int[] { 0 };

    /**
     * Return whether the stateSetOrSpec is matched by all StateSets.
+10 −0
Original line number Diff line number Diff line
@@ -8619,6 +8619,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
        return baseState;
    }

    /**
     * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()}
     * on all Drawable objects associated with this view.
     */
    public void jumpDrawablesToCurrentState() {
        if (mBGDrawable != null) {
            mBGDrawable.jumpToCurrentState();
        }
    }

    /**
     * Sets the background color for this view.
     * @param color the color of the background
+90 −33
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import android.util.AttributeSet;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.SparseBooleanArray;
import android.util.StateSet;
import android.view.ActionMode;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
@@ -253,6 +254,17 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
     */
    Drawable mSelector;

    /**
     * Set to true if we would like to have the selector showing itself.
     * We still need to draw and position it even if this is false.
     */
    boolean mSelectorShowing;

    /**
     * The current position of the selector in the list.
     */
    int mSelectorPosition = INVALID_POSITION;

    /**
     * Defines the selector's location and dimension at drawing time
     */
@@ -1324,6 +1336,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
            setSelectedPositionInt(INVALID_POSITION);
            // Do this before setting mNeedSync since setNextSelectedPosition looks at mNeedSync
            setNextSelectedPositionInt(INVALID_POSITION);
            mSelectorPosition = INVALID_POSITION;
            mNeedSync = true;
            mSyncRowId = ss.firstId;
            mSyncPosition = ss.position;
@@ -1416,6 +1429,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
        setSelectedPositionInt(INVALID_POSITION);
        setNextSelectedPositionInt(INVALID_POSITION);
        mSelectedTop = 0;
        mSelectorShowing = false;
        mSelectorPosition = INVALID_POSITION;
        mSelectorRect.setEmpty();
        invalidate();
    }
@@ -1708,7 +1723,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
            }

            if (child != scrapView) {
                mRecycler.addScrapView(scrapView);
                mRecycler.addScrapView(scrapView, position);
                if (mCacheColorHint != 0) {
                    child.setDrawingCacheBackgroundColor(mCacheColorHint);
                }
@@ -1734,7 +1749,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
        return child;
    }

    void positionSelector(View sel) {
    void positionSelector(int position, View sel) {
        if (position != INVALID_POSITION) {
            mSelectorPosition = position;
        }

        final Rect selectorRect = mSelectorRect;
        selectorRect.set(sel.getLeft(), sel.getTop(), sel.getRight(), sel.getBottom());
        positionSelector(selectorRect.left, selectorRect.top, selectorRect.right,
@@ -1743,9 +1762,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
        final boolean isChildViewEnabled = mIsChildViewEnabled;
        if (sel.isEnabled() != isChildViewEnabled) {
            mIsChildViewEnabled = !isChildViewEnabled;
            if (mSelectorShowing) {
                refreshDrawableState();
            }
        }
    }

    private void positionSelector(int l, int t, int r, int b) {
        mSelectorRect.set(l - mSelectionLeftPadding, t - mSelectionTopPadding, r
@@ -1822,7 +1843,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
    }

    private void drawSelector(Canvas canvas) {
        if (shouldShowSelector() && mSelectorRect != null && !mSelectorRect.isEmpty()) {
        if (!mSelectorRect.isEmpty()) {
            final Drawable selector = mSelector;
            selector.setBounds(mSelectorRect);
            selector.draw(canvas);
@@ -1866,7 +1887,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
        mSelectionRightPadding = padding.right;
        mSelectionBottomPadding = padding.bottom;
        sel.setCallback(this);
        sel.setState(getDrawableState());
        updateSelectorState();
    }

    /**
@@ -1891,7 +1912,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
        Drawable selector = mSelector;
        Rect selectorRect = mSelectorRect;
        if (selector != null && (isFocused() || touchModeDrawsInPressedState())
                && selectorRect != null && !selectorRect.isEmpty()) {
                && !selectorRect.isEmpty()) {

            final View v = getChildAt(mSelectedPosition - mFirstPosition);

@@ -1926,14 +1947,22 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
        mScrollDown = down;
    }

    @Override
    protected void drawableStateChanged() {
        super.drawableStateChanged();
    void updateSelectorState() {
        if (mSelector != null) {
            if (shouldShowSelector()) {
                mSelector.setState(getDrawableState());
            } else {
                mSelector.setState(StateSet.NOTHING);
            }
        }
    }

    @Override
    protected void drawableStateChanged() {
        super.drawableStateChanged();
        updateSelectorState();
    }

    @Override
    protected int[] onCreateDrawableState(int extraSpace) {
        // If the child view is enabled then do the default behavior.
@@ -2141,7 +2170,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                } else {
                    mTouchMode = TOUCH_MODE_DONE_WAITING;
                }

            }
        }
    }
@@ -2316,10 +2344,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                    mLayoutMode = LAYOUT_NORMAL;

                    if (!mDataChanged) {
                        layoutChildren();
                        child.setPressed(true);
                        positionSelector(child);
                        setPressed(true);
                        layoutChildren();
                        positionSelector(mMotionPosition, child);

                        final int longPressTimeout = ViewConfiguration.getLongPressTimeout();
                        final boolean longClickable = isLongClickable();
@@ -2566,7 +2594,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                            setSelectedPositionInt(mMotionPosition);
                            layoutChildren();
                            child.setPressed(true);
                            positionSelector(child);
                            positionSelector(mMotionPosition, child);
                            setPressed(true);
                            if (mSelector != null) {
                                Drawable d = mSelector.getCurrent();
@@ -2576,16 +2604,17 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                            }
                            postDelayed(new Runnable() {
                                public void run() {
                                    mTouchMode = TOUCH_MODE_REST;
                                    child.setPressed(false);
                                    setPressed(false);
                                    if (!mDataChanged) {
                                        post(performClick);
                                    }
                                    mTouchMode = TOUCH_MODE_REST;
                                }
                            }, ViewConfiguration.getPressedStateDuration());
                        } else {
                            mTouchMode = TOUCH_MODE_REST;
                            updateSelectorState();
                        }
                        return true;
                    } else if (!mDataChanged && mAdapter.isEnabled(motionPosition)) {
@@ -2593,6 +2622,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                    }
                }
                mTouchMode = TOUCH_MODE_REST;
                updateSelectorState();
                break;
            case TOUCH_MODE_SCROLL:
                final int childCount = getChildCount();
@@ -3507,7 +3537,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                    count++;
                    int position = firstPosition + i;
                    if (position >= headerViewsCount && position < footerViewsStart) {
                        mRecycler.addScrapView(child);
                        mRecycler.addScrapView(child, position);

                        if (ViewDebug.TRACE_RECYCLER) {
                            ViewDebug.trace(child,
@@ -3528,7 +3558,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                    count++;
                    int position = firstPosition + i;
                    if (position >= headerViewsCount && position < footerViewsStart) {
                        mRecycler.addScrapView(child);
                        mRecycler.addScrapView(child, position);

                        if (ViewDebug.TRACE_RECYCLER) {
                            ViewDebug.trace(child,
@@ -3563,8 +3593,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
        if (!inTouchMode && mSelectedPosition != INVALID_POSITION) {
            final int childIndex = mSelectedPosition - mFirstPosition;
            if (childIndex >= 0 && childIndex < getChildCount()) {
                positionSelector(getChildAt(childIndex));
                positionSelector(mSelectedPosition, getChildAt(childIndex));
            }
        } else if (mSelectorPosition != INVALID_POSITION) {
            final int childIndex = mSelectorPosition - mFirstPosition;
            if (childIndex >= 0 && childIndex < getChildCount()) {
                positionSelector(INVALID_POSITION, getChildAt(childIndex));
            }
        } else {
            mSelectorRect.setEmpty();
        }

        mBlockLayoutRequests = false;
@@ -3616,7 +3653,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
            setSelectedPositionInt(INVALID_POSITION);
            setNextSelectedPositionInt(INVALID_POSITION);
            mSelectedTop = 0;
            mSelectorRect.setEmpty();
            mSelectorShowing = false;
        }
    }

@@ -3876,6 +3913,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
        mNextSelectedPosition = INVALID_POSITION;
        mNextSelectedRowId = INVALID_ROW_ID;
        mNeedSync = false;
        mSelectorPosition = INVALID_POSITION;
        checkSelectionChanged();
    }

@@ -4562,6 +4600,13 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
        @ViewDebug.ExportedProperty(category = "list")
        boolean forceAdd;

        /**
         * The position the view was removed from when pulled out of the
         * scrap heap.
         * @hide
         */
        int scrappedFromPosition;

        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
        }
@@ -4741,23 +4786,12 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
         * @return A view from the ScrapViews collection. These are unordered.
         */
        View getScrapView(int position) {
            ArrayList<View> scrapViews;
            if (mViewTypeCount == 1) {
                scrapViews = mCurrentScrap;
                int size = scrapViews.size();
                if (size > 0) {
                    return scrapViews.remove(size - 1);
                } else {
                    return null;
                }
                return retrieveFromScrap(mCurrentScrap, position);
            } else {
                int whichScrap = mAdapter.getItemViewType(position);
                if (whichScrap >= 0 && whichScrap < mScrapViews.length) {
                    scrapViews = mScrapViews[whichScrap];
                    int size = scrapViews.size();
                    if (size > 0) {
                        return scrapViews.remove(size - 1);
                    }
                    return retrieveFromScrap(mScrapViews[whichScrap], position);
                }
            }
            return null;
@@ -4768,7 +4802,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
         *
         * @param scrap The view to add
         */
        void addScrapView(View scrap) {
        void addScrapView(View scrap, int position) {
            AbsListView.LayoutParams lp = (AbsListView.LayoutParams) scrap.getLayoutParams();
            if (lp == null) {
                return;
@@ -4784,6 +4818,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                return;
            }

            lp.scrappedFromPosition = position;

            if (mViewTypeCount == 1) {
                scrap.dispatchStartTemporaryDetach();
                mCurrentScrap.add(scrap);
@@ -4810,7 +4846,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
            for (int i = count - 1; i >= 0; i--) {
                final View victim = activeViews[i];
                if (victim != null) {
                    int whichScrap = ((AbsListView.LayoutParams) victim.getLayoutParams()).viewType;
                    final AbsListView.LayoutParams lp
                            = (AbsListView.LayoutParams) victim.getLayoutParams();
                    int whichScrap = lp.viewType;

                    activeViews[i] = null;

@@ -4826,6 +4864,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
                        scrapViews = mScrapViews[whichScrap];
                    }
                    victim.dispatchStartTemporaryDetach();
                    lp.scrappedFromPosition = mFirstActivePosition + i;
                    scrapViews.add(victim);

                    if (hasListener) {
@@ -4911,4 +4950,22 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
            }
        }
    }

    static View retrieveFromScrap(ArrayList<View> scrapViews, int position) {
        int size = scrapViews.size();
        if (size > 0) {
            // See if we still have a view for this position.
            for (int i=0; i<size; i++) {
                View view = scrapViews.get(i);
                if (((AbsListView.LayoutParams)view.getLayoutParams())
                        .scrappedFromPosition == position) {
                    scrapViews.remove(i);
                    return view;
                }
            }
            return scrapViews.remove(size - 1);
        } else {
            return null;
        }
    }
}
+0 −1
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package android.widget;

import android.content.Context;
import android.database.DataSetObserver;
import android.os.Handler;
import android.os.Parcelable;
import android.os.SystemClock;
import android.util.AttributeSet;
Loading