Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2018 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.assertNotEquals;
     22 import static org.junit.Assert.assertNotNull;
     23 import static org.junit.Assert.assertTrue;
     24 import static org.junit.Assert.fail;
     25 
     26 import android.app.Activity;
     27 import android.content.ContentResolver;
     28 import android.content.res.Resources;
     29 import android.graphics.Bitmap;
     30 import android.graphics.Canvas;
     31 import android.graphics.Color;
     32 import android.graphics.ColorFilter;
     33 import android.graphics.ImageDecoder;
     34 import android.graphics.LightingColorFilter;
     35 import android.graphics.Paint;
     36 import android.graphics.PixelFormat;
     37 import android.graphics.Rect;
     38 import android.graphics.cts.R;
     39 import android.graphics.drawable.AnimatedImageDrawable;
     40 import android.graphics.drawable.Drawable;
     41 import android.net.Uri;
     42 import android.support.test.InstrumentationRegistry;
     43 import android.support.test.rule.ActivityTestRule;
     44 import android.support.test.runner.AndroidJUnit4;
     45 import android.view.View;
     46 import android.widget.ImageView;
     47 
     48 import com.android.compatibility.common.util.BitmapUtils;
     49 
     50 import org.junit.Before;
     51 import org.junit.Rule;
     52 import org.junit.Test;
     53 import org.junit.runner.RunWith;
     54 import org.xmlpull.v1.XmlPullParser;
     55 import org.xmlpull.v1.XmlPullParserException;
     56 
     57 import java.io.IOException;
     58 import java.util.function.BiFunction;
     59 
     60 @RunWith(AndroidJUnit4.class)
     61 public class AnimatedImageDrawableTest {
     62     private Resources mRes;
     63     private ContentResolver mContentResolver;
     64 
     65     private static final int RES_ID = R.drawable.animated;
     66     private static final int WIDTH = 278;
     67     private static final int HEIGHT = 183;
     68     private static final int NUM_FRAMES = 4;
     69     private static final int FRAME_DURATION = 250; // in milliseconds
     70     private static final int DURATION = NUM_FRAMES * FRAME_DURATION;
     71     private static final int LAYOUT = R.layout.animated_image_layout;
     72     private static final int IMAGE_ID = R.id.animated_image;
     73     @Rule
     74     public ActivityTestRule<DrawableStubActivity> mActivityRule =
     75             new ActivityTestRule<DrawableStubActivity>(DrawableStubActivity.class);
     76     private Activity mActivity;
     77 
     78     private Uri getAsResourceUri(int resId) {
     79         return new Uri.Builder()
     80             .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
     81             .authority(mRes.getResourcePackageName(resId))
     82             .appendPath(mRes.getResourceTypeName(resId))
     83             .appendPath(mRes.getResourceEntryName(resId))
     84             .build();
     85     }
     86 
     87     @Before
     88     public void setup() {
     89         mRes = InstrumentationRegistry.getTargetContext().getResources();
     90         mContentResolver = InstrumentationRegistry.getTargetContext().getContentResolver();
     91         mActivity = mActivityRule.getActivity();
     92     }
     93 
     94     @Test
     95     public void testEmptyConstructor() {
     96         new AnimatedImageDrawable();
     97     }
     98 
     99     @Test
    100     public void testMutate() {
    101         AnimatedImageDrawable aid1 = (AnimatedImageDrawable) mRes.getDrawable(R.drawable.animated);
    102         AnimatedImageDrawable aid2 = (AnimatedImageDrawable) mRes.getDrawable(R.drawable.animated);
    103 
    104         final int originalAlpha = aid1.getAlpha();
    105         assertEquals(255, originalAlpha);
    106         assertEquals(255, aid2.getAlpha());
    107 
    108         try {
    109             aid1.mutate();
    110             aid1.setAlpha(100);
    111             assertEquals(originalAlpha, aid2.getAlpha());
    112         } finally {
    113             mRes.getDrawable(R.drawable.animated).setAlpha(originalAlpha);
    114         }
    115     }
    116 
    117     private AnimatedImageDrawable createFromImageDecoder(int resId) {
    118         Uri uri = null;
    119         try {
    120             uri = getAsResourceUri(resId);
    121             ImageDecoder.Source source = ImageDecoder.createSource(mContentResolver, uri);
    122             Drawable drawable = ImageDecoder.decodeDrawable(source);
    123             assertTrue(drawable instanceof AnimatedImageDrawable);
    124             return (AnimatedImageDrawable) drawable;
    125         } catch (IOException e) {
    126             fail("failed to create image from " + uri);
    127             return null;
    128         }
    129     }
    130 
    131     @Test
    132     public void testDecodeAnimatedImageDrawable() {
    133         Drawable drawable = createFromImageDecoder(RES_ID);
    134         assertEquals(WIDTH,  drawable.getIntrinsicWidth());
    135         assertEquals(HEIGHT, drawable.getIntrinsicHeight());
    136     }
    137 
    138     private static class Callback extends Animatable2Callback {
    139         private final Drawable mDrawable;
    140 
    141         public Callback(Drawable d) {
    142             mDrawable = d;
    143         }
    144 
    145         @Override
    146         public void onAnimationStart(Drawable drawable) {
    147             assertNotNull(drawable);
    148             assertEquals(mDrawable, drawable);
    149             super.onAnimationStart(drawable);
    150         }
    151 
    152         @Override
    153         public void onAnimationEnd(Drawable drawable) {
    154             assertNotNull(drawable);
    155             assertEquals(mDrawable, drawable);
    156             super.onAnimationEnd(drawable);
    157         }
    158     };
    159 
    160     @Test(expected=IllegalStateException.class)
    161     public void testRegisterWithoutLooper() {
    162         AnimatedImageDrawable drawable = createFromImageDecoder(R.drawable.animated);
    163 
    164         // registerAnimationCallback must be run on a thread with a Looper,
    165         // which the test thread does not have.
    166         Callback cb = new Callback(drawable);
    167         drawable.registerAnimationCallback(cb);
    168     }
    169 
    170     @Test
    171     public void testRegisterCallback() throws Throwable {
    172         AnimatedImageDrawable drawable = createFromImageDecoder(R.drawable.animated);
    173 
    174         mActivityRule.runOnUiThread(() -> {
    175             // Register a callback.
    176             Callback cb = new Callback(drawable);
    177             drawable.registerAnimationCallback(cb);
    178             assertTrue(drawable.unregisterAnimationCallback(cb));
    179 
    180             // Now that it has been removed, it cannot be removed again.
    181             assertFalse(drawable.unregisterAnimationCallback(cb));
    182         });
    183     }
    184 
    185     @Test
    186     public void testClearCallbacks() throws Throwable {
    187         AnimatedImageDrawable drawable = createFromImageDecoder(R.drawable.animated);
    188 
    189         Callback[] callbacks = new Callback[] {
    190             new Callback(drawable),
    191             new Callback(drawable),
    192             new Callback(drawable),
    193             new Callback(drawable),
    194             new Callback(drawable),
    195             new Callback(drawable),
    196             new Callback(drawable),
    197             new Callback(drawable),
    198         };
    199 
    200         mActivityRule.runOnUiThread(() -> {
    201             for (Callback cb : callbacks) {
    202                 drawable.registerAnimationCallback(cb);
    203             }
    204         });
    205 
    206         drawable.clearAnimationCallbacks();
    207 
    208         for (Callback cb : callbacks) {
    209             // It has already been removed.
    210             assertFalse(drawable.unregisterAnimationCallback(cb));
    211         }
    212     }
    213 
    214     /**
    215      *  Helper for attaching drawable to the view system.
    216      *
    217      *  Necessary for the drawable to animate.
    218      *
    219      *  Must be called from UI thread.
    220      */
    221     private void setContentView(AnimatedImageDrawable drawable) {
    222         mActivity.setContentView(LAYOUT);
    223         ImageView imageView = (ImageView) mActivity.findViewById(IMAGE_ID);
    224         imageView.setImageDrawable(drawable);
    225     }
    226 
    227     @Test
    228     public void testUnregisterCallback() throws Throwable {
    229         AnimatedImageDrawable drawable = createFromImageDecoder(R.drawable.animated);
    230 
    231         Callback cb = new Callback(drawable);
    232         mActivityRule.runOnUiThread(() -> {
    233             setContentView(drawable);
    234 
    235             drawable.registerAnimationCallback(cb);
    236             assertTrue(drawable.unregisterAnimationCallback(cb));
    237             drawable.setRepeatCount(0);
    238             drawable.start();
    239         });
    240 
    241         cb.waitForStart();
    242         cb.assertStarted(false);
    243 
    244         cb.waitForEnd(DURATION * 2);
    245         cb.assertEnded(false);
    246     }
    247 
    248     @Test
    249     public void testLifeCycle() throws Throwable {
    250         AnimatedImageDrawable drawable = createFromImageDecoder(RES_ID);
    251 
    252         // Only run the animation one time.
    253         drawable.setRepeatCount(0);
    254 
    255         Callback cb = new Callback(drawable);
    256         mActivityRule.runOnUiThread(() -> {
    257             setContentView(drawable);
    258 
    259             drawable.registerAnimationCallback(cb);
    260         });
    261 
    262         assertFalse(drawable.isRunning());
    263         cb.assertStarted(false);
    264         cb.assertEnded(false);
    265 
    266         mActivityRule.runOnUiThread(() -> {
    267             drawable.start();
    268             assertTrue(drawable.isRunning());
    269         });
    270         cb.waitForStart();
    271         cb.assertStarted(true);
    272 
    273         // Extra time, to wait for the message to post.
    274         cb.waitForEnd(DURATION * 3);
    275         cb.assertEnded(true);
    276         assertFalse(drawable.isRunning());
    277     }
    278 
    279     @Test
    280     public void testLifeCycleSoftware() throws Throwable {
    281         AnimatedImageDrawable drawable = createFromImageDecoder(RES_ID);
    282 
    283         Bitmap bm = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
    284                 Bitmap.Config.ARGB_8888);
    285         Canvas canvas = new Canvas(bm);
    286 
    287         Callback cb = new Callback(drawable);
    288         mActivityRule.runOnUiThread(() -> {
    289             drawable.registerAnimationCallback(cb);
    290             drawable.draw(canvas);
    291         });
    292 
    293         assertFalse(drawable.isRunning());
    294         cb.assertStarted(false);
    295         cb.assertEnded(false);
    296 
    297         mActivityRule.runOnUiThread(() -> {
    298             drawable.start();
    299             assertTrue(drawable.isRunning());
    300             drawable.draw(canvas);
    301         });
    302         cb.waitForStart();
    303         cb.assertStarted(true);
    304 
    305         // Only run the animation one time.
    306         drawable.setRepeatCount(0);
    307 
    308         // The drawable will prevent skipping frames, so we actually have to
    309         // draw each frame. (Start with 1, since we already drew frame 0.)
    310         for (int i = 1; i < NUM_FRAMES; i++) {
    311             cb.waitForEnd(FRAME_DURATION);
    312             cb.assertEnded(false);
    313             mActivityRule.runOnUiThread(() -> {
    314                 assertTrue(drawable.isRunning());
    315                 drawable.draw(canvas);
    316             });
    317         }
    318 
    319         cb.waitForEnd(FRAME_DURATION);
    320         assertFalse(drawable.isRunning());
    321         cb.assertEnded(true);
    322     }
    323 
    324     @Test
    325     public void testAddCallbackAfterStart() throws Throwable {
    326         AnimatedImageDrawable drawable = createFromImageDecoder(RES_ID);
    327         Callback cb = new Callback(drawable);
    328         mActivityRule.runOnUiThread(() -> {
    329             setContentView(drawable);
    330 
    331             drawable.setRepeatCount(0);
    332             drawable.start();
    333             drawable.registerAnimationCallback(cb);
    334         });
    335 
    336         // Add extra duration to wait for the message posted by the end of the
    337         // animation. This should help fix flakiness.
    338         cb.waitForEnd(DURATION * 3);
    339         cb.assertEnded(true);
    340     }
    341 
    342     @Test
    343     public void testStop() throws Throwable {
    344         AnimatedImageDrawable drawable = createFromImageDecoder(RES_ID);
    345         Callback cb = new Callback(drawable);
    346         mActivityRule.runOnUiThread(() -> {
    347             setContentView(drawable);
    348 
    349             drawable.registerAnimationCallback(cb);
    350 
    351             drawable.start();
    352             assertTrue(drawable.isRunning());
    353 
    354             drawable.stop();
    355             assertFalse(drawable.isRunning());
    356         });
    357 
    358         // This duration may be overkill, but we need to wait for the message
    359         // to post. Increasing it should help with flakiness on bots.
    360         cb.waitForEnd(DURATION * 3);
    361         cb.assertStarted(true);
    362         cb.assertEnded(true);
    363     }
    364 
    365     @Test
    366     public void testRepeatCounts() throws Throwable {
    367         for (int repeatCount : new int[] { 3, 5, 7, 16 }) {
    368             AnimatedImageDrawable drawable = createFromImageDecoder(RES_ID);
    369             assertEquals(AnimatedImageDrawable.REPEAT_INFINITE, drawable.getRepeatCount());
    370 
    371             Callback cb = new Callback(drawable);
    372             mActivityRule.runOnUiThread(() -> {
    373                 setContentView(drawable);
    374 
    375                 drawable.registerAnimationCallback(cb);
    376                 drawable.setRepeatCount(repeatCount);
    377                 assertEquals(repeatCount, drawable.getRepeatCount());
    378                 drawable.start();
    379             });
    380 
    381             // The animation runs repeatCount + 1 total times.
    382             cb.waitForEnd(DURATION * repeatCount);
    383             cb.assertEnded(false);
    384 
    385             cb.waitForEnd(DURATION * 2);
    386             cb.assertEnded(true);
    387 
    388             drawable.setRepeatCount(AnimatedImageDrawable.REPEAT_INFINITE);
    389             assertEquals(AnimatedImageDrawable.REPEAT_INFINITE, drawable.getRepeatCount());
    390         }
    391     }
    392 
    393     @Test
    394     public void testRepeatCountInfinite() throws Throwable {
    395         AnimatedImageDrawable drawable = createFromImageDecoder(RES_ID);
    396         Callback cb = new Callback(drawable);
    397         mActivityRule.runOnUiThread(() -> {
    398             setContentView(drawable);
    399 
    400             drawable.registerAnimationCallback(cb);
    401             drawable.setRepeatCount(AnimatedImageDrawable.REPEAT_INFINITE);
    402             drawable.start();
    403         });
    404 
    405         // There is no way to truly test infinite, but let it run for a long
    406         // time and verify that it's still running.
    407         cb.waitForEnd(DURATION * 30);
    408         cb.assertEnded(false);
    409         assertTrue(drawable.isRunning());
    410     }
    411 
    412     @Test
    413     public void testGetOpacity() {
    414         AnimatedImageDrawable drawable = createFromImageDecoder(RES_ID);
    415         assertEquals(PixelFormat.TRANSLUCENT, drawable.getOpacity());
    416     }
    417 
    418     @Test
    419     public void testColorFilter() {
    420         AnimatedImageDrawable drawable = createFromImageDecoder(RES_ID);
    421 
    422         ColorFilter filter = new LightingColorFilter(0, Color.RED);
    423         drawable.setColorFilter(filter);
    424         assertEquals(filter, drawable.getColorFilter());
    425 
    426         Bitmap actual = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
    427                 drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    428         {
    429             Canvas canvas = new Canvas(actual);
    430             drawable.draw(canvas);
    431         }
    432 
    433         for (int i = 0; i < actual.getWidth(); ++i) {
    434             for (int j = 0; j < actual.getHeight(); ++j) {
    435                 int color = actual.getPixel(i, j);
    436                 // The LightingColorFilter does not affect the transparent pixels,
    437                 // so all pixels should either remain transparent or turn red.
    438                 if (color != Color.RED && color != Color.TRANSPARENT) {
    439                     fail("pixel at " + i + ", " + j + " does not match expected. "
    440                             + "expected: " + Color.RED + " OR " + Color.TRANSPARENT
    441                             + " actual: " + color);
    442                 }
    443             }
    444         }
    445     }
    446 
    447     @Test
    448     public void testPostProcess() {
    449         // Compare post processing a Rect in the middle of the (not-animating)
    450         // image with drawing manually. They should be exactly the same.
    451         BiFunction<Integer, Integer, Rect> rectCreator = (width, height) -> {
    452             int quarterWidth  = width  / 4;
    453             int quarterHeight = height / 4;
    454             return new Rect(quarterWidth, quarterHeight,
    455                     3 * quarterWidth, 3 * quarterHeight);
    456         };
    457 
    458         AnimatedImageDrawable drawable = createFromImageDecoder(RES_ID);
    459         Bitmap expected = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
    460                 drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    461 
    462         Paint paint = new Paint();
    463         paint.setColor(Color.RED);
    464 
    465         {
    466             Rect r = rectCreator.apply(drawable.getIntrinsicWidth(),
    467                                        drawable.getIntrinsicHeight());
    468             Canvas canvas = new Canvas(expected);
    469             drawable.draw(canvas);
    470 
    471             for (int i = r.left; i < r.right; ++i) {
    472                 for (int j = r.top; j < r.bottom; ++j) {
    473                     assertNotEquals(Color.RED, expected.getPixel(i, j));
    474                 }
    475             }
    476 
    477             canvas.drawRect(r, paint);
    478 
    479             for (int i = r.left; i < r.right; ++i) {
    480                 for (int j = r.top; j < r.bottom; ++j) {
    481                     assertEquals(Color.RED, expected.getPixel(i, j));
    482                 }
    483             }
    484         }
    485 
    486 
    487         AnimatedImageDrawable testDrawable = null;
    488         Uri uri = null;
    489         try {
    490             uri = getAsResourceUri(RES_ID);
    491             ImageDecoder.Source source = ImageDecoder.createSource(mContentResolver, uri);
    492             Drawable dr = ImageDecoder.decodeDrawable(source, (decoder, info, src) -> {
    493                 decoder.setPostProcessor((canvas) -> {
    494                     canvas.drawRect(rectCreator.apply(canvas.getWidth(),
    495                                                       canvas.getHeight()), paint);
    496                     return PixelFormat.TRANSLUCENT;
    497                 });
    498             });
    499             assertTrue(dr instanceof AnimatedImageDrawable);
    500             testDrawable = (AnimatedImageDrawable) dr;
    501         } catch (IOException e) {
    502             fail("failed to create image from " + uri);
    503         }
    504 
    505         Bitmap actual = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
    506                 drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    507 
    508         {
    509             Canvas canvas = new Canvas(actual);
    510             testDrawable.draw(canvas);
    511         }
    512 
    513         BitmapUtils.compareBitmaps(expected, actual);
    514     }
    515 
    516     @Test
    517     public void testCreateFromXml() throws XmlPullParserException, IOException {
    518         XmlPullParser parser = mRes.getXml(R.drawable.animatedimagedrawable_tag);
    519         Drawable drawable = Drawable.createFromXml(mRes, parser);
    520         assertNotNull(drawable);
    521         assertTrue(drawable instanceof AnimatedImageDrawable);
    522     }
    523 
    524     @Test
    525     public void testCreateFromXmlClass() throws XmlPullParserException, IOException {
    526         XmlPullParser parser = mRes.getXml(R.drawable.animatedimagedrawable);
    527         Drawable drawable = Drawable.createFromXml(mRes, parser);
    528         assertNotNull(drawable);
    529         assertTrue(drawable instanceof AnimatedImageDrawable);
    530     }
    531 
    532     @Test
    533     public void testCreateFromXmlClassAttribute() throws XmlPullParserException, IOException {
    534         XmlPullParser parser = mRes.getXml(R.drawable.animatedimagedrawable_class);
    535         Drawable drawable = Drawable.createFromXml(mRes, parser);
    536         assertNotNull(drawable);
    537         assertTrue(drawable instanceof AnimatedImageDrawable);
    538     }
    539 
    540     @Test(expected=XmlPullParserException.class)
    541     public void testMissingSrcInflate() throws XmlPullParserException, IOException  {
    542         XmlPullParser parser = mRes.getXml(R.drawable.animatedimagedrawable_nosrc);
    543         Drawable drawable = Drawable.createFromXml(mRes, parser);
    544     }
    545 
    546     @Test
    547     public void testAutoMirrored() {
    548         AnimatedImageDrawable drawable = createFromImageDecoder(RES_ID);
    549         assertFalse(drawable.isAutoMirrored());
    550 
    551         drawable.setAutoMirrored(true);
    552         assertTrue(drawable.isAutoMirrored());
    553 
    554         drawable.setAutoMirrored(false);
    555         assertFalse(drawable.isAutoMirrored());
    556     }
    557 
    558     @Test
    559     public void testAutoMirroredFromXml() throws XmlPullParserException, IOException {
    560         AnimatedImageDrawable drawable = parseXml(R.drawable.animatedimagedrawable_tag);
    561         assertFalse(drawable.isAutoMirrored());
    562 
    563         drawable = parseXml(R.drawable.animatedimagedrawable_automirrored);
    564         assertTrue(drawable.isAutoMirrored());
    565     }
    566 
    567     private AnimatedImageDrawable parseXml(int resId) throws XmlPullParserException, IOException {
    568         XmlPullParser parser = mRes.getXml(resId);
    569         Drawable drawable = Drawable.createFromXml(mRes, parser);
    570         assertNotNull(drawable);
    571         assertTrue(drawable instanceof AnimatedImageDrawable);
    572         return (AnimatedImageDrawable) drawable;
    573     }
    574 
    575     @Test
    576     public void testAutoStartFromXml() throws XmlPullParserException, IOException {
    577         AnimatedImageDrawable drawable = parseXml(R.drawable.animatedimagedrawable_tag);
    578         assertFalse(drawable.isRunning());
    579 
    580         drawable = parseXml(R.drawable.animatedimagedrawable_autostart_false);
    581         assertFalse(drawable.isRunning());
    582 
    583         drawable = parseXml(R.drawable.animatedimagedrawable_autostart);
    584         assertTrue(drawable.isRunning());
    585     }
    586 
    587     private void drawAndCompare(Bitmap expected, Drawable drawable) {
    588         Bitmap test = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
    589                 drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    590         Canvas canvas = new Canvas(test);
    591         drawable.draw(canvas);
    592         BitmapUtils.compareBitmaps(expected, test);
    593     }
    594 
    595     @Test
    596     public void testAutoMirroredDrawing() {
    597         AnimatedImageDrawable drawable = createFromImageDecoder(RES_ID);
    598         assertFalse(drawable.isAutoMirrored());
    599 
    600         final int width = drawable.getIntrinsicWidth();
    601         final int height = drawable.getIntrinsicHeight();
    602         Bitmap normal = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    603         {
    604             Canvas canvas = new Canvas(normal);
    605             drawable.draw(canvas);
    606         }
    607 
    608         Bitmap flipped = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    609         {
    610             Canvas canvas = new Canvas(flipped);
    611             canvas.translate(width, 0);
    612             canvas.scale(-1, 1);
    613             drawable.draw(canvas);
    614         }
    615 
    616         for (int i = 0; i < width; ++i) {
    617             for (int j = 0; j < height; ++j) {
    618                 assertEquals(normal.getPixel(i, j), flipped.getPixel(width - 1 - i, j));
    619             }
    620         }
    621 
    622         drawable.setAutoMirrored(true);
    623         drawAndCompare(normal, drawable);
    624 
    625         drawable.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
    626         drawAndCompare(flipped, drawable);
    627 
    628         drawable.setAutoMirrored(false);
    629         drawAndCompare(normal, drawable);
    630     }
    631 
    632     @Test
    633     public void testRepeatCountFromXml() throws XmlPullParserException, IOException {
    634         XmlPullParser parser = mRes.getXml(R.drawable.animatedimagedrawable_loop_count);
    635         Drawable drawable = Drawable.createFromXml(mRes, parser);
    636         assertNotNull(drawable);
    637         assertTrue(drawable instanceof AnimatedImageDrawable);
    638 
    639         AnimatedImageDrawable aid = (AnimatedImageDrawable) drawable;
    640         assertEquals(17, aid.getRepeatCount());
    641     }
    642 
    643     @Test
    644     public void testInfiniteRepeatCountFromXml() throws XmlPullParserException, IOException {
    645         // This image has an encoded repeat count of 1. Verify that.
    646         Drawable drawable = mRes.getDrawable(R.drawable.animated_one_loop);
    647         assertNotNull(drawable);
    648         assertTrue(drawable instanceof AnimatedImageDrawable);
    649         AnimatedImageDrawable aid = (AnimatedImageDrawable) drawable;
    650         assertEquals(1, aid.getRepeatCount());
    651 
    652         // This layout uses the same image and overrides the repeat count to infinity.
    653         XmlPullParser parser = mRes.getXml(R.drawable.animatedimagedrawable_loop_count_infinite);
    654         drawable = Drawable.createFromXml(mRes, parser);
    655         assertNotNull(drawable);
    656         assertTrue(drawable instanceof AnimatedImageDrawable);
    657 
    658         aid = (AnimatedImageDrawable) drawable;
    659         assertEquals(AnimatedImageDrawable.REPEAT_INFINITE, aid.getRepeatCount());
    660     }
    661 }
    662