1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.view.animation; 18 19 import org.xmlpull.v1.XmlPullParser; 20 import org.xmlpull.v1.XmlPullParserException; 21 22 import android.content.Context; 23 import android.content.res.XmlResourceParser; 24 import android.content.res.Resources.NotFoundException; 25 import android.util.AttributeSet; 26 import android.util.Xml; 27 import android.os.SystemClock; 28 29 import java.io.IOException; 30 31 /** 32 * Defines common utilities for working with animations. 33 * 34 */ 35 public class AnimationUtils { 36 37 /** 38 * These flags are used when parsing AnimatorSet objects 39 */ 40 private static final int TOGETHER = 0; 41 private static final int SEQUENTIALLY = 1; 42 43 44 /** 45 * Returns the current animation time in milliseconds. This time should be used when invoking 46 * {@link Animation#setStartTime(long)}. Refer to {@link android.os.SystemClock} for more 47 * information about the different available clocks. The clock used by this method is 48 * <em>not</em> the "wall" clock (it is not {@link System#currentTimeMillis}). 49 * 50 * @return the current animation time in milliseconds 51 * 52 * @see android.os.SystemClock 53 */ currentAnimationTimeMillis()54 public static long currentAnimationTimeMillis() { 55 return SystemClock.uptimeMillis(); 56 } 57 58 /** 59 * Loads an {@link Animation} object from a resource 60 * 61 * @param context Application context used to access resources 62 * @param id The resource id of the animation to load 63 * @return The animation object reference by the specified id 64 * @throws NotFoundException when the animation cannot be loaded 65 */ loadAnimation(Context context, int id)66 public static Animation loadAnimation(Context context, int id) 67 throws NotFoundException { 68 69 XmlResourceParser parser = null; 70 try { 71 parser = context.getResources().getAnimation(id); 72 return createAnimationFromXml(context, parser); 73 } catch (XmlPullParserException ex) { 74 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + 75 Integer.toHexString(id)); 76 rnf.initCause(ex); 77 throw rnf; 78 } catch (IOException ex) { 79 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + 80 Integer.toHexString(id)); 81 rnf.initCause(ex); 82 throw rnf; 83 } finally { 84 if (parser != null) parser.close(); 85 } 86 } 87 createAnimationFromXml(Context c, XmlPullParser parser)88 private static Animation createAnimationFromXml(Context c, XmlPullParser parser) 89 throws XmlPullParserException, IOException { 90 91 return createAnimationFromXml(c, parser, null, Xml.asAttributeSet(parser)); 92 } 93 createAnimationFromXml(Context c, XmlPullParser parser, AnimationSet parent, AttributeSet attrs)94 private static Animation createAnimationFromXml(Context c, XmlPullParser parser, 95 AnimationSet parent, AttributeSet attrs) throws XmlPullParserException, IOException { 96 97 Animation anim = null; 98 99 // Make sure we are on a start tag. 100 int type; 101 int depth = parser.getDepth(); 102 103 while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) 104 && type != XmlPullParser.END_DOCUMENT) { 105 106 if (type != XmlPullParser.START_TAG) { 107 continue; 108 } 109 110 String name = parser.getName(); 111 112 if (name.equals("set")) { 113 anim = new AnimationSet(c, attrs); 114 createAnimationFromXml(c, parser, (AnimationSet)anim, attrs); 115 } else if (name.equals("alpha")) { 116 anim = new AlphaAnimation(c, attrs); 117 } else if (name.equals("scale")) { 118 anim = new ScaleAnimation(c, attrs); 119 } else if (name.equals("rotate")) { 120 anim = new RotateAnimation(c, attrs); 121 } else if (name.equals("translate")) { 122 anim = new TranslateAnimation(c, attrs); 123 } else { 124 throw new RuntimeException("Unknown animation name: " + parser.getName()); 125 } 126 127 if (parent != null) { 128 parent.addAnimation(anim); 129 } 130 } 131 132 return anim; 133 134 } 135 136 /** 137 * Loads a {@link LayoutAnimationController} object from a resource 138 * 139 * @param context Application context used to access resources 140 * @param id The resource id of the animation to load 141 * @return The animation object reference by the specified id 142 * @throws NotFoundException when the layout animation controller cannot be loaded 143 */ loadLayoutAnimation(Context context, int id)144 public static LayoutAnimationController loadLayoutAnimation(Context context, int id) 145 throws NotFoundException { 146 147 XmlResourceParser parser = null; 148 try { 149 parser = context.getResources().getAnimation(id); 150 return createLayoutAnimationFromXml(context, parser); 151 } catch (XmlPullParserException ex) { 152 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + 153 Integer.toHexString(id)); 154 rnf.initCause(ex); 155 throw rnf; 156 } catch (IOException ex) { 157 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + 158 Integer.toHexString(id)); 159 rnf.initCause(ex); 160 throw rnf; 161 } finally { 162 if (parser != null) parser.close(); 163 } 164 } 165 createLayoutAnimationFromXml(Context c, XmlPullParser parser)166 private static LayoutAnimationController createLayoutAnimationFromXml(Context c, 167 XmlPullParser parser) throws XmlPullParserException, IOException { 168 169 return createLayoutAnimationFromXml(c, parser, Xml.asAttributeSet(parser)); 170 } 171 createLayoutAnimationFromXml(Context c, XmlPullParser parser, AttributeSet attrs)172 private static LayoutAnimationController createLayoutAnimationFromXml(Context c, 173 XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException { 174 175 LayoutAnimationController controller = null; 176 177 int type; 178 int depth = parser.getDepth(); 179 180 while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) 181 && type != XmlPullParser.END_DOCUMENT) { 182 183 if (type != XmlPullParser.START_TAG) { 184 continue; 185 } 186 187 String name = parser.getName(); 188 189 if ("layoutAnimation".equals(name)) { 190 controller = new LayoutAnimationController(c, attrs); 191 } else if ("gridLayoutAnimation".equals(name)) { 192 controller = new GridLayoutAnimationController(c, attrs); 193 } else { 194 throw new RuntimeException("Unknown layout animation name: " + name); 195 } 196 } 197 198 return controller; 199 } 200 201 /** 202 * Make an animation for objects becoming visible. Uses a slide and fade 203 * effect. 204 * 205 * @param c Context for loading resources 206 * @param fromLeft is the object to be animated coming from the left 207 * @return The new animation 208 */ makeInAnimation(Context c, boolean fromLeft)209 public static Animation makeInAnimation(Context c, boolean fromLeft) { 210 Animation a; 211 if (fromLeft) { 212 a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_in_left); 213 } else { 214 a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_in_right); 215 } 216 217 a.setInterpolator(new DecelerateInterpolator()); 218 a.setStartTime(currentAnimationTimeMillis()); 219 return a; 220 } 221 222 /** 223 * Make an animation for objects becoming invisible. Uses a slide and fade 224 * effect. 225 * 226 * @param c Context for loading resources 227 * @param toRight is the object to be animated exiting to the right 228 * @return The new animation 229 */ makeOutAnimation(Context c, boolean toRight)230 public static Animation makeOutAnimation(Context c, boolean toRight) { 231 Animation a; 232 if (toRight) { 233 a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_out_right); 234 } else { 235 a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_out_left); 236 } 237 238 a.setInterpolator(new AccelerateInterpolator()); 239 a.setStartTime(currentAnimationTimeMillis()); 240 return a; 241 } 242 243 244 /** 245 * Make an animation for objects becoming visible. Uses a slide up and fade 246 * effect. 247 * 248 * @param c Context for loading resources 249 * @return The new animation 250 */ makeInChildBottomAnimation(Context c)251 public static Animation makeInChildBottomAnimation(Context c) { 252 Animation a; 253 a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_in_child_bottom); 254 a.setInterpolator(new AccelerateInterpolator()); 255 a.setStartTime(currentAnimationTimeMillis()); 256 return a; 257 } 258 259 /** 260 * Loads an {@link Interpolator} object from a resource 261 * 262 * @param context Application context used to access resources 263 * @param id The resource id of the animation to load 264 * @return The animation object reference by the specified id 265 * @throws NotFoundException 266 */ loadInterpolator(Context context, int id)267 public static Interpolator loadInterpolator(Context context, int id) throws NotFoundException { 268 XmlResourceParser parser = null; 269 try { 270 parser = context.getResources().getAnimation(id); 271 return createInterpolatorFromXml(context, parser); 272 } catch (XmlPullParserException ex) { 273 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + 274 Integer.toHexString(id)); 275 rnf.initCause(ex); 276 throw rnf; 277 } catch (IOException ex) { 278 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + 279 Integer.toHexString(id)); 280 rnf.initCause(ex); 281 throw rnf; 282 } finally { 283 if (parser != null) parser.close(); 284 } 285 286 } 287 createInterpolatorFromXml(Context c, XmlPullParser parser)288 private static Interpolator createInterpolatorFromXml(Context c, XmlPullParser parser) 289 throws XmlPullParserException, IOException { 290 291 Interpolator interpolator = null; 292 293 // Make sure we are on a start tag. 294 int type; 295 int depth = parser.getDepth(); 296 297 while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) 298 && type != XmlPullParser.END_DOCUMENT) { 299 300 if (type != XmlPullParser.START_TAG) { 301 continue; 302 } 303 304 AttributeSet attrs = Xml.asAttributeSet(parser); 305 306 String name = parser.getName(); 307 308 309 if (name.equals("linearInterpolator")) { 310 interpolator = new LinearInterpolator(c, attrs); 311 } else if (name.equals("accelerateInterpolator")) { 312 interpolator = new AccelerateInterpolator(c, attrs); 313 } else if (name.equals("decelerateInterpolator")) { 314 interpolator = new DecelerateInterpolator(c, attrs); 315 } else if (name.equals("accelerateDecelerateInterpolator")) { 316 interpolator = new AccelerateDecelerateInterpolator(c, attrs); 317 } else if (name.equals("cycleInterpolator")) { 318 interpolator = new CycleInterpolator(c, attrs); 319 } else if (name.equals("anticipateInterpolator")) { 320 interpolator = new AnticipateInterpolator(c, attrs); 321 } else if (name.equals("overshootInterpolator")) { 322 interpolator = new OvershootInterpolator(c, attrs); 323 } else if (name.equals("anticipateOvershootInterpolator")) { 324 interpolator = new AnticipateOvershootInterpolator(c, attrs); 325 } else if (name.equals("bounceInterpolator")) { 326 interpolator = new BounceInterpolator(c, attrs); 327 } else { 328 throw new RuntimeException("Unknown interpolator name: " + parser.getName()); 329 } 330 331 } 332 333 return interpolator; 334 335 } 336 } 337