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

Commit 5ca9fa32 authored by Adam Cohen's avatar Adam Cohen Committed by Android (Google) Code Review
Browse files

Merge "Added looping parameter to AdapterViewAnimator / StackView"

parents 4768a16c 1b065cd1
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -6928,6 +6928,17 @@
 visibility="public"
>
</field>
<field name="loopViews"
 type="int"
 transient="false"
 volatile="false"
 value="16843592"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="manageSpaceActivity"
 type="int"
 transient="false"
+82 −59
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.widget;

import java.util.ArrayList;
import java.util.HashMap;

import android.animation.ObjectAnimator;
import android.content.Context;
@@ -40,6 +41,7 @@ import android.view.animation.AnimationUtils;
 * @attr ref android.R.styleable#AdapterViewAnimator_inAnimation
 * @attr ref android.R.styleable#AdapterViewAnimator_outAnimation
 * @attr ref android.R.styleable#AdapterViewAnimator_animateFirstView
 * @attr ref android.R.styleable#AdapterViewAnimator_loopViews
 */
public abstract class AdapterViewAnimator extends AdapterView<Adapter>
        implements RemoteViewsAdapter.RemoteAdapterConnectionCallback {
@@ -69,15 +71,14 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
    int mNumActiveViews = 1;

    /**
     * Array of the children of the {@link AdapterViewAnimator}. This array
     * is accessed in a circular fashion
     * Map of the children of the {@link AdapterViewAnimator}.
     */
    View[] mActiveViews;
    private HashMap<Integer, ViewAndIndex> mViewsMap = new HashMap<Integer, ViewAndIndex>();

    /**
     * List of views pending removal from the {@link AdapterViewAnimator}
     */
    ArrayList<View> mPreviousViews;
    ArrayList<Integer> mPreviousViews;

    /**
     * The index, relative to the adapter, of the beginning of the window of views
@@ -124,7 +125,7 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
     * Specifies if the animator should wrap from 0 to the end and vice versa
     * or have hard boundaries at the beginning and end
     */
    boolean mShouldLoop = true;
    boolean mLoopViews = true;

    /**
     * The width and height of some child, used as a size reference in-case our
@@ -149,22 +150,25 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
        super(context, attrs);

        TypedArray a = context.obtainStyledAttributes(attrs,
                com.android.internal.R.styleable.ViewAnimator);
                com.android.internal.R.styleable.AdapterViewAnimator);
        int resource = a.getResourceId(
                com.android.internal.R.styleable.ViewAnimator_inAnimation, 0);
                com.android.internal.R.styleable.AdapterViewAnimator_inAnimation, 0);
        if (resource > 0) {
            setInAnimation(context, resource);
        }

        resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_outAnimation, 0);
        resource = a.getResourceId(com.android.internal.R.styleable.AdapterViewAnimator_outAnimation, 0);
        if (resource > 0) {
            setOutAnimation(context, resource);
        }

        boolean flag = a.getBoolean(
                com.android.internal.R.styleable.ViewAnimator_animateFirstView, true);
                com.android.internal.R.styleable.AdapterViewAnimator_animateFirstView, true);
        setAnimateFirstView(flag);

        mLoopViews = a.getBoolean(
                com.android.internal.R.styleable.AdapterViewAnimator_loopViews, false);

        a.recycle();

        initViewAnimator();
@@ -175,11 +179,19 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
     */
    private void initViewAnimator() {
        mMainQueue = new Handler(Looper.myLooper());
        mActiveViews = new View[mNumActiveViews];
        mPreviousViews = new ArrayList<View>();
        mPreviousViews = new ArrayList<Integer>();
        mViewsToBringToFront = new ArrayList<View>();
    }

    private class ViewAndIndex {
        ViewAndIndex(View v, int i) {
            view = v;
            index = i;
        }
        View view;
        int index;
    }

    /**
     * This method is used by subclasses to configure the animator to display the
     * desired number of views, and specify the offset
@@ -193,18 +205,17 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
     * @param shouldLoop If the animator is show view 0, and setPrevious() is called, do we
     *        we loop back to the end, or do we do nothing
     */
     void configureViewAnimator(int numVisibleViews, int activeOffset, boolean shouldLoop) {
     void configureViewAnimator(int numVisibleViews, int activeOffset) {
        if (activeOffset > numVisibleViews - 1) {
            // Throw an exception here.
        }
        mNumActiveViews = numVisibleViews;
        mActiveOffset = activeOffset;
        mActiveViews = new View[mNumActiveViews];
        mPreviousViews.clear();
        mViewsMap.clear();
        removeAllViewsInLayout();
        mCurrentWindowStart = 0;
        mCurrentWindowEnd = -1;
        mShouldLoop = shouldLoop;
    }

    /**
@@ -238,9 +249,9 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
        if (mAdapter != null) {
            mWhichChild = whichChild;
            if (whichChild >= mAdapter.getCount()) {
                mWhichChild = mShouldLoop ? 0 : mAdapter.getCount() - 1;
                mWhichChild = mLoopViews ? 0 : mAdapter.getCount() - 1;
            } else if (whichChild < 0) {
                mWhichChild = mShouldLoop ? mAdapter.getCount() - 1 : 0;
                mWhichChild = mLoopViews ? mAdapter.getCount() - 1 : 0;
            }

            boolean hasFocus = getFocusedChild() != null;
@@ -323,9 +334,10 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
     * @return View at this index, null if the index is outside the bounds
     */
    View getViewAtRelativeIndex(int relativeIndex) {
        if (relativeIndex >= 0 && relativeIndex <= mNumActiveViews - 1) {
            int index = mCurrentWindowStartUnbounded + relativeIndex;
            return mActiveViews[modulo(index, mNumActiveViews)];
        if (relativeIndex >= 0 && relativeIndex <= mNumActiveViews - 1 && mAdapter != null) {
            int adapterCount =  mAdapter.getCount();
            int i = modulo(mCurrentWindowStartUnbounded + relativeIndex, adapterCount);
            return mViewsMap.get(i).view;
        }
        return null;
    }
@@ -346,8 +358,8 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
            // get the fresh child from the adapter
            View updatedChild = mAdapter.getView(i, null, this);

            if (mActiveViews[index] != null) {
                FrameLayout fl = (FrameLayout) mActiveViews[index];
            if (mViewsMap.containsKey(index)) {
                FrameLayout fl = (FrameLayout) mViewsMap.get(index).view;
                // flush out the old child
                fl.removeAllViewsInLayout();
                // add the new child to the frame, if it exists
@@ -373,7 +385,8 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
        if (mAdapter == null) return;

        for (int i = 0; i < mPreviousViews.size(); i++) {
            View viewToRemove = mPreviousViews.get(i);
            View viewToRemove = mViewsMap.get(mPreviousViews.get(i)).view;
            mViewsMap.remove(mPreviousViews.get(i));
            viewToRemove.clearAnimation();
            if (viewToRemove instanceof ViewGroup) {
                ViewGroup vg = (ViewGroup) viewToRemove;
@@ -386,26 +399,42 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
            removeViewInLayout(viewToRemove);
        }
        mPreviousViews.clear();
        int adapterCount = mAdapter.getCount();
        int newWindowStartUnbounded = childIndex - mActiveOffset;
        int newWindowEndUnbounded = newWindowStartUnbounded + mNumActiveViews - 1;
        int newWindowStart = Math.max(0, newWindowStartUnbounded);
        int newWindowEnd = Math.min(mAdapter.getCount() - 1, newWindowEndUnbounded);
        int newWindowEnd = Math.min(adapterCount - 1, newWindowEndUnbounded);

        if (mLoopViews) {
            newWindowStart = newWindowStartUnbounded;
            newWindowEnd = newWindowEndUnbounded;
        }
        int rangeStart = modulo(newWindowStart, adapterCount);
        int rangeEnd = modulo(newWindowEnd, adapterCount);

        boolean wrap = false;
        if (rangeStart > rangeEnd) {
            wrap = true;
        }

        // This section clears out any items that are in our mActiveViews list
        // This section clears out any items that are in our active views list
        // but are outside the effective bounds of our window (this is becomes an issue
        // at the extremities of the list, eg. where newWindowStartUnbounded < 0 or
        // newWindowEndUnbounded > mAdapter.getCount() - 1
        for (int i = newWindowStartUnbounded; i < newWindowEndUnbounded; i++) {
            if (i < newWindowStart || i > newWindowEnd) {
                int index = modulo(i, mNumActiveViews);
                if (mActiveViews[index] != null) {
                    View previousView = mActiveViews[index];
                    mPreviousViews.add(previousView);
                    int previousViewRelativeIndex = modulo(index - mCurrentWindowStart,
                            mNumActiveViews);
                    animateViewForTransition(previousViewRelativeIndex, -1, previousView);
                    mActiveViews[index] = null;
        for (Integer index : mViewsMap.keySet()) {
            boolean remove = false;
            if (!wrap && (index < rangeStart || index > rangeEnd)) {
                remove = true;
            } else if (wrap && (index > rangeEnd && index < rangeStart)) {
                remove = true;
            }

            if (remove) {
                View previousView = mViewsMap.get(index).view;
                int oldRelativeIndex = mViewsMap.get(index).index;

                mPreviousViews.add(index);
                animateViewForTransition(oldRelativeIndex, -1, previousView);
            }
        }

@@ -414,36 +443,30 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
            // Run through the indices in the new range
            for (int i = newWindowStart; i <= newWindowEnd; i++) {

                int oldRelativeIndex = i - mCurrentWindowStartUnbounded;
                int index = modulo(i, adapterCount);
                int oldRelativeIndex;
                if (mViewsMap.containsKey(index)) {
                    oldRelativeIndex = mViewsMap.get(index).index;
                } else {
                    oldRelativeIndex = -1;
                }
                int newRelativeIndex = i - newWindowStartUnbounded;
                int index = modulo(i, mNumActiveViews);

                // If this item is in the current window, great, we just need to apply
                // the transform for it's new relative position in the window, and animate
                // between it's current and new relative positions
                if (i >= mCurrentWindowStart && i <= mCurrentWindowEnd) {
                    View view = mActiveViews[index];
                boolean inOldRange = mViewsMap.containsKey(index) && !mPreviousViews.contains(index);

                if (inOldRange) {
                    View view = mViewsMap.get(index).view;
                    mViewsMap.get(index).index = newRelativeIndex;
                    applyTransformForChildAtIndex(view, newRelativeIndex);
                    animateViewForTransition(oldRelativeIndex, newRelativeIndex, view);

                // Otherwise this view is new, so first we have to displace the view that's
                // taking the new view's place within our cache (a circular array)
                // Otherwise this view is new to the window
                } else {
                    if (mActiveViews[index] != null) {
                        View previousView = mActiveViews[index];
                        mPreviousViews.add(previousView);
                        int previousViewRelativeIndex = modulo(index - mCurrentWindowStart,
                                mNumActiveViews);
                        animateViewForTransition(previousViewRelativeIndex, -1, previousView);

                        if (mCurrentWindowStart > newWindowStart) {
                            mViewsToBringToFront.add(previousView);
                        }
                    }

                    // We've cleared a spot for the new view. Get it from the adapter, add it
                    // and apply any transform / animation
                    View newView = mAdapter.getView(i, null, this);
                    // Get the new view from the adapter, add it and apply any transform / animation
                    View newView = mAdapter.getView(modulo(i, adapterCount), null, this);

                    // We wrap the new view in a FrameLayout so as to respect the contract
                    // with the adapter, that is, that we don't modify this view directly
@@ -453,12 +476,12 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
                    if (newView != null) {
                       fl.addView(newView);
                    }
                    mActiveViews[index] = fl;
                    mViewsMap.put(index, new ViewAndIndex(fl, newRelativeIndex));
                    addChild(fl);
                    applyTransformForChildAtIndex(fl, newRelativeIndex);
                    animateViewForTransition(-1, newRelativeIndex, fl);
                }
                mActiveViews[index].bringToFront();
                mViewsMap.get(index).view.bringToFront();
            }

            for (int i = 0; i < mViewsToBringToFront.size(); i++) {
+5 −2
Original line number Diff line number Diff line
@@ -68,6 +68,11 @@ public class AdapterViewFlipper extends AdapterViewAnimator {
                com.android.internal.R.styleable.ViewFlipper_flipInterval, DEFAULT_INTERVAL);
        mAutoStart = a.getBoolean(
                com.android.internal.R.styleable.ViewFlipper_autoStart, false);

        // By default we want the flipper to loop
        mLoopViews = a.getBoolean(
                com.android.internal.R.styleable.AdapterViewAnimator_loopViews, true);

        a.recycle();
        initDefaultAnimations();
    }
@@ -194,8 +199,6 @@ public class AdapterViewFlipper extends AdapterViewAnimator {
       super.showPrevious();
   }

   /**

    /**
     * Internal method to start or stop dispatching flip {@link Message} based
     * on {@link #mRunning} and {@link #mVisible} state.
+4 −3
Original line number Diff line number Diff line
@@ -132,7 +132,7 @@ public class StackView extends AdapterViewAnimator {
    }

    private void initStackView() {
        configureViewAnimator(NUM_ACTIVE_VIEWS, NUM_ACTIVE_VIEWS - 2, false);
        configureViewAnimator(NUM_ACTIVE_VIEWS, NUM_ACTIVE_VIEWS - 2);
        setStaticTransformationsEnabled(true);
        final ViewConfiguration configuration = ViewConfiguration.get(getContext());
        mTouchSlop = configuration.getScaledTouchSlop();
@@ -287,7 +287,6 @@ public class StackView extends AdapterViewAnimator {
    // framework level support for drawing outside of a parent's bounds.
    private void disableParentalClipping() {
        if (mAncestorContainingAllChildren != null) {
            Log.v(TAG, "Disabling parental clipping.");
            ViewGroup vg = this;
            while (vg.getParent() != null && vg.getParent() instanceof ViewGroup) {
                if (vg == mAncestorContainingAllChildren) break;
@@ -363,7 +362,9 @@ public class StackView extends AdapterViewAnimator {

            if (mAdapter == null) return;

            if (mCurrentWindowStartUnbounded + activeIndex == 0) {
            if (mLoopViews) {
                mStackSlider.setMode(StackSlider.NORMAL_MODE);
            } else if (mCurrentWindowStartUnbounded + activeIndex == 0) {
                mStackSlider.setMode(StackSlider.BEGINNING_OF_STACK_MODE);
            } else if (mCurrentWindowStartUnbounded + activeIndex == mAdapter.getCount()) {
                activeIndex--;
+4 −1
Original line number Diff line number Diff line
@@ -2384,6 +2384,9 @@
        <attr name="inAnimation" />
        <!-- Identifier for the animation to use when a view is hidden. -->
        <attr name="outAnimation" />
        <!--Defines whether the animator loops to the first view once it
        has reached the end of the list. -->
        <attr name="loopViews" format="boolean" />
        <!-- Defines whether to animate the current View when the ViewAnimation
        is first displayed. -->
        <attr name="animateFirstView" />
Loading