15e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette/*
25e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * Copyright (C) 2014 The Android Open Source Project
35e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette *
45e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * Licensed under the Apache License, Version 2.0 (the "License");
55e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * you may not use this file except in compliance with the License.
65e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * You may obtain a copy of the License at
75e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette *
85e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette *      http://www.apache.org/licenses/LICENSE-2.0
95e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette *
105e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * Unless required by applicable law or agreed to in writing, software
115e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * distributed under the License is distributed on an "AS IS" BASIS,
125e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * See the License for the specific language governing permissions and
145e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * limitations under the License.
155e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette */
165e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
175e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverettepackage android.graphics.drawable;
185e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
195e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viveretteimport android.animation.ObjectAnimator;
205e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viveretteimport android.animation.TimeInterpolator;
21f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viveretteimport android.annotation.NonNull;
22f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viveretteimport android.annotation.Nullable;
235e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viveretteimport android.content.res.Resources;
245e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viveretteimport android.content.res.Resources.Theme;
255e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viveretteimport android.content.res.TypedArray;
265e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viveretteimport android.util.AttributeSet;
277bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghuiimport android.util.Log;
285e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viveretteimport android.util.LongSparseLongArray;
295e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viveretteimport android.util.SparseIntArray;
305e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viveretteimport android.util.StateSet;
315e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
325e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viveretteimport com.android.internal.R;
335e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
345e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viveretteimport org.xmlpull.v1.XmlPullParser;
355e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viveretteimport org.xmlpull.v1.XmlPullParserException;
365e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
375e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viveretteimport java.io.IOException;
385e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
395e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette/**
405e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * Drawable containing a set of Drawable keyframes where the currently displayed
415e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * keyframe is chosen based on the current state set. Animations between
425e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * keyframes may optionally be defined using transition elements.
435e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * <p>
445e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * This drawable can be defined in an XML file with the <code>
455e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * &lt;animated-selector></code> element. Each keyframe Drawable is defined in a
465e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * nested <code>&lt;item></code> element. Transitions are defined in a nested
475e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * <code>&lt;transition></code> element.
485e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette *
495e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * @attr ref android.R.styleable#DrawableStates_state_focused
505e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * @attr ref android.R.styleable#DrawableStates_state_window_focused
515e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * @attr ref android.R.styleable#DrawableStates_state_enabled
525e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * @attr ref android.R.styleable#DrawableStates_state_checkable
535e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * @attr ref android.R.styleable#DrawableStates_state_checked
545e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * @attr ref android.R.styleable#DrawableStates_state_selected
555e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * @attr ref android.R.styleable#DrawableStates_state_activated
565e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * @attr ref android.R.styleable#DrawableStates_state_active
575e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * @attr ref android.R.styleable#DrawableStates_state_single
585e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * @attr ref android.R.styleable#DrawableStates_state_first
595e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * @attr ref android.R.styleable#DrawableStates_state_middle
605e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * @attr ref android.R.styleable#DrawableStates_state_last
615e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * @attr ref android.R.styleable#DrawableStates_state_pressed
625e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette */
635e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverettepublic class AnimatedStateListDrawable extends StateListDrawable {
647bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui    private static final String LOGTAG = AnimatedStateListDrawable.class.getSimpleName();
657bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui
665e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    private static final String ELEMENT_TRANSITION = "transition";
675e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    private static final String ELEMENT_ITEM = "item";
685e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
695e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    private AnimatedStateListState mState;
705e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
716e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette    /** The currently running transition, if any. */
726e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette    private Transition mTransition;
735e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
746e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette    /** Index to be set after the transition ends. */
756e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette    private int mTransitionToIndex = -1;
765e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
776e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette    /** Index away from which we are transitioning. */
786e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette    private int mTransitionFromIndex = -1;
795e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
805e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    private boolean mMutated;
815e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
825e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    public AnimatedStateListDrawable() {
835e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        this(null, null);
845e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    }
855e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
862356c5e69b0911e6334ebf6374217898371be5acAlan Viverette    @Override
872356c5e69b0911e6334ebf6374217898371be5acAlan Viverette    public boolean setVisible(boolean visible, boolean restart) {
882356c5e69b0911e6334ebf6374217898371be5acAlan Viverette        final boolean changed = super.setVisible(visible, restart);
89f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette
906e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        if (mTransition != null && (changed || restart)) {
912356c5e69b0911e6334ebf6374217898371be5acAlan Viverette            if (visible) {
926e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette                mTransition.start();
936e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            } else {
94b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette                // Ensure we're showing the correct state when visible.
95b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette                jumpToCurrentState();
962356c5e69b0911e6334ebf6374217898371be5acAlan Viverette            }
972356c5e69b0911e6334ebf6374217898371be5acAlan Viverette        }
98f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette
992356c5e69b0911e6334ebf6374217898371be5acAlan Viverette        return changed;
1002356c5e69b0911e6334ebf6374217898371be5acAlan Viverette    }
1012356c5e69b0911e6334ebf6374217898371be5acAlan Viverette
1025e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    /**
1035e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette     * Add a new drawable to the set of keyframes.
1045e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette     *
1055e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette     * @param stateSet An array of resource IDs to associate with the keyframe
106f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette     * @param drawable The drawable to show when in the specified state, may not be null
1075e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette     * @param id The unique identifier for the keyframe
1085e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette     */
109f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette    public void addState(@NonNull int[] stateSet, @NonNull Drawable drawable, int id) {
110f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette        if (drawable == null) {
111f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette            throw new IllegalArgumentException("Drawable must not be null");
1125e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
113f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette
114f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette        mState.addStateSet(stateSet, drawable, id);
115f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette        onStateChange(getState());
1165e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    }
1175e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
1185e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    /**
1195e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette     * Adds a new transition between keyframes.
1205e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette     *
1215e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette     * @param fromId Unique identifier of the starting keyframe
1225e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette     * @param toId Unique identifier of the ending keyframe
1236beeb75723cec42603b47664bce794a2b97d7bacChet Haase     * @param transition An {@link Animatable} drawable to use as a transition, may not be null
1245e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette     * @param reversible Whether the transition can be reversed
1255e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette     */
1266beeb75723cec42603b47664bce794a2b97d7bacChet Haase    public <T extends Drawable & Animatable> void addTransition(int fromId, int toId,
1276beeb75723cec42603b47664bce794a2b97d7bacChet Haase            @NonNull T transition, boolean reversible) {
128f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette        if (transition == null) {
129f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette            throw new IllegalArgumentException("Transition drawable must not be null");
130f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette        }
131f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette
132f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette        mState.addTransition(fromId, toId, transition, reversible);
1335e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    }
1345e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
1355e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    @Override
1365e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    public boolean isStateful() {
1375e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        return true;
1385e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    }
1395e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
1405e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    @Override
1415e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    protected boolean onStateChange(int[] stateSet) {
142f81c6af10ef3041eeddb4a4560611a17dd3d399bAlan Viverette        // If we're not already at the target index, either attempt to find a
143f81c6af10ef3041eeddb4a4560611a17dd3d399bAlan Viverette        // valid transition to it or jump directly there.
144f81c6af10ef3041eeddb4a4560611a17dd3d399bAlan Viverette        final int targetIndex = mState.indexOfKeyframe(stateSet);
1452d91f63ec20c4b06e87c80451a656462eceba17fAlan Viverette        boolean changed = targetIndex != getCurrentIndex()
146f81c6af10ef3041eeddb4a4560611a17dd3d399bAlan Viverette                && (selectTransition(targetIndex) || selectDrawable(targetIndex));
147f81c6af10ef3041eeddb4a4560611a17dd3d399bAlan Viverette
1482d91f63ec20c4b06e87c80451a656462eceba17fAlan Viverette        // We need to propagate the state change to the current drawable, but
1492d91f63ec20c4b06e87c80451a656462eceba17fAlan Viverette        // we can't call StateListDrawable.onStateChange() without changing the
1502d91f63ec20c4b06e87c80451a656462eceba17fAlan Viverette        // current drawable.
1512d91f63ec20c4b06e87c80451a656462eceba17fAlan Viverette        final Drawable current = getCurrent();
1522d91f63ec20c4b06e87c80451a656462eceba17fAlan Viverette        if (current != null) {
1532d91f63ec20c4b06e87c80451a656462eceba17fAlan Viverette            changed |= current.setState(stateSet);
1542d91f63ec20c4b06e87c80451a656462eceba17fAlan Viverette        }
1552d91f63ec20c4b06e87c80451a656462eceba17fAlan Viverette
1562d91f63ec20c4b06e87c80451a656462eceba17fAlan Viverette        return changed;
1575e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    }
1585e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
1595e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    private boolean selectTransition(int toIndex) {
160d646fa2933ddcbfd4ed9c7686bf5e8253b4ba980Alan Viverette        final int fromIndex;
1616e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        final Transition currentTransition = mTransition;
1626e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        if (currentTransition != null) {
1636e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            if (toIndex == mTransitionToIndex) {
164d646fa2933ddcbfd4ed9c7686bf5e8253b4ba980Alan Viverette                // Already animating to that keyframe.
1655e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                return true;
166d646fa2933ddcbfd4ed9c7686bf5e8253b4ba980Alan Viverette            } else if (toIndex == mTransitionFromIndex && currentTransition.canReverse()) {
1675e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                // Reverse the current animation.
1686e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette                currentTransition.reverse();
169d646fa2933ddcbfd4ed9c7686bf5e8253b4ba980Alan Viverette                mTransitionToIndex = mTransitionFromIndex;
170d646fa2933ddcbfd4ed9c7686bf5e8253b4ba980Alan Viverette                mTransitionFromIndex = toIndex;
1715e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                return true;
1725e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            }
1735e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
174d646fa2933ddcbfd4ed9c7686bf5e8253b4ba980Alan Viverette            // Start the next transition from the end of the current one.
175d646fa2933ddcbfd4ed9c7686bf5e8253b4ba980Alan Viverette            fromIndex = mTransitionToIndex;
176d646fa2933ddcbfd4ed9c7686bf5e8253b4ba980Alan Viverette
1775e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            // Changing animation, end the current animation.
1786e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            currentTransition.stop();
179d646fa2933ddcbfd4ed9c7686bf5e8253b4ba980Alan Viverette        } else {
180d646fa2933ddcbfd4ed9c7686bf5e8253b4ba980Alan Viverette            fromIndex = getCurrentIndex();
1815e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
1825e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
183f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette        // Reset state.
184d646fa2933ddcbfd4ed9c7686bf5e8253b4ba980Alan Viverette        mTransition = null;
1856e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        mTransitionFromIndex = -1;
1866e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        mTransitionToIndex = -1;
187f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette
1885e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        final AnimatedStateListState state = mState;
1895e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        final int fromId = state.getKeyframeIdAt(fromIndex);
1905e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        final int toId = state.getKeyframeIdAt(toIndex);
1915e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        if (toId == 0 || fromId == 0) {
1925e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            // Missing a keyframe ID.
1935e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            return false;
1945e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
1955e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
1965e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        final int transitionIndex = state.indexOfTransition(fromId, toId);
197d646fa2933ddcbfd4ed9c7686bf5e8253b4ba980Alan Viverette        if (transitionIndex < 0) {
1985e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            // Couldn't select a transition.
1995e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            return false;
2005e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
2015e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
2025b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui        boolean hasReversibleFlag = state.transitionHasReversibleFlag(fromId, toId);
2035b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui
204d646fa2933ddcbfd4ed9c7686bf5e8253b4ba980Alan Viverette        // This may fail if we're already on the transition, but that's okay!
205d646fa2933ddcbfd4ed9c7686bf5e8253b4ba980Alan Viverette        selectDrawable(transitionIndex);
206d646fa2933ddcbfd4ed9c7686bf5e8253b4ba980Alan Viverette
2076e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        final Transition transition;
2085e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        final Drawable d = getCurrent();
209f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette        if (d instanceof AnimationDrawable) {
2106e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            final boolean reversed = state.isTransitionReversed(fromId, toId);
2115b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui
2125b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui            transition = new AnimationDrawableTransition((AnimationDrawable) d,
2135b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui                    reversed, hasReversibleFlag);
2146e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        } else if (d instanceof AnimatedVectorDrawable) {
2156e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            final boolean reversed = state.isTransitionReversed(fromId, toId);
2165b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui
2175b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui            transition = new AnimatedVectorDrawableTransition((AnimatedVectorDrawable) d,
2185b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui                    reversed, hasReversibleFlag);
219f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette        } else if (d instanceof Animatable) {
2206e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            transition = new AnimatableTransition((Animatable) d);
221f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette        } else {
222f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette            // We don't know how to animate this transition.
2235e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            return false;
2245e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
2255e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
2266e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        transition.start();
2276e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
2286e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        mTransition = transition;
2296e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        mTransitionFromIndex = fromIndex;
2306e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        mTransitionToIndex = toIndex;
231f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette        return true;
232f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette    }
233f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette
2346e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette    private static abstract class Transition {
2356e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        public abstract void start();
2366e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        public abstract void stop();
2376e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
2386e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        public void reverse() {
2396e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            // Not supported by default.
2406e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        }
2416e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
2426e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        public boolean canReverse() {
2436e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            return false;
2446e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        }
2456e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette    }
2466e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
2476e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette    private static class AnimatableTransition  extends Transition {
2486e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        private final Animatable mA;
2496e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
2506e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        public AnimatableTransition(Animatable a) {
2516e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            mA = a;
2526e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        }
2536e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
2546e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        @Override
2556e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        public void start() {
2566e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            mA.start();
2576e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        }
2586e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
2596e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        @Override
2606e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        public void stop() {
2616e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            mA.stop();
2626e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        }
2635e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    }
2645e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
2656e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
2666e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette    private static class AnimationDrawableTransition  extends Transition {
2676e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        private final ObjectAnimator mAnim;
2686e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
2695b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui        // Even AnimationDrawable is always reversible technically, but
2705b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui        // we should obey the XML's android:reversible flag.
2715b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui        private final boolean mHasReversibleFlag;
2725b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui
2735b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui        public AnimationDrawableTransition(AnimationDrawable ad,
2745b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui                boolean reversed, boolean hasReversibleFlag) {
2756e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            final int frameCount = ad.getNumberOfFrames();
2766e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            final int fromFrame = reversed ? frameCount - 1 : 0;
2776e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            final int toFrame = reversed ? 0 : frameCount - 1;
2786e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            final FrameInterpolator interp = new FrameInterpolator(ad, reversed);
2796e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            final ObjectAnimator anim = ObjectAnimator.ofInt(ad, "currentIndex", fromFrame, toFrame);
2806e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            anim.setAutoCancel(true);
2816e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            anim.setDuration(interp.getTotalDuration());
2826e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            anim.setInterpolator(interp);
2835b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui            mHasReversibleFlag = hasReversibleFlag;
2846e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            mAnim = anim;
2856e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        }
2866e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
2876e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        @Override
2886e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        public boolean canReverse() {
2895b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui            return mHasReversibleFlag;
2906e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        }
2916e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
2926e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        @Override
2936e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        public void start() {
2946e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            mAnim.start();
2956e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        }
2966e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
2976e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        @Override
2986e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        public void reverse() {
2996e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            mAnim.reverse();
3006e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        }
3016e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
3026e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        @Override
3036e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        public void stop() {
3046e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            mAnim.cancel();
3056e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        }
3066e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette    }
3076e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
3086e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette    private static class AnimatedVectorDrawableTransition  extends Transition {
3096e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        private final AnimatedVectorDrawable mAvd;
3105b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui
3115b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui        // mReversed is indicating the current transition's direction.
3126e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        private final boolean mReversed;
3136e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
3145b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui        // mHasReversibleFlag is indicating whether the whole transition has
3155b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui        // reversible flag set to true.
3165b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui        // If mHasReversibleFlag is false, then mReversed is always false.
3175b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui        private final boolean mHasReversibleFlag;
3185b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui
3195b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui        public AnimatedVectorDrawableTransition(AnimatedVectorDrawable avd,
3205b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui                boolean reversed, boolean hasReversibleFlag) {
3216e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            mAvd = avd;
3226e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            mReversed = reversed;
3235b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui            mHasReversibleFlag = hasReversibleFlag;
3246e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        }
3256e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
3266e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        @Override
3276e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        public boolean canReverse() {
3285b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui            // When the transition's XML says it is not reversible, then we obey
3295b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui            // it, even if the AVD itself is reversible.
3305b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui            // This will help the single direction transition.
3315b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui            return mAvd.canReverse() && mHasReversibleFlag;
3326e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        }
3336e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
3346e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        @Override
3356e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        public void start() {
3366e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            if (mReversed) {
3377bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui                reverse();
3386e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            } else {
3396e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette                mAvd.start();
3406e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            }
3416e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        }
3426e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
3436e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        @Override
3446e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        public void reverse() {
3457bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui            if (canReverse()) {
3467bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui                mAvd.reverse();
3477bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui            } else {
3485b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui                Log.w(LOGTAG, "Can't reverse, either the reversible is set to false,"
3495b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui                        + " or the AnimatedVectorDrawable can't reverse");
3507bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui            }
3516e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        }
3526e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
3536e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        @Override
3546e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        public void stop() {
3556e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            mAvd.stop();
3566e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        }
3576e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette    }
3586e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
3596e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
3605e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    @Override
3615e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    public void jumpToCurrentState() {
3625e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        super.jumpToCurrentState();
3635e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
3646e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette        if (mTransition != null) {
3656e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            mTransition.stop();
3666e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            mTransition = null;
3676e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette
3686e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            selectDrawable(mTransitionToIndex);
3696e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            mTransitionToIndex = -1;
3706e0a9fa6ed86e918bfed5310d2522b2c2a527ef0Alan Viverette            mTransitionFromIndex = -1;
3715e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
3725e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    }
3735e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
3745e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    @Override
375f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette    public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
376f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette            @NonNull AttributeSet attrs, @Nullable Theme theme)
3775e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            throws XmlPullParserException, IOException {
37839e33621a725bcdaa21a723866e53c6ea3356169Alan Viverette        final TypedArray a = obtainAttributes(
37939e33621a725bcdaa21a723866e53c6ea3356169Alan Viverette                r, theme, attrs, R.styleable.AnimatedStateListDrawable);
3805e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedStateListDrawable_visible);
381d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        updateStateFromTypedArray(a);
382f1f5f6fcaa768c5b88e9a56f18cbd6ecf72755a8Alan Viverette        updateDensity(r);
383d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        a.recycle();
384d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette
385d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        inflateChildElements(r, parser, attrs, theme);
3865e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
387d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        init();
388d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    }
389d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette
390d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    @Override
391d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    public void applyTheme(@Nullable Theme theme) {
392d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        super.applyTheme(theme);
3935e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
394d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        final AnimatedStateListState state = mState;
3957f4a63d1ebc13c6499a48331ecb78c4d27446dbcAlan Viverette        if (state == null || state.mAnimThemeAttrs == null) {
396d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette            return;
397d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        }
3985e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
399d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        final TypedArray a = theme.resolveAttributes(
400d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                state.mAnimThemeAttrs, R.styleable.AnimatedRotateDrawable);
401d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        updateStateFromTypedArray(a);
4025e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        a.recycle();
4035e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
404d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        init();
405d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    }
406d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette
407d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    private void updateStateFromTypedArray(TypedArray a) {
408d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        final AnimatedStateListState state = mState;
409d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette
410d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        // Account for any configuration changes.
411d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        state.mChangingConfigurations |= a.getChangingConfigurations();
412d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette
413d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        // Extract the theme attributes, if any.
414d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        state.mAnimThemeAttrs = a.extractThemeAttrs();
415d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette
416d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        state.setVariablePadding(a.getBoolean(
417d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                R.styleable.AnimatedStateListDrawable_variablePadding, state.mVariablePadding));
418d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        state.setConstantSize(a.getBoolean(
419d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                R.styleable.AnimatedStateListDrawable_constantSize, state.mConstantSize));
420d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        state.setEnterFadeDuration(a.getInt(
421d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                R.styleable.AnimatedStateListDrawable_enterFadeDuration, state.mEnterFadeDuration));
422d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        state.setExitFadeDuration(a.getInt(
423d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                R.styleable.AnimatedStateListDrawable_exitFadeDuration, state.mExitFadeDuration));
424d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette
425d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        setDither(a.getBoolean(
426d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                R.styleable.AnimatedStateListDrawable_dither, state.mDither));
427d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        setAutoMirrored(a.getBoolean(
428d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                R.styleable.AnimatedStateListDrawable_autoMirrored, state.mAutoMirrored));
429d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    }
430d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette
431d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    private void init() {
432d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        onStateChange(getState());
433d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    }
434d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette
435d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
436d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette            Theme theme) throws XmlPullParserException, IOException {
4375e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        int type;
4385e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
4395e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        final int innerDepth = parser.getDepth() + 1;
4405e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        int depth;
4415e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
4425e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                && ((depth = parser.getDepth()) >= innerDepth
4435e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                || type != XmlPullParser.END_TAG)) {
4445e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            if (type != XmlPullParser.START_TAG) {
4455e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                continue;
4465e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            }
4475e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
4485e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            if (depth > innerDepth) {
4495e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                continue;
4505e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            }
4515e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
4525e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            if (parser.getName().equals(ELEMENT_ITEM)) {
4535e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                parseItem(r, parser, attrs, theme);
4545e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            } else if (parser.getName().equals(ELEMENT_TRANSITION)) {
4555e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                parseTransition(r, parser, attrs, theme);
4565e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            }
4575e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
4585e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    }
4595e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
460f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette    private int parseTransition(@NonNull Resources r, @NonNull XmlPullParser parser,
461f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette            @NonNull AttributeSet attrs, @Nullable Theme theme)
4625e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            throws XmlPullParserException, IOException {
463d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        // This allows state list drawable item elements to be themed at
464d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        // inflation time but does NOT make them work for Zygote preload.
465d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        final TypedArray a = obtainAttributes(r, theme, attrs,
466d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette                R.styleable.AnimatedStateListDrawableTransition);
467d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        final int fromId = a.getResourceId(
468d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette                R.styleable.AnimatedStateListDrawableTransition_fromId, 0);
469d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        final int toId = a.getResourceId(
470d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette                R.styleable.AnimatedStateListDrawableTransition_toId, 0);
471d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        final boolean reversible = a.getBoolean(
472d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette                R.styleable.AnimatedStateListDrawableTransition_reversible, false);
473d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        Drawable dr = a.getDrawable(
474d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette                R.styleable.AnimatedStateListDrawableTransition_drawable);
475d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        a.recycle();
4765e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
477d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        // Loading child elements modifies the state of the AttributeSet's
478d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        // underlying parser, so it needs to happen after obtaining
479d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        // attributes and extracting states.
480d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        if (dr == null) {
4815e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            int type;
4825e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            while ((type = parser.next()) == XmlPullParser.TEXT) {
4835e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            }
4845e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            if (type != XmlPullParser.START_TAG) {
4855e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                throw new XmlPullParserException(
4865e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                        parser.getPositionDescription()
487d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette                                + ": <transition> tag requires a 'drawable' attribute or "
4885e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                                + "child tag defining a drawable");
4895e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            }
4906dbe51b50e82057af4d29882889444d22ac19c9cAlan Viverette            dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
4915e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
4925e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
493f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette        return mState.addTransition(fromId, toId, dr, reversible);
4945e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    }
4955e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
496f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette    private int parseItem(@NonNull Resources r, @NonNull XmlPullParser parser,
497f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette            @NonNull AttributeSet attrs, @Nullable Theme theme)
4985e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            throws XmlPullParserException, IOException {
499d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        // This allows state list drawable item elements to be themed at
500d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        // inflation time but does NOT make them work for Zygote preload.
501d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        final TypedArray a = obtainAttributes(r, theme, attrs,
502d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette                R.styleable.AnimatedStateListDrawableItem);
503d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        final int keyframeId = a.getResourceId(R.styleable.AnimatedStateListDrawableItem_id, 0);
504d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        Drawable dr = a.getDrawable(R.styleable.AnimatedStateListDrawableItem_drawable);
505d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        a.recycle();
5065e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
507d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        final int[] states = extractStateSet(attrs);
508d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette
509d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        // Loading child elements modifies the state of the AttributeSet's
510d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        // underlying parser, so it needs to happen after obtaining
511d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        // attributes and extracting states.
512d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette        if (dr == null) {
5135e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            int type;
5145e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            while ((type = parser.next()) == XmlPullParser.TEXT) {
5155e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            }
5165e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            if (type != XmlPullParser.START_TAG) {
5175e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                throw new XmlPullParserException(
5185e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                        parser.getPositionDescription()
5195e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                                + ": <item> tag requires a 'drawable' attribute or "
5205e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                                + "child tag defining a drawable");
5215e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            }
5226dbe51b50e82057af4d29882889444d22ac19c9cAlan Viverette            dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
5235e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
5245e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
5255e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        return mState.addStateSet(states, dr, keyframeId);
5265e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    }
5275e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
5285e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    @Override
5295e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    public Drawable mutate() {
5305004032ebc2aee97c5884b7f91cc33d2f98ae8b5Alan Viverette        if (!mMutated && super.mutate() == this) {
5318dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette            mState.mutate();
5325e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            mMutated = true;
5335e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
5345e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
5355e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        return this;
5365e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    }
5375e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
5388dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette    @Override
5398dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette    AnimatedStateListState cloneConstantState() {
5408dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette        return new AnimatedStateListState(mState, this, null);
5418dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette    }
5428dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette
543727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette    /**
544727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette     * @hide
545727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette     */
546727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette    public void clearMutated() {
547727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette        super.clearMutated();
548727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette        mMutated = false;
549727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette    }
550727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette
5515e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    static class AnimatedStateListState extends StateListState {
5525b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui        // REVERSED_BIT is indicating the current transition's direction.
5535b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui        private static final long REVERSED_BIT = 0x100000000l;
5545b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui
5555b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui        // REVERSIBLE_FLAG_BIT is indicating whether the whole transition has
5565b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui        // reversible flag set to true.
5575b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui        private static final long REVERSIBLE_FLAG_BIT = 0x200000000l;
5585e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
559d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        int[] mAnimThemeAttrs;
560d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette
5618dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette        LongSparseLongArray mTransitions;
5628dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette        SparseIntArray mStateIds;
5635e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
564f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette        AnimatedStateListState(@Nullable AnimatedStateListState orig,
565f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette                @NonNull AnimatedStateListDrawable owner, @Nullable Resources res) {
5665e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            super(orig, owner, res);
5675e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
5685e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            if (orig != null) {
5698dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette                // Perform a shallow copy and rely on mutate() to deep-copy.
570d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                mAnimThemeAttrs = orig.mAnimThemeAttrs;
5718dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette                mTransitions = orig.mTransitions;
5728dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette                mStateIds = orig.mStateIds;
5735e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            } else {
5745e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                mTransitions = new LongSparseLongArray();
5755e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                mStateIds = new SparseIntArray();
5765e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            }
5775e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
5785e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
57906ff2af68aa1041eeb26778e994e0fe196bf8b1eAlan Viverette        void mutate() {
5808dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette            mTransitions = mTransitions.clone();
5818dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette            mStateIds = mStateIds.clone();
5828dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette        }
5838dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette
584f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette        int addTransition(int fromId, int toId, @NonNull Drawable anim, boolean reversible) {
5855e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            final int pos = super.addChild(anim);
5865e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            final long keyFromTo = generateTransitionKey(fromId, toId);
5875b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui            long reversibleBit = 0;
5885b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui            if (reversible) {
5895b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui                reversibleBit = REVERSIBLE_FLAG_BIT;
5905b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui            }
5915b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui            mTransitions.append(keyFromTo, pos | reversibleBit);
5925e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
5935e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            if (reversible) {
5945e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                final long keyToFrom = generateTransitionKey(toId, fromId);
5955b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui                mTransitions.append(keyToFrom, pos | REVERSED_BIT | reversibleBit);
5965e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            }
5975e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
598102a6bff77c618112762245dbd798c8d7f6d44eaAlan Viverette            return pos;
5995e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
6005e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
601f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette        int addStateSet(@NonNull int[] stateSet, @NonNull Drawable drawable, int id) {
6025e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            final int index = super.addStateSet(stateSet, drawable);
6035e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            mStateIds.put(index, id);
6045e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            return index;
6055e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
6065e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
607f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette        int indexOfKeyframe(@NonNull int[] stateSet) {
6085e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            final int index = super.indexOfStateSet(stateSet);
6095e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            if (index >= 0) {
6105e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                return index;
6115e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            }
6125e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
6135e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            return super.indexOfStateSet(StateSet.WILD_CARD);
6145e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
6155e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
6165e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        int getKeyframeIdAt(int index) {
6175e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            return index < 0 ? 0 : mStateIds.get(index, 0);
6185e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
6195e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
6205e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        int indexOfTransition(int fromId, int toId) {
6215e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            final long keyFromTo = generateTransitionKey(fromId, toId);
6225e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            return (int) mTransitions.get(keyFromTo, -1);
6235e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
6245e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
6255e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        boolean isTransitionReversed(int fromId, int toId) {
6265e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            final long keyFromTo = generateTransitionKey(fromId, toId);
6275b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui            return (mTransitions.get(keyFromTo, -1) & REVERSED_BIT) != 0;
6285b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui        }
6295b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui
6305b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui        boolean transitionHasReversibleFlag(int fromId, int toId) {
6315b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui            final long keyFromTo = generateTransitionKey(fromId, toId);
6325b84eace6cb79c42fe43480f08c68b7dea4e074aztenghui            return (mTransitions.get(keyFromTo, -1) & REVERSIBLE_FLAG_BIT) != 0;
6335e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
6345e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
6355e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        @Override
636d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        public boolean canApplyTheme() {
637d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette            return mAnimThemeAttrs != null || super.canApplyTheme();
638d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        }
639d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette
640d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        @Override
6415e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        public Drawable newDrawable() {
6425e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            return new AnimatedStateListDrawable(this, null);
6435e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
6445e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
6455e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        @Override
6465e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        public Drawable newDrawable(Resources res) {
6475e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            return new AnimatedStateListDrawable(this, res);
6485e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
6495e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
6505e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        private static long generateTransitionKey(int fromId, int toId) {
6515e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            return (long) fromId << 32 | toId;
6525e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
6535e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    }
6545e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
6555ed8f27858dbdf85203068eca46eef0a65f3344eAlan Viverette    @Override
6568dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette    protected void setConstantState(@NonNull DrawableContainerState state) {
6575e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        super.setConstantState(state);
6585e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
6598dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette        if (state instanceof AnimatedStateListState) {
6608dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette            mState = (AnimatedStateListState) state;
6618dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette        }
6625e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    }
6635e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
664f456b1f078639a422f966ef2e9376cbd5ae3d274Alan Viverette    private AnimatedStateListDrawable(@Nullable AnimatedStateListState state, @Nullable Resources res) {
6655e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        super(null);
6665e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
6678dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette        // Every animated state list drawable has its own constant state.
6685e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        final AnimatedStateListState newState = new AnimatedStateListState(state, this, res);
6695e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        setConstantState(newState);
6705e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        onStateChange(getState());
6715e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        jumpToCurrentState();
6725e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    }
6735e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
6745e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    /**
6755e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette     * Interpolates between frames with respect to their individual durations.
6765e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette     */
6775e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    private static class FrameInterpolator implements TimeInterpolator {
6785e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        private int[] mFrameTimes;
6795e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        private int mFrames;
6805e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        private int mTotalDuration;
6815e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
6825e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        public FrameInterpolator(AnimationDrawable d, boolean reversed) {
6835e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            updateFrames(d, reversed);
6845e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
6855e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
6865e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        public int updateFrames(AnimationDrawable d, boolean reversed) {
6875e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            final int N = d.getNumberOfFrames();
6885e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            mFrames = N;
6895e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
6905e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            if (mFrameTimes == null || mFrameTimes.length < N) {
6915e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                mFrameTimes = new int[N];
6925e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            }
6935e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
6945e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            final int[] frameTimes = mFrameTimes;
6955e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            int totalDuration = 0;
6965e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            for (int i = 0; i < N; i++) {
6975e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                final int duration = d.getDuration(reversed ? N - i - 1 : i);
6985e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                frameTimes[i] = duration;
6995e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                totalDuration += duration;
7005e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            }
7015e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
7025e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            mTotalDuration = totalDuration;
7035e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            return totalDuration;
7045e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
7055e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
7065e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        public int getTotalDuration() {
7075e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            return mTotalDuration;
7085e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
7095e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
7105e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        @Override
7115e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        public float getInterpolation(float input) {
7125e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            final int elapsed = (int) (input * mTotalDuration + 0.5f);
7135e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            final int N = mFrames;
7145e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            final int[] frameTimes = mFrameTimes;
7155e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
7165e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            // Find the current frame and remaining time within that frame.
7175e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            int remaining = elapsed;
7185e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            int i = 0;
7195e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            while (i < N && remaining >= frameTimes[i]) {
7205e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                remaining -= frameTimes[i];
7215e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                i++;
7225e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            }
7235e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
7245e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            // Remaining time is relative of total duration.
7255e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            final float frameElapsed;
7265e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            if (i < N) {
7275e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                frameElapsed = remaining / (float) mTotalDuration;
7285e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            } else {
7295e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette                frameElapsed = 0;
7305e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            }
7315e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
7325e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            return i / (float) N + frameElapsed;
7335e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
7345e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    }
7355e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette}
736