AnimationUtils.java revision d51d368f2d512ab657b8ae45780c82c0dbea94c3
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
17package android.view.animation;
18
19import org.xmlpull.v1.XmlPullParser;
20import org.xmlpull.v1.XmlPullParserException;
21
22import android.content.Context;
23import android.content.res.XmlResourceParser;
24import android.content.res.Resources.NotFoundException;
25import android.util.AttributeSet;
26import android.util.Xml;
27import android.os.SystemClock;
28
29import java.io.IOException;
30
31/**
32 * Defines common utilities for working with animations.
33 *
34 */
35public class AnimationUtils {
36
37    /**
38     * These flags are used when parsing Sequencer 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     */
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     */
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
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
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    public static LayoutAnimationController loadLayoutAnimation(Context context, int id)
137            throws NotFoundException {
138
139        XmlResourceParser parser = null;
140        try {
141            parser = context.getResources().getAnimation(id);
142            return createLayoutAnimationFromXml(context, parser);
143        } catch (XmlPullParserException ex) {
144            NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
145                    Integer.toHexString(id));
146            rnf.initCause(ex);
147            throw rnf;
148        } catch (IOException ex) {
149            NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
150                    Integer.toHexString(id));
151            rnf.initCause(ex);
152            throw rnf;
153        } finally {
154            if (parser != null) parser.close();
155        }
156    }
157
158    private static LayoutAnimationController createLayoutAnimationFromXml(Context c,
159            XmlPullParser parser) throws XmlPullParserException, IOException {
160
161        return createLayoutAnimationFromXml(c, parser, Xml.asAttributeSet(parser));
162    }
163
164    private static LayoutAnimationController createLayoutAnimationFromXml(Context c,
165            XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException {
166
167        LayoutAnimationController controller = null;
168
169        int type;
170        int depth = parser.getDepth();
171
172        while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
173                && type != XmlPullParser.END_DOCUMENT) {
174
175            if (type != XmlPullParser.START_TAG) {
176                continue;
177            }
178
179            String name = parser.getName();
180
181            if ("layoutAnimation".equals(name)) {
182                controller = new LayoutAnimationController(c, attrs);
183            } else if ("gridLayoutAnimation".equals(name)) {
184                controller = new GridLayoutAnimationController(c, attrs);
185            } else {
186                throw new RuntimeException("Unknown layout animation name: " + name);
187            }
188        }
189
190        return controller;
191    }
192
193    /**
194     * Make an animation for objects becoming visible. Uses a slide and fade
195     * effect.
196     *
197     * @param c Context for loading resources
198     * @param fromLeft is the object to be animated coming from the left
199     * @return The new animation
200     */
201    public static Animation makeInAnimation(Context c, boolean fromLeft) {
202        Animation a;
203        if (fromLeft) {
204            a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_in_left);
205        } else {
206            a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_in_right);
207        }
208
209        a.setInterpolator(new DecelerateInterpolator());
210        a.setStartTime(currentAnimationTimeMillis());
211        return a;
212    }
213
214    /**
215     * Make an animation for objects becoming invisible. Uses a slide and fade
216     * effect.
217     *
218     * @param c Context for loading resources
219     * @param toRight is the object to be animated exiting to the right
220     * @return The new animation
221     */
222    public static Animation makeOutAnimation(Context c, boolean toRight) {
223        Animation a;
224        if (toRight) {
225            a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_out_right);
226        } else {
227            a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_out_left);
228        }
229
230        a.setInterpolator(new AccelerateInterpolator());
231        a.setStartTime(currentAnimationTimeMillis());
232        return a;
233    }
234
235
236    /**
237     * Make an animation for objects becoming visible. Uses a slide up and fade
238     * effect.
239     *
240     * @param c Context for loading resources
241     * @return The new animation
242     */
243    public static Animation makeInChildBottomAnimation(Context c) {
244        Animation a;
245        a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_in_child_bottom);
246        a.setInterpolator(new AccelerateInterpolator());
247        a.setStartTime(currentAnimationTimeMillis());
248        return a;
249    }
250
251    /**
252     * Loads an {@link Interpolator} object from a resource
253     *
254     * @param context Application context used to access resources
255     * @param id The resource id of the animation to load
256     * @return The animation object reference by the specified id
257     * @throws NotFoundException
258     */
259    public static Interpolator loadInterpolator(Context context, int id) throws NotFoundException {
260        XmlResourceParser parser = null;
261        try {
262            parser = context.getResources().getAnimation(id);
263            return createInterpolatorFromXml(context, parser);
264        } catch (XmlPullParserException ex) {
265            NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
266                    Integer.toHexString(id));
267            rnf.initCause(ex);
268            throw rnf;
269        } catch (IOException ex) {
270            NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
271                    Integer.toHexString(id));
272            rnf.initCause(ex);
273            throw rnf;
274        } finally {
275            if (parser != null) parser.close();
276        }
277
278    }
279
280    private static Interpolator createInterpolatorFromXml(Context c, XmlPullParser parser)
281            throws XmlPullParserException, IOException {
282
283        Interpolator interpolator = null;
284
285        // Make sure we are on a start tag.
286        int type;
287        int depth = parser.getDepth();
288
289        while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
290               && type != XmlPullParser.END_DOCUMENT) {
291
292            if (type != XmlPullParser.START_TAG) {
293                continue;
294            }
295
296            AttributeSet attrs = Xml.asAttributeSet(parser);
297
298            String  name = parser.getName();
299
300
301            if (name.equals("linearInterpolator")) {
302                interpolator = new LinearInterpolator(c, attrs);
303            } else if (name.equals("accelerateInterpolator")) {
304                interpolator = new AccelerateInterpolator(c, attrs);
305            } else if (name.equals("decelerateInterpolator")) {
306                interpolator = new DecelerateInterpolator(c, attrs);
307            }  else if (name.equals("accelerateDecelerateInterpolator")) {
308                interpolator = new AccelerateDecelerateInterpolator(c, attrs);
309            }  else if (name.equals("cycleInterpolator")) {
310                interpolator = new CycleInterpolator(c, attrs);
311            } else if (name.equals("anticipateInterpolator")) {
312                interpolator = new AnticipateInterpolator(c, attrs);
313            } else if (name.equals("overshootInterpolator")) {
314                interpolator = new OvershootInterpolator(c, attrs);
315            } else if (name.equals("anticipateOvershootInterpolator")) {
316                interpolator = new AnticipateOvershootInterpolator(c, attrs);
317            } else if (name.equals("bounceInterpolator")) {
318                interpolator = new BounceInterpolator(c, attrs);
319            } else {
320                throw new RuntimeException("Unknown interpolator name: " + parser.getName());
321            }
322
323        }
324
325        return interpolator;
326
327    }
328}
329