AnimatorInflater.java revision 6aac06ab940566020d050fdaa0d5e8d2e6c128ae
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; 71d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 72eb034fbca40006c55db143047eb628c4b657730aztenghui private static final boolean DBG_ANIMATOR_INFLATER = false; 73eb034fbca40006c55db143047eb628c4b657730aztenghui 74d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar // used to calculate changing configs for resource references 75d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar private static final TypedValue sTmpTypedValue = new TypedValue(); 76d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar 77d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase /** 78a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * Loads an {@link Animator} object from a resource 79d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * 80d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * @param context Application context used to access resources 81d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * @param id The resource id of the animation to load 82a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * @return The animator object reference by the specified id 83d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded 84d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase */ 857b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye public static Animator loadAnimator(Context context, @AnimatorRes int id) 86d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase throws NotFoundException { 87e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return loadAnimator(context.getResources(), context.getTheme(), id); 88e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 89e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 90e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui /** 91e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * Loads an {@link Animator} object from a resource 92e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * 93e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @param resources The resources 94e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @param theme The theme 95e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @param id The resource id of the animation to load 96e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @return The animator object reference by the specified id 97e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded 98e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @hide 99e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui */ 100e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public static Animator loadAnimator(Resources resources, Theme theme, int id) 101e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui throws NotFoundException { 102fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount return loadAnimator(resources, theme, id, 1); 103fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount } 104fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount 105fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount /** @hide */ 106fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount public static Animator loadAnimator(Resources resources, Theme theme, int id, 107fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount float pathErrorScale) throws NotFoundException { 108d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final ConfigurationBoundResourceCache<Animator> animatorCache = resources 109d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar .getAnimatorCache(); 110d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar Animator animator = animatorCache.get(id, theme); 111d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (animator != null) { 112d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (DBG_ANIMATOR_INFLATER) { 113d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar Log.d(TAG, "loaded animator from cache, " + resources.getResourceName(id)); 114d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 115d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar return animator; 116d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } else if (DBG_ANIMATOR_INFLATER) { 117d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar Log.d(TAG, "cache miss for animator " + resources.getResourceName(id)); 118d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 119d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase XmlResourceParser parser = null; 120d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase try { 121e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui parser = resources.getAnimation(id); 122d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animator = createAnimatorFromXml(resources, theme, parser, pathErrorScale); 123d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (animator != null) { 124d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animator.appendChangingConfigurations(getChangingConfigs(resources, id)); 125d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final ConstantState<Animator> constantState = animator.createConstantState(); 126d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (constantState != null) { 127d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (DBG_ANIMATOR_INFLATER) { 128d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar Log.d(TAG, "caching animator for res " + resources.getResourceName(id)); 129d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 130d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animatorCache.put(id, theme, constantState); 131d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar // create a new animator so that cached version is never used by the user 132d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animator = constantState.newInstance(resources, theme); 133d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 134d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 135d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar return animator; 136d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } catch (XmlPullParserException ex) { 137d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase Resources.NotFoundException rnf = 138d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase new Resources.NotFoundException("Can't load animation resource ID #0x" + 139fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount Integer.toHexString(id)); 140d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase rnf.initCause(ex); 141d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase throw rnf; 142d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } catch (IOException ex) { 143d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase Resources.NotFoundException rnf = 144d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase new Resources.NotFoundException("Can't load animation resource ID #0x" + 145fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount Integer.toHexString(id)); 146d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase rnf.initCause(ex); 147d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase throw rnf; 148d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } finally { 149d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase if (parser != null) parser.close(); 150d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 151d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 152d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 153f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar public static StateListAnimator loadStateListAnimator(Context context, int id) 154f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throws NotFoundException { 155d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final Resources resources = context.getResources(); 156d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final ConfigurationBoundResourceCache<StateListAnimator> cache = resources 157d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar .getStateListAnimatorCache(); 158d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final Theme theme = context.getTheme(); 159d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar StateListAnimator animator = cache.get(id, theme); 160d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (animator != null) { 161d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar return animator; 162d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 163f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar XmlResourceParser parser = null; 164f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar try { 165d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar parser = resources.getAnimation(id); 166d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animator = createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser)); 167d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (animator != null) { 168d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animator.appendChangingConfigurations(getChangingConfigs(resources, id)); 169d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final ConstantState<StateListAnimator> constantState = animator 170d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar .createConstantState(); 171d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (constantState != null) { 172d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar cache.put(id, theme, constantState); 173d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar // return a clone so that the animator in constant state is never used. 174d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animator = constantState.newInstance(resources, theme); 175d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 176d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 177d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar return animator; 178f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } catch (XmlPullParserException ex) { 179f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Resources.NotFoundException rnf = 180f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar new Resources.NotFoundException( 181f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar "Can't load state list animator resource ID #0x" + 182f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Integer.toHexString(id) 183f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar ); 184f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar rnf.initCause(ex); 185f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throw rnf; 186f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } catch (IOException ex) { 187f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Resources.NotFoundException rnf = 188f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar new Resources.NotFoundException( 189f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar "Can't load state list animator resource ID #0x" + 190f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Integer.toHexString(id) 191f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar ); 192f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar rnf.initCause(ex); 193f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throw rnf; 194f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } finally { 195f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar if (parser != null) { 196f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar parser.close(); 197f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 198f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 199f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 200f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 201f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar private static StateListAnimator createStateListAnimatorFromXml(Context context, 202f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar XmlPullParser parser, AttributeSet attributeSet) 203f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throws IOException, XmlPullParserException { 204f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int type; 205f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar StateListAnimator stateListAnimator = new StateListAnimator(); 206f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 207f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar while (true) { 208f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar type = parser.next(); 209f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar switch (type) { 210f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar case XmlPullParser.END_DOCUMENT: 211f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar case XmlPullParser.END_TAG: 212f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar return stateListAnimator; 213f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 214f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar case XmlPullParser.START_TAG: 215f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar // parse item 216f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Animator animator = null; 217f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar if ("item".equals(parser.getName())) { 218f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int attributeCount = parser.getAttributeCount(); 219f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int[] states = new int[attributeCount]; 220f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int stateIndex = 0; 221f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar for (int i = 0; i < attributeCount; i++) { 222f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int attrName = attributeSet.getAttributeNameResource(i); 223cf4832f69c8786b098ce18c24319021f8cd6733aztenghui if (attrName == R.attr.animation) { 224d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final int animId = attributeSet.getAttributeResourceValue(i, 0); 225d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar animator = loadAnimator(context, animId); 226f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } else { 227f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar states[stateIndex++] = 228f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar attributeSet.getAttributeBooleanValue(i, false) ? 229f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar attrName : -attrName; 230f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 231f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 232f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar if (animator == null) { 233e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui animator = createAnimatorFromXml(context.getResources(), 234fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount context.getTheme(), parser, 1f); 235f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 236f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 237f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar if (animator == null) { 238f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throw new Resources.NotFoundException( 239f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar "animation state item must have a valid animation"); 240f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 241f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar stateListAnimator 242f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar .addState(StateSet.trimStateSet(states, stateIndex), animator); 243f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 244f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar break; 245f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 246f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 247f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 248f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 249cf4832f69c8786b098ce18c24319021f8cd6733aztenghui /** 250eb034fbca40006c55db143047eb628c4b657730aztenghui * PathDataEvaluator is used to interpolate between two paths which are 251eb034fbca40006c55db143047eb628c4b657730aztenghui * represented in the same format but different control points' values. 252eb034fbca40006c55db143047eb628c4b657730aztenghui * The path is represented as an array of PathDataNode here, which is 253eb034fbca40006c55db143047eb628c4b657730aztenghui * fundamentally an array of floating point numbers. 254eb034fbca40006c55db143047eb628c4b657730aztenghui */ 255eb034fbca40006c55db143047eb628c4b657730aztenghui private static class PathDataEvaluator implements TypeEvaluator<PathParser.PathDataNode[]> { 256eb034fbca40006c55db143047eb628c4b657730aztenghui private PathParser.PathDataNode[] mNodeArray; 257eb034fbca40006c55db143047eb628c4b657730aztenghui 258eb034fbca40006c55db143047eb628c4b657730aztenghui /** 259eb034fbca40006c55db143047eb628c4b657730aztenghui * Create a PathParser.PathDataNode[] that does not reuse the animated value. 260eb034fbca40006c55db143047eb628c4b657730aztenghui * Care must be taken when using this option because on every evaluation 261eb034fbca40006c55db143047eb628c4b657730aztenghui * a new <code>PathParser.PathDataNode[]</code> will be allocated. 262eb034fbca40006c55db143047eb628c4b657730aztenghui */ 263eb034fbca40006c55db143047eb628c4b657730aztenghui private PathDataEvaluator() {} 264eb034fbca40006c55db143047eb628c4b657730aztenghui 265eb034fbca40006c55db143047eb628c4b657730aztenghui /** 266eb034fbca40006c55db143047eb628c4b657730aztenghui * Create a PathDataEvaluator that reuses <code>nodeArray</code> for every evaluate() call. 267eb034fbca40006c55db143047eb628c4b657730aztenghui * Caution must be taken to ensure that the value returned from 268eb034fbca40006c55db143047eb628c4b657730aztenghui * {@link android.animation.ValueAnimator#getAnimatedValue()} is not cached, modified, or 269eb034fbca40006c55db143047eb628c4b657730aztenghui * used across threads. The value will be modified on each <code>evaluate()</code> call. 270eb034fbca40006c55db143047eb628c4b657730aztenghui * 271eb034fbca40006c55db143047eb628c4b657730aztenghui * @param nodeArray The array to modify and return from <code>evaluate</code>. 272eb034fbca40006c55db143047eb628c4b657730aztenghui */ 273eb034fbca40006c55db143047eb628c4b657730aztenghui public PathDataEvaluator(PathParser.PathDataNode[] nodeArray) { 274eb034fbca40006c55db143047eb628c4b657730aztenghui mNodeArray = nodeArray; 275eb034fbca40006c55db143047eb628c4b657730aztenghui } 276eb034fbca40006c55db143047eb628c4b657730aztenghui 277eb034fbca40006c55db143047eb628c4b657730aztenghui @Override 278eb034fbca40006c55db143047eb628c4b657730aztenghui public PathParser.PathDataNode[] evaluate(float fraction, 279eb034fbca40006c55db143047eb628c4b657730aztenghui PathParser.PathDataNode[] startPathData, 280eb034fbca40006c55db143047eb628c4b657730aztenghui PathParser.PathDataNode[] endPathData) { 281eb034fbca40006c55db143047eb628c4b657730aztenghui if (!PathParser.canMorph(startPathData, endPathData)) { 282eb034fbca40006c55db143047eb628c4b657730aztenghui throw new IllegalArgumentException("Can't interpolate between" 283eb034fbca40006c55db143047eb628c4b657730aztenghui + " two incompatible pathData"); 284eb034fbca40006c55db143047eb628c4b657730aztenghui } 285eb034fbca40006c55db143047eb628c4b657730aztenghui 286eb034fbca40006c55db143047eb628c4b657730aztenghui if (mNodeArray == null || !PathParser.canMorph(mNodeArray, startPathData)) { 287eb034fbca40006c55db143047eb628c4b657730aztenghui mNodeArray = PathParser.deepCopyNodes(startPathData); 288eb034fbca40006c55db143047eb628c4b657730aztenghui } 289eb034fbca40006c55db143047eb628c4b657730aztenghui 290eb034fbca40006c55db143047eb628c4b657730aztenghui for (int i = 0; i < startPathData.length; i++) { 291eb034fbca40006c55db143047eb628c4b657730aztenghui mNodeArray[i].interpolatePathDataNode(startPathData[i], 292eb034fbca40006c55db143047eb628c4b657730aztenghui endPathData[i], fraction); 293eb034fbca40006c55db143047eb628c4b657730aztenghui } 294eb034fbca40006c55db143047eb628c4b657730aztenghui 295eb034fbca40006c55db143047eb628c4b657730aztenghui return mNodeArray; 296eb034fbca40006c55db143047eb628c4b657730aztenghui } 297eb034fbca40006c55db143047eb628c4b657730aztenghui } 298eb034fbca40006c55db143047eb628c4b657730aztenghui 299d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static PropertyValuesHolder getPVH(TypedArray styledAttributes, int valueType, 300d430753cba09acb07af8b313286f247c78a41a32Chet Haase int valueFromId, int valueToId, String propertyName) { 3015bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase 3025bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase boolean getFloats = (valueType == VALUE_TYPE_FLOAT); 3035bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase 304d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypedValue tvFrom = styledAttributes.peekValue(valueFromId); 3055bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase boolean hasFrom = (tvFrom != null); 3065bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase int fromType = hasFrom ? tvFrom.type : 0; 307d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypedValue tvTo = styledAttributes.peekValue(valueToId); 3085bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase boolean hasTo = (tvTo != null); 3095bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase int toType = hasTo ? tvTo.type : 0; 3105bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase 311d430753cba09acb07af8b313286f247c78a41a32Chet Haase PropertyValuesHolder returnValue = null; 312d430753cba09acb07af8b313286f247c78a41a32Chet Haase 313eb034fbca40006c55db143047eb628c4b657730aztenghui if (valueType == VALUE_TYPE_PATH) { 314d430753cba09acb07af8b313286f247c78a41a32Chet Haase String fromString = styledAttributes.getString(valueFromId); 315d430753cba09acb07af8b313286f247c78a41a32Chet Haase String toString = styledAttributes.getString(valueToId); 316d430753cba09acb07af8b313286f247c78a41a32Chet Haase PathParser.PathDataNode[] nodesFrom = PathParser.createNodesFromPathData(fromString); 317d430753cba09acb07af8b313286f247c78a41a32Chet Haase PathParser.PathDataNode[] nodesTo = PathParser.createNodesFromPathData(toString); 318d430753cba09acb07af8b313286f247c78a41a32Chet Haase 319d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (nodesFrom != null || nodesTo != null) { 320d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (nodesFrom != null) { 321d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypeEvaluator evaluator = 322d430753cba09acb07af8b313286f247c78a41a32Chet Haase new PathDataEvaluator(PathParser.deepCopyNodes(nodesFrom)); 323d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (nodesTo != null) { 324d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (!PathParser.canMorph(nodesFrom, nodesTo)) { 325d430753cba09acb07af8b313286f247c78a41a32Chet Haase throw new InflateException(" Can't morph from " + fromString + " to " + 326d430753cba09acb07af8b313286f247c78a41a32Chet Haase toString); 327d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 328d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofObject(propertyName, evaluator, 329d430753cba09acb07af8b313286f247c78a41a32Chet Haase nodesFrom, nodesTo); 330d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 331d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofObject(propertyName, evaluator, 332d430753cba09acb07af8b313286f247c78a41a32Chet Haase (Object) nodesFrom); 333d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 334d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else if (nodesTo != null) { 335d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypeEvaluator evaluator = 336d430753cba09acb07af8b313286f247c78a41a32Chet Haase new PathDataEvaluator(PathParser.deepCopyNodes(nodesTo)); 337d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofObject(propertyName, evaluator, 338d430753cba09acb07af8b313286f247c78a41a32Chet Haase (Object) nodesTo); 339d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 340d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 341eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 342d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypeEvaluator evaluator = null; 343eb034fbca40006c55db143047eb628c4b657730aztenghui // Integer and float value types are handled here. 344eb034fbca40006c55db143047eb628c4b657730aztenghui if ((hasFrom && (fromType >= TypedValue.TYPE_FIRST_COLOR_INT) && 345eb034fbca40006c55db143047eb628c4b657730aztenghui (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) || 346eb034fbca40006c55db143047eb628c4b657730aztenghui (hasTo && (toType >= TypedValue.TYPE_FIRST_COLOR_INT) && 347eb034fbca40006c55db143047eb628c4b657730aztenghui (toType <= TypedValue.TYPE_LAST_COLOR_INT))) { 348eb034fbca40006c55db143047eb628c4b657730aztenghui // special case for colors: ignore valueType and get ints 349eb034fbca40006c55db143047eb628c4b657730aztenghui getFloats = false; 350eb034fbca40006c55db143047eb628c4b657730aztenghui evaluator = ArgbEvaluator.getInstance(); 351eb034fbca40006c55db143047eb628c4b657730aztenghui } 352d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (getFloats) { 353d430753cba09acb07af8b313286f247c78a41a32Chet Haase float valueFrom; 354d430753cba09acb07af8b313286f247c78a41a32Chet Haase float valueTo; 355d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (hasFrom) { 356d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (fromType == TypedValue.TYPE_DIMENSION) { 357d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueFrom = styledAttributes.getDimension(valueFromId, 0f); 358d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 359d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueFrom = styledAttributes.getFloat(valueFromId, 0f); 360d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 361d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (hasTo) { 362d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 363d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getDimension(valueToId, 0f); 364d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 365d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getFloat(valueToId, 0f); 366d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 367d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofFloat(propertyName, 368d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueFrom, valueTo); 369d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 370d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofFloat(propertyName, valueFrom); 371d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 372d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 373d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 374d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getDimension(valueToId, 0f); 375d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 376d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getFloat(valueToId, 0f); 377d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 378d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofFloat(propertyName, valueTo); 379d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 380d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 381d430753cba09acb07af8b313286f247c78a41a32Chet Haase int valueFrom; 382d430753cba09acb07af8b313286f247c78a41a32Chet Haase int valueTo; 383d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (hasFrom) { 384d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (fromType == TypedValue.TYPE_DIMENSION) { 385d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueFrom = (int) styledAttributes.getDimension(valueFromId, 0f); 386d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else if ((fromType >= TypedValue.TYPE_FIRST_COLOR_INT) && 387d430753cba09acb07af8b313286f247c78a41a32Chet Haase (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) { 388d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueFrom = styledAttributes.getColor(valueFromId, 0); 389d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 390d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueFrom = styledAttributes.getInt(valueFromId, 0); 391d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 392d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (hasTo) { 393d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 394d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = (int) styledAttributes.getDimension(valueToId, 0f); 395d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) && 396d430753cba09acb07af8b313286f247c78a41a32Chet Haase (toType <= TypedValue.TYPE_LAST_COLOR_INT)) { 397d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getColor(valueToId, 0); 398d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 399d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getInt(valueToId, 0); 400d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 401d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofInt(propertyName, valueFrom, valueTo); 402d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 403d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofInt(propertyName, valueFrom); 404d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 405d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 406d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (hasTo) { 407d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 408d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = (int) styledAttributes.getDimension(valueToId, 0f); 409d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) && 410d430753cba09acb07af8b313286f247c78a41a32Chet Haase (toType <= TypedValue.TYPE_LAST_COLOR_INT)) { 411d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getColor(valueToId, 0); 412d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 413d430753cba09acb07af8b313286f247c78a41a32Chet Haase valueTo = styledAttributes.getInt(valueToId, 0); 414d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 415d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue = PropertyValuesHolder.ofInt(propertyName, valueTo); 416d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 417d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 418d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 419d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (returnValue != null && evaluator != null) { 420d430753cba09acb07af8b313286f247c78a41a32Chet Haase returnValue.setEvaluator(evaluator); 421d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 422d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 423d430753cba09acb07af8b313286f247c78a41a32Chet Haase 424d430753cba09acb07af8b313286f247c78a41a32Chet Haase return returnValue; 425d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 426d430753cba09acb07af8b313286f247c78a41a32Chet Haase 427d430753cba09acb07af8b313286f247c78a41a32Chet Haase /** 428d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param anim The animator, must not be null 429d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param arrayAnimator Incoming typed array for Animator's attributes. 430d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param arrayObjectAnimator Incoming typed array for Object Animator's 431d430753cba09acb07af8b313286f247c78a41a32Chet Haase * attributes. 432d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param pixelSize The relative pixel size, used to calculate the 433d430753cba09acb07af8b313286f247c78a41a32Chet Haase * maximum error for path animations. 434d430753cba09acb07af8b313286f247c78a41a32Chet Haase */ 435d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static void parseAnimatorFromTypeArray(ValueAnimator anim, 436d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypedArray arrayAnimator, TypedArray arrayObjectAnimator, float pixelSize) { 437d430753cba09acb07af8b313286f247c78a41a32Chet Haase long duration = arrayAnimator.getInt(R.styleable.Animator_duration, 300); 438d430753cba09acb07af8b313286f247c78a41a32Chet Haase 439d430753cba09acb07af8b313286f247c78a41a32Chet Haase long startDelay = arrayAnimator.getInt(R.styleable.Animator_startOffset, 0); 440d430753cba09acb07af8b313286f247c78a41a32Chet Haase 441d430753cba09acb07af8b313286f247c78a41a32Chet Haase int valueType = arrayAnimator.getInt(R.styleable.Animator_valueType, VALUE_TYPE_FLOAT); 442d430753cba09acb07af8b313286f247c78a41a32Chet Haase 443d430753cba09acb07af8b313286f247c78a41a32Chet Haase PropertyValuesHolder pvh = getPVH(arrayAnimator, valueType, 444d430753cba09acb07af8b313286f247c78a41a32Chet Haase R.styleable.Animator_valueFrom, R.styleable.Animator_valueTo, ""); 445d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (pvh != null) { 446d430753cba09acb07af8b313286f247c78a41a32Chet Haase anim.setValues(pvh); 4475bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } 4485bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase 449eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setDuration(duration); 450eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setStartDelay(startDelay); 451eb034fbca40006c55db143047eb628c4b657730aztenghui 452eb034fbca40006c55db143047eb628c4b657730aztenghui if (arrayAnimator.hasValue(R.styleable.Animator_repeatCount)) { 453eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setRepeatCount( 454eb034fbca40006c55db143047eb628c4b657730aztenghui arrayAnimator.getInt(R.styleable.Animator_repeatCount, 0)); 455eb034fbca40006c55db143047eb628c4b657730aztenghui } 456eb034fbca40006c55db143047eb628c4b657730aztenghui if (arrayAnimator.hasValue(R.styleable.Animator_repeatMode)) { 457eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setRepeatMode( 458eb034fbca40006c55db143047eb628c4b657730aztenghui arrayAnimator.getInt(R.styleable.Animator_repeatMode, 459eb034fbca40006c55db143047eb628c4b657730aztenghui ValueAnimator.RESTART)); 460eb034fbca40006c55db143047eb628c4b657730aztenghui } 461eb034fbca40006c55db143047eb628c4b657730aztenghui 462eb034fbca40006c55db143047eb628c4b657730aztenghui if (arrayObjectAnimator != null) { 463d430753cba09acb07af8b313286f247c78a41a32Chet Haase setupObjectAnimator(anim, arrayObjectAnimator, valueType == VALUE_TYPE_FLOAT, 464d430753cba09acb07af8b313286f247c78a41a32Chet Haase pixelSize); 465eb034fbca40006c55db143047eb628c4b657730aztenghui } 466eb034fbca40006c55db143047eb628c4b657730aztenghui } 467eb034fbca40006c55db143047eb628c4b657730aztenghui 468eb034fbca40006c55db143047eb628c4b657730aztenghui /** 469eb034fbca40006c55db143047eb628c4b657730aztenghui * Setup the Animator to achieve path morphing. 470eb034fbca40006c55db143047eb628c4b657730aztenghui * 471eb034fbca40006c55db143047eb628c4b657730aztenghui * @param anim The target Animator which will be updated. 472eb034fbca40006c55db143047eb628c4b657730aztenghui * @param arrayAnimator TypedArray for the ValueAnimator. 473eb034fbca40006c55db143047eb628c4b657730aztenghui * @return the PathDataEvaluator. 474eb034fbca40006c55db143047eb628c4b657730aztenghui */ 475eb034fbca40006c55db143047eb628c4b657730aztenghui private static TypeEvaluator setupAnimatorForPath(ValueAnimator anim, 476eb034fbca40006c55db143047eb628c4b657730aztenghui TypedArray arrayAnimator) { 477eb034fbca40006c55db143047eb628c4b657730aztenghui TypeEvaluator evaluator = null; 478eb034fbca40006c55db143047eb628c4b657730aztenghui String fromString = arrayAnimator.getString(R.styleable.Animator_valueFrom); 479eb034fbca40006c55db143047eb628c4b657730aztenghui String toString = arrayAnimator.getString(R.styleable.Animator_valueTo); 480eb034fbca40006c55db143047eb628c4b657730aztenghui PathParser.PathDataNode[] nodesFrom = PathParser.createNodesFromPathData(fromString); 481eb034fbca40006c55db143047eb628c4b657730aztenghui PathParser.PathDataNode[] nodesTo = PathParser.createNodesFromPathData(toString); 482eb034fbca40006c55db143047eb628c4b657730aztenghui 483eb034fbca40006c55db143047eb628c4b657730aztenghui if (nodesFrom != null) { 484eb034fbca40006c55db143047eb628c4b657730aztenghui if (nodesTo != null) { 485eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setObjectValues(nodesFrom, nodesTo); 486eb034fbca40006c55db143047eb628c4b657730aztenghui if (!PathParser.canMorph(nodesFrom, nodesTo)) { 487eb034fbca40006c55db143047eb628c4b657730aztenghui throw new InflateException(arrayAnimator.getPositionDescription() 488eb034fbca40006c55db143047eb628c4b657730aztenghui + " Can't morph from " + fromString + " to " + toString); 489eb034fbca40006c55db143047eb628c4b657730aztenghui } 490eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 491eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setObjectValues((Object)nodesFrom); 492eb034fbca40006c55db143047eb628c4b657730aztenghui } 493eb034fbca40006c55db143047eb628c4b657730aztenghui evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesFrom)); 494eb034fbca40006c55db143047eb628c4b657730aztenghui } else if (nodesTo != null) { 495eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setObjectValues((Object)nodesTo); 496eb034fbca40006c55db143047eb628c4b657730aztenghui evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesTo)); 497eb034fbca40006c55db143047eb628c4b657730aztenghui } 498eb034fbca40006c55db143047eb628c4b657730aztenghui 499eb034fbca40006c55db143047eb628c4b657730aztenghui if (DBG_ANIMATOR_INFLATER && evaluator != null) { 500eb034fbca40006c55db143047eb628c4b657730aztenghui Log.v(TAG, "create a new PathDataEvaluator here"); 501eb034fbca40006c55db143047eb628c4b657730aztenghui } 502eb034fbca40006c55db143047eb628c4b657730aztenghui 503eb034fbca40006c55db143047eb628c4b657730aztenghui return evaluator; 504eb034fbca40006c55db143047eb628c4b657730aztenghui } 505eb034fbca40006c55db143047eb628c4b657730aztenghui 506eb034fbca40006c55db143047eb628c4b657730aztenghui /** 507eb034fbca40006c55db143047eb628c4b657730aztenghui * Setup ObjectAnimator's property or values from pathData. 508eb034fbca40006c55db143047eb628c4b657730aztenghui * 509eb034fbca40006c55db143047eb628c4b657730aztenghui * @param anim The target Animator which will be updated. 510eb034fbca40006c55db143047eb628c4b657730aztenghui * @param arrayObjectAnimator TypedArray for the ObjectAnimator. 511eb034fbca40006c55db143047eb628c4b657730aztenghui * @param getFloats True if the value type is float. 512fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount * @param pixelSize The relative pixel size, used to calculate the 513fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount * maximum error for path animations. 514eb034fbca40006c55db143047eb628c4b657730aztenghui */ 515eb034fbca40006c55db143047eb628c4b657730aztenghui private static void setupObjectAnimator(ValueAnimator anim, TypedArray arrayObjectAnimator, 516fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount boolean getFloats, float pixelSize) { 517eb034fbca40006c55db143047eb628c4b657730aztenghui ObjectAnimator oa = (ObjectAnimator) anim; 518eb034fbca40006c55db143047eb628c4b657730aztenghui String pathData = arrayObjectAnimator.getString(R.styleable.PropertyAnimator_pathData); 519eb034fbca40006c55db143047eb628c4b657730aztenghui 520eb034fbca40006c55db143047eb628c4b657730aztenghui // Note that if there is a pathData defined in the Object Animator, 521eb034fbca40006c55db143047eb628c4b657730aztenghui // valueFrom / valueTo will be ignored. 522eb034fbca40006c55db143047eb628c4b657730aztenghui if (pathData != null) { 523eb034fbca40006c55db143047eb628c4b657730aztenghui String propertyXName = 524eb034fbca40006c55db143047eb628c4b657730aztenghui arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyXName); 525eb034fbca40006c55db143047eb628c4b657730aztenghui String propertyYName = 526eb034fbca40006c55db143047eb628c4b657730aztenghui arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyYName); 527eb034fbca40006c55db143047eb628c4b657730aztenghui 528eb034fbca40006c55db143047eb628c4b657730aztenghui if (propertyXName == null && propertyYName == null) { 529eb034fbca40006c55db143047eb628c4b657730aztenghui throw new InflateException(arrayObjectAnimator.getPositionDescription() 530eb034fbca40006c55db143047eb628c4b657730aztenghui + " propertyXName or propertyYName is needed for PathData"); 531eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 532eb034fbca40006c55db143047eb628c4b657730aztenghui Path path = PathParser.createPathFromPathData(pathData); 533fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount float error = 0.5f * pixelSize; // max half a pixel error 534fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount PathKeyframes keyframeSet = KeyframeSet.ofPath(path, error); 535984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount Keyframes xKeyframes; 536984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount Keyframes yKeyframes; 537984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount if (getFloats) { 538984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount xKeyframes = keyframeSet.createXFloatKeyframes(); 539984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount yKeyframes = keyframeSet.createYFloatKeyframes(); 540984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount } else { 541984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount xKeyframes = keyframeSet.createXIntKeyframes(); 542984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount yKeyframes = keyframeSet.createYIntKeyframes(); 543984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount } 544eb034fbca40006c55db143047eb628c4b657730aztenghui PropertyValuesHolder x = null; 545eb034fbca40006c55db143047eb628c4b657730aztenghui PropertyValuesHolder y = null; 546eb034fbca40006c55db143047eb628c4b657730aztenghui if (propertyXName != null) { 547984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount x = PropertyValuesHolder.ofKeyframes(propertyXName, xKeyframes); 548eb034fbca40006c55db143047eb628c4b657730aztenghui } 549eb034fbca40006c55db143047eb628c4b657730aztenghui if (propertyYName != null) { 550984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount y = PropertyValuesHolder.ofKeyframes(propertyYName, yKeyframes); 551eb034fbca40006c55db143047eb628c4b657730aztenghui } 552eb034fbca40006c55db143047eb628c4b657730aztenghui if (x == null) { 553eb034fbca40006c55db143047eb628c4b657730aztenghui oa.setValues(y); 554eb034fbca40006c55db143047eb628c4b657730aztenghui } else if (y == null) { 555eb034fbca40006c55db143047eb628c4b657730aztenghui oa.setValues(x); 556eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 557eb034fbca40006c55db143047eb628c4b657730aztenghui oa.setValues(x, y); 558eb034fbca40006c55db143047eb628c4b657730aztenghui } 559eb034fbca40006c55db143047eb628c4b657730aztenghui } 560eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 561eb034fbca40006c55db143047eb628c4b657730aztenghui String propertyName = 562eb034fbca40006c55db143047eb628c4b657730aztenghui arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyName); 563eb034fbca40006c55db143047eb628c4b657730aztenghui oa.setPropertyName(propertyName); 564eb034fbca40006c55db143047eb628c4b657730aztenghui } 565eb034fbca40006c55db143047eb628c4b657730aztenghui } 566eb034fbca40006c55db143047eb628c4b657730aztenghui 567eb034fbca40006c55db143047eb628c4b657730aztenghui /** 568eb034fbca40006c55db143047eb628c4b657730aztenghui * Setup ValueAnimator's values. 569eb034fbca40006c55db143047eb628c4b657730aztenghui * This will handle all of the integer, float and color types. 570eb034fbca40006c55db143047eb628c4b657730aztenghui * 571eb034fbca40006c55db143047eb628c4b657730aztenghui * @param anim The target Animator which will be updated. 572eb034fbca40006c55db143047eb628c4b657730aztenghui * @param arrayAnimator TypedArray for the ValueAnimator. 573eb034fbca40006c55db143047eb628c4b657730aztenghui * @param getFloats True if the value type is float. 574eb034fbca40006c55db143047eb628c4b657730aztenghui * @param hasFrom True if "valueFrom" exists. 575eb034fbca40006c55db143047eb628c4b657730aztenghui * @param fromType The type of "valueFrom". 576eb034fbca40006c55db143047eb628c4b657730aztenghui * @param hasTo True if "valueTo" exists. 577eb034fbca40006c55db143047eb628c4b657730aztenghui * @param toType The type of "valueTo". 578eb034fbca40006c55db143047eb628c4b657730aztenghui */ 579eb034fbca40006c55db143047eb628c4b657730aztenghui private static void setupValues(ValueAnimator anim, TypedArray arrayAnimator, 580eb034fbca40006c55db143047eb628c4b657730aztenghui boolean getFloats, boolean hasFrom, int fromType, boolean hasTo, int toType) { 581eb034fbca40006c55db143047eb628c4b657730aztenghui int valueFromIndex = R.styleable.Animator_valueFrom; 582eb034fbca40006c55db143047eb628c4b657730aztenghui int valueToIndex = R.styleable.Animator_valueTo; 5835bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (getFloats) { 5845bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase float valueFrom; 5855bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase float valueTo; 5865bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasFrom) { 5875bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (fromType == TypedValue.TYPE_DIMENSION) { 588cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = arrayAnimator.getDimension(valueFromIndex, 0f); 5895bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 590cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = arrayAnimator.getFloat(valueFromIndex, 0f); 5915bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } 5925bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasTo) { 5935bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 594cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getDimension(valueToIndex, 0f); 5952794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 596cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getFloat(valueToIndex, 0f); 5972794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 5985bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setFloatValues(valueFrom, valueTo); 5995bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 6005bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setFloatValues(valueFrom); 6015bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } 6025bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 6035bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 604cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getDimension(valueToIndex, 0f); 6052794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 606cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getFloat(valueToIndex, 0f); 607d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 6085bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setFloatValues(valueTo); 6092794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 6105bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 6115bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase int valueFrom; 6125bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase int valueTo; 6135bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasFrom) { 6145bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (fromType == TypedValue.TYPE_DIMENSION) { 615cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = (int) arrayAnimator.getDimension(valueFromIndex, 0f); 6165bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else if ((fromType >= TypedValue.TYPE_FIRST_COLOR_INT) && 6175bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) { 618cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = arrayAnimator.getColor(valueFromIndex, 0); 6195bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 620cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = arrayAnimator.getInt(valueFromIndex, 0); 6215bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } 6225bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasTo) { 6235bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 624cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = (int) arrayAnimator.getDimension(valueToIndex, 0f); 6255bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) && 6265bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase (toType <= TypedValue.TYPE_LAST_COLOR_INT)) { 627cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getColor(valueToIndex, 0); 6282794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 629cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getInt(valueToIndex, 0); 6302794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 6315bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setIntValues(valueFrom, valueTo); 6322794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 6335bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setIntValues(valueFrom); 634d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 6355bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 6365bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasTo) { 6375bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 638cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = (int) arrayAnimator.getDimension(valueToIndex, 0f); 6395bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) && 640cf4832f69c8786b098ce18c24319021f8cd6733aztenghui (toType <= TypedValue.TYPE_LAST_COLOR_INT)) { 641cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getColor(valueToIndex, 0); 6422794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 643cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getInt(valueToIndex, 0); 6442794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 6455bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setIntValues(valueTo); 646d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 6472794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 648d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 649e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 650e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 651fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser, 652fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount float pixelSize) 653e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui throws XmlPullParserException, IOException { 654fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount return createAnimatorFromXml(res, theme, parser, Xml.asAttributeSet(parser), null, 0, 655fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount pixelSize); 656e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 657e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 658e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser, 659fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount AttributeSet attrs, AnimatorSet parent, int sequenceOrdering, float pixelSize) 660e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui throws XmlPullParserException, IOException { 661e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui Animator anim = null; 662e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui ArrayList<Animator> childAnims = null; 663e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 664e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui // Make sure we are on a start tag. 665e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui int type; 666e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui int depth = parser.getDepth(); 667e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 668e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) 669e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui && type != XmlPullParser.END_DOCUMENT) { 670e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 671e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (type != XmlPullParser.START_TAG) { 672e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui continue; 673e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 674e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 675e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui String name = parser.getName(); 676d430753cba09acb07af8b313286f247c78a41a32Chet Haase boolean gotValues = false; 677e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 678e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (name.equals("objectAnimator")) { 679fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount anim = loadObjectAnimator(res, theme, attrs, pixelSize); 680e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else if (name.equals("animator")) { 681fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount anim = loadAnimator(res, theme, attrs, null, pixelSize); 682e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else if (name.equals("set")) { 683e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui anim = new AnimatorSet(); 684e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui TypedArray a; 685e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (theme != null) { 686cf4832f69c8786b098ce18c24319021f8cd6733aztenghui a = theme.obtainStyledAttributes(attrs, R.styleable.AnimatorSet, 0, 0); 687e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else { 688cf4832f69c8786b098ce18c24319021f8cd6733aztenghui a = res.obtainAttributes(attrs, R.styleable.AnimatorSet); 689e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 690d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar anim.appendChangingConfigurations(a.getChangingConfigurations()); 691d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar int ordering = a.getInt(R.styleable.AnimatorSet_ordering, TOGETHER); 692fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering, 693fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount pixelSize); 694e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui a.recycle(); 695d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else if (name.equals("propertyValuesHolder")) { 696d430753cba09acb07af8b313286f247c78a41a32Chet Haase PropertyValuesHolder[] values = loadValues(res, theme, parser, 697d430753cba09acb07af8b313286f247c78a41a32Chet Haase Xml.asAttributeSet(parser)); 698d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (values != null && anim != null && (anim instanceof ValueAnimator)) { 699d430753cba09acb07af8b313286f247c78a41a32Chet Haase ((ValueAnimator) anim).setValues(values); 700d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 701d430753cba09acb07af8b313286f247c78a41a32Chet Haase gotValues = true; 702e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else { 703e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui throw new RuntimeException("Unknown animator name: " + parser.getName()); 704e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 705e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 706d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (parent != null && !gotValues) { 707e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (childAnims == null) { 708e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui childAnims = new ArrayList<Animator>(); 709e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 710e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui childAnims.add(anim); 711e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 712e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 713e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (parent != null && childAnims != null) { 714e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui Animator[] animsArray = new Animator[childAnims.size()]; 715e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui int index = 0; 716e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui for (Animator a : childAnims) { 717e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui animsArray[index++] = a; 718e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 719e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (sequenceOrdering == TOGETHER) { 720e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui parent.playTogether(animsArray); 721e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else { 722e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui parent.playSequentially(animsArray); 723e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 724e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 725e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return anim; 726d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 727d430753cba09acb07af8b313286f247c78a41a32Chet Haase 728d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static PropertyValuesHolder[] loadValues(Resources res, Theme theme, 729d430753cba09acb07af8b313286f247c78a41a32Chet Haase XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException { 730d430753cba09acb07af8b313286f247c78a41a32Chet Haase ArrayList<PropertyValuesHolder> values = null; 731d430753cba09acb07af8b313286f247c78a41a32Chet Haase 732d430753cba09acb07af8b313286f247c78a41a32Chet Haase int type; 733d430753cba09acb07af8b313286f247c78a41a32Chet Haase while ((type = parser.getEventType()) != XmlPullParser.END_TAG && 734d430753cba09acb07af8b313286f247c78a41a32Chet Haase type != XmlPullParser.END_DOCUMENT) { 735d430753cba09acb07af8b313286f247c78a41a32Chet Haase 736d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (type != XmlPullParser.START_TAG) { 737d430753cba09acb07af8b313286f247c78a41a32Chet Haase parser.next(); 738d430753cba09acb07af8b313286f247c78a41a32Chet Haase continue; 739d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 740d430753cba09acb07af8b313286f247c78a41a32Chet Haase 741d430753cba09acb07af8b313286f247c78a41a32Chet Haase String name = parser.getName(); 742d430753cba09acb07af8b313286f247c78a41a32Chet Haase 743d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (name.equals("propertyValuesHolder")) { 744d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypedArray a; 745d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (theme != null) { 746d430753cba09acb07af8b313286f247c78a41a32Chet Haase a = theme.obtainStyledAttributes(attrs, R.styleable.PropertyValuesHolder, 0, 0); 747d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 748d430753cba09acb07af8b313286f247c78a41a32Chet Haase a = res.obtainAttributes(attrs, R.styleable.PropertyValuesHolder); 749d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 750d430753cba09acb07af8b313286f247c78a41a32Chet Haase String propertyName = a.getString(R.styleable.PropertyValuesHolder_propertyName); 751d430753cba09acb07af8b313286f247c78a41a32Chet Haase int valueType = a.getInt(R.styleable.PropertyValuesHolder_valueType, 752d430753cba09acb07af8b313286f247c78a41a32Chet Haase VALUE_TYPE_FLOAT); 753d430753cba09acb07af8b313286f247c78a41a32Chet Haase PropertyValuesHolder pvh = loadPvh(res, theme, parser, propertyName, valueType); 754d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (pvh == null) { 755d430753cba09acb07af8b313286f247c78a41a32Chet Haase pvh = getPVH(a, valueType, 756d430753cba09acb07af8b313286f247c78a41a32Chet Haase R.styleable.PropertyValuesHolder_valueFrom, 757d430753cba09acb07af8b313286f247c78a41a32Chet Haase R.styleable.PropertyValuesHolder_valueTo, propertyName); 758d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 759d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (pvh != null) { 760d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (values == null) { 761d430753cba09acb07af8b313286f247c78a41a32Chet Haase values = new ArrayList<PropertyValuesHolder>(); 762d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 763d430753cba09acb07af8b313286f247c78a41a32Chet Haase values.add(pvh); 764d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 765d430753cba09acb07af8b313286f247c78a41a32Chet Haase a.recycle(); 766d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 767d430753cba09acb07af8b313286f247c78a41a32Chet Haase 768d430753cba09acb07af8b313286f247c78a41a32Chet Haase parser.next(); 769d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 770d430753cba09acb07af8b313286f247c78a41a32Chet Haase 771d430753cba09acb07af8b313286f247c78a41a32Chet Haase PropertyValuesHolder[] valuesArray = null; 772d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (values != null) { 773d430753cba09acb07af8b313286f247c78a41a32Chet Haase int count = values.size(); 774d430753cba09acb07af8b313286f247c78a41a32Chet Haase valuesArray = new PropertyValuesHolder[count]; 775d430753cba09acb07af8b313286f247c78a41a32Chet Haase for (int i = 0; i < count; ++i) { 776d430753cba09acb07af8b313286f247c78a41a32Chet Haase valuesArray[i] = values.get(i); 777d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 778d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 779d430753cba09acb07af8b313286f247c78a41a32Chet Haase return valuesArray; 780d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 781d430753cba09acb07af8b313286f247c78a41a32Chet Haase 782d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static void dumpKeyframes(Object[] keyframes, String header) { 783d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (keyframes == null || keyframes.length == 0) { 784d430753cba09acb07af8b313286f247c78a41a32Chet Haase return; 785d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 786d430753cba09acb07af8b313286f247c78a41a32Chet Haase Log.d(TAG, header); 787d430753cba09acb07af8b313286f247c78a41a32Chet Haase int count = keyframes.length; 788d430753cba09acb07af8b313286f247c78a41a32Chet Haase for (int i = 0; i < count; ++i) { 789d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe keyframe = (Keyframe) keyframes[i]; 790d430753cba09acb07af8b313286f247c78a41a32Chet Haase Log.d(TAG, "Keyframe " + i + ": fraction " + 791d430753cba09acb07af8b313286f247c78a41a32Chet Haase (keyframe.getFraction() < 0 ? "null" : keyframe.getFraction()) + ", " + 792d430753cba09acb07af8b313286f247c78a41a32Chet Haase ", value : " + ((keyframe.hasValue()) ? keyframe.getValue() : "null")); 793d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 794d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 795d430753cba09acb07af8b313286f247c78a41a32Chet Haase 796d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static PropertyValuesHolder loadPvh(Resources res, Theme theme, XmlPullParser parser, 797d430753cba09acb07af8b313286f247c78a41a32Chet Haase String propertyName, int valueType) 798d430753cba09acb07af8b313286f247c78a41a32Chet Haase throws XmlPullParserException, IOException { 799d430753cba09acb07af8b313286f247c78a41a32Chet Haase 800d430753cba09acb07af8b313286f247c78a41a32Chet Haase PropertyValuesHolder value = null; 801d430753cba09acb07af8b313286f247c78a41a32Chet Haase ArrayList<Keyframe> keyframes = null; 802d430753cba09acb07af8b313286f247c78a41a32Chet Haase 803d430753cba09acb07af8b313286f247c78a41a32Chet Haase int type; 804d430753cba09acb07af8b313286f247c78a41a32Chet Haase while ((type = parser.next()) != XmlPullParser.END_TAG && 805d430753cba09acb07af8b313286f247c78a41a32Chet Haase type != XmlPullParser.END_DOCUMENT) { 806d430753cba09acb07af8b313286f247c78a41a32Chet Haase String name = parser.getName(); 807d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (name.equals("keyframe")) { 808d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe keyframe = loadKeyframe(res, theme, Xml.asAttributeSet(parser), valueType); 809d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (keyframe != null) { 810d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (keyframes == null) { 811d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframes = new ArrayList<Keyframe>(); 812d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 813d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframes.add(keyframe); 814d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 815d430753cba09acb07af8b313286f247c78a41a32Chet Haase parser.next(); 816d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 817d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 818d430753cba09acb07af8b313286f247c78a41a32Chet Haase 819d430753cba09acb07af8b313286f247c78a41a32Chet Haase int count; 820d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (keyframes != null && (count = keyframes.size()) > 0) { 821d430753cba09acb07af8b313286f247c78a41a32Chet Haase // make sure we have keyframes at 0 and 1 822d430753cba09acb07af8b313286f247c78a41a32Chet Haase // If we have keyframes with set fractions, add keyframes at start/end 823d430753cba09acb07af8b313286f247c78a41a32Chet Haase // appropriately. If start/end have no set fractions: 824d430753cba09acb07af8b313286f247c78a41a32Chet Haase // if there's only one keyframe, set its fraction to 1 and add one at 0 825d430753cba09acb07af8b313286f247c78a41a32Chet Haase // if >1 keyframe, set the last fraction to 1, the first fraction to 0 826d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe firstKeyframe = keyframes.get(0); 827d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe lastKeyframe = keyframes.get(count - 1); 828d430753cba09acb07af8b313286f247c78a41a32Chet Haase float endFraction = lastKeyframe.getFraction(); 829d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (endFraction < 1) { 830d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (endFraction < 0) { 831d430753cba09acb07af8b313286f247c78a41a32Chet Haase lastKeyframe.setFraction(1); 832d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 833d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframes.add(keyframes.size(), createNewKeyframe(lastKeyframe, 1)); 834d430753cba09acb07af8b313286f247c78a41a32Chet Haase ++count; 835d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 836d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 837d430753cba09acb07af8b313286f247c78a41a32Chet Haase float startFraction = firstKeyframe.getFraction(); 838d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (startFraction != 0) { 839d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (startFraction < 0) { 840d430753cba09acb07af8b313286f247c78a41a32Chet Haase firstKeyframe.setFraction(0); 841d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 842d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframes.add(0, createNewKeyframe(firstKeyframe, 0)); 843d430753cba09acb07af8b313286f247c78a41a32Chet Haase ++count; 844d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 845d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 846d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe[] keyframeArray = new Keyframe[count]; 847d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframes.toArray(keyframeArray); 848d430753cba09acb07af8b313286f247c78a41a32Chet Haase for (int i = 0; i < count; ++i) { 849d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe keyframe = keyframeArray[i]; 850d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (keyframe.getFraction() < 0) { 851d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (i == 0) { 852d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframe.setFraction(0); 853d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else if (i == count - 1) { 854d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframe.setFraction(1); 855d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 856d430753cba09acb07af8b313286f247c78a41a32Chet Haase // figure out the start/end parameters of the current gap 857d430753cba09acb07af8b313286f247c78a41a32Chet Haase // in fractions and distribute the gap among those keyframes 858d430753cba09acb07af8b313286f247c78a41a32Chet Haase int startIndex = i; 859d430753cba09acb07af8b313286f247c78a41a32Chet Haase int endIndex = i; 860d430753cba09acb07af8b313286f247c78a41a32Chet Haase for (int j = startIndex + 1; j < count - 1; ++j) { 861d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (keyframeArray[j].getFraction() >= 0) { 862d430753cba09acb07af8b313286f247c78a41a32Chet Haase break; 863d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 864d430753cba09acb07af8b313286f247c78a41a32Chet Haase endIndex = j; 865d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 866d430753cba09acb07af8b313286f247c78a41a32Chet Haase float gap = keyframeArray[endIndex + 1].getFraction() - 867d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframeArray[startIndex - 1].getFraction(); 868d430753cba09acb07af8b313286f247c78a41a32Chet Haase distributeKeyframes(keyframeArray, gap, startIndex, endIndex); 869d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 870d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 871d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 872d430753cba09acb07af8b313286f247c78a41a32Chet Haase value = PropertyValuesHolder.ofKeyframe(propertyName, keyframeArray); 873d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (valueType == VALUE_TYPE_COLOR) { 874d430753cba09acb07af8b313286f247c78a41a32Chet Haase value.setEvaluator(ArgbEvaluator.getInstance()); 875d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 876d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 877d430753cba09acb07af8b313286f247c78a41a32Chet Haase 878d430753cba09acb07af8b313286f247c78a41a32Chet Haase return value; 879d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 880d430753cba09acb07af8b313286f247c78a41a32Chet Haase 881d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static Keyframe createNewKeyframe(Keyframe sampleKeyframe, float fraction) { 882d430753cba09acb07af8b313286f247c78a41a32Chet Haase return sampleKeyframe.getType() == float.class ? 883d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe.ofFloat(fraction) : 884d430753cba09acb07af8b313286f247c78a41a32Chet Haase (sampleKeyframe.getType() == int.class) ? 885d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe.ofInt(fraction) : 886d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe.ofObject(fraction); 887d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 888d430753cba09acb07af8b313286f247c78a41a32Chet Haase 889d430753cba09acb07af8b313286f247c78a41a32Chet Haase /** 890d430753cba09acb07af8b313286f247c78a41a32Chet Haase * Utility function to set fractions on keyframes to cover a gap in which the 891d430753cba09acb07af8b313286f247c78a41a32Chet Haase * fractions are not currently set. Keyframe fractions will be distributed evenly 892d430753cba09acb07af8b313286f247c78a41a32Chet Haase * in this gap. For example, a gap of 1 keyframe in the range 0-1 will be at .5, a gap 893d430753cba09acb07af8b313286f247c78a41a32Chet Haase * of .6 spread between two keyframes will be at .2 and .4 beyond the fraction at the 894d430753cba09acb07af8b313286f247c78a41a32Chet Haase * keyframe before startIndex. 895d430753cba09acb07af8b313286f247c78a41a32Chet Haase * Assumptions: 896d430753cba09acb07af8b313286f247c78a41a32Chet Haase * - First and last keyframe fractions (bounding this spread) are already set. So, 897d430753cba09acb07af8b313286f247c78a41a32Chet Haase * for example, if no fractions are set, we will already set first and last keyframe 898d430753cba09acb07af8b313286f247c78a41a32Chet Haase * fraction values to 0 and 1. 899d430753cba09acb07af8b313286f247c78a41a32Chet Haase * - startIndex must be >0 (which follows from first assumption). 900d430753cba09acb07af8b313286f247c78a41a32Chet Haase * - endIndex must be >= startIndex. 901d430753cba09acb07af8b313286f247c78a41a32Chet Haase * 902d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param keyframes the array of keyframes 903d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param gap The total gap we need to distribute 904d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param startIndex The index of the first keyframe whose fraction must be set 905d430753cba09acb07af8b313286f247c78a41a32Chet Haase * @param endIndex The index of the last keyframe whose fraction must be set 906d430753cba09acb07af8b313286f247c78a41a32Chet Haase */ 907d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static void distributeKeyframes(Keyframe[] keyframes, float gap, 908d430753cba09acb07af8b313286f247c78a41a32Chet Haase int startIndex, int endIndex) { 909d430753cba09acb07af8b313286f247c78a41a32Chet Haase int count = endIndex - startIndex + 2; 910d430753cba09acb07af8b313286f247c78a41a32Chet Haase float increment = gap / count; 911d430753cba09acb07af8b313286f247c78a41a32Chet Haase for (int i = startIndex; i <= endIndex; ++i) { 912d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframes[i].setFraction(keyframes[i-1].getFraction() + increment); 913d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 914d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 915d430753cba09acb07af8b313286f247c78a41a32Chet Haase 916d430753cba09acb07af8b313286f247c78a41a32Chet Haase private static Keyframe loadKeyframe(Resources res, Theme theme, AttributeSet attrs, 917d430753cba09acb07af8b313286f247c78a41a32Chet Haase int valueType) 918d430753cba09acb07af8b313286f247c78a41a32Chet Haase throws XmlPullParserException, IOException { 919d430753cba09acb07af8b313286f247c78a41a32Chet Haase 920d430753cba09acb07af8b313286f247c78a41a32Chet Haase TypedArray a; 921d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (theme != null) { 922d430753cba09acb07af8b313286f247c78a41a32Chet Haase a = theme.obtainStyledAttributes(attrs, R.styleable.Keyframe, 0, 0); 923d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 924d430753cba09acb07af8b313286f247c78a41a32Chet Haase a = res.obtainAttributes(attrs, R.styleable.Keyframe); 925d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 926d430753cba09acb07af8b313286f247c78a41a32Chet Haase 927d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe keyframe = null; 928d430753cba09acb07af8b313286f247c78a41a32Chet Haase 929d430753cba09acb07af8b313286f247c78a41a32Chet Haase float fraction = a.getFloat(R.styleable.Keyframe_fraction, -1); 930d430753cba09acb07af8b313286f247c78a41a32Chet Haase 931d430753cba09acb07af8b313286f247c78a41a32Chet Haase boolean hasValue = a.peekValue(R.styleable.Keyframe_value) != null; 932d430753cba09acb07af8b313286f247c78a41a32Chet Haase 933d430753cba09acb07af8b313286f247c78a41a32Chet Haase if (hasValue) { 934d430753cba09acb07af8b313286f247c78a41a32Chet Haase switch (valueType) { 935d430753cba09acb07af8b313286f247c78a41a32Chet Haase case VALUE_TYPE_FLOAT: 936d430753cba09acb07af8b313286f247c78a41a32Chet Haase float value = a.getFloat(R.styleable.Keyframe_value, 0); 937d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframe = Keyframe.ofFloat(fraction, value); 938d430753cba09acb07af8b313286f247c78a41a32Chet Haase break; 939d430753cba09acb07af8b313286f247c78a41a32Chet Haase case VALUE_TYPE_COLOR: 940d430753cba09acb07af8b313286f247c78a41a32Chet Haase case VALUE_TYPE_INT: 941d430753cba09acb07af8b313286f247c78a41a32Chet Haase int intValue = a.getInt(R.styleable.Keyframe_value, 0); 942d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframe = Keyframe.ofInt(fraction, intValue); 943d430753cba09acb07af8b313286f247c78a41a32Chet Haase break; 944d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 945d430753cba09acb07af8b313286f247c78a41a32Chet Haase } else { 946d430753cba09acb07af8b313286f247c78a41a32Chet Haase keyframe = (valueType == VALUE_TYPE_FLOAT) ? Keyframe.ofFloat(fraction) : 947d430753cba09acb07af8b313286f247c78a41a32Chet Haase Keyframe.ofInt(fraction); 948d430753cba09acb07af8b313286f247c78a41a32Chet Haase } 949d430753cba09acb07af8b313286f247c78a41a32Chet Haase 9506aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu final int resID = a.getResourceId(R.styleable.Keyframe_interpolator, 0); 9516aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu if (resID > 0) { 9526aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu final Interpolator interpolator = AnimationUtils.loadInterpolator(res, theme, resID); 9536aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu keyframe.setInterpolator(interpolator); 9546aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu } 955d430753cba09acb07af8b313286f247c78a41a32Chet Haase a.recycle(); 956e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 957d430753cba09acb07af8b313286f247c78a41a32Chet Haase return keyframe; 958e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 959e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 960fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs, 961fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount float pathErrorScale) throws NotFoundException { 962e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui ObjectAnimator anim = new ObjectAnimator(); 963e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 964fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount loadAnimator(res, theme, attrs, anim, pathErrorScale); 965e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 966e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return anim; 967e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 968e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 969e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui /** 970e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * Creates a new animation whose parameters come from the specified context 971e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * and attributes set. 972e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * 973e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @param res The resources 974e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @param attrs The set of attributes holding the animation parameters 975cf4832f69c8786b098ce18c24319021f8cd6733aztenghui * @param anim Null if this is a ValueAnimator, otherwise this is an 976cf4832f69c8786b098ce18c24319021f8cd6733aztenghui * ObjectAnimator 977e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui */ 978e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui private static ValueAnimator loadAnimator(Resources res, Theme theme, 979fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount AttributeSet attrs, ValueAnimator anim, float pathErrorScale) 980e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui throws NotFoundException { 981cf4832f69c8786b098ce18c24319021f8cd6733aztenghui TypedArray arrayAnimator = null; 982cf4832f69c8786b098ce18c24319021f8cd6733aztenghui TypedArray arrayObjectAnimator = null; 983cf4832f69c8786b098ce18c24319021f8cd6733aztenghui 984e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (theme != null) { 985cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayAnimator = theme.obtainStyledAttributes(attrs, R.styleable.Animator, 0, 0); 986e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else { 987cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayAnimator = res.obtainAttributes(attrs, R.styleable.Animator); 988e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 989e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 990cf4832f69c8786b098ce18c24319021f8cd6733aztenghui // If anim is not null, then it is an object animator. 991cf4832f69c8786b098ce18c24319021f8cd6733aztenghui if (anim != null) { 992cf4832f69c8786b098ce18c24319021f8cd6733aztenghui if (theme != null) { 993cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayObjectAnimator = theme.obtainStyledAttributes(attrs, 994cf4832f69c8786b098ce18c24319021f8cd6733aztenghui R.styleable.PropertyAnimator, 0, 0); 995cf4832f69c8786b098ce18c24319021f8cd6733aztenghui } else { 996cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayObjectAnimator = res.obtainAttributes(attrs, R.styleable.PropertyAnimator); 997cf4832f69c8786b098ce18c24319021f8cd6733aztenghui } 998d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar anim.appendChangingConfigurations(arrayObjectAnimator.getChangingConfigurations()); 999cf4832f69c8786b098ce18c24319021f8cd6733aztenghui } 10007f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout 10017f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout if (anim == null) { 10027f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout anim = new ValueAnimator(); 10037f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout } 1004d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar anim.appendChangingConfigurations(arrayAnimator.getChangingConfigurations()); 10057f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout 1006fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount parseAnimatorFromTypeArray(anim, arrayAnimator, arrayObjectAnimator, pathErrorScale); 1007d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 1008d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final int resID = arrayAnimator.getResourceId(R.styleable.Animator_interpolator, 0); 1009d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase if (resID > 0) { 1010d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar final Interpolator interpolator = AnimationUtils.loadInterpolator(res, theme, resID); 1011d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar if (interpolator instanceof BaseInterpolator) { 1012d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar anim.appendChangingConfigurations( 1013d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar ((BaseInterpolator) interpolator).getChangingConfiguration()); 1014d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 1015d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar anim.setInterpolator(interpolator); 1016d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 1017cf4832f69c8786b098ce18c24319021f8cd6733aztenghui 1018cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayAnimator.recycle(); 10197f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout if (arrayObjectAnimator != null) { 10207f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout arrayObjectAnimator.recycle(); 10217f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout } 1022d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase return anim; 1023d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 1024d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar 1025d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar private static int getChangingConfigs(Resources resources, int id) { 1026d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar synchronized (sTmpTypedValue) { 1027d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar resources.getValue(id, sTmpTypedValue, true); 1028d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar return sTmpTypedValue.changingConfigurations; 1029d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 1030d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar } 1031d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase} 1032