Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2014 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 junit.framework.Assert.fail;
     20 import static junit.framework.TestCase.assertFalse;
     21 import static junit.framework.TestCase.assertTrue;
     22 
     23 import static org.junit.Assert.assertEquals;
     24 import static org.junit.Assert.assertNotNull;
     25 
     26 import android.app.Activity;
     27 import android.content.res.Resources;
     28 import android.graphics.Bitmap;
     29 import android.graphics.Canvas;
     30 import android.graphics.Color;
     31 import android.graphics.PixelFormat;
     32 import android.graphics.PorterDuff;
     33 import android.graphics.PorterDuffColorFilter;
     34 import android.graphics.cts.R;
     35 import android.graphics.drawable.Animatable2;
     36 import android.graphics.drawable.AnimatedVectorDrawable;
     37 import android.graphics.drawable.Drawable;
     38 import android.graphics.drawable.Drawable.ConstantState;
     39 import android.support.test.filters.LargeTest;
     40 import android.support.test.filters.SmallTest;
     41 import android.support.test.rule.ActivityTestRule;
     42 import android.support.test.runner.AndroidJUnit4;
     43 import android.util.AttributeSet;
     44 import android.util.Xml;
     45 import android.widget.ImageView;
     46 
     47 import org.junit.Before;
     48 import org.junit.Rule;
     49 import org.junit.Test;
     50 import org.junit.runner.RunWith;
     51 import org.xmlpull.v1.XmlPullParser;
     52 import org.xmlpull.v1.XmlPullParserException;
     53 
     54 @LargeTest
     55 @RunWith(AndroidJUnit4.class)
     56 public class AnimatedVectorDrawableTest {
     57     private static final int IMAGE_WIDTH = 64;
     58     private static final int IMAGE_HEIGHT = 64;
     59     private static final long MAX_TIMEOUT_MS = 1000;
     60     private static final int MS_TO_NS = 1000000;
     61 
     62     @Rule
     63     public ActivityTestRule<DrawableStubActivity> mActivityRule =
     64             new ActivityTestRule<DrawableStubActivity>(DrawableStubActivity.class);
     65     private Activity mActivity;
     66     private Resources mResources;
     67     private static final boolean DBG_DUMP_PNG = false;
     68     private final int mResId = R.drawable.animation_vector_drawable_grouping_1;
     69     private final int mLayoutId = R.layout.animated_vector_drawable_source;
     70     private final int mImageViewId = R.id.avd_view;
     71 
     72     @Before
     73     public void setup() {
     74         mActivity = mActivityRule.getActivity();
     75         mResources = mActivity.getResources();
     76     }
     77 
     78     @SmallTest
     79     @Test
     80     public void testInflate() throws Exception {
     81         // Setup AnimatedVectorDrawable from xml file
     82         XmlPullParser parser = mResources.getXml(mResId);
     83         AttributeSet attrs = Xml.asAttributeSet(parser);
     84 
     85         int type;
     86         while ((type=parser.next()) != XmlPullParser.START_TAG &&
     87                 type != XmlPullParser.END_DOCUMENT) {
     88             // Empty loop
     89         }
     90 
     91         if (type != XmlPullParser.START_TAG) {
     92             throw new XmlPullParserException("No start tag found");
     93         }
     94         Bitmap bitmap = Bitmap.createBitmap(IMAGE_WIDTH, IMAGE_HEIGHT, Bitmap.Config.ARGB_8888);
     95         Canvas canvas = new Canvas(bitmap);
     96         AnimatedVectorDrawable drawable = new AnimatedVectorDrawable();
     97         drawable.inflate(mResources, parser, attrs);
     98         drawable.setBounds(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
     99         bitmap.eraseColor(0);
    100         drawable.draw(canvas);
    101         int sunColor = bitmap.getPixel(IMAGE_WIDTH / 2, IMAGE_HEIGHT / 2);
    102         int earthColor = bitmap.getPixel(IMAGE_WIDTH * 3 / 4 + 2, IMAGE_HEIGHT / 2);
    103         assertTrue(sunColor == 0xFFFF8000);
    104         assertTrue(earthColor == 0xFF5656EA);
    105 
    106         if (DBG_DUMP_PNG) {
    107             DrawableTestUtils.saveAutoNamedVectorDrawableIntoPNG(mActivity, bitmap, mResId, null);
    108         }
    109     }
    110 
    111     @Test
    112     public void testGetChangingConfigurations() {
    113         AnimatedVectorDrawable avd = new AnimatedVectorDrawable();
    114         ConstantState constantState = avd.getConstantState();
    115 
    116         // default
    117         assertEquals(0, constantState.getChangingConfigurations());
    118         assertEquals(0, avd.getChangingConfigurations());
    119 
    120         // change the drawable's configuration does not affect the state's configuration
    121         avd.setChangingConfigurations(0xff);
    122         assertEquals(0xff, avd.getChangingConfigurations());
    123         assertEquals(0, constantState.getChangingConfigurations());
    124 
    125         // the state's configuration get refreshed
    126         constantState = avd.getConstantState();
    127         assertEquals(0xff,  constantState.getChangingConfigurations());
    128 
    129         // set a new configuration to drawable
    130         avd.setChangingConfigurations(0xff00);
    131         assertEquals(0xff,  constantState.getChangingConfigurations());
    132         assertEquals(0xffff,  avd.getChangingConfigurations());
    133     }
    134 
    135     @Test
    136     public void testGetConstantState() {
    137         AnimatedVectorDrawable AnimatedVectorDrawable = new AnimatedVectorDrawable();
    138         ConstantState constantState = AnimatedVectorDrawable.getConstantState();
    139         assertNotNull(constantState);
    140         assertEquals(0, constantState.getChangingConfigurations());
    141 
    142         AnimatedVectorDrawable.setChangingConfigurations(1);
    143         constantState = AnimatedVectorDrawable.getConstantState();
    144         assertNotNull(constantState);
    145         assertEquals(1, constantState.getChangingConfigurations());
    146     }
    147 
    148     @SmallTest
    149     @Test
    150     public void testMutate() {
    151         AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
    152         AnimatedVectorDrawable d2 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
    153         AnimatedVectorDrawable d3 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
    154         int restoreAlpha = d1.getAlpha();
    155 
    156         try {
    157             int originalAlpha = d2.getAlpha();
    158             int newAlpha = (originalAlpha + 1) % 255;
    159 
    160             // AVD is different than VectorDrawable. Every instance of it is a deep copy
    161             // of the VectorDrawable.
    162             // So every setAlpha operation will happen only to that specific object.
    163             d1.setAlpha(newAlpha);
    164             assertEquals(newAlpha, d1.getAlpha());
    165             assertEquals(originalAlpha, d2.getAlpha());
    166             assertEquals(originalAlpha, d3.getAlpha());
    167 
    168             d1.mutate();
    169             d1.setAlpha(0x40);
    170             assertEquals(0x40, d1.getAlpha());
    171             assertEquals(originalAlpha, d2.getAlpha());
    172             assertEquals(originalAlpha, d3.getAlpha());
    173 
    174             d2.setAlpha(0x20);
    175             assertEquals(0x40, d1.getAlpha());
    176             assertEquals(0x20, d2.getAlpha());
    177             assertEquals(originalAlpha, d3.getAlpha());
    178         } finally {
    179             mResources.getDrawable(mResId).setAlpha(restoreAlpha);
    180         }
    181     }
    182 
    183     @SmallTest
    184     @Test
    185     public void testGetOpacity() {
    186         AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
    187         assertEquals("Default is translucent", PixelFormat.TRANSLUCENT, d1.getOpacity());
    188         d1.setAlpha(0);
    189         assertEquals("Still translucent", PixelFormat.TRANSLUCENT, d1.getOpacity());
    190     }
    191 
    192     @SmallTest
    193     @Test
    194     public void testColorFilter() {
    195         PorterDuffColorFilter filter = new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_IN);
    196         AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
    197         d1.setColorFilter(filter);
    198 
    199         assertEquals(filter, d1.getColorFilter());
    200     }
    201 
    202     @Test
    203     public void testReset() throws Throwable {
    204         final Animatable2Callback callback = new Animatable2Callback();
    205         final AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
    206         // The AVD has a duration as 100ms.
    207         mActivityRule.runOnUiThread(() -> {
    208             d1.registerAnimationCallback(callback);
    209             d1.start();
    210             d1.reset();
    211         });
    212         waitForAVDStop(callback, MAX_TIMEOUT_MS);
    213         assertFalse(d1.isRunning());
    214 
    215     }
    216 
    217     @Test
    218     public void testStop() throws Throwable {
    219         final Animatable2Callback callback = new Animatable2Callback();
    220         final AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
    221         // The AVD has a duration as 100ms.
    222         mActivityRule.runOnUiThread(() -> {
    223             d1.registerAnimationCallback(callback);
    224             d1.start();
    225             d1.stop();
    226         });
    227         waitForAVDStop(callback, MAX_TIMEOUT_MS);
    228         assertFalse(d1.isRunning());
    229     }
    230 
    231     @Test
    232     public void testAddCallbackBeforeStart() throws Throwable {
    233         final Animatable2Callback callback = new Animatable2Callback();
    234         // The AVD has a duration as 100ms.
    235         mActivityRule.runOnUiThread(() -> {
    236             mActivity.setContentView(mLayoutId);
    237             ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
    238             AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
    239             d1.registerAnimationCallback(callback);
    240             d1.start();
    241         });
    242         callback.waitForStart();
    243         waitForAVDStop(callback, MAX_TIMEOUT_MS);
    244         callback.assertStarted(true);
    245         callback.assertEnded(true);
    246     }
    247 
    248     @Test
    249     public void testAddCallbackAfterTrigger() throws Throwable {
    250         final Animatable2Callback callback = new Animatable2Callback();
    251         // The AVD has a duration as 100ms.
    252         mActivityRule.runOnUiThread(() -> {
    253             mActivity.setContentView(mLayoutId);
    254             ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
    255             AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
    256             // This reset call can enforce the AnimatorSet is setup properly in AVD, when
    257             // running on UI thread.
    258             d1.reset();
    259             d1.registerAnimationCallback(callback);
    260             d1.start();
    261         });
    262         callback.waitForStart();
    263         waitForAVDStop(callback, MAX_TIMEOUT_MS);
    264 
    265         callback.assertStarted(true);
    266         callback.assertEnded(true);
    267     }
    268 
    269     @Test
    270     public void testAddCallbackAfterStart() throws Throwable {
    271         final Animatable2Callback callback = new Animatable2Callback();
    272         // The AVD has a duration as 100ms.
    273         mActivityRule.runOnUiThread(() -> {
    274             mActivity.setContentView(mLayoutId);
    275             ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
    276             AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
    277             d1.start();
    278             d1.registerAnimationCallback(callback);
    279         });
    280         callback.waitForStart();
    281 
    282         waitForAVDStop(callback, MAX_TIMEOUT_MS);
    283         // Whether or not the callback.start is true could vary when running on Render Thread.
    284         // Therefore, we don't make assertion here. The most useful flag is the callback.mEnded.
    285         callback.assertEnded(true);
    286         callback.assertAVDRuntime(0, 400 * MS_TO_NS); // 4 times of the duration of the AVD.
    287     }
    288 
    289     @Test
    290     public void testRemoveCallback() throws Throwable {
    291         final Animatable2Callback callback = new Animatable2Callback();
    292         // The AVD has a duration as 100ms.
    293         mActivityRule.runOnUiThread(() -> {
    294             mActivity.setContentView(mLayoutId);
    295             ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
    296             AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
    297             d1.registerAnimationCallback(callback);
    298             assertTrue(d1.unregisterAnimationCallback(callback));
    299             d1.start();
    300         });
    301         callback.waitForStart();
    302 
    303         waitForAVDStop(callback, MAX_TIMEOUT_MS);
    304         callback.assertStarted(false);
    305         callback.assertEnded(false);
    306     }
    307 
    308     @Test
    309     public void testClearCallback() throws Throwable {
    310         final Animatable2Callback callback = new Animatable2Callback();
    311 
    312         // The AVD has a duration as 100ms.
    313         mActivityRule.runOnUiThread(() -> {
    314             mActivity.setContentView(mLayoutId);
    315             ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
    316             AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
    317             d1.registerAnimationCallback(callback);
    318             d1.clearAnimationCallbacks();
    319             d1.start();
    320         });
    321         callback.waitForStart();
    322 
    323         waitForAVDStop(callback, MAX_TIMEOUT_MS);
    324         callback.assertStarted(false);
    325         callback.assertEnded(false);
    326     }
    327 
    328     // The time out is expected when the listener is removed successfully.
    329     // Such that we don't get the end event.
    330     static void waitForAVDStop(Animatable2Callback callback, long timeout) {
    331         try {
    332             callback.waitForEnd(timeout);
    333         } catch (InterruptedException e) {
    334             e.printStackTrace();
    335             fail("We should not see the AVD run this long time!");
    336         }
    337     }
    338 }
    339