AnimatorInflater.java revision fd3c4744f265c5277e6e2641a18d5ec3dff19f6b
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 18d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.Context; 19d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.res.Resources; 20cf4832f69c8786b098ce18c24319021f8cd6733aztenghuiimport android.content.res.Resources.NotFoundException; 21e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghuiimport android.content.res.Resources.Theme; 22d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.res.TypedArray; 23d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.res.XmlResourceParser; 24cf4832f69c8786b098ce18c24319021f8cd6733aztenghuiimport android.graphics.Path; 25d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.util.AttributeSet; 26eb034fbca40006c55db143047eb628c4b657730aztenghuiimport android.util.Log; 27cf4832f69c8786b098ce18c24319021f8cd6733aztenghuiimport android.util.PathParser; 28f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyarimport android.util.StateSet; 295bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haaseimport android.util.TypedValue; 30d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.util.Xml; 31eb034fbca40006c55db143047eb628c4b657730aztenghuiimport android.view.InflateException; 32d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.view.animation.AnimationUtils; 33e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 34e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghuiimport com.android.internal.R; 35e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 36d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport org.xmlpull.v1.XmlPullParser; 37d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport org.xmlpull.v1.XmlPullParserException; 38d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 39d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport java.io.IOException; 40d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport java.util.ArrayList; 41d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 42d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase/** 436cfdf4538049e4b96f50d8c0fe3119664420cc34Chet Haase * This class is used to instantiate animator XML files into Animator objects. 44d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * <p> 456cfdf4538049e4b96f50d8c0fe3119664420cc34Chet Haase * For performance reasons, inflation relies heavily on pre-processing of 46d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * XML files that is done at build time. Therefore, it is not currently possible 476cfdf4538049e4b96f50d8c0fe3119664420cc34Chet Haase * to use this inflater with an XmlPullParser over a plain XML file at runtime; 48d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * it only works with an XmlPullParser returned from a compiled resource (R. 49d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * <em>something</em> file.) 50d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase */ 51a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haasepublic class AnimatorInflater { 52eb034fbca40006c55db143047eb628c4b657730aztenghui private static final String TAG = "AnimatorInflater"; 53d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase /** 54a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * These flags are used when parsing AnimatorSet objects 55d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase */ 56d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase private static final int TOGETHER = 0; 57d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase private static final int SEQUENTIALLY = 1; 58d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 59d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase /** 60d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * Enum values used in XML attributes to indicate the value for mValueType 61d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase */ 62d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase private static final int VALUE_TYPE_FLOAT = 0; 63d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase private static final int VALUE_TYPE_INT = 1; 64eb034fbca40006c55db143047eb628c4b657730aztenghui private static final int VALUE_TYPE_PATH = 2; 652794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase private static final int VALUE_TYPE_COLOR = 4; 662794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase private static final int VALUE_TYPE_CUSTOM = 5; 67d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 68eb034fbca40006c55db143047eb628c4b657730aztenghui private static final boolean DBG_ANIMATOR_INFLATER = false; 69eb034fbca40006c55db143047eb628c4b657730aztenghui 70d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase /** 71a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * Loads an {@link Animator} object from a resource 72d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * 73d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * @param context Application context used to access resources 74d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * @param id The resource id of the animation to load 75a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * @return The animator object reference by the specified id 76d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded 77d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase */ 78a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase public static Animator loadAnimator(Context context, int id) 79d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase throws NotFoundException { 80e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return loadAnimator(context.getResources(), context.getTheme(), id); 81e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 82e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 83e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui /** 84e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * Loads an {@link Animator} object from a resource 85e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * 86e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @param resources The resources 87e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @param theme The theme 88e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @param id The resource id of the animation to load 89e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @return The animator object reference by the specified id 90e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded 91e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @hide 92e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui */ 93e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public static Animator loadAnimator(Resources resources, Theme theme, int id) 94e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui throws NotFoundException { 95fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount return loadAnimator(resources, theme, id, 1); 96fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount } 97fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount 98fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount /** @hide */ 99fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount public static Animator loadAnimator(Resources resources, Theme theme, int id, 100fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount float pathErrorScale) throws NotFoundException { 101d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 102d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase XmlResourceParser parser = null; 103d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase try { 104e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui parser = resources.getAnimation(id); 105fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount return createAnimatorFromXml(resources, theme, parser, pathErrorScale); 106d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } catch (XmlPullParserException ex) { 107d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase Resources.NotFoundException rnf = 108d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase new Resources.NotFoundException("Can't load animation resource ID #0x" + 109fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount Integer.toHexString(id)); 110d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase rnf.initCause(ex); 111d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase throw rnf; 112d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } catch (IOException ex) { 113d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase Resources.NotFoundException rnf = 114d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase new Resources.NotFoundException("Can't load animation resource ID #0x" + 115fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount Integer.toHexString(id)); 116d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase rnf.initCause(ex); 117d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase throw rnf; 118d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } finally { 119d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase if (parser != null) parser.close(); 120d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 121d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 122d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 123f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar public static StateListAnimator loadStateListAnimator(Context context, int id) 124f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throws NotFoundException { 125f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar XmlResourceParser parser = null; 126f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar try { 127f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar parser = context.getResources().getAnimation(id); 128f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar return createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser)); 129f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } catch (XmlPullParserException ex) { 130f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Resources.NotFoundException rnf = 131f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar new Resources.NotFoundException( 132f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar "Can't load state list animator resource ID #0x" + 133f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Integer.toHexString(id) 134f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar ); 135f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar rnf.initCause(ex); 136f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throw rnf; 137f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } catch (IOException ex) { 138f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Resources.NotFoundException rnf = 139f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar new Resources.NotFoundException( 140f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar "Can't load state list animator resource ID #0x" + 141f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Integer.toHexString(id) 142f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar ); 143f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar rnf.initCause(ex); 144f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throw rnf; 145f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } finally { 146f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar if (parser != null) { 147f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar parser.close(); 148f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 149f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 150f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 151f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 152f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar private static StateListAnimator createStateListAnimatorFromXml(Context context, 153f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar XmlPullParser parser, AttributeSet attributeSet) 154f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throws IOException, XmlPullParserException { 155f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int type; 156f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar StateListAnimator stateListAnimator = new StateListAnimator(); 157f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 158f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar while (true) { 159f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar type = parser.next(); 160f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar switch (type) { 161f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar case XmlPullParser.END_DOCUMENT: 162f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar case XmlPullParser.END_TAG: 163f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar return stateListAnimator; 164f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 165f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar case XmlPullParser.START_TAG: 166f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar // parse item 167f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar Animator animator = null; 168f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar if ("item".equals(parser.getName())) { 169f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int attributeCount = parser.getAttributeCount(); 170f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int[] states = new int[attributeCount]; 171f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int stateIndex = 0; 172f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar for (int i = 0; i < attributeCount; i++) { 173f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar int attrName = attributeSet.getAttributeNameResource(i); 174cf4832f69c8786b098ce18c24319021f8cd6733aztenghui if (attrName == R.attr.animation) { 175f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar animator = loadAnimator(context, 176f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar attributeSet.getAttributeResourceValue(i, 0)); 177f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } else { 178f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar states[stateIndex++] = 179f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar attributeSet.getAttributeBooleanValue(i, false) ? 180f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar attrName : -attrName; 181f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 182f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 183f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 184f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar if (animator == null) { 185e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui animator = createAnimatorFromXml(context.getResources(), 186fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount context.getTheme(), parser, 1f); 187f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 188f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 189f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar if (animator == null) { 190f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar throw new Resources.NotFoundException( 191f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar "animation state item must have a valid animation"); 192f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 193f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar stateListAnimator 194f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar .addState(StateSet.trimStateSet(states, stateIndex), animator); 195f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 196f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 197f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar break; 198f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 199f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 200f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar } 201f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar 202cf4832f69c8786b098ce18c24319021f8cd6733aztenghui /** 203eb034fbca40006c55db143047eb628c4b657730aztenghui * PathDataEvaluator is used to interpolate between two paths which are 204eb034fbca40006c55db143047eb628c4b657730aztenghui * represented in the same format but different control points' values. 205eb034fbca40006c55db143047eb628c4b657730aztenghui * The path is represented as an array of PathDataNode here, which is 206eb034fbca40006c55db143047eb628c4b657730aztenghui * fundamentally an array of floating point numbers. 207eb034fbca40006c55db143047eb628c4b657730aztenghui */ 208eb034fbca40006c55db143047eb628c4b657730aztenghui private static class PathDataEvaluator implements TypeEvaluator<PathParser.PathDataNode[]> { 209eb034fbca40006c55db143047eb628c4b657730aztenghui private PathParser.PathDataNode[] mNodeArray; 210eb034fbca40006c55db143047eb628c4b657730aztenghui 211eb034fbca40006c55db143047eb628c4b657730aztenghui /** 212eb034fbca40006c55db143047eb628c4b657730aztenghui * Create a PathParser.PathDataNode[] that does not reuse the animated value. 213eb034fbca40006c55db143047eb628c4b657730aztenghui * Care must be taken when using this option because on every evaluation 214eb034fbca40006c55db143047eb628c4b657730aztenghui * a new <code>PathParser.PathDataNode[]</code> will be allocated. 215eb034fbca40006c55db143047eb628c4b657730aztenghui */ 216eb034fbca40006c55db143047eb628c4b657730aztenghui private PathDataEvaluator() {} 217eb034fbca40006c55db143047eb628c4b657730aztenghui 218eb034fbca40006c55db143047eb628c4b657730aztenghui /** 219eb034fbca40006c55db143047eb628c4b657730aztenghui * Create a PathDataEvaluator that reuses <code>nodeArray</code> for every evaluate() call. 220eb034fbca40006c55db143047eb628c4b657730aztenghui * Caution must be taken to ensure that the value returned from 221eb034fbca40006c55db143047eb628c4b657730aztenghui * {@link android.animation.ValueAnimator#getAnimatedValue()} is not cached, modified, or 222eb034fbca40006c55db143047eb628c4b657730aztenghui * used across threads. The value will be modified on each <code>evaluate()</code> call. 223eb034fbca40006c55db143047eb628c4b657730aztenghui * 224eb034fbca40006c55db143047eb628c4b657730aztenghui * @param nodeArray The array to modify and return from <code>evaluate</code>. 225eb034fbca40006c55db143047eb628c4b657730aztenghui */ 226eb034fbca40006c55db143047eb628c4b657730aztenghui public PathDataEvaluator(PathParser.PathDataNode[] nodeArray) { 227eb034fbca40006c55db143047eb628c4b657730aztenghui mNodeArray = nodeArray; 228eb034fbca40006c55db143047eb628c4b657730aztenghui } 229eb034fbca40006c55db143047eb628c4b657730aztenghui 230eb034fbca40006c55db143047eb628c4b657730aztenghui @Override 231eb034fbca40006c55db143047eb628c4b657730aztenghui public PathParser.PathDataNode[] evaluate(float fraction, 232eb034fbca40006c55db143047eb628c4b657730aztenghui PathParser.PathDataNode[] startPathData, 233eb034fbca40006c55db143047eb628c4b657730aztenghui PathParser.PathDataNode[] endPathData) { 234eb034fbca40006c55db143047eb628c4b657730aztenghui if (!PathParser.canMorph(startPathData, endPathData)) { 235eb034fbca40006c55db143047eb628c4b657730aztenghui throw new IllegalArgumentException("Can't interpolate between" 236eb034fbca40006c55db143047eb628c4b657730aztenghui + " two incompatible pathData"); 237eb034fbca40006c55db143047eb628c4b657730aztenghui } 238eb034fbca40006c55db143047eb628c4b657730aztenghui 239eb034fbca40006c55db143047eb628c4b657730aztenghui if (mNodeArray == null || !PathParser.canMorph(mNodeArray, startPathData)) { 240eb034fbca40006c55db143047eb628c4b657730aztenghui mNodeArray = PathParser.deepCopyNodes(startPathData); 241eb034fbca40006c55db143047eb628c4b657730aztenghui } 242eb034fbca40006c55db143047eb628c4b657730aztenghui 243eb034fbca40006c55db143047eb628c4b657730aztenghui for (int i = 0; i < startPathData.length; i++) { 244eb034fbca40006c55db143047eb628c4b657730aztenghui mNodeArray[i].interpolatePathDataNode(startPathData[i], 245eb034fbca40006c55db143047eb628c4b657730aztenghui endPathData[i], fraction); 246eb034fbca40006c55db143047eb628c4b657730aztenghui } 247eb034fbca40006c55db143047eb628c4b657730aztenghui 248eb034fbca40006c55db143047eb628c4b657730aztenghui return mNodeArray; 249eb034fbca40006c55db143047eb628c4b657730aztenghui } 250eb034fbca40006c55db143047eb628c4b657730aztenghui } 251eb034fbca40006c55db143047eb628c4b657730aztenghui 252eb034fbca40006c55db143047eb628c4b657730aztenghui /** 2537f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout * @param anim The animator, must not be null 254cf4832f69c8786b098ce18c24319021f8cd6733aztenghui * @param arrayAnimator Incoming typed array for Animator's attributes. 255cf4832f69c8786b098ce18c24319021f8cd6733aztenghui * @param arrayObjectAnimator Incoming typed array for Object Animator's 256cf4832f69c8786b098ce18c24319021f8cd6733aztenghui * attributes. 257fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount * @param pixelSize The relative pixel size, used to calculate the 258fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount * maximum error for path animations. 259cf4832f69c8786b098ce18c24319021f8cd6733aztenghui */ 260cf4832f69c8786b098ce18c24319021f8cd6733aztenghui private static void parseAnimatorFromTypeArray(ValueAnimator anim, 261fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount TypedArray arrayAnimator, TypedArray arrayObjectAnimator, float pixelSize) { 262cf4832f69c8786b098ce18c24319021f8cd6733aztenghui long duration = arrayAnimator.getInt(R.styleable.Animator_duration, 300); 263d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 264cf4832f69c8786b098ce18c24319021f8cd6733aztenghui long startDelay = arrayAnimator.getInt(R.styleable.Animator_startOffset, 0); 265d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 266cf4832f69c8786b098ce18c24319021f8cd6733aztenghui int valueType = arrayAnimator.getInt(R.styleable.Animator_valueType, 267d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase VALUE_TYPE_FLOAT); 268d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 269cf4832f69c8786b098ce18c24319021f8cd6733aztenghui TypeEvaluator evaluator = null; 2705bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase 2715bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase boolean getFloats = (valueType == VALUE_TYPE_FLOAT); 2725bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase 273eb034fbca40006c55db143047eb628c4b657730aztenghui TypedValue tvFrom = arrayAnimator.peekValue(R.styleable.Animator_valueFrom); 2745bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase boolean hasFrom = (tvFrom != null); 2755bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase int fromType = hasFrom ? tvFrom.type : 0; 276eb034fbca40006c55db143047eb628c4b657730aztenghui TypedValue tvTo = arrayAnimator.peekValue(R.styleable.Animator_valueTo); 2775bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase boolean hasTo = (tvTo != null); 2785bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase int toType = hasTo ? tvTo.type : 0; 2795bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase 280eb034fbca40006c55db143047eb628c4b657730aztenghui // TODO: Further clean up this part of code into 4 types : path, color, 281eb034fbca40006c55db143047eb628c4b657730aztenghui // integer and float. 282eb034fbca40006c55db143047eb628c4b657730aztenghui if (valueType == VALUE_TYPE_PATH) { 283eb034fbca40006c55db143047eb628c4b657730aztenghui evaluator = setupAnimatorForPath(anim, arrayAnimator); 284eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 285eb034fbca40006c55db143047eb628c4b657730aztenghui // Integer and float value types are handled here. 286eb034fbca40006c55db143047eb628c4b657730aztenghui if ((hasFrom && (fromType >= TypedValue.TYPE_FIRST_COLOR_INT) && 287eb034fbca40006c55db143047eb628c4b657730aztenghui (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) || 288eb034fbca40006c55db143047eb628c4b657730aztenghui (hasTo && (toType >= TypedValue.TYPE_FIRST_COLOR_INT) && 289eb034fbca40006c55db143047eb628c4b657730aztenghui (toType <= TypedValue.TYPE_LAST_COLOR_INT))) { 290eb034fbca40006c55db143047eb628c4b657730aztenghui // special case for colors: ignore valueType and get ints 291eb034fbca40006c55db143047eb628c4b657730aztenghui getFloats = false; 292eb034fbca40006c55db143047eb628c4b657730aztenghui evaluator = ArgbEvaluator.getInstance(); 293eb034fbca40006c55db143047eb628c4b657730aztenghui } 294eb034fbca40006c55db143047eb628c4b657730aztenghui setupValues(anim, arrayAnimator, getFloats, hasFrom, fromType, hasTo, toType); 2955bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } 2965bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase 297eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setDuration(duration); 298eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setStartDelay(startDelay); 299eb034fbca40006c55db143047eb628c4b657730aztenghui 300eb034fbca40006c55db143047eb628c4b657730aztenghui if (arrayAnimator.hasValue(R.styleable.Animator_repeatCount)) { 301eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setRepeatCount( 302eb034fbca40006c55db143047eb628c4b657730aztenghui arrayAnimator.getInt(R.styleable.Animator_repeatCount, 0)); 303eb034fbca40006c55db143047eb628c4b657730aztenghui } 304eb034fbca40006c55db143047eb628c4b657730aztenghui if (arrayAnimator.hasValue(R.styleable.Animator_repeatMode)) { 305eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setRepeatMode( 306eb034fbca40006c55db143047eb628c4b657730aztenghui arrayAnimator.getInt(R.styleable.Animator_repeatMode, 307eb034fbca40006c55db143047eb628c4b657730aztenghui ValueAnimator.RESTART)); 308eb034fbca40006c55db143047eb628c4b657730aztenghui } 309eb034fbca40006c55db143047eb628c4b657730aztenghui if (evaluator != null) { 310eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setEvaluator(evaluator); 311eb034fbca40006c55db143047eb628c4b657730aztenghui } 312eb034fbca40006c55db143047eb628c4b657730aztenghui 313eb034fbca40006c55db143047eb628c4b657730aztenghui if (arrayObjectAnimator != null) { 314fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount setupObjectAnimator(anim, arrayObjectAnimator, getFloats, pixelSize); 315eb034fbca40006c55db143047eb628c4b657730aztenghui } 316eb034fbca40006c55db143047eb628c4b657730aztenghui } 317eb034fbca40006c55db143047eb628c4b657730aztenghui 318eb034fbca40006c55db143047eb628c4b657730aztenghui /** 319eb034fbca40006c55db143047eb628c4b657730aztenghui * Setup the Animator to achieve path morphing. 320eb034fbca40006c55db143047eb628c4b657730aztenghui * 321eb034fbca40006c55db143047eb628c4b657730aztenghui * @param anim The target Animator which will be updated. 322eb034fbca40006c55db143047eb628c4b657730aztenghui * @param arrayAnimator TypedArray for the ValueAnimator. 323eb034fbca40006c55db143047eb628c4b657730aztenghui * @return the PathDataEvaluator. 324eb034fbca40006c55db143047eb628c4b657730aztenghui */ 325eb034fbca40006c55db143047eb628c4b657730aztenghui private static TypeEvaluator setupAnimatorForPath(ValueAnimator anim, 326eb034fbca40006c55db143047eb628c4b657730aztenghui TypedArray arrayAnimator) { 327eb034fbca40006c55db143047eb628c4b657730aztenghui TypeEvaluator evaluator = null; 328eb034fbca40006c55db143047eb628c4b657730aztenghui String fromString = arrayAnimator.getString(R.styleable.Animator_valueFrom); 329eb034fbca40006c55db143047eb628c4b657730aztenghui String toString = arrayAnimator.getString(R.styleable.Animator_valueTo); 330eb034fbca40006c55db143047eb628c4b657730aztenghui PathParser.PathDataNode[] nodesFrom = PathParser.createNodesFromPathData(fromString); 331eb034fbca40006c55db143047eb628c4b657730aztenghui PathParser.PathDataNode[] nodesTo = PathParser.createNodesFromPathData(toString); 332eb034fbca40006c55db143047eb628c4b657730aztenghui 333eb034fbca40006c55db143047eb628c4b657730aztenghui if (nodesFrom != null) { 334eb034fbca40006c55db143047eb628c4b657730aztenghui if (nodesTo != null) { 335eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setObjectValues(nodesFrom, nodesTo); 336eb034fbca40006c55db143047eb628c4b657730aztenghui if (!PathParser.canMorph(nodesFrom, nodesTo)) { 337eb034fbca40006c55db143047eb628c4b657730aztenghui throw new InflateException(arrayAnimator.getPositionDescription() 338eb034fbca40006c55db143047eb628c4b657730aztenghui + " Can't morph from " + fromString + " to " + toString); 339eb034fbca40006c55db143047eb628c4b657730aztenghui } 340eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 341eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setObjectValues((Object)nodesFrom); 342eb034fbca40006c55db143047eb628c4b657730aztenghui } 343eb034fbca40006c55db143047eb628c4b657730aztenghui evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesFrom)); 344eb034fbca40006c55db143047eb628c4b657730aztenghui } else if (nodesTo != null) { 345eb034fbca40006c55db143047eb628c4b657730aztenghui anim.setObjectValues((Object)nodesTo); 346eb034fbca40006c55db143047eb628c4b657730aztenghui evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesTo)); 347eb034fbca40006c55db143047eb628c4b657730aztenghui } 348eb034fbca40006c55db143047eb628c4b657730aztenghui 349eb034fbca40006c55db143047eb628c4b657730aztenghui if (DBG_ANIMATOR_INFLATER && evaluator != null) { 350eb034fbca40006c55db143047eb628c4b657730aztenghui Log.v(TAG, "create a new PathDataEvaluator here"); 351eb034fbca40006c55db143047eb628c4b657730aztenghui } 352eb034fbca40006c55db143047eb628c4b657730aztenghui 353eb034fbca40006c55db143047eb628c4b657730aztenghui return evaluator; 354eb034fbca40006c55db143047eb628c4b657730aztenghui } 355eb034fbca40006c55db143047eb628c4b657730aztenghui 356eb034fbca40006c55db143047eb628c4b657730aztenghui /** 357eb034fbca40006c55db143047eb628c4b657730aztenghui * Setup ObjectAnimator's property or values from pathData. 358eb034fbca40006c55db143047eb628c4b657730aztenghui * 359eb034fbca40006c55db143047eb628c4b657730aztenghui * @param anim The target Animator which will be updated. 360eb034fbca40006c55db143047eb628c4b657730aztenghui * @param arrayObjectAnimator TypedArray for the ObjectAnimator. 361eb034fbca40006c55db143047eb628c4b657730aztenghui * @param getFloats True if the value type is float. 362fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount * @param pixelSize The relative pixel size, used to calculate the 363fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount * maximum error for path animations. 364eb034fbca40006c55db143047eb628c4b657730aztenghui */ 365eb034fbca40006c55db143047eb628c4b657730aztenghui private static void setupObjectAnimator(ValueAnimator anim, TypedArray arrayObjectAnimator, 366fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount boolean getFloats, float pixelSize) { 367eb034fbca40006c55db143047eb628c4b657730aztenghui ObjectAnimator oa = (ObjectAnimator) anim; 368eb034fbca40006c55db143047eb628c4b657730aztenghui String pathData = arrayObjectAnimator.getString(R.styleable.PropertyAnimator_pathData); 369eb034fbca40006c55db143047eb628c4b657730aztenghui 370eb034fbca40006c55db143047eb628c4b657730aztenghui // Note that if there is a pathData defined in the Object Animator, 371eb034fbca40006c55db143047eb628c4b657730aztenghui // valueFrom / valueTo will be ignored. 372eb034fbca40006c55db143047eb628c4b657730aztenghui if (pathData != null) { 373eb034fbca40006c55db143047eb628c4b657730aztenghui String propertyXName = 374eb034fbca40006c55db143047eb628c4b657730aztenghui arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyXName); 375eb034fbca40006c55db143047eb628c4b657730aztenghui String propertyYName = 376eb034fbca40006c55db143047eb628c4b657730aztenghui arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyYName); 377eb034fbca40006c55db143047eb628c4b657730aztenghui 378eb034fbca40006c55db143047eb628c4b657730aztenghui if (propertyXName == null && propertyYName == null) { 379eb034fbca40006c55db143047eb628c4b657730aztenghui throw new InflateException(arrayObjectAnimator.getPositionDescription() 380eb034fbca40006c55db143047eb628c4b657730aztenghui + " propertyXName or propertyYName is needed for PathData"); 381eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 382eb034fbca40006c55db143047eb628c4b657730aztenghui Path path = PathParser.createPathFromPathData(pathData); 383fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount float error = 0.5f * pixelSize; // max half a pixel error 384fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount PathKeyframes keyframeSet = KeyframeSet.ofPath(path, error); 385984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount Keyframes xKeyframes; 386984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount Keyframes yKeyframes; 387984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount if (getFloats) { 388984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount xKeyframes = keyframeSet.createXFloatKeyframes(); 389984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount yKeyframes = keyframeSet.createYFloatKeyframes(); 390984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount } else { 391984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount xKeyframes = keyframeSet.createXIntKeyframes(); 392984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount yKeyframes = keyframeSet.createYIntKeyframes(); 393984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount } 394eb034fbca40006c55db143047eb628c4b657730aztenghui PropertyValuesHolder x = null; 395eb034fbca40006c55db143047eb628c4b657730aztenghui PropertyValuesHolder y = null; 396eb034fbca40006c55db143047eb628c4b657730aztenghui if (propertyXName != null) { 397984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount x = PropertyValuesHolder.ofKeyframes(propertyXName, xKeyframes); 398eb034fbca40006c55db143047eb628c4b657730aztenghui } 399eb034fbca40006c55db143047eb628c4b657730aztenghui if (propertyYName != null) { 400984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount y = PropertyValuesHolder.ofKeyframes(propertyYName, yKeyframes); 401eb034fbca40006c55db143047eb628c4b657730aztenghui } 402eb034fbca40006c55db143047eb628c4b657730aztenghui if (x == null) { 403eb034fbca40006c55db143047eb628c4b657730aztenghui oa.setValues(y); 404eb034fbca40006c55db143047eb628c4b657730aztenghui } else if (y == null) { 405eb034fbca40006c55db143047eb628c4b657730aztenghui oa.setValues(x); 406eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 407eb034fbca40006c55db143047eb628c4b657730aztenghui oa.setValues(x, y); 408eb034fbca40006c55db143047eb628c4b657730aztenghui } 409eb034fbca40006c55db143047eb628c4b657730aztenghui } 410eb034fbca40006c55db143047eb628c4b657730aztenghui } else { 411eb034fbca40006c55db143047eb628c4b657730aztenghui String propertyName = 412eb034fbca40006c55db143047eb628c4b657730aztenghui arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyName); 413eb034fbca40006c55db143047eb628c4b657730aztenghui oa.setPropertyName(propertyName); 414eb034fbca40006c55db143047eb628c4b657730aztenghui } 415eb034fbca40006c55db143047eb628c4b657730aztenghui } 416eb034fbca40006c55db143047eb628c4b657730aztenghui 417eb034fbca40006c55db143047eb628c4b657730aztenghui /** 418eb034fbca40006c55db143047eb628c4b657730aztenghui * Setup ValueAnimator's values. 419eb034fbca40006c55db143047eb628c4b657730aztenghui * This will handle all of the integer, float and color types. 420eb034fbca40006c55db143047eb628c4b657730aztenghui * 421eb034fbca40006c55db143047eb628c4b657730aztenghui * @param anim The target Animator which will be updated. 422eb034fbca40006c55db143047eb628c4b657730aztenghui * @param arrayAnimator TypedArray for the ValueAnimator. 423eb034fbca40006c55db143047eb628c4b657730aztenghui * @param getFloats True if the value type is float. 424eb034fbca40006c55db143047eb628c4b657730aztenghui * @param hasFrom True if "valueFrom" exists. 425eb034fbca40006c55db143047eb628c4b657730aztenghui * @param fromType The type of "valueFrom". 426eb034fbca40006c55db143047eb628c4b657730aztenghui * @param hasTo True if "valueTo" exists. 427eb034fbca40006c55db143047eb628c4b657730aztenghui * @param toType The type of "valueTo". 428eb034fbca40006c55db143047eb628c4b657730aztenghui */ 429eb034fbca40006c55db143047eb628c4b657730aztenghui private static void setupValues(ValueAnimator anim, TypedArray arrayAnimator, 430eb034fbca40006c55db143047eb628c4b657730aztenghui boolean getFloats, boolean hasFrom, int fromType, boolean hasTo, int toType) { 431eb034fbca40006c55db143047eb628c4b657730aztenghui int valueFromIndex = R.styleable.Animator_valueFrom; 432eb034fbca40006c55db143047eb628c4b657730aztenghui int valueToIndex = R.styleable.Animator_valueTo; 4335bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (getFloats) { 4345bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase float valueFrom; 4355bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase float valueTo; 4365bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasFrom) { 4375bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (fromType == TypedValue.TYPE_DIMENSION) { 438cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = arrayAnimator.getDimension(valueFromIndex, 0f); 4395bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 440cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = arrayAnimator.getFloat(valueFromIndex, 0f); 4415bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } 4425bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasTo) { 4435bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 444cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getDimension(valueToIndex, 0f); 4452794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 446cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getFloat(valueToIndex, 0f); 4472794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 4485bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setFloatValues(valueFrom, valueTo); 4495bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 4505bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setFloatValues(valueFrom); 4515bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } 4525bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 4535bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 454cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getDimension(valueToIndex, 0f); 4552794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 456cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getFloat(valueToIndex, 0f); 457d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 4585bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setFloatValues(valueTo); 4592794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 4605bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 4615bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase int valueFrom; 4625bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase int valueTo; 4635bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasFrom) { 4645bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (fromType == TypedValue.TYPE_DIMENSION) { 465cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = (int) arrayAnimator.getDimension(valueFromIndex, 0f); 4665bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else if ((fromType >= TypedValue.TYPE_FIRST_COLOR_INT) && 4675bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) { 468cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = arrayAnimator.getColor(valueFromIndex, 0); 4695bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 470cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueFrom = arrayAnimator.getInt(valueFromIndex, 0); 4715bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } 4725bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasTo) { 4735bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 474cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = (int) arrayAnimator.getDimension(valueToIndex, 0f); 4755bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) && 4765bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase (toType <= TypedValue.TYPE_LAST_COLOR_INT)) { 477cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getColor(valueToIndex, 0); 4782794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 479cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getInt(valueToIndex, 0); 4802794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 4815bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setIntValues(valueFrom, valueTo); 4822794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 4835bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setIntValues(valueFrom); 484d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 4855bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else { 4865bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (hasTo) { 4875bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase if (toType == TypedValue.TYPE_DIMENSION) { 488cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = (int) arrayAnimator.getDimension(valueToIndex, 0f); 4895bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) && 490cf4832f69c8786b098ce18c24319021f8cd6733aztenghui (toType <= TypedValue.TYPE_LAST_COLOR_INT)) { 491cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getColor(valueToIndex, 0); 4922794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } else { 493cf4832f69c8786b098ce18c24319021f8cd6733aztenghui valueTo = arrayAnimator.getInt(valueToIndex, 0); 4942794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 4955bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase anim.setIntValues(valueTo); 496d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 4972794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase } 498d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 499e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 500e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 501fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser, 502fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount float pixelSize) 503e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui throws XmlPullParserException, IOException { 504fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount return createAnimatorFromXml(res, theme, parser, Xml.asAttributeSet(parser), null, 0, 505fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount pixelSize); 506e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 507e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 508e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser, 509fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount AttributeSet attrs, AnimatorSet parent, int sequenceOrdering, float pixelSize) 510e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui throws XmlPullParserException, IOException { 511e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 512e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui Animator anim = null; 513e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui ArrayList<Animator> childAnims = null; 514e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 515e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui // Make sure we are on a start tag. 516e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui int type; 517e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui int depth = parser.getDepth(); 518e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 519e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) 520e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui && type != XmlPullParser.END_DOCUMENT) { 521e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 522e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (type != XmlPullParser.START_TAG) { 523e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui continue; 524e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 525e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 526e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui String name = parser.getName(); 527e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 528e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (name.equals("objectAnimator")) { 529fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount anim = loadObjectAnimator(res, theme, attrs, pixelSize); 530e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else if (name.equals("animator")) { 531fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount anim = loadAnimator(res, theme, attrs, null, pixelSize); 532e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else if (name.equals("set")) { 533e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui anim = new AnimatorSet(); 534e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui TypedArray a; 535e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (theme != null) { 536cf4832f69c8786b098ce18c24319021f8cd6733aztenghui a = theme.obtainStyledAttributes(attrs, R.styleable.AnimatorSet, 0, 0); 537e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else { 538cf4832f69c8786b098ce18c24319021f8cd6733aztenghui a = res.obtainAttributes(attrs, R.styleable.AnimatorSet); 539e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 540cf4832f69c8786b098ce18c24319021f8cd6733aztenghui int ordering = a.getInt(R.styleable.AnimatorSet_ordering, 541e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui TOGETHER); 542fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering, 543fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount pixelSize); 544e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui a.recycle(); 545e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else { 546e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui throw new RuntimeException("Unknown animator name: " + parser.getName()); 547e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 548e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 549e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (parent != null) { 550e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (childAnims == null) { 551e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui childAnims = new ArrayList<Animator>(); 552e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 553e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui childAnims.add(anim); 554e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 555e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 556e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (parent != null && childAnims != null) { 557e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui Animator[] animsArray = new Animator[childAnims.size()]; 558e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui int index = 0; 559e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui for (Animator a : childAnims) { 560e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui animsArray[index++] = a; 561e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 562e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (sequenceOrdering == TOGETHER) { 563e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui parent.playTogether(animsArray); 564e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else { 565e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui parent.playSequentially(animsArray); 566e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 567e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 568e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 569e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return anim; 570e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 571e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 572e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 573fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs, 574fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount float pathErrorScale) throws NotFoundException { 575e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui ObjectAnimator anim = new ObjectAnimator(); 576e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 577fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount loadAnimator(res, theme, attrs, anim, pathErrorScale); 578e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 579e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return anim; 580e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 581e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 582e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui /** 583e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * Creates a new animation whose parameters come from the specified context 584e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * and attributes set. 585e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * 586e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @param res The resources 587e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui * @param attrs The set of attributes holding the animation parameters 588cf4832f69c8786b098ce18c24319021f8cd6733aztenghui * @param anim Null if this is a ValueAnimator, otherwise this is an 589cf4832f69c8786b098ce18c24319021f8cd6733aztenghui * ObjectAnimator 590e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui */ 591e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui private static ValueAnimator loadAnimator(Resources res, Theme theme, 592fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount AttributeSet attrs, ValueAnimator anim, float pathErrorScale) 593e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui throws NotFoundException { 594e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 595cf4832f69c8786b098ce18c24319021f8cd6733aztenghui TypedArray arrayAnimator = null; 596cf4832f69c8786b098ce18c24319021f8cd6733aztenghui TypedArray arrayObjectAnimator = null; 597cf4832f69c8786b098ce18c24319021f8cd6733aztenghui 598e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (theme != null) { 599cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayAnimator = theme.obtainStyledAttributes(attrs, R.styleable.Animator, 0, 0); 600e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } else { 601cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayAnimator = res.obtainAttributes(attrs, R.styleable.Animator); 602e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 603e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 604cf4832f69c8786b098ce18c24319021f8cd6733aztenghui // If anim is not null, then it is an object animator. 605cf4832f69c8786b098ce18c24319021f8cd6733aztenghui if (anim != null) { 606cf4832f69c8786b098ce18c24319021f8cd6733aztenghui if (theme != null) { 607cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayObjectAnimator = theme.obtainStyledAttributes(attrs, 608cf4832f69c8786b098ce18c24319021f8cd6733aztenghui R.styleable.PropertyAnimator, 0, 0); 609cf4832f69c8786b098ce18c24319021f8cd6733aztenghui } else { 610cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayObjectAnimator = res.obtainAttributes(attrs, R.styleable.PropertyAnimator); 611cf4832f69c8786b098ce18c24319021f8cd6733aztenghui } 612cf4832f69c8786b098ce18c24319021f8cd6733aztenghui } 6137f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout 6147f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout if (anim == null) { 6157f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout anim = new ValueAnimator(); 6167f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout } 6177f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout 618fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount parseAnimatorFromTypeArray(anim, arrayAnimator, arrayObjectAnimator, pathErrorScale); 619d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 620d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase final int resID = 621cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayAnimator.getResourceId(R.styleable.Animator_interpolator, 0); 622d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase if (resID > 0) { 623e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui anim.setInterpolator(AnimationUtils.loadInterpolator(res, theme, resID)); 624d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 625cf4832f69c8786b098ce18c24319021f8cd6733aztenghui 626cf4832f69c8786b098ce18c24319021f8cd6733aztenghui arrayAnimator.recycle(); 6277f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout if (arrayObjectAnimator != null) { 6287f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout arrayObjectAnimator.recycle(); 6297f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout } 630d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase 631d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase return anim; 632d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase } 633d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase} 634