Home | History | Annotate | Download | only in cts
      1 package android.graphics.drawable.cts;
      2 
      3 import static org.junit.Assert.assertEquals;
      4 import static org.junit.Assert.assertFalse;
      5 import static org.junit.Assert.assertNotNull;
      6 import static org.junit.Assert.assertTrue;
      7 import static org.junit.Assert.fail;
      8 
      9 import android.content.Context;
     10 import android.content.res.Resources;
     11 import android.graphics.Bitmap;
     12 import android.graphics.Bitmap.Config;
     13 import android.graphics.Canvas;
     14 import android.graphics.Color;
     15 import android.graphics.ColorFilter;
     16 import android.graphics.Path;
     17 import android.graphics.Path.Direction;
     18 import android.graphics.PixelFormat;
     19 import android.graphics.Rect;
     20 import android.graphics.Region;
     21 import android.graphics.cts.R;
     22 import android.graphics.drawable.AdaptiveIconDrawable;
     23 import android.graphics.drawable.BitmapDrawable;
     24 import android.graphics.drawable.ColorDrawable;
     25 import android.graphics.drawable.Drawable;
     26 import android.graphics.drawable.Drawable.ConstantState;
     27 import android.graphics.drawable.StateListDrawable;
     28 import android.support.test.InstrumentationRegistry;
     29 import android.support.test.filters.SmallTest;
     30 import android.support.test.runner.AndroidJUnit4;
     31 import android.util.AttributeSet;
     32 import android.util.Log;
     33 import android.util.Xml;
     34 
     35 import org.junit.Test;
     36 import org.junit.runner.RunWith;
     37 import org.xmlpull.v1.XmlPullParser;
     38 
     39 import java.io.File;
     40 import java.io.FileOutputStream;
     41 import java.util.Arrays;
     42 
     43 @SmallTest
     44 @RunWith(AndroidJUnit4.class)
     45 public class AdaptiveIconDrawableTest {
     46 
     47     public static final String TAG = AdaptiveIconDrawableTest.class.getSimpleName();
     48     public static void L(String s, Object... parts) {
     49         Log.d(TAG, (parts.length == 0) ? s : String.format(s, parts));
     50     }
     51 
     52     @Test
     53     public void testConstructor() {
     54         new AdaptiveIconDrawable(null, null);
     55     }
     56 
     57     @Test
     58     public void testInflate() throws Throwable {
     59         AdaptiveIconDrawable dr = new AdaptiveIconDrawable(null, null);
     60 
     61         Resources r = InstrumentationRegistry.getTargetContext().getResources();
     62         XmlPullParser parser = r.getXml(R.layout.framelayout_layout);
     63         AttributeSet attrs = Xml.asAttributeSet(parser);
     64 
     65         // Should not throw inflate exception
     66         dr.inflate(r, parser, attrs);
     67     }
     68 
     69     @Test(expected=NullPointerException.class)
     70     public void testInflateNull() throws Throwable {
     71         AdaptiveIconDrawable dr = new AdaptiveIconDrawable(null, null);
     72         dr.inflate(null, null, null);
     73     }
     74 
     75     @Test
     76     public void testDraw() {
     77         Canvas c = new Canvas();
     78         AdaptiveIconDrawable dr = new AdaptiveIconDrawable(null, null);
     79         dr.draw(c);
     80     }
     81 
     82     @Test(expected=NullPointerException.class)
     83     public void testDrawNull() {
     84         AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
     85             new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
     86         iconDrawable.setBounds(0, 0, 100, 100);
     87         iconDrawable.draw(null);
     88     }
     89 
     90     @Test
     91     public void testInvalidateDrawable() {
     92         AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
     93             new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
     94         iconDrawable.invalidateDrawable(
     95             InstrumentationRegistry.getTargetContext().getDrawable(R.drawable.pass));
     96     }
     97 
     98     @Test
     99     public void testScheduleDrawable() {
    100         AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
    101             new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
    102         iconDrawable.scheduleDrawable(
    103             InstrumentationRegistry.getTargetContext().getDrawable(R.drawable.pass),
    104             () -> {}, 10);
    105 
    106         // input null as params
    107         iconDrawable.scheduleDrawable(null, null, -1);
    108         // expected, no Exception thrown out, test success
    109     }
    110 
    111     @Test
    112     public void testUnscheduleDrawable() {
    113         AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
    114             new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
    115         iconDrawable.unscheduleDrawable(
    116             InstrumentationRegistry.getTargetContext().getDrawable(R.drawable.pass), () -> {});
    117 
    118         // input null as params
    119         iconDrawable.unscheduleDrawable(null, null);
    120         // expected, no Exception thrown out, test success
    121     }
    122 
    123     @Test
    124     public void testGetChangingConfigurations() {
    125         AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
    126             new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
    127         iconDrawable.setChangingConfigurations(11);
    128         assertEquals(11, iconDrawable.getChangingConfigurations());
    129 
    130         iconDrawable.setChangingConfigurations(-21);
    131         assertEquals(-21, iconDrawable.getChangingConfigurations());
    132     }
    133 
    134     /**
    135      * When setBound isn't called before draw method is called.
    136      * Nothing is drawn.
    137      */
    138     @Test
    139     public void testDrawWithoutSetBounds() throws Exception {
    140         Drawable backgroundDrawable = new ColorDrawable(Color.BLUE);
    141         Drawable foregroundDrawable = new ColorDrawable(Color.RED);
    142         AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(backgroundDrawable, foregroundDrawable);
    143         Context context = InstrumentationRegistry.getTargetContext();
    144         File dir = context.getExternalFilesDir(null);
    145         L("writing temp bitmaps to %s...", dir);
    146 
    147         final Bitmap bm_test = Bitmap.createBitmap(150, 150, Bitmap.Config.ARGB_8888);
    148         final Bitmap bm_org = bm_test.copy(Config.ARGB_8888, false);
    149         final Canvas can1 = new Canvas(bm_test);
    150 
    151         // Even when setBounds is not called, should not crash
    152         iconDrawable.draw(can1);
    153         // Draws nothing! Hence same as original.
    154         if (!equalBitmaps(bm_test, bm_org)) {
    155             findBitmapDifferences(bm_test, bm_org);
    156             fail("bm differs, check " + dir);
    157         }
    158     }
    159 
    160     /**
    161      * When setBound is called, translate accordingly.
    162      */
    163     @Test
    164     public void testDrawSetBounds() throws Exception {
    165         int dpi = 4 ;
    166         int top = 18 * dpi;
    167         int left = 18 * dpi;
    168         int right = 90 * dpi;
    169         int bottom = 90 * dpi;
    170         int width = right - left;
    171         int height = bottom - top;
    172         Context context = InstrumentationRegistry.getTargetContext();
    173         AdaptiveIconDrawable iconDrawable = (AdaptiveIconDrawable) context.getResources().getDrawable(android.R.drawable.sym_def_app_icon);
    174         File dir = context.getExternalFilesDir(null);
    175         L("writing temp bitmaps to %s...", dir);
    176         final Bitmap bm_org = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    177         final Canvas can_org = new Canvas(bm_org);
    178         iconDrawable.setBounds(0, 0, width, height);
    179         iconDrawable.draw(can_org);
    180 
    181         // Tested bitmap is drawn from the adaptive icon drawable.
    182         final Bitmap bm_test = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    183         final Canvas can_test = new Canvas(bm_test);
    184 
    185         iconDrawable.setBounds(left, top, right, bottom);
    186         can_test.translate(-left, -top);
    187         iconDrawable.draw(can_test);
    188         can_test.translate(left, top);
    189 
    190 
    191         bm_org.compress(Bitmap.CompressFormat.PNG, 100,
    192             new FileOutputStream(new File(dir, "adaptive-bm-original.png")));
    193         bm_test.compress(Bitmap.CompressFormat.PNG, 100,
    194             new FileOutputStream(new File(dir, "adaptive-bm-test.png")));
    195         Region region = new Region(new Rect(0, 0, width, height));
    196 
    197         Path circle = new Path();
    198         circle.addCircle(width / 2, height / 2,  (right - left)/2 -10 /* room for anti-alias */, Direction.CW);
    199 
    200         region.setPath(circle, region);
    201         if (!equalBitmaps(bm_test, bm_org, region)) {
    202             findBitmapDifferences(bm_test, bm_org);
    203             fail("bm differs, check " + dir);
    204         }
    205     }
    206 
    207     @Test
    208     public void testSetVisible() {
    209         AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
    210             new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
    211         assertFalse(iconDrawable.setVisible(true, true)); /* unchanged */
    212         assertTrue(iconDrawable.setVisible(false, true)); /* changed */
    213         assertFalse(iconDrawable.setVisible(false, true)); /* unchanged */
    214     }
    215 
    216     @Test
    217     public void testSetAlpha() {
    218         AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
    219             new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
    220         iconDrawable.setBounds(0, 0, 100, 100);
    221 
    222         Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
    223         Canvas canvas = new Canvas(bitmap);
    224 
    225         iconDrawable.draw(canvas);
    226         assertEquals(255, Color.alpha(bitmap.getPixel(50, 50)));
    227 
    228         iconDrawable.setAlpha(200);
    229         bitmap.eraseColor(Color.TRANSPARENT);
    230         iconDrawable.draw(canvas);
    231         assertEquals(200, Color.alpha(bitmap.getPixel(50, 50)));
    232 
    233         iconDrawable.setAlpha(100);
    234         bitmap.eraseColor(Color.TRANSPARENT);
    235         iconDrawable.draw(canvas);
    236         assertEquals(100, Color.alpha(bitmap.getPixel(50, 50)));
    237     }
    238 
    239     @Test
    240     public void testSetColorFilter() {
    241         AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
    242             new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
    243         ColorFilter cf = new ColorFilter();
    244         iconDrawable.setColorFilter(cf);
    245 
    246         // input null as param
    247         iconDrawable.setColorFilter(null);
    248         // expected, no Exception thrown out, test success
    249     }
    250 
    251     @Test
    252     public void testGetOpacity() {
    253         AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
    254             new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
    255         iconDrawable.setOpacity(PixelFormat.OPAQUE);
    256         assertEquals(PixelFormat.OPAQUE, iconDrawable.getOpacity());
    257 
    258         iconDrawable.setOpacity(PixelFormat.TRANSPARENT);
    259         assertEquals(PixelFormat.TRANSPARENT, iconDrawable.getOpacity());
    260     }
    261 
    262     @Test
    263     public void testIsStateful() {
    264         AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
    265             new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
    266         assertFalse(iconDrawable.isStateful());
    267 
    268         iconDrawable = new AdaptiveIconDrawable(new StateListDrawable(), new ColorDrawable(Color.RED));
    269         assertTrue(iconDrawable.isStateful());
    270     }
    271 
    272 
    273     @Test
    274     public void testGetConstantState() {
    275         AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
    276             new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
    277         ConstantState constantState = iconDrawable.getConstantState();
    278         assertNotNull(constantState);
    279     }
    280 
    281     @Test
    282     public void testMutate() {
    283         // Obtain the first instance, then mutate and modify a property held by
    284         // constant state. If mutate() works correctly, the property should not
    285         // be modified on the second or third instances.
    286         Resources res = InstrumentationRegistry.getTargetContext().getResources();
    287         AdaptiveIconDrawable first = (AdaptiveIconDrawable) res.getDrawable(R.drawable.adaptive_icon_drawable, null);
    288         AdaptiveIconDrawable pre = (AdaptiveIconDrawable) res.getDrawable(R.drawable.adaptive_icon_drawable, null);
    289 
    290         first.mutate().setBounds(0, 0, 100, 100);
    291 
    292         assertEquals("Modified first loaded instance", 100, first.getBounds().width());
    293         assertEquals("Did not modify pre-mutate() instance", 0, pre.getBounds().width());
    294 
    295         AdaptiveIconDrawable post = (AdaptiveIconDrawable) res.getDrawable(R.drawable.adaptive_icon_drawable, null);
    296 
    297         assertEquals("Did not modify post-mutate() instance", 0, post.getBounds().width());
    298     }
    299 
    300     @Test
    301     public void testGetForegroundBackground() {
    302         Context context = InstrumentationRegistry.getTargetContext();
    303         AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
    304             new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
    305         Drawable fgDrawable = iconDrawable.getForeground();
    306         Drawable bgDrawable = iconDrawable.getBackground();
    307         assertTrue("Foreground layer is color drawable.", fgDrawable instanceof ColorDrawable);
    308         assertTrue("Backgroud layer is color drawable.", bgDrawable instanceof ColorDrawable);
    309 
    310         AdaptiveIconDrawable iconDrawableInflated =
    311             (AdaptiveIconDrawable) context.getDrawable(R.drawable.adaptive_icon_drawable);
    312         fgDrawable = iconDrawableInflated.getForeground();
    313         bgDrawable = iconDrawableInflated.getBackground();
    314         assertTrue("Foreground layer is color drawable.", fgDrawable instanceof BitmapDrawable);
    315         assertTrue("Backgroud layer is color drawable.", bgDrawable instanceof BitmapDrawable);
    316     }
    317 
    318     @Test
    319     public void testGetIntrinsicWidth() {
    320         Context context = InstrumentationRegistry.getTargetContext();
    321         AdaptiveIconDrawable iconDrawableInflated =
    322             (AdaptiveIconDrawable) context.getDrawable(R.drawable.adaptive_icon_drawable);
    323         int fgWidth = iconDrawableInflated.getForeground().getIntrinsicWidth();
    324         int bgWidth = iconDrawableInflated.getBackground().getIntrinsicWidth();
    325         float iconIntrinsicWidth = Math.max(fgWidth, bgWidth) / (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction());
    326         assertEquals("Max intrinsic width of the layers should be icon's intrinsic width",
    327             (int) iconIntrinsicWidth, iconDrawableInflated.getIntrinsicWidth());
    328     }
    329 
    330     @Test
    331     public void testGetIntrinsicHeight() {
    332         Context context = InstrumentationRegistry.getTargetContext();
    333         AdaptiveIconDrawable iconDrawableInflated =
    334             (AdaptiveIconDrawable) context.getDrawable(R.drawable.adaptive_icon_drawable);
    335         int fgWidth = iconDrawableInflated.getForeground().getIntrinsicHeight();
    336         int bgWidth = iconDrawableInflated.getBackground().getIntrinsicHeight();
    337         float iconIntrinsicHeight = Math.max(fgWidth, bgWidth) / (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction());
    338         assertEquals("Max intrinsic height of the layers should be icon's intrinsic height",
    339             (int) iconIntrinsicHeight, iconDrawableInflated.getIntrinsicHeight());
    340     }
    341 
    342     //
    343     // Utils
    344     //
    345 
    346     boolean equalBitmaps(Bitmap a, Bitmap b) {
    347       return equalBitmaps(a, b, null);
    348     }
    349 
    350     boolean equalBitmaps(Bitmap a, Bitmap b, Region region) {
    351         if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) return false;
    352 
    353         final int w = a.getWidth();
    354         final int h = a.getHeight();
    355         int[] aPix = new int[w * h];
    356         int[] bPix = new int[w * h];
    357 
    358         if (region != null) {
    359             for (int i = 0; i < w; i++) {
    360                 for (int j = 0; j < h; j++) {
    361                     int ra = (a.getPixel(i, j) >> 16) & 0xff;
    362                     int ga = (a.getPixel(i, j) >> 8) & 0xff;
    363                     int ba = a.getPixel(i, j) & 0xff;
    364                     int rb = (b.getPixel(i, j) >> 16) & 0xff;
    365                     int gb = (b.getPixel(i, j) >> 8) & 0xff;
    366                     int bb = b.getPixel(i, j) & 0xff;
    367                     if (region.contains(i, j) && a.getPixel(i, j) != b.getPixel(i, j) ) {
    368                         return false;
    369                     }
    370                 }
    371             }
    372             return true;
    373         } else {
    374             a.getPixels(aPix, 0, w, 0, 0, w, h);
    375             b.getPixels(bPix, 0, w, 0, 0, w, h);
    376             return Arrays.equals(aPix, bPix);
    377         }
    378     }
    379 
    380     void findBitmapDifferences(Bitmap a, Bitmap b) {
    381         if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) {
    382             L("different sizes: %dx%d vs %dx%d",
    383                 a.getWidth(), a.getHeight(), b.getWidth(), b.getHeight());
    384             return;
    385         }
    386 
    387         final int w = a.getWidth();
    388         final int h = a.getHeight();
    389         int[] aPix = new int[w * h];
    390         int[] bPix = new int[w * h];
    391 
    392         a.getPixels(aPix, 0, w, 0, 0, w, h);
    393         b.getPixels(bPix, 0, w, 0, 0, w, h);
    394 
    395         L("bitmap a (%dx%d)", w, h);
    396         printBits(aPix, w, h);
    397         L("bitmap b (%dx%d)", w, h);
    398         printBits(bPix, w, h);
    399 
    400         StringBuffer sb = new StringBuffer("Different pixels: ");
    401         for (int i=0; i<w; i++) {
    402             for (int j=0; j<h; j++) {
    403                 if (aPix[i+w*j] != bPix[i+w*j]) {
    404                     sb.append(" ").append(i).append(",").append(j).append("<")
    405                         .append(aPix[i+w*j]).append(",").append(bPix[i+w*j]).append(">");
    406                 }
    407             }
    408         }
    409         L(sb.toString());
    410     }
    411 
    412     static void printBits(int[] a, int w, int h) {
    413         final StringBuilder sb = new StringBuilder();
    414         for (int i=0; i<w; i++) {
    415             for (int j=0; j<h; j++) {
    416                 sb.append(colorToChar(a[i+w*j]));
    417             }
    418             sb.append('\n');
    419         }
    420         L(sb.toString());
    421     }
    422 
    423     static char colorToChar(int color) {
    424         int sum = ((color >> 16) & 0xff)
    425             + ((color >> 8)  & 0xff)
    426             + ((color)       & 0xff);
    427         return GRADIENT[sum * (GRADIENT.length-1) / (3*0xff)];
    428     }
    429     static final char[] GRADIENT = " .:;+=xX$#".toCharArray();
    430 }
    431