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; 19d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.Context; 20d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyarimport android.content.res.ConfigurationBoundResourceCache; 21d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyarimport android.content.res.ConstantState; 22d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.res.Resources; 23cf4832f69c8786b098ce18c24319021f8cd6733aztenghuiimport android.content.res.Resources.NotFoundException; 24e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghuiimport android.content.res.Resources.Theme; 25d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.res.TypedArray; 26d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.res.XmlResourceParser; 27cf4832f69c8786b098ce18c24319021f8cd6733aztenghuiimport android.graphics.Path; 28d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.util.AttributeSet; 29eb034fbca40006c55db143047eb628c4b657730aztenghuiimport android.util.Log; 30cf4832f69c8786b098ce18c24319021f8cd6733aztenghuiimport android.util.PathParser; 31f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyarimport android.util.StateSet; 325bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haaseimport android.util.TypedValue; 33d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.util.Xml; 34eb034fbca40006c55db143047eb628c4b657730aztenghuiimport android.view.InflateException; 35d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.view.animation.AnimationUtils; 36d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyarimport android.view.animation.BaseInterpolator; 37d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyarimport android.view.animation.Interpolator; 38e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 39e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghuiimport com.android.internal.R; 40e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 41d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport org.xmlpull.v1.XmlPullParser; 42d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport org.xmlpull.v1.XmlPullParserException; 43d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 44d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport java.io.IOException; 45d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport java.util.ArrayList; 46d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 47d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase/** 486cfdf4538049e4b96f50d8c0fe3119664420cc34Chet Haase * This class is used to instantiate animator XML files into Animator objects. 49d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * <p> 506cfdf4538049e4b96f50d8c0fe3119664420cc34Chet Haase * For performance reasons, inflation relies heavily on pre-processing of 51d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * XML files that is done at build time. Therefore, it is not currently possible 526cfdf4538049e4b96f50d8c0fe3119664420cc34Chet Haase * to use this inflater with an XmlPullParser over a plain XML file at runtime; 53d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * it only works with an XmlPullParser returned from a compiled resource (R. 54d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * <em>something</em> file.) 55d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase */ 56a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haasepublic class AnimatorInflater { 57eb034fbca40006c55db143047eb628c4b657730aztenghui private static final String TAG = "AnimatorInflater"; 58d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase /** 59a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * These flags are used when parsing AnimatorSet objects 60d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase */ 61d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase private static final int TOGETHER = 0; 62d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase private static final int SEQUENTIALLY = 1; 63d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 64d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase /** 65d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * Enum values used in XML attributes to indicate the value for mValueType 66d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase */ 67d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase private static final int VALUE_TYPE_FLOAT = 0; 68d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase private static final int VALUE_TYPE_INT = 1; 69eb034fbca40006c55db143047eb628c4b657730aztenghui private static final int VALUE_TYPE_PATH = 2; 70d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static final int VALUE_TYPE_COLOR = 3; 719032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu private static final int VALUE_TYPE_UNDEFINED = 4; 72d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 73eb034fbca40006c55db143047eb628c4b657730aztenghui private static final boolean DBG_ANIMATOR_INFLATER = false; 74eb034fbca40006c55db143047eb628c4b657730aztenghui 75d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar // used to calculate changing configs for resource references 76d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar private static final TypedValue sTmpTypedValue = new TypedValue(); 77d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar 78d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase /** 79a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * Loads an {@link Animator} object from a resource 80d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * 817513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu * @param context Application context used to access resources 82d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * @param id The resource id of the animation to load 83a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * @return The animator object reference by the specified id 84d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded 85d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase */ 867b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye public static Animator loadAnimator(Context context, @AnimatorRes int id) 87d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase throws NotFoundException { 887513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu return loadAnimator(context.getResources(), context.getTheme(), id); 89e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 90e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 91e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui /** 92e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * Loads an {@link Animator} object from a resource 93e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * 947513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu * @param resources The resources 95e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @param theme The theme 96e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @param id The resource id of the animation to load 97e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @return The animator object reference by the specified id 98e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded 99e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @hide 100e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui */ 1017513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu public static Animator loadAnimator(Resources resources, Theme theme, int id) 102e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui throws NotFoundException { 1037513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu return loadAnimator(resources, theme, id, 1); 104fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount } 105fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount 106fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount /** @hide */ 107fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount public static Animator loadAnimator(Resources resources, Theme theme, int id, 108fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount float pathErrorScale) throws NotFoundException { 109d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final ConfigurationBoundResourceCache<Animator> animatorCache = resources 110d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar .getAnimatorCache(); 111e54d245b993e1347cb32c23a6bdc907a45fab324Alan Viverette Animator animator = animatorCache.getInstance(id, theme); 112d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (animator != null) { 113d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (DBG_ANIMATOR_INFLATER) { 114d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar Log.d(TAG, "loaded animator from cache, " + resources.getResourceName(id)); 115d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 116d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar return animator; 117d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } else if (DBG_ANIMATOR_INFLATER) { 118d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar Log.d(TAG, "cache miss for animator " + resources.getResourceName(id)); 119d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 120d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase XmlResourceParser parser = null; 121d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase try { 122e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui parser = resources.getAnimation(id); 1237513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu animator = createAnimatorFromXml(resources, theme, parser, pathErrorScale); 124d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (animator != null) { 125d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animator.appendChangingConfigurations(getChangingConfigs(resources, id)); 126d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final ConstantState<Animator> constantState = animator.createConstantState(); 127d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (constantState != null) { 128d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (DBG_ANIMATOR_INFLATER) { 129d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar Log.d(TAG, "caching animator for res " + resources.getResourceName(id)); 130d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 131d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animatorCache.put(id, theme, constantState); 132d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar // create a new animator so that cached version is never used by the user 133d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animator = constantState.newInstance(resources, theme); 134d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 135d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 136d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar return animator; 137d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } catch (XmlPullParserException ex) { 138d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase Resources.NotFoundException rnf = 139d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase new Resources.NotFoundException("Can't load animation resource ID #0x" + 140fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount Integer.toHexString(id)); 141d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase rnf.initCause(ex); 142d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase throw rnf; 143d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } catch (IOException ex) { 144d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase Resources.NotFoundException rnf = 145d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase new Resources.NotFoundException("Can't load animation resource ID #0x" + 146fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount Integer.toHexString(id)); 147d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase rnf.initCause(ex); 148d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase throw rnf; 149d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } finally { 150d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase if (parser != null) parser.close(); 151d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 152d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 153d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 154f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar public static StateListAnimator loadStateListAnimator(Context context, int id) 155f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throws NotFoundException { 156d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final Resources resources = context.getResources(); 157d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final ConfigurationBoundResourceCache<StateListAnimator> cache = resources 158d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar .getStateListAnimatorCache(); 159d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final Theme theme = context.getTheme(); 160e54d245b993e1347cb32c23a6bdc907a45fab324Alan Viverette StateListAnimator animator = cache.getInstance(id, theme); 161d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (animator != null) { 162d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar return animator; 163d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 164f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar XmlResourceParser parser = null; 165f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar try { 166d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar parser = resources.getAnimation(id); 167d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animator = createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser)); 168d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (animator != null) { 169d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animator.appendChangingConfigurations(getChangingConfigs(resources, id)); 170d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final ConstantState<StateListAnimator> constantState = animator 171d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar .createConstantState(); 172d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (constantState != null) { 173d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar cache.put(id, theme, constantState); 174d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar // return a clone so that the animator in constant state is never used. 175d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animator = constantState.newInstance(resources, theme); 176d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 177d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 178d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar return animator; 179f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } catch (XmlPullParserException ex) { 180f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Resources.NotFoundException rnf = 181f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar new Resources.NotFoundException( 182f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar "Can't load state list animator resource ID #0x" + 183f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Integer.toHexString(id) 184f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar ); 185f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar rnf.initCause(ex); 186f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throw rnf; 187f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } catch (IOException ex) { 188f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Resources.NotFoundException rnf = 189f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar new Resources.NotFoundException( 190f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar "Can't load state list animator resource ID #0x" + 191f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Integer.toHexString(id) 192f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar ); 193f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar rnf.initCause(ex); 194f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throw rnf; 195f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } finally { 196f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar if (parser != null) { 197f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar parser.close(); 198f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 199f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 200f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 201f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 202f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar private static StateListAnimator createStateListAnimatorFromXml(Context context, 203f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar XmlPullParser parser, AttributeSet attributeSet) 204f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throws IOException, XmlPullParserException { 205f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int type; 206f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar StateListAnimator stateListAnimator = new StateListAnimator(); 207f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 208f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar while (true) { 209f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar type = parser.next(); 210f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar switch (type) { 211f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar case XmlPullParser.END_DOCUMENT: 212f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar case XmlPullParser.END_TAG: 213f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar return stateListAnimator; 214f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 215f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar case XmlPullParser.START_TAG: 216f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar // parse item 217f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Animator animator = null; 218f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar if ("item".equals(parser.getName())) { 219f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int attributeCount = parser.getAttributeCount(); 220f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int[] states = new int[attributeCount]; 221f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int stateIndex = 0; 222f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar for (int i = 0; i < attributeCount; i++) { 223f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int attrName = attributeSet.getAttributeNameResource(i); 224cf4832f69c8786b098ce18c24319021f8cd6733aztenghui if (attrName == R.attr.animation) { 225d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final int animId = attributeSet.getAttributeResourceValue(i, 0); 226d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animator = loadAnimator(context, animId); 227f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } else { 228f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar states[stateIndex++] = 229f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar attributeSet.getAttributeBooleanValue(i, false) ? 230f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar attrName : -attrName; 231f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 232f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 233f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar if (animator == null) { 234e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui animator = createAnimatorFromXml(context.getResources(), 2357513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu context.getTheme(), parser, 1f); 236f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 237f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 238f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar if (animator == null) { 239f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throw new Resources.NotFoundException( 240f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar "animation state item must have a valid animation"); 241f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 242f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar stateListAnimator 243f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar .addState(StateSet.trimStateSet(states, stateIndex), animator); 244f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 245f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar break; 246f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 247f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 248f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 249f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 250cf4832f69c8786b098ce18c24319021f8cd6733aztenghui /** 251eb034fbca40006c55db143047eb628c4b657730aztenghui * PathDataEvaluator is used to interpolate between two paths which are 252eb034fbca40006c55db143047eb628c4b657730aztenghui * represented in the same format but different control points' values. 253eb034fbca40006c55db143047eb628c4b657730aztenghui * The path is represented as an array of PathDataNode here, which is 254eb034fbca40006c55db143047eb628c4b657730aztenghui * fundamentally an array of floating point numbers. 255eb034fbca40006c55db143047eb628c4b657730aztenghui */ 256eb034fbca40006c55db143047eb628c4b657730aztenghui private static class PathDataEvaluator implements TypeEvaluator<PathParser.PathDataNode[]> { 257eb034fbca40006c55db143047eb628c4b657730aztenghui private PathParser.PathDataNode[] mNodeArray; 258eb034fbca40006c55db143047eb628c4b657730aztenghui 259eb034fbca40006c55db143047eb628c4b657730aztenghui /** 260eb034fbca40006c55db143047eb628c4b657730aztenghui * Create a PathParser.PathDataNode[] that does not reuse the animated value. 261eb034fbca40006c55db143047eb628c4b657730aztenghui * Care must be taken when using this option because on every evaluation 262eb034fbca40006c55db143047eb628c4b657730aztenghui * a new <code>PathParser.PathDataNode[]</code> will be allocated. 263eb034fbca40006c55db143047eb628c4b657730aztenghui */ 264eb034fbca40006c55db143047eb628c4b657730aztenghui private PathDataEvaluator() {} 265eb034fbca40006c55db143047eb628c4b657730aztenghui 266eb034fbca40006c55db143047eb628c4b657730aztenghui /** 267eb034fbca40006c55db143047eb628c4b657730aztenghui * Create a PathDataEvaluator that reuses <code>nodeArray</code> for every evaluate() call. 268eb034fbca40006c55db143047eb628c4b657730aztenghui * Caution must be taken to ensure that the value returned from 269eb034fbca40006c55db143047eb628c4b657730aztenghui * {@link android.animation.ValueAnimator#getAnimatedValue()} is not cached, modified, or 270eb034fbca40006c55db143047eb628c4b657730aztenghui * used across threads. The value will be modified on each <code>evaluate()</code> call. 271eb034fbca40006c55db143047eb628c4b657730aztenghui * 272eb034fbca40006c55db143047eb628c4b657730aztenghui * @param nodeArray The array to modify and return from <code>evaluate</code>. 273eb034fbca40006c55db143047eb628c4b657730aztenghui */ 274eb034fbca40006c55db143047eb628c4b657730aztenghui public PathDataEvaluator(PathParser.PathDataNode[] nodeArray) { 275eb034fbca40006c55db143047eb628c4b657730aztenghui mNodeArray = nodeArray; 276eb034fbca40006c55db143047eb628c4b657730aztenghui } 277eb034fbca40006c55db143047eb628c4b657730aztenghui 278eb034fbca40006c55db143047eb628c4b657730aztenghui @Override 279eb034fbca40006c55db143047eb628c4b657730aztenghui public PathParser.PathDataNode[] evaluate(float fraction, 280eb034fbca40006c55db143047eb628c4b657730aztenghui PathParser.PathDataNode[] startPathData, 281eb034fbca40006c55db143047eb628c4b657730aztenghui PathParser.PathDataNode[] endPathData) { 282eb034fbca40006c55db143047eb628c4b657730aztenghui if (!PathParser.canMorph(startPathData, endPathData)) { 283eb034fbca40006c55db143047eb628c4b657730aztenghui throw new IllegalArgumentException("Can't interpolate between" 284eb034fbca40006c55db143047eb628c4b657730aztenghui + " two incompatible pathData"); 285eb034fbca40006c55db143047eb628c4b657730aztenghui } 286eb034fbca40006c55db143047eb628c4b657730aztenghui 287eb034fbca40006c55db143047eb628c4b657730aztenghui if (mNodeArray == null || !PathParser.canMorph(mNodeArray, startPathData)) { 288eb034fbca40006c55db143047eb628c4b657730aztenghui mNodeArray = PathParser.deepCopyNodes(startPathData); 289eb034fbca40006c55db143047eb628c4b657730aztenghui } 290eb034fbca40006c55db143047eb628c4b657730aztenghui 291eb034fbca40006c55db143047eb628c4b657730aztenghui for (int i = 0; i < startPathData.length; i++) { 292eb034fbca40006c55db143047eb628c4b657730aztenghui mNodeArray[i].interpolatePathDataNode(startPathData[i], 293eb034fbca40006c55db143047eb628c4b657730aztenghui endPathData[i], fraction); 294eb034fbca40006c55db143047eb628c4b657730aztenghui } 295eb034fbca40006c55db143047eb628c4b657730aztenghui 296eb034fbca40006c55db143047eb628c4b657730aztenghui return mNodeArray; 297eb034fbca40006c55db143047eb628c4b657730aztenghui } 298eb034fbca40006c55db143047eb628c4b657730aztenghui } 299eb034fbca40006c55db143047eb628c4b657730aztenghui 300d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static PropertyValuesHolder getPVH(TypedArray styledAttributes, int valueType, 301d430753cba09acb07af8b313286f247c78a41a32Chet Haase int valueFromId, int valueToId, String propertyName) { 3025bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase 303d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypedValue tvFrom = styledAttributes.peekValue(valueFromId); 3045bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase boolean hasFrom = (tvFrom != null); 3055bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase int fromType = hasFrom ? tvFrom.type : 0; 306d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypedValue tvTo = styledAttributes.peekValue(valueToId); 3075bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase boolean hasTo = (tvTo != null); 3085bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase int toType = hasTo ? tvTo.type : 0; 3095bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase 3109032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu if (valueType == VALUE_TYPE_UNDEFINED) { 3119032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu // Check whether it's color type. If not, fall back to default type (i.e. float type) 3129032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu if ((hasFrom && isColorType(fromType)) || (hasTo && isColorType(toType))) { 3139032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu valueType = VALUE_TYPE_COLOR; 3149032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } else { 3159032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu valueType = VALUE_TYPE_FLOAT; 3169032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } 3179032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } 3189032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu 3199032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu boolean getFloats = (valueType == VALUE_TYPE_FLOAT); 3209032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu 321d430753cba09acb07af8b313286f247c78a41a32Chet Haase PropertyValuesHolder returnValue = null; 322d430753cba09acb07af8b313286f247c78a41a32Chet Haase 323eb034fbca40006c55db143047eb628c4b657730aztenghui if (valueType == VALUE_TYPE_PATH) { 324d430753cba09acb07af8b313286f247c78a41a32Chet Haase String fromString = styledAttributes.getString(valueFromId); 325d430753cba09acb07af8b313286f247c78a41a32Chet Haase String toString = styledAttributes.getString(valueToId); 326d430753cba09acb07af8b313286f247c78a41a32Chet Haase PathParser.PathDataNode[] nodesFrom = PathParser.createNodesFromPathData(fromString); 327d430753cba09acb07af8b313286f247c78a41a32Chet Haase PathParser.PathDataNode[] nodesTo = PathParser.createNodesFromPathData(toString); 328d430753cba09acb07af8b313286f247c78a41a32Chet Haase 329d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (nodesFrom != null || nodesTo != null) { 330d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (nodesFrom != null) { 331d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypeEvaluator evaluator = 332d430753cba09acb07af8b313286f247c78a41a32Chet Haase new PathDataEvaluator(PathParser.deepCopyNodes(nodesFrom)); 333d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (nodesTo != null) { 334d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (!PathParser.canMorph(nodesFrom, nodesTo)) { 335d430753cba09acb07af8b313286f247c78a41a32Chet Haase throw new InflateException(" Can't morph from " + fromString + " to " + 336d430753cba09acb07af8b313286f247c78a41a32Chet Haase toString); 337d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 338d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofObject(propertyName, evaluator, 339d430753cba09acb07af8b313286f247c78a41a32Chet Haase nodesFrom, nodesTo); 340d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 341d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofObject(propertyName, evaluator, 342d430753cba09acb07af8b313286f247c78a41a32Chet Haase (Object) nodesFrom); 343d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 344d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else if (nodesTo != null) { 345d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypeEvaluator evaluator = 346d430753cba09acb07af8b313286f247c78a41a32Chet Haase new PathDataEvaluator(PathParser.deepCopyNodes(nodesTo)); 347d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofObject(propertyName, evaluator, 348d430753cba09acb07af8b313286f247c78a41a32Chet Haase (Object) nodesTo); 349d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 350d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 351eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 352d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypeEvaluator evaluator = null; 353eb034fbca40006c55db143047eb628c4b657730aztenghui // Integer and float value types are handled here. 3549032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu if (valueType == VALUE_TYPE_COLOR) { 355eb034fbca40006c55db143047eb628c4b657730aztenghui // special case for colors: ignore valueType and get ints 356eb034fbca40006c55db143047eb628c4b657730aztenghui evaluator = ArgbEvaluator.getInstance(); 357eb034fbca40006c55db143047eb628c4b657730aztenghui } 358d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (getFloats) { 359d430753cba09acb07af8b313286f247c78a41a32Chet Haase float valueFrom; 360d430753cba09acb07af8b313286f247c78a41a32Chet Haase float valueTo; 361d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (hasFrom) { 362d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (fromType == TypedValue.TYPE_DIMENSION) { 363d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueFrom = styledAttributes.getDimension(valueFromId, 0f); 364d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 365d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueFrom = styledAttributes.getFloat(valueFromId, 0f); 366d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 367d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (hasTo) { 368d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 369d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getDimension(valueToId, 0f); 370d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 371d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getFloat(valueToId, 0f); 372d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 373d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofFloat(propertyName, 374d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueFrom, valueTo); 375d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 376d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofFloat(propertyName, valueFrom); 377d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 378d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 379d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 380d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getDimension(valueToId, 0f); 381d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 382d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getFloat(valueToId, 0f); 383d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 384d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofFloat(propertyName, valueTo); 385d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 386d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 387d430753cba09acb07af8b313286f247c78a41a32Chet Haase int valueFrom; 388d430753cba09acb07af8b313286f247c78a41a32Chet Haase int valueTo; 389d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (hasFrom) { 390d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (fromType == TypedValue.TYPE_DIMENSION) { 391d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueFrom = (int) styledAttributes.getDimension(valueFromId, 0f); 3929032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } else if (isColorType(fromType)) { 393d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueFrom = styledAttributes.getColor(valueFromId, 0); 394d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 395d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueFrom = styledAttributes.getInt(valueFromId, 0); 396d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 397d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (hasTo) { 398d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 399d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = (int) styledAttributes.getDimension(valueToId, 0f); 4009032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } else if (isColorType(toType)) { 401d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getColor(valueToId, 0); 402d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 403d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getInt(valueToId, 0); 404d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 405d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofInt(propertyName, valueFrom, valueTo); 406d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 407d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofInt(propertyName, valueFrom); 408d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 409d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 410d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (hasTo) { 411d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 412d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = (int) styledAttributes.getDimension(valueToId, 0f); 4139032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } else if (isColorType(toType)) { 414d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getColor(valueToId, 0); 415d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 416d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getInt(valueToId, 0); 417d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 418d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofInt(propertyName, valueTo); 419d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 420d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 421d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 422d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (returnValue != null && evaluator != null) { 423d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue.setEvaluator(evaluator); 424d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 425d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 426d430753cba09acb07af8b313286f247c78a41a32Chet Haase 427d430753cba09acb07af8b313286f247c78a41a32Chet Haase return returnValue; 428d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 429d430753cba09acb07af8b313286f247c78a41a32Chet Haase 430d430753cba09acb07af8b313286f247c78a41a32Chet Haase /** 431d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param anim The animator, must not be null 432d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param arrayAnimator Incoming typed array for Animator's attributes. 433d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param arrayObjectAnimator Incoming typed array for Object Animator's 434d430753cba09acb07af8b313286f247c78a41a32Chet Haase * attributes. 435d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param pixelSize The relative pixel size, used to calculate the 436d430753cba09acb07af8b313286f247c78a41a32Chet Haase * maximum error for path animations. 437d430753cba09acb07af8b313286f247c78a41a32Chet Haase */ 438d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static void parseAnimatorFromTypeArray(ValueAnimator anim, 439d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypedArray arrayAnimator, TypedArray arrayObjectAnimator, float pixelSize) { 440d430753cba09acb07af8b313286f247c78a41a32Chet Haase long duration = arrayAnimator.getInt(R.styleable.Animator_duration, 300); 441d430753cba09acb07af8b313286f247c78a41a32Chet Haase 442d430753cba09acb07af8b313286f247c78a41a32Chet Haase long startDelay = arrayAnimator.getInt(R.styleable.Animator_startOffset, 0); 443d430753cba09acb07af8b313286f247c78a41a32Chet Haase 4442787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu int valueType = arrayAnimator.getInt(R.styleable.Animator_valueType, VALUE_TYPE_UNDEFINED); 445d430753cba09acb07af8b313286f247c78a41a32Chet Haase 4462787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu if (valueType == VALUE_TYPE_UNDEFINED) { 4472787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu valueType = inferValueTypeFromValues(arrayAnimator, R.styleable.Animator_valueFrom, 4482787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu R.styleable.Animator_valueTo); 4492787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu } 450d430753cba09acb07af8b313286f247c78a41a32Chet Haase PropertyValuesHolder pvh = getPVH(arrayAnimator, valueType, 451d430753cba09acb07af8b313286f247c78a41a32Chet Haase R.styleable.Animator_valueFrom, R.styleable.Animator_valueTo, ""); 452d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (pvh != null) { 453d430753cba09acb07af8b313286f247c78a41a32Chet Haase anim.setValues(pvh); 4545bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } 4555bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase 456eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setDuration(duration); 457eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setStartDelay(startDelay); 458eb034fbca40006c55db143047eb628c4b657730aztenghui 459eb034fbca40006c55db143047eb628c4b657730aztenghui if (arrayAnimator.hasValue(R.styleable.Animator_repeatCount)) { 460eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setRepeatCount( 461eb034fbca40006c55db143047eb628c4b657730aztenghui arrayAnimator.getInt(R.styleable.Animator_repeatCount, 0)); 462eb034fbca40006c55db143047eb628c4b657730aztenghui } 463eb034fbca40006c55db143047eb628c4b657730aztenghui if (arrayAnimator.hasValue(R.styleable.Animator_repeatMode)) { 464eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setRepeatMode( 465eb034fbca40006c55db143047eb628c4b657730aztenghui arrayAnimator.getInt(R.styleable.Animator_repeatMode, 466eb034fbca40006c55db143047eb628c4b657730aztenghui ValueAnimator.RESTART)); 467eb034fbca40006c55db143047eb628c4b657730aztenghui } 468eb034fbca40006c55db143047eb628c4b657730aztenghui 469eb034fbca40006c55db143047eb628c4b657730aztenghui if (arrayObjectAnimator != null) { 470d430753cba09acb07af8b313286f247c78a41a32Chet Haase setupObjectAnimator(anim, arrayObjectAnimator, valueType == VALUE_TYPE_FLOAT, 471d430753cba09acb07af8b313286f247c78a41a32Chet Haase pixelSize); 472eb034fbca40006c55db143047eb628c4b657730aztenghui } 473eb034fbca40006c55db143047eb628c4b657730aztenghui } 474eb034fbca40006c55db143047eb628c4b657730aztenghui 475eb034fbca40006c55db143047eb628c4b657730aztenghui /** 476eb034fbca40006c55db143047eb628c4b657730aztenghui * Setup the Animator to achieve path morphing. 477eb034fbca40006c55db143047eb628c4b657730aztenghui * 478eb034fbca40006c55db143047eb628c4b657730aztenghui * @param anim The target Animator which will be updated. 479eb034fbca40006c55db143047eb628c4b657730aztenghui * @param arrayAnimator TypedArray for the ValueAnimator. 480eb034fbca40006c55db143047eb628c4b657730aztenghui * @return the PathDataEvaluator. 481eb034fbca40006c55db143047eb628c4b657730aztenghui */ 482eb034fbca40006c55db143047eb628c4b657730aztenghui private static TypeEvaluator setupAnimatorForPath(ValueAnimator anim, 483eb034fbca40006c55db143047eb628c4b657730aztenghui TypedArray arrayAnimator) { 484eb034fbca40006c55db143047eb628c4b657730aztenghui TypeEvaluator evaluator = null; 485eb034fbca40006c55db143047eb628c4b657730aztenghui String fromString = arrayAnimator.getString(R.styleable.Animator_valueFrom); 486eb034fbca40006c55db143047eb628c4b657730aztenghui String toString = arrayAnimator.getString(R.styleable.Animator_valueTo); 487eb034fbca40006c55db143047eb628c4b657730aztenghui PathParser.PathDataNode[] nodesFrom = PathParser.createNodesFromPathData(fromString); 488eb034fbca40006c55db143047eb628c4b657730aztenghui PathParser.PathDataNode[] nodesTo = PathParser.createNodesFromPathData(toString); 489eb034fbca40006c55db143047eb628c4b657730aztenghui 490eb034fbca40006c55db143047eb628c4b657730aztenghui if (nodesFrom != null) { 491eb034fbca40006c55db143047eb628c4b657730aztenghui if (nodesTo != null) { 492eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setObjectValues(nodesFrom, nodesTo); 493eb034fbca40006c55db143047eb628c4b657730aztenghui if (!PathParser.canMorph(nodesFrom, nodesTo)) { 494eb034fbca40006c55db143047eb628c4b657730aztenghui throw new InflateException(arrayAnimator.getPositionDescription() 495eb034fbca40006c55db143047eb628c4b657730aztenghui + " Can't morph from " + fromString + " to " + toString); 496eb034fbca40006c55db143047eb628c4b657730aztenghui } 497eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 498eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setObjectValues((Object)nodesFrom); 499eb034fbca40006c55db143047eb628c4b657730aztenghui } 500eb034fbca40006c55db143047eb628c4b657730aztenghui evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesFrom)); 501eb034fbca40006c55db143047eb628c4b657730aztenghui } else if (nodesTo != null) { 502eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setObjectValues((Object)nodesTo); 503eb034fbca40006c55db143047eb628c4b657730aztenghui evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesTo)); 504eb034fbca40006c55db143047eb628c4b657730aztenghui } 505eb034fbca40006c55db143047eb628c4b657730aztenghui 506eb034fbca40006c55db143047eb628c4b657730aztenghui if (DBG_ANIMATOR_INFLATER && evaluator != null) { 507eb034fbca40006c55db143047eb628c4b657730aztenghui Log.v(TAG, "create a new PathDataEvaluator here"); 508eb034fbca40006c55db143047eb628c4b657730aztenghui } 509eb034fbca40006c55db143047eb628c4b657730aztenghui 510eb034fbca40006c55db143047eb628c4b657730aztenghui return evaluator; 511eb034fbca40006c55db143047eb628c4b657730aztenghui } 512eb034fbca40006c55db143047eb628c4b657730aztenghui 513eb034fbca40006c55db143047eb628c4b657730aztenghui /** 514eb034fbca40006c55db143047eb628c4b657730aztenghui * Setup ObjectAnimator's property or values from pathData. 515eb034fbca40006c55db143047eb628c4b657730aztenghui * 516eb034fbca40006c55db143047eb628c4b657730aztenghui * @param anim The target Animator which will be updated. 517eb034fbca40006c55db143047eb628c4b657730aztenghui * @param arrayObjectAnimator TypedArray for the ObjectAnimator. 518eb034fbca40006c55db143047eb628c4b657730aztenghui * @param getFloats True if the value type is float. 519fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount * @param pixelSize The relative pixel size, used to calculate the 520fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount * maximum error for path animations. 521eb034fbca40006c55db143047eb628c4b657730aztenghui */ 522eb034fbca40006c55db143047eb628c4b657730aztenghui private static void setupObjectAnimator(ValueAnimator anim, TypedArray arrayObjectAnimator, 523fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount boolean getFloats, float pixelSize) { 524eb034fbca40006c55db143047eb628c4b657730aztenghui ObjectAnimator oa = (ObjectAnimator) anim; 525eb034fbca40006c55db143047eb628c4b657730aztenghui String pathData = arrayObjectAnimator.getString(R.styleable.PropertyAnimator_pathData); 526eb034fbca40006c55db143047eb628c4b657730aztenghui 5272787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu // Path can be involved in an ObjectAnimator in the following 3 ways: 5282787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu // 1) Path morphing: the property to be animated is pathData, and valueFrom and valueTo 5292787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu // are both of pathType. valueType = pathType needs to be explicitly defined. 5302787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu // 2) A property in X or Y dimension can be animated along a path: the property needs to be 5312787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu // defined in propertyXName or propertyYName attribute, the path will be defined in the 5322787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu // pathData attribute. valueFrom and valueTo will not be necessary for this animation. 5332787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu // 3) PathInterpolator can also define a path (in pathData) for its interpolation curve. 5342787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu // Here we are dealing with case 2: 535eb034fbca40006c55db143047eb628c4b657730aztenghui if (pathData != null) { 536eb034fbca40006c55db143047eb628c4b657730aztenghui String propertyXName = 537eb034fbca40006c55db143047eb628c4b657730aztenghui arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyXName); 538eb034fbca40006c55db143047eb628c4b657730aztenghui String propertyYName = 539eb034fbca40006c55db143047eb628c4b657730aztenghui arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyYName); 540eb034fbca40006c55db143047eb628c4b657730aztenghui 541eb034fbca40006c55db143047eb628c4b657730aztenghui if (propertyXName == null && propertyYName == null) { 542eb034fbca40006c55db143047eb628c4b657730aztenghui throw new InflateException(arrayObjectAnimator.getPositionDescription() 543eb034fbca40006c55db143047eb628c4b657730aztenghui + " propertyXName or propertyYName is needed for PathData"); 544eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 545eb034fbca40006c55db143047eb628c4b657730aztenghui Path path = PathParser.createPathFromPathData(pathData); 546fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount float error = 0.5f * pixelSize; // max half a pixel error 547fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount PathKeyframes keyframeSet = KeyframeSet.ofPath(path, error); 548984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount Keyframes xKeyframes; 549984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount Keyframes yKeyframes; 550984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount if (getFloats) { 551984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount xKeyframes = keyframeSet.createXFloatKeyframes(); 552984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount yKeyframes = keyframeSet.createYFloatKeyframes(); 553984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount } else { 554984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount xKeyframes = keyframeSet.createXIntKeyframes(); 555984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount yKeyframes = keyframeSet.createYIntKeyframes(); 556984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount } 557eb034fbca40006c55db143047eb628c4b657730aztenghui PropertyValuesHolder x = null; 558eb034fbca40006c55db143047eb628c4b657730aztenghui PropertyValuesHolder y = null; 559eb034fbca40006c55db143047eb628c4b657730aztenghui if (propertyXName != null) { 560984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount x = PropertyValuesHolder.ofKeyframes(propertyXName, xKeyframes); 561eb034fbca40006c55db143047eb628c4b657730aztenghui } 562eb034fbca40006c55db143047eb628c4b657730aztenghui if (propertyYName != null) { 563984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount y = PropertyValuesHolder.ofKeyframes(propertyYName, yKeyframes); 564eb034fbca40006c55db143047eb628c4b657730aztenghui } 565eb034fbca40006c55db143047eb628c4b657730aztenghui if (x == null) { 566eb034fbca40006c55db143047eb628c4b657730aztenghui oa.setValues(y); 567eb034fbca40006c55db143047eb628c4b657730aztenghui } else if (y == null) { 568eb034fbca40006c55db143047eb628c4b657730aztenghui oa.setValues(x); 569eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 570eb034fbca40006c55db143047eb628c4b657730aztenghui oa.setValues(x, y); 571eb034fbca40006c55db143047eb628c4b657730aztenghui } 572eb034fbca40006c55db143047eb628c4b657730aztenghui } 573eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 574eb034fbca40006c55db143047eb628c4b657730aztenghui String propertyName = 575eb034fbca40006c55db143047eb628c4b657730aztenghui arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyName); 576eb034fbca40006c55db143047eb628c4b657730aztenghui oa.setPropertyName(propertyName); 577eb034fbca40006c55db143047eb628c4b657730aztenghui } 578eb034fbca40006c55db143047eb628c4b657730aztenghui } 579eb034fbca40006c55db143047eb628c4b657730aztenghui 580eb034fbca40006c55db143047eb628c4b657730aztenghui /** 581eb034fbca40006c55db143047eb628c4b657730aztenghui * Setup ValueAnimator's values. 582eb034fbca40006c55db143047eb628c4b657730aztenghui * This will handle all of the integer, float and color types. 583eb034fbca40006c55db143047eb628c4b657730aztenghui * 584eb034fbca40006c55db143047eb628c4b657730aztenghui * @param anim The target Animator which will be updated. 585eb034fbca40006c55db143047eb628c4b657730aztenghui * @param arrayAnimator TypedArray for the ValueAnimator. 586eb034fbca40006c55db143047eb628c4b657730aztenghui * @param getFloats True if the value type is float. 587eb034fbca40006c55db143047eb628c4b657730aztenghui * @param hasFrom True if "valueFrom" exists. 588eb034fbca40006c55db143047eb628c4b657730aztenghui * @param fromType The type of "valueFrom". 589eb034fbca40006c55db143047eb628c4b657730aztenghui * @param hasTo True if "valueTo" exists. 590eb034fbca40006c55db143047eb628c4b657730aztenghui * @param toType The type of "valueTo". 591eb034fbca40006c55db143047eb628c4b657730aztenghui */ 592eb034fbca40006c55db143047eb628c4b657730aztenghui private static void setupValues(ValueAnimator anim, TypedArray arrayAnimator, 593eb034fbca40006c55db143047eb628c4b657730aztenghui boolean getFloats, boolean hasFrom, int fromType, boolean hasTo, int toType) { 594eb034fbca40006c55db143047eb628c4b657730aztenghui int valueFromIndex = R.styleable.Animator_valueFrom; 595eb034fbca40006c55db143047eb628c4b657730aztenghui int valueToIndex = R.styleable.Animator_valueTo; 5965bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (getFloats) { 5975bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase float valueFrom; 5985bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase float valueTo; 5995bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasFrom) { 6005bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (fromType == TypedValue.TYPE_DIMENSION) { 601cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = arrayAnimator.getDimension(valueFromIndex, 0f); 6025bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 603cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = arrayAnimator.getFloat(valueFromIndex, 0f); 6045bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } 6055bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasTo) { 6065bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 607cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getDimension(valueToIndex, 0f); 6082794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 609cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getFloat(valueToIndex, 0f); 6102794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 6115bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setFloatValues(valueFrom, valueTo); 6125bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 6135bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setFloatValues(valueFrom); 6145bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } 6155bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 6165bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 617cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getDimension(valueToIndex, 0f); 6182794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 619cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getFloat(valueToIndex, 0f); 620d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 6215bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setFloatValues(valueTo); 6222794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 6235bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 6245bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase int valueFrom; 6255bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase int valueTo; 6265bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasFrom) { 6275bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (fromType == TypedValue.TYPE_DIMENSION) { 628cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = (int) arrayAnimator.getDimension(valueFromIndex, 0f); 6299032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } else if (isColorType(fromType)) { 630cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = arrayAnimator.getColor(valueFromIndex, 0); 6315bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 632cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = arrayAnimator.getInt(valueFromIndex, 0); 6335bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } 6345bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasTo) { 6355bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 636cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = (int) arrayAnimator.getDimension(valueToIndex, 0f); 6379032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } else if (isColorType(toType)) { 638cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getColor(valueToIndex, 0); 6392794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 640cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getInt(valueToIndex, 0); 6412794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 6425bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setIntValues(valueFrom, valueTo); 6432794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 6445bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setIntValues(valueFrom); 645d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 6465bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 6475bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasTo) { 6485bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 649cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = (int) arrayAnimator.getDimension(valueToIndex, 0f); 6509032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } else if (isColorType(toType)) { 651cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getColor(valueToIndex, 0); 6522794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 653cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getInt(valueToIndex, 0); 6542794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 6555bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setIntValues(valueTo); 656d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 6572794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 658d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 659e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 660e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 661fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser, 6627513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu float pixelSize) 663e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui throws XmlPullParserException, IOException { 664fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount return createAnimatorFromXml(res, theme, parser, Xml.asAttributeSet(parser), null, 0, 6657513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu pixelSize); 666e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 667e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 668e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser, 6697513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu AttributeSet attrs, AnimatorSet parent, int sequenceOrdering, float pixelSize) 6707513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu throws XmlPullParserException, IOException { 671e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui Animator anim = null; 672e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui ArrayList<Animator> childAnims = null; 673e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 674e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui // Make sure we are on a start tag. 675e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui int type; 676e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui int depth = parser.getDepth(); 677e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 678e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) 679e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui && type != XmlPullParser.END_DOCUMENT) { 680e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 681e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (type != XmlPullParser.START_TAG) { 682e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui continue; 683e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 684e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 685e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui String name = parser.getName(); 686d430753cba09acb07af8b313286f247c78a41a32Chet Haase boolean gotValues = false; 687e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 688e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (name.equals("objectAnimator")) { 6897513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu anim = loadObjectAnimator(res, theme, attrs, pixelSize); 690e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else if (name.equals("animator")) { 6917513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu anim = loadAnimator(res, theme, attrs, null, pixelSize); 692e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else if (name.equals("set")) { 693e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui anim = new AnimatorSet(); 694e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui TypedArray a; 695e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (theme != null) { 696cf4832f69c8786b098ce18c24319021f8cd6733aztenghui a = theme.obtainStyledAttributes(attrs, R.styleable.AnimatorSet, 0, 0); 697e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else { 698cf4832f69c8786b098ce18c24319021f8cd6733aztenghui a = res.obtainAttributes(attrs, R.styleable.AnimatorSet); 699e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 700d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar anim.appendChangingConfigurations(a.getChangingConfigurations()); 701d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar int ordering = a.getInt(R.styleable.AnimatorSet_ordering, TOGETHER); 702fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering, 7037513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu pixelSize); 704e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui a.recycle(); 705d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else if (name.equals("propertyValuesHolder")) { 706d430753cba09acb07af8b313286f247c78a41a32Chet Haase PropertyValuesHolder[] values = loadValues(res, theme, parser, 707d430753cba09acb07af8b313286f247c78a41a32Chet Haase Xml.asAttributeSet(parser)); 708d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (values != null && anim != null && (anim instanceof ValueAnimator)) { 709d430753cba09acb07af8b313286f247c78a41a32Chet Haase ((ValueAnimator) anim).setValues(values); 710d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 711d430753cba09acb07af8b313286f247c78a41a32Chet Haase gotValues = true; 712e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else { 713e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui throw new RuntimeException("Unknown animator name: " + parser.getName()); 714e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 715e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 716d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (parent != null && !gotValues) { 717e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (childAnims == null) { 718e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui childAnims = new ArrayList<Animator>(); 719e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 720e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui childAnims.add(anim); 721e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 722e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 723e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (parent != null && childAnims != null) { 724e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui Animator[] animsArray = new Animator[childAnims.size()]; 725e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui int index = 0; 726e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui for (Animator a : childAnims) { 727e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui animsArray[index++] = a; 728e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 729e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (sequenceOrdering == TOGETHER) { 730e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui parent.playTogether(animsArray); 731e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else { 732e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui parent.playSequentially(animsArray); 733e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 734e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 735e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return anim; 736d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 737d430753cba09acb07af8b313286f247c78a41a32Chet Haase 738d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static PropertyValuesHolder[] loadValues(Resources res, Theme theme, 739d430753cba09acb07af8b313286f247c78a41a32Chet Haase XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException { 740d430753cba09acb07af8b313286f247c78a41a32Chet Haase ArrayList<PropertyValuesHolder> values = null; 741d430753cba09acb07af8b313286f247c78a41a32Chet Haase 742d430753cba09acb07af8b313286f247c78a41a32Chet Haase int type; 743d430753cba09acb07af8b313286f247c78a41a32Chet Haase while ((type = parser.getEventType()) != XmlPullParser.END_TAG && 744d430753cba09acb07af8b313286f247c78a41a32Chet Haase type != XmlPullParser.END_DOCUMENT) { 745d430753cba09acb07af8b313286f247c78a41a32Chet Haase 746d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (type != XmlPullParser.START_TAG) { 747d430753cba09acb07af8b313286f247c78a41a32Chet Haase parser.next(); 748d430753cba09acb07af8b313286f247c78a41a32Chet Haase continue; 749d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 750d430753cba09acb07af8b313286f247c78a41a32Chet Haase 751d430753cba09acb07af8b313286f247c78a41a32Chet Haase String name = parser.getName(); 752d430753cba09acb07af8b313286f247c78a41a32Chet Haase 753d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (name.equals("propertyValuesHolder")) { 754d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypedArray a; 755d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (theme != null) { 756d430753cba09acb07af8b313286f247c78a41a32Chet Haase a = theme.obtainStyledAttributes(attrs, R.styleable.PropertyValuesHolder, 0, 0); 757d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 758d430753cba09acb07af8b313286f247c78a41a32Chet Haase a = res.obtainAttributes(attrs, R.styleable.PropertyValuesHolder); 759d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 760d430753cba09acb07af8b313286f247c78a41a32Chet Haase String propertyName = a.getString(R.styleable.PropertyValuesHolder_propertyName); 761d430753cba09acb07af8b313286f247c78a41a32Chet Haase int valueType = a.getInt(R.styleable.PropertyValuesHolder_valueType, 7629032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu VALUE_TYPE_UNDEFINED); 7639032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu 764d430753cba09acb07af8b313286f247c78a41a32Chet Haase PropertyValuesHolder pvh = loadPvh(res, theme, parser, propertyName, valueType); 765d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (pvh == null) { 766d430753cba09acb07af8b313286f247c78a41a32Chet Haase pvh = getPVH(a, valueType, 767d430753cba09acb07af8b313286f247c78a41a32Chet Haase R.styleable.PropertyValuesHolder_valueFrom, 768d430753cba09acb07af8b313286f247c78a41a32Chet Haase R.styleable.PropertyValuesHolder_valueTo, propertyName); 769d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 770d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (pvh != null) { 771d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (values == null) { 772d430753cba09acb07af8b313286f247c78a41a32Chet Haase values = new ArrayList<PropertyValuesHolder>(); 773d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 774d430753cba09acb07af8b313286f247c78a41a32Chet Haase values.add(pvh); 775d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 776d430753cba09acb07af8b313286f247c78a41a32Chet Haase a.recycle(); 777d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 778d430753cba09acb07af8b313286f247c78a41a32Chet Haase 779d430753cba09acb07af8b313286f247c78a41a32Chet Haase parser.next(); 780d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 781d430753cba09acb07af8b313286f247c78a41a32Chet Haase 782d430753cba09acb07af8b313286f247c78a41a32Chet Haase PropertyValuesHolder[] valuesArray = null; 783d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (values != null) { 784d430753cba09acb07af8b313286f247c78a41a32Chet Haase int count = values.size(); 785d430753cba09acb07af8b313286f247c78a41a32Chet Haase valuesArray = new PropertyValuesHolder[count]; 786d430753cba09acb07af8b313286f247c78a41a32Chet Haase for (int i = 0; i < count; ++i) { 787d430753cba09acb07af8b313286f247c78a41a32Chet Haase valuesArray[i] = values.get(i); 788d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 789d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 790d430753cba09acb07af8b313286f247c78a41a32Chet Haase return valuesArray; 791d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 792d430753cba09acb07af8b313286f247c78a41a32Chet Haase 793a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu // When no value type is provided in keyframe, we need to infer the type from the value. i.e. 794a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu // if value is defined in the style of a color value, then the color type is returned. 795a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu // Otherwise, default float type is returned. 796a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu private static int inferValueTypeOfKeyframe(Resources res, Theme theme, AttributeSet attrs) { 797a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu int valueType; 798a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu TypedArray a; 799a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu if (theme != null) { 800a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu a = theme.obtainStyledAttributes(attrs, R.styleable.Keyframe, 0, 0); 801a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu } else { 802a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu a = res.obtainAttributes(attrs, R.styleable.Keyframe); 803a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu } 804a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu 805a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu TypedValue keyframeValue = a.peekValue(R.styleable.Keyframe_value); 806a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu boolean hasValue = (keyframeValue != null); 807a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu // When no value type is provided, check whether it's a color type first. 808a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu // If not, fall back to default value type (i.e. float type). 809a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu if (hasValue && isColorType(keyframeValue.type)) { 810a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu valueType = VALUE_TYPE_COLOR; 811a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu } else { 812a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu valueType = VALUE_TYPE_FLOAT; 813a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu } 814a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu a.recycle(); 815a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu return valueType; 816a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu } 817a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu 8182787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu private static int inferValueTypeFromValues(TypedArray styledAttributes, int valueFromId, 8192787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu int valueToId) { 8202787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu TypedValue tvFrom = styledAttributes.peekValue(valueFromId); 8212787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu boolean hasFrom = (tvFrom != null); 8222787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu int fromType = hasFrom ? tvFrom.type : 0; 8232787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu TypedValue tvTo = styledAttributes.peekValue(valueToId); 8242787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu boolean hasTo = (tvTo != null); 8252787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu int toType = hasTo ? tvTo.type : 0; 8262787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu 8272787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu int valueType; 8282787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu // Check whether it's color type. If not, fall back to default type (i.e. float type) 8292787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu if ((hasFrom && isColorType(fromType)) || (hasTo && isColorType(toType))) { 8302787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu valueType = VALUE_TYPE_COLOR; 8312787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu } else { 8322787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu valueType = VALUE_TYPE_FLOAT; 8332787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu } 8342787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu return valueType; 8352787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu } 8362787cebfdc78b662e8742b7eb8dacf9b4a6e80c1Doris Liu 837d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static void dumpKeyframes(Object[] keyframes, String header) { 838d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (keyframes == null || keyframes.length == 0) { 839d430753cba09acb07af8b313286f247c78a41a32Chet Haase return; 840d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 841d430753cba09acb07af8b313286f247c78a41a32Chet Haase Log.d(TAG, header); 842d430753cba09acb07af8b313286f247c78a41a32Chet Haase int count = keyframes.length; 843d430753cba09acb07af8b313286f247c78a41a32Chet Haase for (int i = 0; i < count; ++i) { 844d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe keyframe = (Keyframe) keyframes[i]; 845d430753cba09acb07af8b313286f247c78a41a32Chet Haase Log.d(TAG, "Keyframe " + i + ": fraction " + 846d430753cba09acb07af8b313286f247c78a41a32Chet Haase (keyframe.getFraction() < 0 ? "null" : keyframe.getFraction()) + ", " + 847d430753cba09acb07af8b313286f247c78a41a32Chet Haase ", value : " + ((keyframe.hasValue()) ? keyframe.getValue() : "null")); 848d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 849d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 850d430753cba09acb07af8b313286f247c78a41a32Chet Haase 8519032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu // Load property values holder if there are keyframes defined in it. Otherwise return null. 852d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static PropertyValuesHolder loadPvh(Resources res, Theme theme, XmlPullParser parser, 853d430753cba09acb07af8b313286f247c78a41a32Chet Haase String propertyName, int valueType) 854d430753cba09acb07af8b313286f247c78a41a32Chet Haase throws XmlPullParserException, IOException { 855d430753cba09acb07af8b313286f247c78a41a32Chet Haase 856d430753cba09acb07af8b313286f247c78a41a32Chet Haase PropertyValuesHolder value = null; 857d430753cba09acb07af8b313286f247c78a41a32Chet Haase ArrayList<Keyframe> keyframes = null; 858d430753cba09acb07af8b313286f247c78a41a32Chet Haase 859d430753cba09acb07af8b313286f247c78a41a32Chet Haase int type; 860d430753cba09acb07af8b313286f247c78a41a32Chet Haase while ((type = parser.next()) != XmlPullParser.END_TAG && 861d430753cba09acb07af8b313286f247c78a41a32Chet Haase type != XmlPullParser.END_DOCUMENT) { 862d430753cba09acb07af8b313286f247c78a41a32Chet Haase String name = parser.getName(); 863d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (name.equals("keyframe")) { 864a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu if (valueType == VALUE_TYPE_UNDEFINED) { 865a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu valueType = inferValueTypeOfKeyframe(res, theme, Xml.asAttributeSet(parser)); 866a01fbf35de21cd595d4cda2e83b67c1238e12550Doris Liu } 867d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe keyframe = loadKeyframe(res, theme, Xml.asAttributeSet(parser), valueType); 868d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (keyframe != null) { 869d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (keyframes == null) { 870d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframes = new ArrayList<Keyframe>(); 871d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 872d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframes.add(keyframe); 873d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 874d430753cba09acb07af8b313286f247c78a41a32Chet Haase parser.next(); 875d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 876d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 877d430753cba09acb07af8b313286f247c78a41a32Chet Haase 878d430753cba09acb07af8b313286f247c78a41a32Chet Haase int count; 879d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (keyframes != null && (count = keyframes.size()) > 0) { 880d430753cba09acb07af8b313286f247c78a41a32Chet Haase // make sure we have keyframes at 0 and 1 881d430753cba09acb07af8b313286f247c78a41a32Chet Haase // If we have keyframes with set fractions, add keyframes at start/end 882d430753cba09acb07af8b313286f247c78a41a32Chet Haase // appropriately. If start/end have no set fractions: 883d430753cba09acb07af8b313286f247c78a41a32Chet Haase // if there's only one keyframe, set its fraction to 1 and add one at 0 884d430753cba09acb07af8b313286f247c78a41a32Chet Haase // if >1 keyframe, set the last fraction to 1, the first fraction to 0 885d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe firstKeyframe = keyframes.get(0); 886d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe lastKeyframe = keyframes.get(count - 1); 887d430753cba09acb07af8b313286f247c78a41a32Chet Haase float endFraction = lastKeyframe.getFraction(); 888d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (endFraction < 1) { 889d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (endFraction < 0) { 890d430753cba09acb07af8b313286f247c78a41a32Chet Haase lastKeyframe.setFraction(1); 891d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 892d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframes.add(keyframes.size(), createNewKeyframe(lastKeyframe, 1)); 893d430753cba09acb07af8b313286f247c78a41a32Chet Haase ++count; 894d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 895d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 896d430753cba09acb07af8b313286f247c78a41a32Chet Haase float startFraction = firstKeyframe.getFraction(); 897d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (startFraction != 0) { 898d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (startFraction < 0) { 899d430753cba09acb07af8b313286f247c78a41a32Chet Haase firstKeyframe.setFraction(0); 900d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 901d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframes.add(0, createNewKeyframe(firstKeyframe, 0)); 902d430753cba09acb07af8b313286f247c78a41a32Chet Haase ++count; 903d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 904d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 905d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe[] keyframeArray = new Keyframe[count]; 906d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframes.toArray(keyframeArray); 907d430753cba09acb07af8b313286f247c78a41a32Chet Haase for (int i = 0; i < count; ++i) { 908d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe keyframe = keyframeArray[i]; 909d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (keyframe.getFraction() < 0) { 910d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (i == 0) { 911d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframe.setFraction(0); 912d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else if (i == count - 1) { 913d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframe.setFraction(1); 914d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 915d430753cba09acb07af8b313286f247c78a41a32Chet Haase // figure out the start/end parameters of the current gap 916d430753cba09acb07af8b313286f247c78a41a32Chet Haase // in fractions and distribute the gap among those keyframes 917d430753cba09acb07af8b313286f247c78a41a32Chet Haase int startIndex = i; 918d430753cba09acb07af8b313286f247c78a41a32Chet Haase int endIndex = i; 919d430753cba09acb07af8b313286f247c78a41a32Chet Haase for (int j = startIndex + 1; j < count - 1; ++j) { 920d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (keyframeArray[j].getFraction() >= 0) { 921d430753cba09acb07af8b313286f247c78a41a32Chet Haase break; 922d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 923d430753cba09acb07af8b313286f247c78a41a32Chet Haase endIndex = j; 924d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 925d430753cba09acb07af8b313286f247c78a41a32Chet Haase float gap = keyframeArray[endIndex + 1].getFraction() - 926d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframeArray[startIndex - 1].getFraction(); 927d430753cba09acb07af8b313286f247c78a41a32Chet Haase distributeKeyframes(keyframeArray, gap, startIndex, endIndex); 928d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 929d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 930d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 931d430753cba09acb07af8b313286f247c78a41a32Chet Haase value = PropertyValuesHolder.ofKeyframe(propertyName, keyframeArray); 932d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (valueType == VALUE_TYPE_COLOR) { 933d430753cba09acb07af8b313286f247c78a41a32Chet Haase value.setEvaluator(ArgbEvaluator.getInstance()); 934d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 935d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 936d430753cba09acb07af8b313286f247c78a41a32Chet Haase 937d430753cba09acb07af8b313286f247c78a41a32Chet Haase return value; 938d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 939d430753cba09acb07af8b313286f247c78a41a32Chet Haase 940d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static Keyframe createNewKeyframe(Keyframe sampleKeyframe, float fraction) { 941d430753cba09acb07af8b313286f247c78a41a32Chet Haase return sampleKeyframe.getType() == float.class ? 942d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe.ofFloat(fraction) : 943d430753cba09acb07af8b313286f247c78a41a32Chet Haase (sampleKeyframe.getType() == int.class) ? 944d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe.ofInt(fraction) : 945d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe.ofObject(fraction); 946d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 947d430753cba09acb07af8b313286f247c78a41a32Chet Haase 948d430753cba09acb07af8b313286f247c78a41a32Chet Haase /** 949d430753cba09acb07af8b313286f247c78a41a32Chet Haase * Utility function to set fractions on keyframes to cover a gap in which the 950d430753cba09acb07af8b313286f247c78a41a32Chet Haase * fractions are not currently set. Keyframe fractions will be distributed evenly 951d430753cba09acb07af8b313286f247c78a41a32Chet Haase * in this gap. For example, a gap of 1 keyframe in the range 0-1 will be at .5, a gap 952d430753cba09acb07af8b313286f247c78a41a32Chet Haase * of .6 spread between two keyframes will be at .2 and .4 beyond the fraction at the 953d430753cba09acb07af8b313286f247c78a41a32Chet Haase * keyframe before startIndex. 954d430753cba09acb07af8b313286f247c78a41a32Chet Haase * Assumptions: 955d430753cba09acb07af8b313286f247c78a41a32Chet Haase * - First and last keyframe fractions (bounding this spread) are already set. So, 956d430753cba09acb07af8b313286f247c78a41a32Chet Haase * for example, if no fractions are set, we will already set first and last keyframe 957d430753cba09acb07af8b313286f247c78a41a32Chet Haase * fraction values to 0 and 1. 958d430753cba09acb07af8b313286f247c78a41a32Chet Haase * - startIndex must be >0 (which follows from first assumption). 959d430753cba09acb07af8b313286f247c78a41a32Chet Haase * - endIndex must be >= startIndex. 960d430753cba09acb07af8b313286f247c78a41a32Chet Haase * 961d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param keyframes the array of keyframes 962d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param gap The total gap we need to distribute 963d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param startIndex The index of the first keyframe whose fraction must be set 964d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param endIndex The index of the last keyframe whose fraction must be set 965d430753cba09acb07af8b313286f247c78a41a32Chet Haase */ 966d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static void distributeKeyframes(Keyframe[] keyframes, float gap, 967d430753cba09acb07af8b313286f247c78a41a32Chet Haase int startIndex, int endIndex) { 968d430753cba09acb07af8b313286f247c78a41a32Chet Haase int count = endIndex - startIndex + 2; 969d430753cba09acb07af8b313286f247c78a41a32Chet Haase float increment = gap / count; 970d430753cba09acb07af8b313286f247c78a41a32Chet Haase for (int i = startIndex; i <= endIndex; ++i) { 971d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframes[i].setFraction(keyframes[i-1].getFraction() + increment); 972d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 973d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 974d430753cba09acb07af8b313286f247c78a41a32Chet Haase 975d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static Keyframe loadKeyframe(Resources res, Theme theme, AttributeSet attrs, 976d430753cba09acb07af8b313286f247c78a41a32Chet Haase int valueType) 977d430753cba09acb07af8b313286f247c78a41a32Chet Haase throws XmlPullParserException, IOException { 978d430753cba09acb07af8b313286f247c78a41a32Chet Haase 979d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypedArray a; 980d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (theme != null) { 981d430753cba09acb07af8b313286f247c78a41a32Chet Haase a = theme.obtainStyledAttributes(attrs, R.styleable.Keyframe, 0, 0); 982d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 983d430753cba09acb07af8b313286f247c78a41a32Chet Haase a = res.obtainAttributes(attrs, R.styleable.Keyframe); 984d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 985d430753cba09acb07af8b313286f247c78a41a32Chet Haase 986d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe keyframe = null; 987d430753cba09acb07af8b313286f247c78a41a32Chet Haase 988d430753cba09acb07af8b313286f247c78a41a32Chet Haase float fraction = a.getFloat(R.styleable.Keyframe_fraction, -1); 989d430753cba09acb07af8b313286f247c78a41a32Chet Haase 9909032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu TypedValue keyframeValue = a.peekValue(R.styleable.Keyframe_value); 9919032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu boolean hasValue = (keyframeValue != null); 9929032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu if (valueType == VALUE_TYPE_UNDEFINED) { 9939032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu // When no value type is provided, check whether it's a color type first. 9949032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu // If not, fall back to default value type (i.e. float type). 9959032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu if (hasValue && isColorType(keyframeValue.type)) { 9969032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu valueType = VALUE_TYPE_COLOR; 9979032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } else { 9989032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu valueType = VALUE_TYPE_FLOAT; 9999032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } 10009032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } 1001d430753cba09acb07af8b313286f247c78a41a32Chet Haase 1002d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (hasValue) { 1003d430753cba09acb07af8b313286f247c78a41a32Chet Haase switch (valueType) { 1004d430753cba09acb07af8b313286f247c78a41a32Chet Haase case VALUE_TYPE_FLOAT: 1005d430753cba09acb07af8b313286f247c78a41a32Chet Haase float value = a.getFloat(R.styleable.Keyframe_value, 0); 1006d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframe = Keyframe.ofFloat(fraction, value); 1007d430753cba09acb07af8b313286f247c78a41a32Chet Haase break; 1008d430753cba09acb07af8b313286f247c78a41a32Chet Haase case VALUE_TYPE_COLOR: 1009d430753cba09acb07af8b313286f247c78a41a32Chet Haase case VALUE_TYPE_INT: 1010d430753cba09acb07af8b313286f247c78a41a32Chet Haase int intValue = a.getInt(R.styleable.Keyframe_value, 0); 1011d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframe = Keyframe.ofInt(fraction, intValue); 1012d430753cba09acb07af8b313286f247c78a41a32Chet Haase break; 1013d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 1014d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 1015d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframe = (valueType == VALUE_TYPE_FLOAT) ? Keyframe.ofFloat(fraction) : 1016d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe.ofInt(fraction); 1017d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 1018d430753cba09acb07af8b313286f247c78a41a32Chet Haase 10196aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu final int resID = a.getResourceId(R.styleable.Keyframe_interpolator, 0); 10206aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu if (resID > 0) { 10216aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu final Interpolator interpolator = AnimationUtils.loadInterpolator(res, theme, resID); 10226aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu keyframe.setInterpolator(interpolator); 10236aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu } 1024d430753cba09acb07af8b313286f247c78a41a32Chet Haase a.recycle(); 1025e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1026d430753cba09acb07af8b313286f247c78a41a32Chet Haase return keyframe; 1027e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1028e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1029fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs, 10307513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu float pathErrorScale) throws NotFoundException { 1031e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui ObjectAnimator anim = new ObjectAnimator(); 1032e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 10337513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu loadAnimator(res, theme, attrs, anim, pathErrorScale); 1034e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1035e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return anim; 1036e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1037e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1038e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui /** 1039e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * Creates a new animation whose parameters come from the specified context 1040e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * and attributes set. 1041e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * 1042e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @param res The resources 1043e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @param attrs The set of attributes holding the animation parameters 1044cf4832f69c8786b098ce18c24319021f8cd6733aztenghui * @param anim Null if this is a ValueAnimator, otherwise this is an 1045cf4832f69c8786b098ce18c24319021f8cd6733aztenghui * ObjectAnimator 1046e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui */ 1047e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui private static ValueAnimator loadAnimator(Resources res, Theme theme, 10487513aab4dfa33130fd846bf033f4878ae1c75914Doris Liu AttributeSet attrs, ValueAnimator anim, float pathErrorScale) 1049e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui throws NotFoundException { 1050cf4832f69c8786b098ce18c24319021f8cd6733aztenghui TypedArray arrayAnimator = null; 1051cf4832f69c8786b098ce18c24319021f8cd6733aztenghui TypedArray arrayObjectAnimator = null; 1052cf4832f69c8786b098ce18c24319021f8cd6733aztenghui 1053e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (theme != null) { 1054cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayAnimator = theme.obtainStyledAttributes(attrs, R.styleable.Animator, 0, 0); 1055e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else { 1056cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayAnimator = res.obtainAttributes(attrs, R.styleable.Animator); 1057e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1058e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1059cf4832f69c8786b098ce18c24319021f8cd6733aztenghui // If anim is not null, then it is an object animator. 1060cf4832f69c8786b098ce18c24319021f8cd6733aztenghui if (anim != null) { 1061cf4832f69c8786b098ce18c24319021f8cd6733aztenghui if (theme != null) { 1062cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayObjectAnimator = theme.obtainStyledAttributes(attrs, 1063cf4832f69c8786b098ce18c24319021f8cd6733aztenghui R.styleable.PropertyAnimator, 0, 0); 1064cf4832f69c8786b098ce18c24319021f8cd6733aztenghui } else { 1065cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayObjectAnimator = res.obtainAttributes(attrs, R.styleable.PropertyAnimator); 1066cf4832f69c8786b098ce18c24319021f8cd6733aztenghui } 1067d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar anim.appendChangingConfigurations(arrayObjectAnimator.getChangingConfigurations()); 1068cf4832f69c8786b098ce18c24319021f8cd6733aztenghui } 10697f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout 10707f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout if (anim == null) { 10717f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout anim = new ValueAnimator(); 10727f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout } 1073d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar anim.appendChangingConfigurations(arrayAnimator.getChangingConfigurations()); 10747f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout 1075fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount parseAnimatorFromTypeArray(anim, arrayAnimator, arrayObjectAnimator, pathErrorScale); 1076d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 1077d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final int resID = arrayAnimator.getResourceId(R.styleable.Animator_interpolator, 0); 1078d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase if (resID > 0) { 1079d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final Interpolator interpolator = AnimationUtils.loadInterpolator(res, theme, resID); 1080d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (interpolator instanceof BaseInterpolator) { 1081d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar anim.appendChangingConfigurations( 1082d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar ((BaseInterpolator) interpolator).getChangingConfiguration()); 1083d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 1084d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar anim.setInterpolator(interpolator); 1085d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 1086cf4832f69c8786b098ce18c24319021f8cd6733aztenghui 1087cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayAnimator.recycle(); 10887f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout if (arrayObjectAnimator != null) { 10897f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout arrayObjectAnimator.recycle(); 10907f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout } 1091d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase return anim; 1092d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 1093d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar 1094d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar private static int getChangingConfigs(Resources resources, int id) { 1095d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar synchronized (sTmpTypedValue) { 1096d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar resources.getValue(id, sTmpTypedValue, true); 1097d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar return sTmpTypedValue.changingConfigurations; 1098d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 1099d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 11009032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu 11019032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu private static boolean isColorType(int type) { 11029032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu return (type >= TypedValue.TYPE_FIRST_COLOR_INT) && (type <= TypedValue.TYPE_LAST_COLOR_INT); 11039032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu } 1104d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase} 1105