Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2009 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.graphics.drawable.cts;
     18 
     19 import static org.junit.Assert.assertEquals;
     20 import static org.junit.Assert.assertFalse;
     21 import static org.junit.Assert.assertNotNull;
     22 import static org.junit.Assert.assertNull;
     23 import static org.junit.Assert.assertSame;
     24 import static org.junit.Assert.assertTrue;
     25 import static org.junit.Assert.fail;
     26 
     27 import android.app.Activity;
     28 import android.content.res.Resources;
     29 import android.content.res.XmlResourceParser;
     30 import android.graphics.cts.ImageViewCtsActivity;
     31 import android.graphics.cts.R;
     32 import android.graphics.drawable.AnimationDrawable;
     33 import android.graphics.drawable.Drawable;
     34 import android.graphics.drawable.DrawableContainer.DrawableContainerState;
     35 import android.support.test.annotation.UiThreadTest;
     36 import android.support.test.filters.LargeTest;
     37 import android.support.test.rule.ActivityTestRule;
     38 import android.support.test.runner.AndroidJUnit4;
     39 import android.util.Xml;
     40 import android.widget.ImageView;
     41 
     42 import com.android.compatibility.common.util.PollingCheck;
     43 
     44 import org.junit.After;
     45 import org.junit.Before;
     46 import org.junit.Rule;
     47 import org.junit.Test;
     48 import org.junit.runner.RunWith;
     49 import org.xmlpull.v1.XmlPullParser;
     50 import org.xmlpull.v1.XmlPullParserException;
     51 
     52 import java.io.IOException;
     53 
     54 @LargeTest
     55 @RunWith(AndroidJUnit4.class)
     56 public class AnimationDrawableTest {
     57     private static final int FRAMES_COUNT        = 3;
     58     private static final int FIRST_FRAME_INDEX   = 0;
     59     private static final int SECOND_FRAME_INDEX  = 1;
     60     private static final int THIRD_FRAME_INDEX   = 2;
     61     private static final long TOLERANCE = 500;
     62     private static final long FIRST_FRAME_DURATION   = 3000;
     63     private static final long SECOND_FRAME_DURATION  = 2000;
     64     private static final long THIRD_FRAME_DURATION   = 1000;
     65 
     66     private AnimationDrawable mAnimationDrawable;
     67     private Resources mResources;
     68     private boolean mInitialOneShotValue;
     69 
     70     @Rule
     71     public ActivityTestRule<ImageViewCtsActivity> mActivityRule =
     72             new ActivityTestRule<>(ImageViewCtsActivity.class);
     73 
     74     @UiThreadTest
     75     @Before
     76     public void setup() throws Throwable {
     77         final Activity activity = mActivityRule.getActivity();
     78         mResources = activity.getResources();
     79 
     80         try {
     81             mActivityRule.runOnUiThread(new Runnable() {
     82                 public void run() {
     83                     ImageView imageView = (ImageView) activity.findViewById(R.id.imageview);
     84                     imageView.setBackgroundResource(R.drawable.animationdrawable);
     85                     mAnimationDrawable = (AnimationDrawable) imageView.getBackground();
     86                     mInitialOneShotValue = mAnimationDrawable.isOneShot();
     87                 }
     88             });
     89         } catch (Throwable t) {
     90             throw new Exception(t);
     91         }
     92     }
     93 
     94     @After
     95     public void tearDown() throws Exception {
     96         mAnimationDrawable.setOneShot(mInitialOneShotValue);
     97     }
     98 
     99     @Test
    100     public void testConstructor() {
    101         AnimationDrawable animationDrawable = new AnimationDrawable();
    102         // Check the values set in the constructor
    103         assertNotNull(animationDrawable.getConstantState());
    104         assertFalse(animationDrawable.isRunning());
    105         assertFalse(animationDrawable.isOneShot());
    106     }
    107 
    108     @Test
    109     public void testSetVisible() throws Throwable {
    110         assertTrue(mAnimationDrawable.isVisible());
    111         mActivityRule.runOnUiThread(mAnimationDrawable::start);
    112         assertTrue(mAnimationDrawable.isRunning());
    113         assertSame(mAnimationDrawable.getFrame(FIRST_FRAME_INDEX), mAnimationDrawable.getCurrent());
    114 
    115         pollingCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
    116 
    117         mActivityRule.runOnUiThread(() -> assertTrue(mAnimationDrawable.setVisible(false, false)));
    118         assertFalse(mAnimationDrawable.isVisible());
    119         assertFalse(mAnimationDrawable.isRunning());
    120         verifyStoppedAnimation(SECOND_FRAME_INDEX, SECOND_FRAME_DURATION);
    121 
    122         // restart animation
    123         mActivityRule.runOnUiThread(() -> assertTrue(mAnimationDrawable.setVisible(true, true)));
    124         assertTrue(mAnimationDrawable.isVisible());
    125         assertTrue(mAnimationDrawable.isRunning());
    126         pollingCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
    127     }
    128 
    129     @Test
    130     public void testStart() throws Throwable {
    131         // animation should play repeat if do not stop it.
    132         assertFalse(mAnimationDrawable.isOneShot());
    133         assertFalse(mAnimationDrawable.isRunning());
    134         mActivityRule.runOnUiThread(mAnimationDrawable::start);
    135 
    136         assertTrue(mAnimationDrawable.isRunning());
    137         assertSame(mAnimationDrawable.getFrame(FIRST_FRAME_INDEX),
    138                 mAnimationDrawable.getCurrent());
    139         pollingCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
    140 
    141         mActivityRule.runOnUiThread(mAnimationDrawable::start);
    142         pollingCheckDrawable(THIRD_FRAME_INDEX, SECOND_FRAME_DURATION);
    143 
    144         mActivityRule.runOnUiThread(mAnimationDrawable::stop);
    145         assertFalse(mAnimationDrawable.isRunning());
    146         verifyStoppedAnimation(THIRD_FRAME_INDEX, THIRD_FRAME_DURATION);
    147 
    148         // This method has no effect if the animation is not running.
    149         mActivityRule.runOnUiThread(mAnimationDrawable::stop);
    150         assertFalse(mAnimationDrawable.isRunning());
    151         verifyStoppedAnimation(THIRD_FRAME_INDEX, THIRD_FRAME_DURATION);
    152     }
    153 
    154     @Test
    155     public void testRun() throws Throwable {
    156         assertFalse(mAnimationDrawable.isRunning());
    157         mActivityRule.runOnUiThread(mAnimationDrawable::run);
    158 
    159         assertTrue(mAnimationDrawable.isRunning());
    160         pollingCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
    161 
    162         mActivityRule.runOnUiThread(() -> mAnimationDrawable.unscheduleSelf(mAnimationDrawable));
    163     }
    164 
    165     @Test
    166     public void testUnscheduleSelf() throws Throwable {
    167         assertFalse(mAnimationDrawable.isRunning());
    168         mActivityRule.runOnUiThread(mAnimationDrawable::start);
    169 
    170         assertTrue(mAnimationDrawable.isRunning());
    171         pollingCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
    172 
    173         mActivityRule.runOnUiThread(() -> mAnimationDrawable.unscheduleSelf(mAnimationDrawable));
    174         assertFalse(mAnimationDrawable.isRunning());
    175         verifyStoppedAnimation(SECOND_FRAME_INDEX, SECOND_FRAME_DURATION);
    176     }
    177 
    178     @Test
    179     public void testGetNumberOfFrames() {
    180         AnimationDrawable mutated = (AnimationDrawable) mAnimationDrawable.mutate();
    181         assertEquals(FRAMES_COUNT, mutated.getNumberOfFrames());
    182 
    183         Drawable frame = mResources.getDrawable(R.drawable.failed);
    184         mAnimationDrawable.addFrame(frame, 2000);
    185         assertEquals(FRAMES_COUNT + 1, mutated.getNumberOfFrames());
    186 
    187         // add same frame with same duration
    188         mAnimationDrawable.addFrame(frame, 2000);
    189         assertEquals(FRAMES_COUNT + 2, mutated.getNumberOfFrames());
    190 
    191         try {
    192             mAnimationDrawable.addFrame(null, 1000);
    193             fail("Should throw NullPointerException if param frame is null.");
    194         } catch (NullPointerException e) {
    195             // expected
    196         }
    197     }
    198 
    199     @Test
    200     public void testGetFrame() {
    201         Drawable frame = mAnimationDrawable.getFrame(FIRST_FRAME_INDEX);
    202         Drawable drawable = mResources.getDrawable(R.drawable.testimage);
    203         assertEquals(drawable.getIntrinsicWidth(), frame.getIntrinsicWidth());
    204         assertEquals(drawable.getIntrinsicHeight(), frame.getIntrinsicHeight());
    205 
    206         frame = mAnimationDrawable.getFrame(SECOND_FRAME_INDEX);
    207         drawable = mResources.getDrawable(R.drawable.pass);
    208         assertEquals(drawable.getIntrinsicWidth(), frame.getIntrinsicWidth());
    209         assertEquals(drawable.getIntrinsicHeight(), frame.getIntrinsicHeight());
    210 
    211         frame = mAnimationDrawable.getFrame(THIRD_FRAME_INDEX);
    212         drawable = mResources.getDrawable(R.drawable.scenery);
    213         assertEquals(drawable.getIntrinsicWidth(), frame.getIntrinsicWidth());
    214         assertEquals(drawable.getIntrinsicHeight(), frame.getIntrinsicHeight());
    215 
    216         assertNull(mAnimationDrawable.getFrame(THIRD_FRAME_INDEX + 1));
    217     }
    218 
    219     @Test(expected=ArrayIndexOutOfBoundsException.class)
    220     public void testGetFrameTooLow() {
    221         mAnimationDrawable.getFrame(-1);
    222     }
    223 
    224     @Test(expected=ArrayIndexOutOfBoundsException.class)
    225     public void testGetFrameTooHigh() {
    226         mAnimationDrawable.getFrame(10);
    227     }
    228 
    229     @Test
    230     public void testGetDuration() {
    231         assertEquals(FIRST_FRAME_DURATION, mAnimationDrawable.getDuration(FIRST_FRAME_INDEX));
    232         assertEquals(SECOND_FRAME_DURATION, mAnimationDrawable.getDuration(SECOND_FRAME_INDEX));
    233         assertEquals(THIRD_FRAME_DURATION, mAnimationDrawable.getDuration(THIRD_FRAME_INDEX));
    234         assertEquals(0, mAnimationDrawable.getDuration(THIRD_FRAME_INDEX + 1));
    235     }
    236 
    237     @Test(expected=ArrayIndexOutOfBoundsException.class)
    238     public void testGetDurationTooLow() {
    239         mAnimationDrawable.getDuration(-1);
    240     }
    241 
    242     @Test(expected=ArrayIndexOutOfBoundsException.class)
    243     public void testGetDurationTooHigh() {
    244         mAnimationDrawable.getDuration(10);
    245     }
    246 
    247     @Test
    248     public void testAccessOneShot() throws Throwable {
    249         // animation should play repeat if do not stop it.
    250         assertFalse(mAnimationDrawable.isOneShot());
    251         mActivityRule.runOnUiThread(mAnimationDrawable::start);
    252         pollingCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
    253         pollingCheckDrawable(THIRD_FRAME_INDEX, SECOND_FRAME_DURATION);
    254         // begin to repeat
    255         pollingCheckDrawable(FIRST_FRAME_INDEX, THIRD_FRAME_DURATION);
    256 
    257         mActivityRule.runOnUiThread(() -> {
    258             mAnimationDrawable.stop();
    259             mAnimationDrawable.setOneShot(true);
    260             assertTrue(mAnimationDrawable.isOneShot());
    261             mAnimationDrawable.start();
    262         });
    263         pollingCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
    264         pollingCheckDrawable(THIRD_FRAME_INDEX, SECOND_FRAME_DURATION);
    265         // do not repeat
    266         verifyStoppedAnimation(THIRD_FRAME_INDEX, THIRD_FRAME_DURATION);
    267         // Set visible to false and restart to false
    268         mActivityRule.runOnUiThread(() -> mAnimationDrawable.setVisible(false, false));
    269         // Check that animation drawable stays on the same frame
    270         verifyStoppedAnimation(THIRD_FRAME_INDEX, THIRD_FRAME_DURATION);
    271 
    272         // Set visible to true and restart to false
    273         mActivityRule.runOnUiThread(() -> mAnimationDrawable.setVisible(true, false));
    274         // Check that animation drawable stays on the same frame
    275         verifyStoppedAnimation(THIRD_FRAME_INDEX, THIRD_FRAME_DURATION);
    276     }
    277 
    278     @Test
    279     public void testInflateCorrect() throws XmlPullParserException, IOException {
    280         XmlResourceParser parser = getResourceParser(R.xml.anim_list_correct);
    281         AnimationDrawable dr = new AnimationDrawable();
    282         dr.inflate(mResources, parser, Xml.asAttributeSet(parser));
    283         // android:visible="false"
    284         assertFalse(dr.isVisible());
    285         // android:oneShot="true"
    286         assertTrue(dr.isOneShot());
    287         // android:variablePadding="true"
    288         DrawableContainerState state =
    289                 (DrawableContainerState) dr.getConstantState();
    290         assertNull(state.getConstantPadding());
    291         assertEquals(2, dr.getNumberOfFrames());
    292         assertEquals(2000, dr.getDuration(0));
    293         assertEquals(1000, dr.getDuration(1));
    294         assertSame(dr.getFrame(0), dr.getCurrent());
    295     }
    296 
    297     @Test
    298     public void testInflateMissingDrawable() throws XmlPullParserException, IOException {
    299         XmlResourceParser parser = getResourceParser(R.xml.anim_list_missing_item_drawable);
    300         AnimationDrawable dr = new AnimationDrawable();
    301         try {
    302             dr.inflate(mResources, parser, Xml.asAttributeSet(parser));
    303             fail("Should throw XmlPullParserException if drawable of item is missing");
    304         } catch (XmlPullParserException e) {
    305             // expected
    306         }
    307     }
    308 
    309     @Test(expected=NullPointerException.class)
    310     public void testInflateNullResources() throws XmlPullParserException, IOException {
    311         XmlResourceParser parser = getResourceParser(R.drawable.animationdrawable);
    312         AnimationDrawable dr = new AnimationDrawable();
    313         // Should throw NullPointerException if resource is null
    314         dr.inflate(null, parser, Xml.asAttributeSet(parser));
    315     }
    316 
    317     @Test(expected=NullPointerException.class)
    318     public void testInflateNullXmlPullParser() throws XmlPullParserException, IOException {
    319         XmlResourceParser parser = getResourceParser(R.drawable.animationdrawable);
    320         AnimationDrawable dr = new AnimationDrawable();
    321         // Should throw NullPointerException if parser is null
    322         dr.inflate(mResources, null, Xml.asAttributeSet(parser));
    323     }
    324 
    325     @Test(expected=NullPointerException.class)
    326     public void testInflateNullAttributeSet() throws XmlPullParserException, IOException {
    327         XmlResourceParser parser = getResourceParser(R.drawable.animationdrawable);
    328         AnimationDrawable dr = new AnimationDrawable();
    329         // Should throw NullPointerException if AttributeSet is null
    330         dr.inflate(mResources, parser, null);
    331     }
    332 
    333     @Test
    334     public void testMutate() {
    335         AnimationDrawable d1 = (AnimationDrawable) mResources
    336                 .getDrawable(R.drawable.animationdrawable);
    337         // multiple instances inflated from the same resource do not share the state
    338         // simply call mutate to make sure it does not throw an exception
    339         d1.mutate();
    340     }
    341 
    342     private XmlResourceParser getResourceParser(int resId) throws XmlPullParserException,
    343             IOException {
    344         XmlResourceParser parser = mResources.getXml(resId);
    345         int type;
    346         while ((type = parser.next()) != XmlPullParser.START_TAG
    347                 && type != XmlPullParser.END_DOCUMENT) {
    348             // Empty loop
    349         }
    350         return parser;
    351     }
    352 
    353     /**
    354      * Polling check specific frame should be current one in timeout.
    355      * @param index - expected index of frame.
    356      * @param timeout - timeout.
    357      */
    358     private void pollingCheckDrawable(final int index, long timeout) {
    359         final Drawable expected = mAnimationDrawable.getFrame(index);
    360         PollingCheck.waitFor(timeout + TOLERANCE,
    361                 () -> mAnimationDrawable.getCurrent().equals(expected));
    362     }
    363 
    364     /**
    365      * Assert animation had been stopped. It will sleep duration + TOLERANCE milliseconds and
    366      * then make sure current frame had not been changed.
    367      * @param index - index of current frame.
    368      * @param duration - duration of current frame.
    369      */
    370     private void verifyStoppedAnimation(int index, long duration) throws InterruptedException {
    371         Thread.sleep(duration + TOLERANCE);
    372         assertSame(mAnimationDrawable.getFrame(index), mAnimationDrawable.getCurrent());
    373     }
    374 }
    375