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