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 * <animated-selector></code> element. Each keyframe Drawable is defined in a 465e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * nested <code><item></code> element. Transitions are defined in a nested 475e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * <code><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