2 * Copyright (C) 2007 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package android.view.animation;
19 import org.xmlpull.v1.XmlPullParser;
20 import org.xmlpull.v1.XmlPullParserException;
22 import android.annotation.AnimRes;
23 import android.annotation.InterpolatorRes;
24 import android.content.Context;
25 import android.content.res.Resources;
26 import android.content.res.Resources.Theme;
27 import android.content.res.XmlResourceParser;
28 import android.content.res.Resources.NotFoundException;
29 import android.util.AttributeSet;
30 import android.util.Xml;
31 import android.os.SystemClock;
33 import java.io.IOException;
36 * Defines common utilities for working with animations.
39 public class AnimationUtils {
42 * These flags are used when parsing AnimatorSet objects
44 private static final int TOGETHER = 0;
45 private static final int SEQUENTIALLY = 1;
49 * Returns the current animation time in milliseconds. This time should be used when invoking
50 * {@link Animation#setStartTime(long)}. Refer to {@link android.os.SystemClock} for more
51 * information about the different available clocks. The clock used by this method is
52 * <em>not</em> the "wall" clock (it is not {@link System#currentTimeMillis}).
54 * @return the current animation time in milliseconds
56 * @see android.os.SystemClock
58 public static long currentAnimationTimeMillis() {
59 return SystemClock.uptimeMillis();
63 * Loads an {@link Animation} object from a resource
65 * @param context Application context used to access resources
66 * @param id The resource id of the animation to load
67 * @return The animation object reference by the specified id
68 * @throws NotFoundException when the animation cannot be loaded
70 public static Animation loadAnimation(Context context, @AnimRes int id)
71 throws NotFoundException {
73 XmlResourceParser parser = null;
75 parser = context.getResources().getAnimation(id);
76 return createAnimationFromXml(context, parser);
77 } catch (XmlPullParserException ex) {
78 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
79 Integer.toHexString(id));
82 } catch (IOException ex) {
83 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
84 Integer.toHexString(id));
88 if (parser != null) parser.close();
92 private static Animation createAnimationFromXml(Context c, XmlPullParser parser)
93 throws XmlPullParserException, IOException {
95 return createAnimationFromXml(c, parser, null, Xml.asAttributeSet(parser));
98 private static Animation createAnimationFromXml(Context c, XmlPullParser parser,
99 AnimationSet parent, AttributeSet attrs) throws XmlPullParserException, IOException {
101 Animation anim = null;
103 // Make sure we are on a start tag.
105 int depth = parser.getDepth();
107 while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
108 && type != XmlPullParser.END_DOCUMENT) {
110 if (type != XmlPullParser.START_TAG) {
114 String name = parser.getName();
116 if (name.equals("set")) {
117 anim = new AnimationSet(c, attrs);
118 createAnimationFromXml(c, parser, (AnimationSet)anim, attrs);
119 } else if (name.equals("alpha")) {
120 anim = new AlphaAnimation(c, attrs);
121 } else if (name.equals("scale")) {
122 anim = new ScaleAnimation(c, attrs);
123 } else if (name.equals("rotate")) {
124 anim = new RotateAnimation(c, attrs);
125 } else if (name.equals("translate")) {
126 anim = new TranslateAnimation(c, attrs);
128 throw new RuntimeException("Unknown animation name: " + parser.getName());
131 if (parent != null) {
132 parent.addAnimation(anim);
141 * Loads a {@link LayoutAnimationController} object from a resource
143 * @param context Application context used to access resources
144 * @param id The resource id of the animation to load
145 * @return The animation object reference by the specified id
146 * @throws NotFoundException when the layout animation controller cannot be loaded
148 public static LayoutAnimationController loadLayoutAnimation(Context context, @AnimRes int id)
149 throws NotFoundException {
151 XmlResourceParser parser = null;
153 parser = context.getResources().getAnimation(id);
154 return createLayoutAnimationFromXml(context, parser);
155 } catch (XmlPullParserException ex) {
156 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
157 Integer.toHexString(id));
160 } catch (IOException ex) {
161 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
162 Integer.toHexString(id));
166 if (parser != null) parser.close();
170 private static LayoutAnimationController createLayoutAnimationFromXml(Context c,
171 XmlPullParser parser) throws XmlPullParserException, IOException {
173 return createLayoutAnimationFromXml(c, parser, Xml.asAttributeSet(parser));
176 private static LayoutAnimationController createLayoutAnimationFromXml(Context c,
177 XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException {
179 LayoutAnimationController controller = null;
182 int depth = parser.getDepth();
184 while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
185 && type != XmlPullParser.END_DOCUMENT) {
187 if (type != XmlPullParser.START_TAG) {
191 String name = parser.getName();
193 if ("layoutAnimation".equals(name)) {
194 controller = new LayoutAnimationController(c, attrs);
195 } else if ("gridLayoutAnimation".equals(name)) {
196 controller = new GridLayoutAnimationController(c, attrs);
198 throw new RuntimeException("Unknown layout animation name: " + name);
206 * Make an animation for objects becoming visible. Uses a slide and fade
209 * @param c Context for loading resources
210 * @param fromLeft is the object to be animated coming from the left
211 * @return The new animation
213 public static Animation makeInAnimation(Context c, boolean fromLeft) {
216 a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_in_left);
218 a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_in_right);
221 a.setInterpolator(new DecelerateInterpolator());
222 a.setStartTime(currentAnimationTimeMillis());
227 * Make an animation for objects becoming invisible. Uses a slide and fade
230 * @param c Context for loading resources
231 * @param toRight is the object to be animated exiting to the right
232 * @return The new animation
234 public static Animation makeOutAnimation(Context c, boolean toRight) {
237 a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_out_right);
239 a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_out_left);
242 a.setInterpolator(new AccelerateInterpolator());
243 a.setStartTime(currentAnimationTimeMillis());
249 * Make an animation for objects becoming visible. Uses a slide up and fade
252 * @param c Context for loading resources
253 * @return The new animation
255 public static Animation makeInChildBottomAnimation(Context c) {
257 a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_in_child_bottom);
258 a.setInterpolator(new AccelerateInterpolator());
259 a.setStartTime(currentAnimationTimeMillis());
264 * Loads an {@link Interpolator} object from a resource
266 * @param context Application context used to access resources
267 * @param id The resource id of the animation to load
268 * @return The animation object reference by the specified id
269 * @throws NotFoundException
271 public static Interpolator loadInterpolator(Context context, @AnimRes @InterpolatorRes int id)
272 throws NotFoundException {
273 XmlResourceParser parser = null;
275 parser = context.getResources().getAnimation(id);
276 return createInterpolatorFromXml(context.getResources(), context.getTheme(), parser);
277 } catch (XmlPullParserException ex) {
278 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
279 Integer.toHexString(id));
282 } catch (IOException ex) {
283 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
284 Integer.toHexString(id));
288 if (parser != null) parser.close();
294 * Loads an {@link Interpolator} object from a resource
296 * @param res The resources
297 * @param id The resource id of the animation to load
298 * @return The interpolator object reference by the specified id
299 * @throws NotFoundException
302 public static Interpolator loadInterpolator(Resources res, Theme theme, int id) throws NotFoundException {
303 XmlResourceParser parser = null;
305 parser = res.getAnimation(id);
306 return createInterpolatorFromXml(res, theme, parser);
307 } catch (XmlPullParserException ex) {
308 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
309 Integer.toHexString(id));
312 } catch (IOException ex) {
313 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
314 Integer.toHexString(id));
324 private static Interpolator createInterpolatorFromXml(Resources res, Theme theme, XmlPullParser parser)
325 throws XmlPullParserException, IOException {
327 BaseInterpolator interpolator = null;
329 // Make sure we are on a start tag.
331 int depth = parser.getDepth();
333 while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
334 && type != XmlPullParser.END_DOCUMENT) {
336 if (type != XmlPullParser.START_TAG) {
340 AttributeSet attrs = Xml.asAttributeSet(parser);
342 String name = parser.getName();
344 if (name.equals("linearInterpolator")) {
345 interpolator = new LinearInterpolator();
346 } else if (name.equals("accelerateInterpolator")) {
347 interpolator = new AccelerateInterpolator(res, theme, attrs);
348 } else if (name.equals("decelerateInterpolator")) {
349 interpolator = new DecelerateInterpolator(res, theme, attrs);
350 } else if (name.equals("accelerateDecelerateInterpolator")) {
351 interpolator = new AccelerateDecelerateInterpolator();
352 } else if (name.equals("cycleInterpolator")) {
353 interpolator = new CycleInterpolator(res, theme, attrs);
354 } else if (name.equals("anticipateInterpolator")) {
355 interpolator = new AnticipateInterpolator(res, theme, attrs);
356 } else if (name.equals("overshootInterpolator")) {
357 interpolator = new OvershootInterpolator(res, theme, attrs);
358 } else if (name.equals("anticipateOvershootInterpolator")) {
359 interpolator = new AnticipateOvershootInterpolator(res, theme, attrs);
360 } else if (name.equals("bounceInterpolator")) {
361 interpolator = new BounceInterpolator();
362 } else if (name.equals("pathInterpolator")) {
363 interpolator = new PathInterpolator(res, theme, attrs);
365 throw new RuntimeException("Unknown interpolator name: " + parser.getName());