1d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase/* 2d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * Copyright (C) 2010 The Android Open Source Project 3d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * 4d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * Licensed under the Apache License, Version 2.0 (the "License"); 5d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * you may not use this file except in compliance with the License. 6d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * You may obtain a copy of the License at 7d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * 8d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * http://www.apache.org/licenses/LICENSE-2.0 9d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * 10d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * Unless required by applicable law or agreed to in writing, software 11d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * distributed under the License is distributed on an "AS IS" BASIS, 12d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * See the License for the specific language governing permissions and 14d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * limitations under the License. 15d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase */ 16d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haasepackage android.animation; 17d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 187b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbyeimport android.annotation.AnimatorRes; 19ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viveretteimport android.annotation.AnyRes; 20ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viveretteimport android.annotation.NonNull; 21d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.Context; 22ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viveretteimport android.content.pm.ActivityInfo.Config; 23d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyarimport android.content.res.ConfigurationBoundResourceCache; 24d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyarimport android.content.res.ConstantState; 25d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.res.Resources; 26cf4832f69c8786b098ce18c24319021f8cd6733aztenghuiimport android.content.res.Resources.NotFoundException; 27e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghuiimport android.content.res.Resources.Theme; 28d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.res.TypedArray; 29d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.res.XmlResourceParser; 30cf4832f69c8786b098ce18c24319021f8cd6733aztenghuiimport android.graphics.Path; 31d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.util.AttributeSet; 32eb034fbca40006c55db143047eb628c4b657730aztenghuiimport android.util.Log; 33cf4832f69c8786b098ce18c24319021f8cd6733aztenghuiimport android.util.PathParser; 34f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyarimport android.util.StateSet; 355bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haaseimport android.util.TypedValue; 36d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.util.Xml; 37eb034fbca40006c55db143047eb628c4b657730aztenghuiimport android.view.InflateException; 38d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.view.animation.AnimationUtils; 39d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyarimport android.view.animation.BaseInterpolator; 40d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyarimport android.view.animation.Interpolator; 41e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 42e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghuiimport com.android.internal.R; 43e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 44d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport org.xmlpull.v1.XmlPullParser; 45d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport org.xmlpull.v1.XmlPullParserException; 46d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 47d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport java.io.IOException; 48d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport java.util.ArrayList; 49d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 50d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase/** 516cfdf4538049e4b96f50d8c0fe3119664420cc34Chet Haase * This class is used to instantiate animator XML files into Animator objects. 52d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * <p> 536cfdf4538049e4b96f50d8c0fe3119664420cc34Chet Haase * For performance reasons, inflation relies heavily on pre-processing of 54d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * XML files that is done at build time. Therefore, it is not currently possible 556cfdf4538049e4b96f50d8c0fe3119664420cc34Chet Haase * to use this inflater with an XmlPullParser over a plain XML file at runtime; 56d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * it only works with an XmlPullParser returned from a compiled resource (R. 57d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * <em>something</em> file.) 58d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase */ 59a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haasepublic class AnimatorInflater { 60eb034fbca40006c55db143047eb628c4b657730aztenghui private static final String TAG = "AnimatorInflater"; 61d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase /** 62a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * These flags are used when parsing AnimatorSet objects 63d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase */ 64d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase private static final int TOGETHER = 0; 65d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase private static final int SEQUENTIALLY = 1; 66d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 67d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase /** 68d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * Enum values used in XML attributes to indicate the value for mValueType 69d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase */ 70d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase private static final int VALUE_TYPE_FLOAT = 0; 71d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase private static final int VALUE_TYPE_INT = 1; 72eb034fbca40006c55db143047eb628c4b657730aztenghui private static final int VALUE_TYPE_PATH = 2; 73d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static final int VALUE_TYPE_COLOR = 3; 749032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu private static final int VALUE_TYPE_UNDEFINED = 4; 75d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 76eb034fbca40006c55db143047eb628c4b657730aztenghui private static final boolean DBG_ANIMATOR_INFLATER = false; 77eb034fbca40006c55db143047eb628c4b657730aztenghui 78d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar // used to calculate changing configs for resource references 79d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar private static final TypedValue sTmpTypedValue = new TypedValue(); 80d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar 81d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase /** 82a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * Loads an {@link Animator} object from a resource 83d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * 847513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu * @param context Application context used to access resources 85d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * @param id The resource id of the animation to load 86a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * @return The animator object reference by the specified id 87d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded 88d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase */ 897b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye public static Animator loadAnimator(Context context, @AnimatorRes int id) 90d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase throws NotFoundException { 917513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu return loadAnimator(context.getResources(), context.getTheme(), id); 92e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 93e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 94e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui /** 95e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * Loads an {@link Animator} object from a resource 96e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * 977513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu * @param resources The resources 98e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @param theme The theme 99e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @param id The resource id of the animation to load 100e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @return The animator object reference by the specified id 101e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded 102e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @hide 103e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui */ 1047513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu public static Animator loadAnimator(Resources resources, Theme theme, int id) 105e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui throws NotFoundException { 1067513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu return loadAnimator(resources, theme, id, 1); 107fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount } 108fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount 109fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount /** @hide */ 110fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount public static Animator loadAnimator(Resources resources, Theme theme, int id, 111fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount float pathErrorScale) throws NotFoundException { 112d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final ConfigurationBoundResourceCache<Animator> animatorCache = resources 113d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar .getAnimatorCache(); 114fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Animator animator = animatorCache.getInstance(id, resources, theme); 115d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (animator != null) { 116d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (DBG_ANIMATOR_INFLATER) { 117d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar Log.d(TAG, "loaded animator from cache, " + resources.getResourceName(id)); 118d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 119d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar return animator; 120d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } else if (DBG_ANIMATOR_INFLATER) { 121d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar Log.d(TAG, "cache miss for animator " + resources.getResourceName(id)); 122d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 123d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase XmlResourceParser parser = null; 124d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase try { 125e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui parser = resources.getAnimation(id); 1267513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu animator = createAnimatorFromXml(resources, theme, parser, pathErrorScale); 127d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (animator != null) { 128d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animator.appendChangingConfigurations(getChangingConfigs(resources, id)); 129d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final ConstantState<Animator> constantState = animator.createConstantState(); 130d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (constantState != null) { 131d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (DBG_ANIMATOR_INFLATER) { 132d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar Log.d(TAG, "caching animator for res " + resources.getResourceName(id)); 133d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 134d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animatorCache.put(id, theme, constantState); 135d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar // create a new animator so that cached version is never used by the user 136d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animator = constantState.newInstance(resources, theme); 137d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 138d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 139d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar return animator; 140d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } catch (XmlPullParserException ex) { 141d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase Resources.NotFoundException rnf = 142d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase new Resources.NotFoundException("Can't load animation resource ID #0x" + 143fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount Integer.toHexString(id)); 144d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase rnf.initCause(ex); 145d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase throw rnf; 146d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } catch (IOException ex) { 147d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase Resources.NotFoundException rnf = 148d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase new Resources.NotFoundException("Can't load animation resource ID #0x" + 149fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount Integer.toHexString(id)); 150d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase rnf.initCause(ex); 151d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase throw rnf; 152d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } finally { 153d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase if (parser != null) parser.close(); 154d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 155d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 156d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 157f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar public static StateListAnimator loadStateListAnimator(Context context, int id) 158f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throws NotFoundException { 159d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final Resources resources = context.getResources(); 160d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final ConfigurationBoundResourceCache<StateListAnimator> cache = resources 161d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar .getStateListAnimatorCache(); 162d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final Theme theme = context.getTheme(); 163fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski StateListAnimator animator = cache.getInstance(id, resources, theme); 164d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (animator != null) { 165d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar return animator; 166d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 167f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar XmlResourceParser parser = null; 168f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar try { 169d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar parser = resources.getAnimation(id); 170d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animator = createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser)); 171d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (animator != null) { 172d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animator.appendChangingConfigurations(getChangingConfigs(resources, id)); 173d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final ConstantState<StateListAnimator> constantState = animator 174d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar .createConstantState(); 175d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (constantState != null) { 176d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar cache.put(id, theme, constantState); 177d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar // return a clone so that the animator in constant state is never used. 178d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animator = constantState.newInstance(resources, theme); 179d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 180d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 181d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar return animator; 182f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } catch (XmlPullParserException ex) { 183f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Resources.NotFoundException rnf = 184f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar new Resources.NotFoundException( 185f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar "Can't load state list animator resource ID #0x" + 186f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Integer.toHexString(id) 187f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar ); 188f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar rnf.initCause(ex); 189f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throw rnf; 190f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } catch (IOException ex) { 191f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Resources.NotFoundException rnf = 192f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar new Resources.NotFoundException( 193f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar "Can't load state list animator resource ID #0x" + 194f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Integer.toHexString(id) 195f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar ); 196f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar rnf.initCause(ex); 197f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throw rnf; 198f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } finally { 199f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar if (parser != null) { 200f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar parser.close(); 201f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 202f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 203f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 204f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 205f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar private static StateListAnimator createStateListAnimatorFromXml(Context context, 206f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar XmlPullParser parser, AttributeSet attributeSet) 207f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throws IOException, XmlPullParserException { 208f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int type; 209f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar StateListAnimator stateListAnimator = new StateListAnimator(); 210f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 211f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar while (true) { 212f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar type = parser.next(); 213f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar switch (type) { 214f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar case XmlPullParser.END_DOCUMENT: 215f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar case XmlPullParser.END_TAG: 216f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar return stateListAnimator; 217f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 218f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar case XmlPullParser.START_TAG: 219f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar // parse item 220f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Animator animator = null; 221f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar if ("item".equals(parser.getName())) { 222f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int attributeCount = parser.getAttributeCount(); 223f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int[] states = new int[attributeCount]; 224f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int stateIndex = 0; 225f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar for (int i = 0; i < attributeCount; i++) { 226f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int attrName = attributeSet.getAttributeNameResource(i); 227cf4832f69c8786b098ce18c24319021f8cd6733aztenghui if (attrName == R.attr.animation) { 228d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final int animId = attributeSet.getAttributeResourceValue(i, 0); 229d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animator = loadAnimator(context, animId); 230f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } else { 231f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar states[stateIndex++] = 232f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar attributeSet.getAttributeBooleanValue(i, false) ? 233f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar attrName : -attrName; 234f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 235f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 236f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar if (animator == null) { 237e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui animator = createAnimatorFromXml(context.getResources(), 2387513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu context.getTheme(), parser, 1f); 239f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 240f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 241f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar if (animator == null) { 242f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throw new Resources.NotFoundException( 243f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar "animation state item must have a valid animation"); 244f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 245f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar stateListAnimator 246f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar .addState(StateSet.trimStateSet(states, stateIndex), animator); 247f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 248f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar break; 249f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 250f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 251f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 252f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 253cf4832f69c8786b098ce18c24319021f8cd6733aztenghui /** 254eb034fbca40006c55db143047eb628c4b657730aztenghui * PathDataEvaluator is used to interpolate between two paths which are 255eb034fbca40006c55db143047eb628c4b657730aztenghui * represented in the same format but different control points' values. 256804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * The path is represented as verbs and points for each of the verbs. 257eb034fbca40006c55db143047eb628c4b657730aztenghui */ 258804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu private static class PathDataEvaluator implements TypeEvaluator<PathParser.PathData> { 259804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu private final PathParser.PathData mPathData = new PathParser.PathData(); 260eb034fbca40006c55db143047eb628c4b657730aztenghui 261eb034fbca40006c55db143047eb628c4b657730aztenghui @Override 262804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu public PathParser.PathData evaluate(float fraction, PathParser.PathData startPathData, 263804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu PathParser.PathData endPathData) { 264804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu if (!PathParser.interpolatePathData(mPathData, startPathData, endPathData, fraction)) { 265eb034fbca40006c55db143047eb628c4b657730aztenghui throw new IllegalArgumentException("Can't interpolate between" 266eb034fbca40006c55db143047eb628c4b657730aztenghui + " two incompatible pathData"); 267eb034fbca40006c55db143047eb628c4b657730aztenghui } 268804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu return mPathData; 269eb034fbca40006c55db143047eb628c4b657730aztenghui } 270eb034fbca40006c55db143047eb628c4b657730aztenghui } 271eb034fbca40006c55db143047eb628c4b657730aztenghui 272d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static PropertyValuesHolder getPVH(TypedArray styledAttributes, int valueType, 273d430753cba09acb07af8b313286f247c78a41a32Chet Haase int valueFromId, int valueToId, String propertyName) { 2745bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase 275d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypedValue tvFrom = styledAttributes.peekValue(valueFromId); 2765bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase boolean hasFrom = (tvFrom != null); 2775bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase int fromType = hasFrom ? tvFrom.type : 0; 278d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypedValue tvTo = styledAttributes.peekValue(valueToId); 2795bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase boolean hasTo = (tvTo != null); 2805bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase int toType = hasTo ? tvTo.type : 0; 2815bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase 2829032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu if (valueType == VALUE_TYPE_UNDEFINED) { 2839032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu // Check whether it's color type. If not, fall back to default type (i.e. float type) 2849032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu if ((hasFrom && isColorType(fromType)) || (hasTo && isColorType(toType))) { 2859032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu valueType = VALUE_TYPE_COLOR; 2869032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } else { 2879032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu valueType = VALUE_TYPE_FLOAT; 2889032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } 2899032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } 2909032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu 2919032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu boolean getFloats = (valueType == VALUE_TYPE_FLOAT); 2929032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu 293d430753cba09acb07af8b313286f247c78a41a32Chet Haase PropertyValuesHolder returnValue = null; 294d430753cba09acb07af8b313286f247c78a41a32Chet Haase 295eb034fbca40006c55db143047eb628c4b657730aztenghui if (valueType == VALUE_TYPE_PATH) { 296d430753cba09acb07af8b313286f247c78a41a32Chet Haase String fromString = styledAttributes.getString(valueFromId); 297d430753cba09acb07af8b313286f247c78a41a32Chet Haase String toString = styledAttributes.getString(valueToId); 298804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu PathParser.PathData nodesFrom = fromString == null 299804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ? null : new PathParser.PathData(fromString); 300804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu PathParser.PathData nodesTo = toString == null 301804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ? null : new PathParser.PathData(toString); 302d430753cba09acb07af8b313286f247c78a41a32Chet Haase 303d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (nodesFrom != null || nodesTo != null) { 304d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (nodesFrom != null) { 305804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu TypeEvaluator evaluator = new PathDataEvaluator(); 306d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (nodesTo != null) { 307d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (!PathParser.canMorph(nodesFrom, nodesTo)) { 308d430753cba09acb07af8b313286f247c78a41a32Chet Haase throw new InflateException(" Can't morph from " + fromString + " to " + 309d430753cba09acb07af8b313286f247c78a41a32Chet Haase toString); 310d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 311d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofObject(propertyName, evaluator, 312d430753cba09acb07af8b313286f247c78a41a32Chet Haase nodesFrom, nodesTo); 313d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 314d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofObject(propertyName, evaluator, 315d430753cba09acb07af8b313286f247c78a41a32Chet Haase (Object) nodesFrom); 316d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 317d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else if (nodesTo != null) { 318804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu TypeEvaluator evaluator = new PathDataEvaluator(); 319d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofObject(propertyName, evaluator, 320d430753cba09acb07af8b313286f247c78a41a32Chet Haase (Object) nodesTo); 321d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 322d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 323eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 324d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypeEvaluator evaluator = null; 325eb034fbca40006c55db143047eb628c4b657730aztenghui // Integer and float value types are handled here. 3269032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu if (valueType == VALUE_TYPE_COLOR) { 327eb034fbca40006c55db143047eb628c4b657730aztenghui // special case for colors: ignore valueType and get ints 328eb034fbca40006c55db143047eb628c4b657730aztenghui evaluator = ArgbEvaluator.getInstance(); 329eb034fbca40006c55db143047eb628c4b657730aztenghui } 330d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (getFloats) { 331d430753cba09acb07af8b313286f247c78a41a32Chet Haase float valueFrom; 332d430753cba09acb07af8b313286f247c78a41a32Chet Haase float valueTo; 333d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (hasFrom) { 334d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (fromType == TypedValue.TYPE_DIMENSION) { 335d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueFrom = styledAttributes.getDimension(valueFromId, 0f); 336d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 337d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueFrom = styledAttributes.getFloat(valueFromId, 0f); 338d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 339d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (hasTo) { 340d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 341d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getDimension(valueToId, 0f); 342d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 343d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getFloat(valueToId, 0f); 344d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 345d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofFloat(propertyName, 346d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueFrom, valueTo); 347d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 348d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofFloat(propertyName, valueFrom); 349d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 350d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 351d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 352d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getDimension(valueToId, 0f); 353d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 354d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getFloat(valueToId, 0f); 355d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 356d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofFloat(propertyName, valueTo); 357d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 358d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 359d430753cba09acb07af8b313286f247c78a41a32Chet Haase int valueFrom; 360d430753cba09acb07af8b313286f247c78a41a32Chet Haase int valueTo; 361d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (hasFrom) { 362d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (fromType == TypedValue.TYPE_DIMENSION) { 363d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueFrom = (int) styledAttributes.getDimension(valueFromId, 0f); 3649032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } else if (isColorType(fromType)) { 365d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueFrom = styledAttributes.getColor(valueFromId, 0); 366d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 367d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueFrom = styledAttributes.getInt(valueFromId, 0); 368d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 369d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (hasTo) { 370d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 371d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = (int) styledAttributes.getDimension(valueToId, 0f); 3729032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } else if (isColorType(toType)) { 373d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getColor(valueToId, 0); 374d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 375d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getInt(valueToId, 0); 376d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 377d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofInt(propertyName, valueFrom, valueTo); 378d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 379d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofInt(propertyName, valueFrom); 380d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 381d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 382d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (hasTo) { 383d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 384d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = (int) styledAttributes.getDimension(valueToId, 0f); 3859032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } else if (isColorType(toType)) { 386d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getColor(valueToId, 0); 387d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 388d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getInt(valueToId, 0); 389d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 390d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofInt(propertyName, valueTo); 391d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 392d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 393d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 394d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (returnValue != null && evaluator != null) { 395d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue.setEvaluator(evaluator); 396d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 397d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 398d430753cba09acb07af8b313286f247c78a41a32Chet Haase 399d430753cba09acb07af8b313286f247c78a41a32Chet Haase return returnValue; 400d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 401d430753cba09acb07af8b313286f247c78a41a32Chet Haase 402d430753cba09acb07af8b313286f247c78a41a32Chet Haase /** 403d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param anim The animator, must not be null 404d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param arrayAnimator Incoming typed array for Animator's attributes. 405d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param arrayObjectAnimator Incoming typed array for Object Animator's 406d430753cba09acb07af8b313286f247c78a41a32Chet Haase * attributes. 407d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param pixelSize The relative pixel size, used to calculate the 408d430753cba09acb07af8b313286f247c78a41a32Chet Haase * maximum error for path animations. 409d430753cba09acb07af8b313286f247c78a41a32Chet Haase */ 410d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static void parseAnimatorFromTypeArray(ValueAnimator anim, 411d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypedArray arrayAnimator, TypedArray arrayObjectAnimator, float pixelSize) { 412d430753cba09acb07af8b313286f247c78a41a32Chet Haase long duration = arrayAnimator.getInt(R.styleable.Animator_duration, 300); 413d430753cba09acb07af8b313286f247c78a41a32Chet Haase 414d430753cba09acb07af8b313286f247c78a41a32Chet Haase long startDelay = arrayAnimator.getInt(R.styleable.Animator_startOffset, 0); 415d430753cba09acb07af8b313286f247c78a41a32Chet Haase 4162787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu int valueType = arrayAnimator.getInt(R.styleable.Animator_valueType, VALUE_TYPE_UNDEFINED); 417d430753cba09acb07af8b313286f247c78a41a32Chet Haase 4182787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu if (valueType == VALUE_TYPE_UNDEFINED) { 4192787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu valueType = inferValueTypeFromValues(arrayAnimator, R.styleable.Animator_valueFrom, 4202787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu R.styleable.Animator_valueTo); 4212787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu } 422d430753cba09acb07af8b313286f247c78a41a32Chet Haase PropertyValuesHolder pvh = getPVH(arrayAnimator, valueType, 423d430753cba09acb07af8b313286f247c78a41a32Chet Haase R.styleable.Animator_valueFrom, R.styleable.Animator_valueTo, ""); 424d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (pvh != null) { 425d430753cba09acb07af8b313286f247c78a41a32Chet Haase anim.setValues(pvh); 4265bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } 4275bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase 428eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setDuration(duration); 429eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setStartDelay(startDelay); 430eb034fbca40006c55db143047eb628c4b657730aztenghui 431eb034fbca40006c55db143047eb628c4b657730aztenghui if (arrayAnimator.hasValue(R.styleable.Animator_repeatCount)) { 432eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setRepeatCount( 433eb034fbca40006c55db143047eb628c4b657730aztenghui arrayAnimator.getInt(R.styleable.Animator_repeatCount, 0)); 434eb034fbca40006c55db143047eb628c4b657730aztenghui } 435eb034fbca40006c55db143047eb628c4b657730aztenghui if (arrayAnimator.hasValue(R.styleable.Animator_repeatMode)) { 436eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setRepeatMode( 437eb034fbca40006c55db143047eb628c4b657730aztenghui arrayAnimator.getInt(R.styleable.Animator_repeatMode, 438eb034fbca40006c55db143047eb628c4b657730aztenghui ValueAnimator.RESTART)); 439eb034fbca40006c55db143047eb628c4b657730aztenghui } 440eb034fbca40006c55db143047eb628c4b657730aztenghui 441eb034fbca40006c55db143047eb628c4b657730aztenghui if (arrayObjectAnimator != null) { 442d430753cba09acb07af8b313286f247c78a41a32Chet Haase setupObjectAnimator(anim, arrayObjectAnimator, valueType == VALUE_TYPE_FLOAT, 443d430753cba09acb07af8b313286f247c78a41a32Chet Haase pixelSize); 444eb034fbca40006c55db143047eb628c4b657730aztenghui } 445eb034fbca40006c55db143047eb628c4b657730aztenghui } 446eb034fbca40006c55db143047eb628c4b657730aztenghui 447eb034fbca40006c55db143047eb628c4b657730aztenghui /** 448eb034fbca40006c55db143047eb628c4b657730aztenghui * Setup the Animator to achieve path morphing. 449eb034fbca40006c55db143047eb628c4b657730aztenghui * 450eb034fbca40006c55db143047eb628c4b657730aztenghui * @param anim The target Animator which will be updated. 451eb034fbca40006c55db143047eb628c4b657730aztenghui * @param arrayAnimator TypedArray for the ValueAnimator. 452eb034fbca40006c55db143047eb628c4b657730aztenghui * @return the PathDataEvaluator. 453eb034fbca40006c55db143047eb628c4b657730aztenghui */ 454eb034fbca40006c55db143047eb628c4b657730aztenghui private static TypeEvaluator setupAnimatorForPath(ValueAnimator anim, 455eb034fbca40006c55db143047eb628c4b657730aztenghui TypedArray arrayAnimator) { 456eb034fbca40006c55db143047eb628c4b657730aztenghui TypeEvaluator evaluator = null; 457eb034fbca40006c55db143047eb628c4b657730aztenghui String fromString = arrayAnimator.getString(R.styleable.Animator_valueFrom); 458eb034fbca40006c55db143047eb628c4b657730aztenghui String toString = arrayAnimator.getString(R.styleable.Animator_valueTo); 459804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu PathParser.PathData pathDataFrom = fromString == null 460804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ? null : new PathParser.PathData(fromString); 461804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu PathParser.PathData pathDataTo = toString == null 462804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ? null : new PathParser.PathData(toString); 463804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 464804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu if (pathDataFrom != null) { 465804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu if (pathDataTo != null) { 466804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu anim.setObjectValues(pathDataFrom, pathDataTo); 467804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu if (!PathParser.canMorph(pathDataFrom, pathDataTo)) { 468eb034fbca40006c55db143047eb628c4b657730aztenghui throw new InflateException(arrayAnimator.getPositionDescription() 469eb034fbca40006c55db143047eb628c4b657730aztenghui + " Can't morph from " + fromString + " to " + toString); 470eb034fbca40006c55db143047eb628c4b657730aztenghui } 471eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 472804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu anim.setObjectValues((Object)pathDataFrom); 473eb034fbca40006c55db143047eb628c4b657730aztenghui } 474804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu evaluator = new PathDataEvaluator(); 475804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } else if (pathDataTo != null) { 476804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu anim.setObjectValues((Object)pathDataTo); 477804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu evaluator = new PathDataEvaluator(); 478eb034fbca40006c55db143047eb628c4b657730aztenghui } 479eb034fbca40006c55db143047eb628c4b657730aztenghui 480eb034fbca40006c55db143047eb628c4b657730aztenghui if (DBG_ANIMATOR_INFLATER && evaluator != null) { 481eb034fbca40006c55db143047eb628c4b657730aztenghui Log.v(TAG, "create a new PathDataEvaluator here"); 482eb034fbca40006c55db143047eb628c4b657730aztenghui } 483eb034fbca40006c55db143047eb628c4b657730aztenghui 484eb034fbca40006c55db143047eb628c4b657730aztenghui return evaluator; 485eb034fbca40006c55db143047eb628c4b657730aztenghui } 486eb034fbca40006c55db143047eb628c4b657730aztenghui 487eb034fbca40006c55db143047eb628c4b657730aztenghui /** 488eb034fbca40006c55db143047eb628c4b657730aztenghui * Setup ObjectAnimator's property or values from pathData. 489eb034fbca40006c55db143047eb628c4b657730aztenghui * 490eb034fbca40006c55db143047eb628c4b657730aztenghui * @param anim The target Animator which will be updated. 491eb034fbca40006c55db143047eb628c4b657730aztenghui * @param arrayObjectAnimator TypedArray for the ObjectAnimator. 492eb034fbca40006c55db143047eb628c4b657730aztenghui * @param getFloats True if the value type is float. 493fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount * @param pixelSize The relative pixel size, used to calculate the 494fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount * maximum error for path animations. 495eb034fbca40006c55db143047eb628c4b657730aztenghui */ 496eb034fbca40006c55db143047eb628c4b657730aztenghui private static void setupObjectAnimator(ValueAnimator anim, TypedArray arrayObjectAnimator, 497fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount boolean getFloats, float pixelSize) { 498eb034fbca40006c55db143047eb628c4b657730aztenghui ObjectAnimator oa = (ObjectAnimator) anim; 499eb034fbca40006c55db143047eb628c4b657730aztenghui String pathData = arrayObjectAnimator.getString(R.styleable.PropertyAnimator_pathData); 500eb034fbca40006c55db143047eb628c4b657730aztenghui 5012787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu // Path can be involved in an ObjectAnimator in the following 3 ways: 5022787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu // 1) Path morphing: the property to be animated is pathData, and valueFrom and valueTo 5032787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu // are both of pathType. valueType = pathType needs to be explicitly defined. 5042787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu // 2) A property in X or Y dimension can be animated along a path: the property needs to be 5052787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu // defined in propertyXName or propertyYName attribute, the path will be defined in the 5062787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu // pathData attribute. valueFrom and valueTo will not be necessary for this animation. 5072787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu // 3) PathInterpolator can also define a path (in pathData) for its interpolation curve. 5082787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu // Here we are dealing with case 2: 509eb034fbca40006c55db143047eb628c4b657730aztenghui if (pathData != null) { 510eb034fbca40006c55db143047eb628c4b657730aztenghui String propertyXName = 511eb034fbca40006c55db143047eb628c4b657730aztenghui arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyXName); 512eb034fbca40006c55db143047eb628c4b657730aztenghui String propertyYName = 513eb034fbca40006c55db143047eb628c4b657730aztenghui arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyYName); 514eb034fbca40006c55db143047eb628c4b657730aztenghui 515eb034fbca40006c55db143047eb628c4b657730aztenghui if (propertyXName == null && propertyYName == null) { 516eb034fbca40006c55db143047eb628c4b657730aztenghui throw new InflateException(arrayObjectAnimator.getPositionDescription() 517eb034fbca40006c55db143047eb628c4b657730aztenghui + " propertyXName or propertyYName is needed for PathData"); 518eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 519eb034fbca40006c55db143047eb628c4b657730aztenghui Path path = PathParser.createPathFromPathData(pathData); 520fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount float error = 0.5f * pixelSize; // max half a pixel error 521fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount PathKeyframes keyframeSet = KeyframeSet.ofPath(path, error); 522984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount Keyframes xKeyframes; 523984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount Keyframes yKeyframes; 524984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount if (getFloats) { 525984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount xKeyframes = keyframeSet.createXFloatKeyframes(); 526984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount yKeyframes = keyframeSet.createYFloatKeyframes(); 527984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount } else { 528984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount xKeyframes = keyframeSet.createXIntKeyframes(); 529984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount yKeyframes = keyframeSet.createYIntKeyframes(); 530984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount } 531eb034fbca40006c55db143047eb628c4b657730aztenghui PropertyValuesHolder x = null; 532eb034fbca40006c55db143047eb628c4b657730aztenghui PropertyValuesHolder y = null; 533eb034fbca40006c55db143047eb628c4b657730aztenghui if (propertyXName != null) { 534984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount x = PropertyValuesHolder.ofKeyframes(propertyXName, xKeyframes); 535eb034fbca40006c55db143047eb628c4b657730aztenghui } 536eb034fbca40006c55db143047eb628c4b657730aztenghui if (propertyYName != null) { 537984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount y = PropertyValuesHolder.ofKeyframes(propertyYName, yKeyframes); 538eb034fbca40006c55db143047eb628c4b657730aztenghui } 539eb034fbca40006c55db143047eb628c4b657730aztenghui if (x == null) { 540eb034fbca40006c55db143047eb628c4b657730aztenghui oa.setValues(y); 541eb034fbca40006c55db143047eb628c4b657730aztenghui } else if (y == null) { 542eb034fbca40006c55db143047eb628c4b657730aztenghui oa.setValues(x); 543eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 544eb034fbca40006c55db143047eb628c4b657730aztenghui oa.setValues(x, y); 545eb034fbca40006c55db143047eb628c4b657730aztenghui } 546eb034fbca40006c55db143047eb628c4b657730aztenghui } 547eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 548eb034fbca40006c55db143047eb628c4b657730aztenghui String propertyName = 549eb034fbca40006c55db143047eb628c4b657730aztenghui arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyName); 550eb034fbca40006c55db143047eb628c4b657730aztenghui oa.setPropertyName(propertyName); 551eb034fbca40006c55db143047eb628c4b657730aztenghui } 552eb034fbca40006c55db143047eb628c4b657730aztenghui } 553eb034fbca40006c55db143047eb628c4b657730aztenghui 554eb034fbca40006c55db143047eb628c4b657730aztenghui /** 555eb034fbca40006c55db143047eb628c4b657730aztenghui * Setup ValueAnimator's values. 556eb034fbca40006c55db143047eb628c4b657730aztenghui * This will handle all of the integer, float and color types. 557eb034fbca40006c55db143047eb628c4b657730aztenghui * 558eb034fbca40006c55db143047eb628c4b657730aztenghui * @param anim The target Animator which will be updated. 559eb034fbca40006c55db143047eb628c4b657730aztenghui * @param arrayAnimator TypedArray for the ValueAnimator. 560eb034fbca40006c55db143047eb628c4b657730aztenghui * @param getFloats True if the value type is float. 561eb034fbca40006c55db143047eb628c4b657730aztenghui * @param hasFrom True if "valueFrom" exists. 562eb034fbca40006c55db143047eb628c4b657730aztenghui * @param fromType The type of "valueFrom". 563eb034fbca40006c55db143047eb628c4b657730aztenghui * @param hasTo True if "valueTo" exists. 564eb034fbca40006c55db143047eb628c4b657730aztenghui * @param toType The type of "valueTo". 565eb034fbca40006c55db143047eb628c4b657730aztenghui */ 566eb034fbca40006c55db143047eb628c4b657730aztenghui private static void setupValues(ValueAnimator anim, TypedArray arrayAnimator, 567eb034fbca40006c55db143047eb628c4b657730aztenghui boolean getFloats, boolean hasFrom, int fromType, boolean hasTo, int toType) { 568eb034fbca40006c55db143047eb628c4b657730aztenghui int valueFromIndex = R.styleable.Animator_valueFrom; 569eb034fbca40006c55db143047eb628c4b657730aztenghui int valueToIndex = R.styleable.Animator_valueTo; 5705bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (getFloats) { 5715bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase float valueFrom; 5725bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase float valueTo; 5735bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasFrom) { 5745bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (fromType == TypedValue.TYPE_DIMENSION) { 575cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = arrayAnimator.getDimension(valueFromIndex, 0f); 5765bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 577cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = arrayAnimator.getFloat(valueFromIndex, 0f); 5785bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } 5795bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasTo) { 5805bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 581cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getDimension(valueToIndex, 0f); 5822794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 583cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getFloat(valueToIndex, 0f); 5842794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 5855bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setFloatValues(valueFrom, valueTo); 5865bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 5875bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setFloatValues(valueFrom); 5885bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } 5895bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 5905bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 591cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getDimension(valueToIndex, 0f); 5922794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 593cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getFloat(valueToIndex, 0f); 594d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 5955bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setFloatValues(valueTo); 5962794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 5975bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 5985bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase int valueFrom; 5995bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase int valueTo; 6005bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasFrom) { 6015bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (fromType == TypedValue.TYPE_DIMENSION) { 602cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = (int) arrayAnimator.getDimension(valueFromIndex, 0f); 6039032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } else if (isColorType(fromType)) { 604cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = arrayAnimator.getColor(valueFromIndex, 0); 6055bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 606cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = arrayAnimator.getInt(valueFromIndex, 0); 6075bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } 6085bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasTo) { 6095bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 610cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = (int) arrayAnimator.getDimension(valueToIndex, 0f); 6119032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } else if (isColorType(toType)) { 612cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getColor(valueToIndex, 0); 6132794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 614cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getInt(valueToIndex, 0); 6152794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 6165bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setIntValues(valueFrom, valueTo); 6172794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 6185bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setIntValues(valueFrom); 619d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 6205bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 6215bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasTo) { 6225bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 623cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = (int) arrayAnimator.getDimension(valueToIndex, 0f); 6249032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } else if (isColorType(toType)) { 625cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getColor(valueToIndex, 0); 6262794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 627cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getInt(valueToIndex, 0); 6282794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 6295bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setIntValues(valueTo); 630d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 6312794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 632d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 633e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 634e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 635fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser, 6367513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu float pixelSize) 637e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui throws XmlPullParserException, IOException { 638fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount return createAnimatorFromXml(res, theme, parser, Xml.asAttributeSet(parser), null, 0, 6397513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu pixelSize); 640e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 641e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 642e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser, 6437513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu AttributeSet attrs, AnimatorSet parent, int sequenceOrdering, float pixelSize) 6447513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu throws XmlPullParserException, IOException { 645e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui Animator anim = null; 646e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui ArrayList<Animator> childAnims = null; 647e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 648e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui // Make sure we are on a start tag. 649e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui int type; 650e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui int depth = parser.getDepth(); 651e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 652e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) 653e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui && type != XmlPullParser.END_DOCUMENT) { 654e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 655e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (type != XmlPullParser.START_TAG) { 656e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui continue; 657e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 658e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 659e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui String name = parser.getName(); 660d430753cba09acb07af8b313286f247c78a41a32Chet Haase boolean gotValues = false; 661e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 662e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (name.equals("objectAnimator")) { 6637513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu anim = loadObjectAnimator(res, theme, attrs, pixelSize); 664e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else if (name.equals("animator")) { 6657513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu anim = loadAnimator(res, theme, attrs, null, pixelSize); 666e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else if (name.equals("set")) { 667e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui anim = new AnimatorSet(); 668e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui TypedArray a; 669e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (theme != null) { 670cf4832f69c8786b098ce18c24319021f8cd6733aztenghui a = theme.obtainStyledAttributes(attrs, R.styleable.AnimatorSet, 0, 0); 671e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else { 672cf4832f69c8786b098ce18c24319021f8cd6733aztenghui a = res.obtainAttributes(attrs, R.styleable.AnimatorSet); 673e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 674d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar anim.appendChangingConfigurations(a.getChangingConfigurations()); 675d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar int ordering = a.getInt(R.styleable.AnimatorSet_ordering, TOGETHER); 676fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering, 6777513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu pixelSize); 678e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui a.recycle(); 679d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else if (name.equals("propertyValuesHolder")) { 680d430753cba09acb07af8b313286f247c78a41a32Chet Haase PropertyValuesHolder[] values = loadValues(res, theme, parser, 681d430753cba09acb07af8b313286f247c78a41a32Chet Haase Xml.asAttributeSet(parser)); 682d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (values != null && anim != null && (anim instanceof ValueAnimator)) { 683d430753cba09acb07af8b313286f247c78a41a32Chet Haase ((ValueAnimator) anim).setValues(values); 684d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 685d430753cba09acb07af8b313286f247c78a41a32Chet Haase gotValues = true; 686e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else { 687e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui throw new RuntimeException("Unknown animator name: " + parser.getName()); 688e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 689e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 690d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (parent != null && !gotValues) { 691e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (childAnims == null) { 692e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui childAnims = new ArrayList<Animator>(); 693e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 694e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui childAnims.add(anim); 695e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 696e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 697e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (parent != null && childAnims != null) { 698e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui Animator[] animsArray = new Animator[childAnims.size()]; 699e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui int index = 0; 700e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui for (Animator a : childAnims) { 701e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui animsArray[index++] = a; 702e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 703e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (sequenceOrdering == TOGETHER) { 704e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui parent.playTogether(animsArray); 705e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else { 706e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui parent.playSequentially(animsArray); 707e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 708e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 709e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return anim; 710d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 711d430753cba09acb07af8b313286f247c78a41a32Chet Haase 712d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static PropertyValuesHolder[] loadValues(Resources res, Theme theme, 713d430753cba09acb07af8b313286f247c78a41a32Chet Haase XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException { 714d430753cba09acb07af8b313286f247c78a41a32Chet Haase ArrayList<PropertyValuesHolder> values = null; 715d430753cba09acb07af8b313286f247c78a41a32Chet Haase 716d430753cba09acb07af8b313286f247c78a41a32Chet Haase int type; 717d430753cba09acb07af8b313286f247c78a41a32Chet Haase while ((type = parser.getEventType()) != XmlPullParser.END_TAG && 718d430753cba09acb07af8b313286f247c78a41a32Chet Haase type != XmlPullParser.END_DOCUMENT) { 719d430753cba09acb07af8b313286f247c78a41a32Chet Haase 720d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (type != XmlPullParser.START_TAG) { 721d430753cba09acb07af8b313286f247c78a41a32Chet Haase parser.next(); 722d430753cba09acb07af8b313286f247c78a41a32Chet Haase continue; 723d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 724d430753cba09acb07af8b313286f247c78a41a32Chet Haase 725d430753cba09acb07af8b313286f247c78a41a32Chet Haase String name = parser.getName(); 726d430753cba09acb07af8b313286f247c78a41a32Chet Haase 727d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (name.equals("propertyValuesHolder")) { 728d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypedArray a; 729d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (theme != null) { 730d430753cba09acb07af8b313286f247c78a41a32Chet Haase a = theme.obtainStyledAttributes(attrs, R.styleable.PropertyValuesHolder, 0, 0); 731d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 732d430753cba09acb07af8b313286f247c78a41a32Chet Haase a = res.obtainAttributes(attrs, R.styleable.PropertyValuesHolder); 733d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 734d430753cba09acb07af8b313286f247c78a41a32Chet Haase String propertyName = a.getString(R.styleable.PropertyValuesHolder_propertyName); 735d430753cba09acb07af8b313286f247c78a41a32Chet Haase int valueType = a.getInt(R.styleable.PropertyValuesHolder_valueType, 7369032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu VALUE_TYPE_UNDEFINED); 7379032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu 738d430753cba09acb07af8b313286f247c78a41a32Chet Haase PropertyValuesHolder pvh = loadPvh(res, theme, parser, propertyName, valueType); 739d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (pvh == null) { 740d430753cba09acb07af8b313286f247c78a41a32Chet Haase pvh = getPVH(a, valueType, 741d430753cba09acb07af8b313286f247c78a41a32Chet Haase R.styleable.PropertyValuesHolder_valueFrom, 742d430753cba09acb07af8b313286f247c78a41a32Chet Haase R.styleable.PropertyValuesHolder_valueTo, propertyName); 743d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 744d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (pvh != null) { 745d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (values == null) { 746d430753cba09acb07af8b313286f247c78a41a32Chet Haase values = new ArrayList<PropertyValuesHolder>(); 747d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 748d430753cba09acb07af8b313286f247c78a41a32Chet Haase values.add(pvh); 749d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 750d430753cba09acb07af8b313286f247c78a41a32Chet Haase a.recycle(); 751d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 752d430753cba09acb07af8b313286f247c78a41a32Chet Haase 753d430753cba09acb07af8b313286f247c78a41a32Chet Haase parser.next(); 754d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 755d430753cba09acb07af8b313286f247c78a41a32Chet Haase 756d430753cba09acb07af8b313286f247c78a41a32Chet Haase PropertyValuesHolder[] valuesArray = null; 757d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (values != null) { 758d430753cba09acb07af8b313286f247c78a41a32Chet Haase int count = values.size(); 759d430753cba09acb07af8b313286f247c78a41a32Chet Haase valuesArray = new PropertyValuesHolder[count]; 760d430753cba09acb07af8b313286f247c78a41a32Chet Haase for (int i = 0; i < count; ++i) { 761d430753cba09acb07af8b313286f247c78a41a32Chet Haase valuesArray[i] = values.get(i); 762d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 763d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 764d430753cba09acb07af8b313286f247c78a41a32Chet Haase return valuesArray; 765d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 766d430753cba09acb07af8b313286f247c78a41a32Chet Haase 767a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu // When no value type is provided in keyframe, we need to infer the type from the value. i.e. 768a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu // if value is defined in the style of a color value, then the color type is returned. 769a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu // Otherwise, default float type is returned. 770a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu private static int inferValueTypeOfKeyframe(Resources res, Theme theme, AttributeSet attrs) { 771a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu int valueType; 772a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu TypedArray a; 773a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu if (theme != null) { 774a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu a = theme.obtainStyledAttributes(attrs, R.styleable.Keyframe, 0, 0); 775a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu } else { 776a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu a = res.obtainAttributes(attrs, R.styleable.Keyframe); 777a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu } 778a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu 779a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu TypedValue keyframeValue = a.peekValue(R.styleable.Keyframe_value); 780a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu boolean hasValue = (keyframeValue != null); 781a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu // When no value type is provided, check whether it's a color type first. 782a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu // If not, fall back to default value type (i.e. float type). 783a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu if (hasValue && isColorType(keyframeValue.type)) { 784a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu valueType = VALUE_TYPE_COLOR; 785a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu } else { 786a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu valueType = VALUE_TYPE_FLOAT; 787a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu } 788a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu a.recycle(); 789a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu return valueType; 790a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu } 791a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu 7922787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu private static int inferValueTypeFromValues(TypedArray styledAttributes, int valueFromId, 7932787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu int valueToId) { 7942787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu TypedValue tvFrom = styledAttributes.peekValue(valueFromId); 7952787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu boolean hasFrom = (tvFrom != null); 7962787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu int fromType = hasFrom ? tvFrom.type : 0; 7972787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu TypedValue tvTo = styledAttributes.peekValue(valueToId); 7982787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu boolean hasTo = (tvTo != null); 7992787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu int toType = hasTo ? tvTo.type : 0; 8002787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu 8012787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu int valueType; 8022787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu // Check whether it's color type. If not, fall back to default type (i.e. float type) 8032787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu if ((hasFrom && isColorType(fromType)) || (hasTo && isColorType(toType))) { 8042787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu valueType = VALUE_TYPE_COLOR; 8052787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu } else { 8062787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu valueType = VALUE_TYPE_FLOAT; 8072787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu } 8082787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu return valueType; 8092787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu } 8102787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu 811d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static void dumpKeyframes(Object[] keyframes, String header) { 812d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (keyframes == null || keyframes.length == 0) { 813d430753cba09acb07af8b313286f247c78a41a32Chet Haase return; 814d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 815d430753cba09acb07af8b313286f247c78a41a32Chet Haase Log.d(TAG, header); 816d430753cba09acb07af8b313286f247c78a41a32Chet Haase int count = keyframes.length; 817d430753cba09acb07af8b313286f247c78a41a32Chet Haase for (int i = 0; i < count; ++i) { 818d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe keyframe = (Keyframe) keyframes[i]; 819d430753cba09acb07af8b313286f247c78a41a32Chet Haase Log.d(TAG, "Keyframe " + i + ": fraction " + 820d430753cba09acb07af8b313286f247c78a41a32Chet Haase (keyframe.getFraction() < 0 ? "null" : keyframe.getFraction()) + ", " + 821d430753cba09acb07af8b313286f247c78a41a32Chet Haase ", value : " + ((keyframe.hasValue()) ? keyframe.getValue() : "null")); 822d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 823d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 824d430753cba09acb07af8b313286f247c78a41a32Chet Haase 8259032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu // Load property values holder if there are keyframes defined in it. Otherwise return null. 826d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static PropertyValuesHolder loadPvh(Resources res, Theme theme, XmlPullParser parser, 827d430753cba09acb07af8b313286f247c78a41a32Chet Haase String propertyName, int valueType) 828d430753cba09acb07af8b313286f247c78a41a32Chet Haase throws XmlPullParserException, IOException { 829d430753cba09acb07af8b313286f247c78a41a32Chet Haase 830d430753cba09acb07af8b313286f247c78a41a32Chet Haase PropertyValuesHolder value = null; 831d430753cba09acb07af8b313286f247c78a41a32Chet Haase ArrayList<Keyframe> keyframes = null; 832d430753cba09acb07af8b313286f247c78a41a32Chet Haase 833d430753cba09acb07af8b313286f247c78a41a32Chet Haase int type; 834d430753cba09acb07af8b313286f247c78a41a32Chet Haase while ((type = parser.next()) != XmlPullParser.END_TAG && 835d430753cba09acb07af8b313286f247c78a41a32Chet Haase type != XmlPullParser.END_DOCUMENT) { 836d430753cba09acb07af8b313286f247c78a41a32Chet Haase String name = parser.getName(); 837d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (name.equals("keyframe")) { 838a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu if (valueType == VALUE_TYPE_UNDEFINED) { 839a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu valueType = inferValueTypeOfKeyframe(res, theme, Xml.asAttributeSet(parser)); 840a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu } 841d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe keyframe = loadKeyframe(res, theme, Xml.asAttributeSet(parser), valueType); 842d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (keyframe != null) { 843d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (keyframes == null) { 844d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframes = new ArrayList<Keyframe>(); 845d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 846d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframes.add(keyframe); 847d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 848d430753cba09acb07af8b313286f247c78a41a32Chet Haase parser.next(); 849d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 850d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 851d430753cba09acb07af8b313286f247c78a41a32Chet Haase 852d430753cba09acb07af8b313286f247c78a41a32Chet Haase int count; 853d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (keyframes != null && (count = keyframes.size()) > 0) { 854d430753cba09acb07af8b313286f247c78a41a32Chet Haase // make sure we have keyframes at 0 and 1 855d430753cba09acb07af8b313286f247c78a41a32Chet Haase // If we have keyframes with set fractions, add keyframes at start/end 856d430753cba09acb07af8b313286f247c78a41a32Chet Haase // appropriately. If start/end have no set fractions: 857d430753cba09acb07af8b313286f247c78a41a32Chet Haase // if there's only one keyframe, set its fraction to 1 and add one at 0 858d430753cba09acb07af8b313286f247c78a41a32Chet Haase // if >1 keyframe, set the last fraction to 1, the first fraction to 0 859d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe firstKeyframe = keyframes.get(0); 860d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe lastKeyframe = keyframes.get(count - 1); 861d430753cba09acb07af8b313286f247c78a41a32Chet Haase float endFraction = lastKeyframe.getFraction(); 862d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (endFraction < 1) { 863d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (endFraction < 0) { 864d430753cba09acb07af8b313286f247c78a41a32Chet Haase lastKeyframe.setFraction(1); 865d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 866d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframes.add(keyframes.size(), createNewKeyframe(lastKeyframe, 1)); 867d430753cba09acb07af8b313286f247c78a41a32Chet Haase ++count; 868d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 869d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 870d430753cba09acb07af8b313286f247c78a41a32Chet Haase float startFraction = firstKeyframe.getFraction(); 871d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (startFraction != 0) { 872d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (startFraction < 0) { 873d430753cba09acb07af8b313286f247c78a41a32Chet Haase firstKeyframe.setFraction(0); 874d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 875d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframes.add(0, createNewKeyframe(firstKeyframe, 0)); 876d430753cba09acb07af8b313286f247c78a41a32Chet Haase ++count; 877d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 878d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 879d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe[] keyframeArray = new Keyframe[count]; 880d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframes.toArray(keyframeArray); 881d430753cba09acb07af8b313286f247c78a41a32Chet Haase for (int i = 0; i < count; ++i) { 882d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe keyframe = keyframeArray[i]; 883d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (keyframe.getFraction() < 0) { 884d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (i == 0) { 885d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframe.setFraction(0); 886d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else if (i == count - 1) { 887d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframe.setFraction(1); 888d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 889d430753cba09acb07af8b313286f247c78a41a32Chet Haase // figure out the start/end parameters of the current gap 890d430753cba09acb07af8b313286f247c78a41a32Chet Haase // in fractions and distribute the gap among those keyframes 891d430753cba09acb07af8b313286f247c78a41a32Chet Haase int startIndex = i; 892d430753cba09acb07af8b313286f247c78a41a32Chet Haase int endIndex = i; 893d430753cba09acb07af8b313286f247c78a41a32Chet Haase for (int j = startIndex + 1; j < count - 1; ++j) { 894d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (keyframeArray[j].getFraction() >= 0) { 895d430753cba09acb07af8b313286f247c78a41a32Chet Haase break; 896d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 897d430753cba09acb07af8b313286f247c78a41a32Chet Haase endIndex = j; 898d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 899d430753cba09acb07af8b313286f247c78a41a32Chet Haase float gap = keyframeArray[endIndex + 1].getFraction() - 900d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframeArray[startIndex - 1].getFraction(); 901d430753cba09acb07af8b313286f247c78a41a32Chet Haase distributeKeyframes(keyframeArray, gap, startIndex, endIndex); 902d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 903d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 904d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 905d430753cba09acb07af8b313286f247c78a41a32Chet Haase value = PropertyValuesHolder.ofKeyframe(propertyName, keyframeArray); 906d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (valueType == VALUE_TYPE_COLOR) { 907d430753cba09acb07af8b313286f247c78a41a32Chet Haase value.setEvaluator(ArgbEvaluator.getInstance()); 908d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 909d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 910d430753cba09acb07af8b313286f247c78a41a32Chet Haase 911d430753cba09acb07af8b313286f247c78a41a32Chet Haase return value; 912d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 913d430753cba09acb07af8b313286f247c78a41a32Chet Haase 914d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static Keyframe createNewKeyframe(Keyframe sampleKeyframe, float fraction) { 915d430753cba09acb07af8b313286f247c78a41a32Chet Haase return sampleKeyframe.getType() == float.class ? 916d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe.ofFloat(fraction) : 917d430753cba09acb07af8b313286f247c78a41a32Chet Haase (sampleKeyframe.getType() == int.class) ? 918d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe.ofInt(fraction) : 919d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe.ofObject(fraction); 920d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 921d430753cba09acb07af8b313286f247c78a41a32Chet Haase 922d430753cba09acb07af8b313286f247c78a41a32Chet Haase /** 923d430753cba09acb07af8b313286f247c78a41a32Chet Haase * Utility function to set fractions on keyframes to cover a gap in which the 924d430753cba09acb07af8b313286f247c78a41a32Chet Haase * fractions are not currently set. Keyframe fractions will be distributed evenly 925d430753cba09acb07af8b313286f247c78a41a32Chet Haase * in this gap. For example, a gap of 1 keyframe in the range 0-1 will be at .5, a gap 926d430753cba09acb07af8b313286f247c78a41a32Chet Haase * of .6 spread between two keyframes will be at .2 and .4 beyond the fraction at the 927d430753cba09acb07af8b313286f247c78a41a32Chet Haase * keyframe before startIndex. 928d430753cba09acb07af8b313286f247c78a41a32Chet Haase * Assumptions: 929d430753cba09acb07af8b313286f247c78a41a32Chet Haase * - First and last keyframe fractions (bounding this spread) are already set. So, 930d430753cba09acb07af8b313286f247c78a41a32Chet Haase * for example, if no fractions are set, we will already set first and last keyframe 931d430753cba09acb07af8b313286f247c78a41a32Chet Haase * fraction values to 0 and 1. 932d430753cba09acb07af8b313286f247c78a41a32Chet Haase * - startIndex must be >0 (which follows from first assumption). 933d430753cba09acb07af8b313286f247c78a41a32Chet Haase * - endIndex must be >= startIndex. 934d430753cba09acb07af8b313286f247c78a41a32Chet Haase * 935d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param keyframes the array of keyframes 936d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param gap The total gap we need to distribute 937d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param startIndex The index of the first keyframe whose fraction must be set 938d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param endIndex The index of the last keyframe whose fraction must be set 939d430753cba09acb07af8b313286f247c78a41a32Chet Haase */ 940d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static void distributeKeyframes(Keyframe[] keyframes, float gap, 941d430753cba09acb07af8b313286f247c78a41a32Chet Haase int startIndex, int endIndex) { 942d430753cba09acb07af8b313286f247c78a41a32Chet Haase int count = endIndex - startIndex + 2; 943d430753cba09acb07af8b313286f247c78a41a32Chet Haase float increment = gap / count; 944d430753cba09acb07af8b313286f247c78a41a32Chet Haase for (int i = startIndex; i <= endIndex; ++i) { 945d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframes[i].setFraction(keyframes[i-1].getFraction() + increment); 946d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 947d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 948d430753cba09acb07af8b313286f247c78a41a32Chet Haase 949d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static Keyframe loadKeyframe(Resources res, Theme theme, AttributeSet attrs, 950d430753cba09acb07af8b313286f247c78a41a32Chet Haase int valueType) 951d430753cba09acb07af8b313286f247c78a41a32Chet Haase throws XmlPullParserException, IOException { 952d430753cba09acb07af8b313286f247c78a41a32Chet Haase 953d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypedArray a; 954d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (theme != null) { 955d430753cba09acb07af8b313286f247c78a41a32Chet Haase a = theme.obtainStyledAttributes(attrs, R.styleable.Keyframe, 0, 0); 956d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 957d430753cba09acb07af8b313286f247c78a41a32Chet Haase a = res.obtainAttributes(attrs, R.styleable.Keyframe); 958d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 959d430753cba09acb07af8b313286f247c78a41a32Chet Haase 960d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe keyframe = null; 961d430753cba09acb07af8b313286f247c78a41a32Chet Haase 962d430753cba09acb07af8b313286f247c78a41a32Chet Haase float fraction = a.getFloat(R.styleable.Keyframe_fraction, -1); 963d430753cba09acb07af8b313286f247c78a41a32Chet Haase 9649032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu TypedValue keyframeValue = a.peekValue(R.styleable.Keyframe_value); 9659032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu boolean hasValue = (keyframeValue != null); 9669032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu if (valueType == VALUE_TYPE_UNDEFINED) { 9679032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu // When no value type is provided, check whether it's a color type first. 9689032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu // If not, fall back to default value type (i.e. float type). 9699032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu if (hasValue && isColorType(keyframeValue.type)) { 9709032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu valueType = VALUE_TYPE_COLOR; 9719032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } else { 9729032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu valueType = VALUE_TYPE_FLOAT; 9739032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } 9749032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } 975d430753cba09acb07af8b313286f247c78a41a32Chet Haase 976d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (hasValue) { 977d430753cba09acb07af8b313286f247c78a41a32Chet Haase switch (valueType) { 978d430753cba09acb07af8b313286f247c78a41a32Chet Haase case VALUE_TYPE_FLOAT: 979d430753cba09acb07af8b313286f247c78a41a32Chet Haase float value = a.getFloat(R.styleable.Keyframe_value, 0); 980d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframe = Keyframe.ofFloat(fraction, value); 981d430753cba09acb07af8b313286f247c78a41a32Chet Haase break; 982d430753cba09acb07af8b313286f247c78a41a32Chet Haase case VALUE_TYPE_COLOR: 983d430753cba09acb07af8b313286f247c78a41a32Chet Haase case VALUE_TYPE_INT: 984d430753cba09acb07af8b313286f247c78a41a32Chet Haase int intValue = a.getInt(R.styleable.Keyframe_value, 0); 985d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframe = Keyframe.ofInt(fraction, intValue); 986d430753cba09acb07af8b313286f247c78a41a32Chet Haase break; 987d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 988d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 989d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframe = (valueType == VALUE_TYPE_FLOAT) ? Keyframe.ofFloat(fraction) : 990d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe.ofInt(fraction); 991d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 992d430753cba09acb07af8b313286f247c78a41a32Chet Haase 9936aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu final int resID = a.getResourceId(R.styleable.Keyframe_interpolator, 0); 9946aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu if (resID > 0) { 9956aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu final Interpolator interpolator = AnimationUtils.loadInterpolator(res, theme, resID); 9966aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu keyframe.setInterpolator(interpolator); 9976aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu } 998d430753cba09acb07af8b313286f247c78a41a32Chet Haase a.recycle(); 999e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1000d430753cba09acb07af8b313286f247c78a41a32Chet Haase return keyframe; 1001e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1002e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1003fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs, 10047513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu float pathErrorScale) throws NotFoundException { 1005e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui ObjectAnimator anim = new ObjectAnimator(); 1006e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 10077513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu loadAnimator(res, theme, attrs, anim, pathErrorScale); 1008e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1009e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return anim; 1010e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1011e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1012e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui /** 1013e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * Creates a new animation whose parameters come from the specified context 1014e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * and attributes set. 1015e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * 1016e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @param res The resources 1017e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @param attrs The set of attributes holding the animation parameters 1018cf4832f69c8786b098ce18c24319021f8cd6733aztenghui * @param anim Null if this is a ValueAnimator, otherwise this is an 1019cf4832f69c8786b098ce18c24319021f8cd6733aztenghui * ObjectAnimator 1020e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui */ 1021e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui private static ValueAnimator loadAnimator(Resources res, Theme theme, 10227513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu AttributeSet attrs, ValueAnimator anim, float pathErrorScale) 1023e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui throws NotFoundException { 1024cf4832f69c8786b098ce18c24319021f8cd6733aztenghui TypedArray arrayAnimator = null; 1025cf4832f69c8786b098ce18c24319021f8cd6733aztenghui TypedArray arrayObjectAnimator = null; 1026cf4832f69c8786b098ce18c24319021f8cd6733aztenghui 1027e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (theme != null) { 1028cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayAnimator = theme.obtainStyledAttributes(attrs, R.styleable.Animator, 0, 0); 1029e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else { 1030cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayAnimator = res.obtainAttributes(attrs, R.styleable.Animator); 1031e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1032e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1033cf4832f69c8786b098ce18c24319021f8cd6733aztenghui // If anim is not null, then it is an object animator. 1034cf4832f69c8786b098ce18c24319021f8cd6733aztenghui if (anim != null) { 1035cf4832f69c8786b098ce18c24319021f8cd6733aztenghui if (theme != null) { 1036cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayObjectAnimator = theme.obtainStyledAttributes(attrs, 1037cf4832f69c8786b098ce18c24319021f8cd6733aztenghui R.styleable.PropertyAnimator, 0, 0); 1038cf4832f69c8786b098ce18c24319021f8cd6733aztenghui } else { 1039cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayObjectAnimator = res.obtainAttributes(attrs, R.styleable.PropertyAnimator); 1040cf4832f69c8786b098ce18c24319021f8cd6733aztenghui } 1041d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar anim.appendChangingConfigurations(arrayObjectAnimator.getChangingConfigurations()); 1042cf4832f69c8786b098ce18c24319021f8cd6733aztenghui } 10437f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout 10447f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout if (anim == null) { 10457f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout anim = new ValueAnimator(); 10467f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout } 1047d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar anim.appendChangingConfigurations(arrayAnimator.getChangingConfigurations()); 10487f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout 1049fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount parseAnimatorFromTypeArray(anim, arrayAnimator, arrayObjectAnimator, pathErrorScale); 1050d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 1051d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final int resID = arrayAnimator.getResourceId(R.styleable.Animator_interpolator, 0); 1052d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase if (resID > 0) { 1053d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final Interpolator interpolator = AnimationUtils.loadInterpolator(res, theme, resID); 1054d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (interpolator instanceof BaseInterpolator) { 1055d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar anim.appendChangingConfigurations( 1056d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar ((BaseInterpolator) interpolator).getChangingConfiguration()); 1057d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 1058d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar anim.setInterpolator(interpolator); 1059d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 1060cf4832f69c8786b098ce18c24319021f8cd6733aztenghui 1061cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayAnimator.recycle(); 10627f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout if (arrayObjectAnimator != null) { 10637f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout arrayObjectAnimator.recycle(); 10647f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout } 1065d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase return anim; 1066d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 1067d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar 1068ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette private static @Config int getChangingConfigs(@NonNull Resources resources, @AnyRes int id) { 1069d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar synchronized (sTmpTypedValue) { 1070d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar resources.getValue(id, sTmpTypedValue, true); 1071d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar return sTmpTypedValue.changingConfigurations; 1072d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 1073d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 10749032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu 10759032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu private static boolean isColorType(int type) { 10769032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu return (type >= TypedValue.TYPE_FIRST_COLOR_INT) && (type <= TypedValue.TYPE_LAST_COLOR_INT); 10779032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } 1078d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase} 1079