Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2008 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 package android.graphics.cts;
     17 
     18 import static org.junit.Assert.assertEquals;
     19 import static org.junit.Assert.assertFalse;
     20 import static org.junit.Assert.assertNotEquals;
     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.content.res.Resources;
     28 import android.graphics.Bitmap;
     29 import android.graphics.Bitmap.CompressFormat;
     30 import android.graphics.Bitmap.Config;
     31 import android.graphics.BitmapFactory;
     32 import android.graphics.Canvas;
     33 import android.graphics.Color;
     34 import android.graphics.ColorSpace;
     35 import android.graphics.ColorSpace.Named;
     36 import android.graphics.Matrix;
     37 import android.graphics.Paint;
     38 import android.graphics.Picture;
     39 import android.hardware.HardwareBuffer;
     40 import android.os.Debug;
     41 import android.os.Parcel;
     42 import android.os.StrictMode;
     43 import android.util.DisplayMetrics;
     44 import android.view.Surface;
     45 
     46 import androidx.test.InstrumentationRegistry;
     47 import androidx.test.filters.LargeTest;
     48 import androidx.test.filters.SmallTest;
     49 import androidx.test.runner.AndroidJUnit4;
     50 
     51 import com.android.compatibility.common.util.ColorUtils;
     52 import com.android.compatibility.common.util.WidgetTestUtils;
     53 
     54 import org.junit.Before;
     55 import org.junit.Test;
     56 import org.junit.runner.RunWith;
     57 
     58 import java.io.ByteArrayOutputStream;
     59 import java.io.File;
     60 import java.nio.ByteBuffer;
     61 import java.nio.CharBuffer;
     62 import java.nio.IntBuffer;
     63 import java.nio.ShortBuffer;
     64 import java.util.ArrayList;
     65 import java.util.List;
     66 import java.util.concurrent.CountDownLatch;
     67 import java.util.concurrent.TimeUnit;
     68 
     69 @SmallTest
     70 @RunWith(AndroidJUnit4.class)
     71 public class BitmapTest {
     72     // small alpha values cause color values to be pre-multiplied down, losing accuracy
     73     private static final int PREMUL_COLOR = Color.argb(2, 255, 254, 253);
     74     private static final int PREMUL_ROUNDED_COLOR = Color.argb(2, 255, 255, 255);
     75     private static final int PREMUL_STORED_COLOR = Color.argb(2, 2, 2, 2);
     76 
     77     private static final BitmapFactory.Options HARDWARE_OPTIONS = createHardwareBitmapOptions();
     78 
     79     static {
     80         System.loadLibrary("ctsgraphics_jni");
     81     }
     82 
     83     private Resources mRes;
     84     private Bitmap mBitmap;
     85     private BitmapFactory.Options mOptions;
     86 
     87     public static List<ColorSpace> getRgbColorSpaces() {
     88         List<ColorSpace> rgbColorSpaces;
     89         rgbColorSpaces = new ArrayList<ColorSpace>();
     90         for (ColorSpace.Named e : ColorSpace.Named.values()) {
     91             ColorSpace cs = ColorSpace.get(e);
     92             if (cs.getModel() != ColorSpace.Model.RGB) {
     93                 continue;
     94             }
     95             if (((ColorSpace.Rgb) cs).getTransferParameters() == null) {
     96                 continue;
     97             }
     98             rgbColorSpaces.add(cs);
     99         }
    100         return rgbColorSpaces;
    101     }
    102 
    103     @Before
    104     public void setup() {
    105         mRes = InstrumentationRegistry.getTargetContext().getResources();
    106         mOptions = new BitmapFactory.Options();
    107         mOptions.inScaled = false;
    108         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
    109     }
    110 
    111     @Test(expected=IllegalStateException.class)
    112     public void testCompressRecycled() {
    113         mBitmap.recycle();
    114         mBitmap.compress(CompressFormat.JPEG, 0, null);
    115     }
    116 
    117     @Test(expected=NullPointerException.class)
    118     public void testCompressNullStream() {
    119         mBitmap.compress(CompressFormat.JPEG, 0, null);
    120     }
    121 
    122     @Test(expected=IllegalArgumentException.class)
    123     public void testCompressQualityTooLow() {
    124         mBitmap.compress(CompressFormat.JPEG, -1, new ByteArrayOutputStream());
    125     }
    126 
    127     @Test(expected=IllegalArgumentException.class)
    128     public void testCompressQualityTooHigh() {
    129         mBitmap.compress(CompressFormat.JPEG, 101, new ByteArrayOutputStream());
    130     }
    131 
    132     @Test
    133     public void testCompress() {
    134         assertTrue(mBitmap.compress(CompressFormat.JPEG, 50, new ByteArrayOutputStream()));
    135     }
    136 
    137     @Test(expected=IllegalStateException.class)
    138     public void testCopyRecycled() {
    139         mBitmap.recycle();
    140         mBitmap.copy(Config.RGB_565, false);
    141     }
    142 
    143     @Test
    144     public void testCopy() {
    145         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
    146         Bitmap bitmap = mBitmap.copy(Config.ARGB_8888, false);
    147         WidgetTestUtils.assertEquals(mBitmap, bitmap);
    148     }
    149 
    150     @Test
    151     public void testCopyConfigs() {
    152         Config[] supportedConfigs = new Config[] {
    153                 Config.ALPHA_8, Config.RGB_565, Config.ARGB_8888, Config.RGBA_F16,
    154         };
    155         for (Config src : supportedConfigs) {
    156             for (Config dst : supportedConfigs) {
    157                 Bitmap srcBitmap = Bitmap.createBitmap(1, 1, src);
    158                 srcBitmap.eraseColor(Color.WHITE);
    159                 Bitmap dstBitmap = srcBitmap.copy(dst, false);
    160                 assertNotNull("Should support copying from " + src + " to " + dst,
    161                         dstBitmap);
    162                 if (Config.ALPHA_8 == dst || Config.ALPHA_8 == src) {
    163                     // Color will be opaque but color information will be lost.
    164                     assertEquals("Color should be black when copying from " + src + " to "
    165                             + dst, Color.BLACK, dstBitmap.getPixel(0, 0));
    166                 } else {
    167                     assertEquals("Color should be preserved when copying from " + src + " to "
    168                             + dst, Color.WHITE, dstBitmap.getPixel(0, 0));
    169                 }
    170             }
    171         }
    172     }
    173 
    174     @Test(expected=IllegalArgumentException.class)
    175     public void testCopyMutableHwBitmap() {
    176         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
    177         mBitmap.copy(Config.HARDWARE, true);
    178     }
    179 
    180     @Test(expected=RuntimeException.class)
    181     public void testCopyPixelsToBufferUnsupportedBufferClass() {
    182         final int pixSize = mBitmap.getRowBytes() * mBitmap.getHeight();
    183 
    184         mBitmap.copyPixelsToBuffer(CharBuffer.allocate(pixSize));
    185     }
    186 
    187     @Test(expected=RuntimeException.class)
    188     public void testCopyPixelsToBufferBufferTooSmall() {
    189         final int pixSize = mBitmap.getRowBytes() * mBitmap.getHeight();
    190         final int tooSmall = pixSize / 2;
    191 
    192         mBitmap.copyPixelsToBuffer(ByteBuffer.allocate(tooSmall));
    193     }
    194 
    195     @Test
    196     public void testCopyPixelsToBuffer() {
    197         final int pixSize = mBitmap.getRowBytes() * mBitmap.getHeight();
    198 
    199         ByteBuffer byteBuf = ByteBuffer.allocate(pixSize);
    200         assertEquals(0, byteBuf.position());
    201         mBitmap.copyPixelsToBuffer(byteBuf);
    202         assertEquals(pixSize, byteBuf.position());
    203 
    204         ShortBuffer shortBuf = ShortBuffer.allocate(pixSize);
    205         assertEquals(0, shortBuf.position());
    206         mBitmap.copyPixelsToBuffer(shortBuf);
    207         assertEquals(pixSize >> 1, shortBuf.position());
    208 
    209         IntBuffer intBuf1 = IntBuffer.allocate(pixSize);
    210         assertEquals(0, intBuf1.position());
    211         mBitmap.copyPixelsToBuffer(intBuf1);
    212         assertEquals(pixSize >> 2, intBuf1.position());
    213 
    214         Bitmap bitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(),
    215                 mBitmap.getConfig());
    216         intBuf1.position(0); // copyPixelsToBuffer adjusted the position, so rewind to start
    217         bitmap.copyPixelsFromBuffer(intBuf1);
    218         IntBuffer intBuf2 = IntBuffer.allocate(pixSize);
    219         bitmap.copyPixelsToBuffer(intBuf2);
    220 
    221         assertEquals(pixSize >> 2, intBuf2.position());
    222         assertEquals(intBuf1.position(), intBuf2.position());
    223         int size = intBuf1.position();
    224         intBuf1.position(0);
    225         intBuf2.position(0);
    226         for (int i = 0; i < size; i++) {
    227             assertEquals("mismatching pixels at position " + i, intBuf1.get(), intBuf2.get());
    228         }
    229     }
    230 
    231     @Test
    232     public void testCreateBitmap1() {
    233         int[] colors = createColors(100);
    234         Bitmap bitmap = Bitmap.createBitmap(colors, 10, 10, Config.RGB_565);
    235         assertFalse(bitmap.isMutable());
    236         Bitmap ret = Bitmap.createBitmap(bitmap);
    237         assertNotNull(ret);
    238         assertFalse(ret.isMutable());
    239         assertEquals(10, ret.getWidth());
    240         assertEquals(10, ret.getHeight());
    241         assertEquals(Config.RGB_565, ret.getConfig());
    242         assertEquals(ANDROID_BITMAP_FORMAT_RGB_565, nGetFormat(ret));
    243     }
    244 
    245     @Test(expected=IllegalArgumentException.class)
    246     public void testCreateBitmapNegativeX() {
    247         Bitmap.createBitmap(mBitmap, -100, 50, 50, 200);
    248     }
    249 
    250     @Test
    251     public void testCreateBitmap2() {
    252         // special case: output bitmap is equal to the input bitmap
    253         mBitmap = Bitmap.createBitmap(new int[100 * 100], 100, 100, Config.ARGB_8888);
    254         assertFalse(mBitmap.isMutable()); // createBitmap w/ colors should be immutable
    255         Bitmap ret = Bitmap.createBitmap(mBitmap, 0, 0, 100, 100);
    256         assertNotNull(ret);
    257         assertFalse(ret.isMutable()); // createBitmap from subset should be immutable
    258         assertTrue(mBitmap.equals(ret));
    259 
    260         //normal case
    261         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
    262         ret = Bitmap.createBitmap(mBitmap, 10, 10, 50, 50);
    263         assertNotNull(ret);
    264         assertFalse(mBitmap.equals(ret));
    265         assertEquals(ANDROID_BITMAP_FORMAT_RGBA_8888, nGetFormat(mBitmap));
    266     }
    267 
    268     @Test(expected=IllegalArgumentException.class)
    269     public void testCreateBitmapNegativeXY() {
    270         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
    271 
    272         // abnormal case: x and/or y less than 0
    273         Bitmap.createBitmap(mBitmap, -1, -1, 10, 10, null, false);
    274     }
    275 
    276     @Test(expected=IllegalArgumentException.class)
    277     public void testCreateBitmapNegativeWidthHeight() {
    278         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
    279 
    280         // abnormal case: width and/or height less than 0
    281         Bitmap.createBitmap(mBitmap, 1, 1, -10, -10, null, false);
    282     }
    283 
    284     @Test(expected=IllegalArgumentException.class)
    285     public void testCreateBitmapXRegionTooWide() {
    286         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
    287 
    288         // abnormal case: (x + width) bigger than source bitmap's width
    289         Bitmap.createBitmap(mBitmap, 10, 10, 95, 50, null, false);
    290     }
    291 
    292     @Test(expected=IllegalArgumentException.class)
    293     public void testCreateBitmapYRegionTooTall() {
    294         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
    295 
    296         // abnormal case: (y + height) bigger than source bitmap's height
    297         Bitmap.createBitmap(mBitmap, 10, 10, 50, 95, null, false);
    298     }
    299 
    300     @Test(expected=IllegalArgumentException.class)
    301     public void testCreateMutableBitmapWithHardwareConfig() {
    302         Bitmap.createBitmap(100, 100, Config.HARDWARE);
    303     }
    304 
    305     @Test
    306     public void testCreateBitmap3() {
    307         // special case: output bitmap is equal to the input bitmap
    308         mBitmap = Bitmap.createBitmap(new int[100 * 100], 100, 100, Config.ARGB_8888);
    309         Bitmap ret = Bitmap.createBitmap(mBitmap, 0, 0, 100, 100, null, false);
    310         assertNotNull(ret);
    311         assertFalse(ret.isMutable()); // subset should be immutable
    312         assertTrue(mBitmap.equals(ret));
    313 
    314         // normal case
    315         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
    316         ret = Bitmap.createBitmap(mBitmap, 10, 10, 50, 50, new Matrix(), true);
    317         assertTrue(ret.isMutable());
    318         assertNotNull(ret);
    319         assertFalse(mBitmap.equals(ret));
    320     }
    321 
    322     @Test
    323     public void testCreateBitmapFromHardwareBitmap() {
    324         Bitmap hardwareBitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot,
    325                 HARDWARE_OPTIONS);
    326         assertEquals(Config.HARDWARE, hardwareBitmap.getConfig());
    327 
    328         Bitmap ret = Bitmap.createBitmap(hardwareBitmap, 0, 0, 100, 100, null, false);
    329         assertEquals(Config.HARDWARE, ret.getConfig());
    330         assertFalse(ret.isMutable());
    331     }
    332 
    333     @Test
    334     public void testCreateBitmap4() {
    335         Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565);
    336         assertNotNull(ret);
    337         assertTrue(ret.isMutable());
    338         assertEquals(100, ret.getWidth());
    339         assertEquals(200, ret.getHeight());
    340         assertEquals(Config.RGB_565, ret.getConfig());
    341     }
    342 
    343     private static void verify2x2BitmapContents(int[] expected, Bitmap observed) {
    344         ColorUtils.verifyColor(expected[0], observed.getPixel(0, 0));
    345         ColorUtils.verifyColor(expected[1], observed.getPixel(1, 0));
    346         ColorUtils.verifyColor(expected[2], observed.getPixel(0, 1));
    347         ColorUtils.verifyColor(expected[3], observed.getPixel(1, 1));
    348     }
    349 
    350     @Test
    351     public void testCreateBitmap_matrix() {
    352         int[] colorArray = new int[] { Color.RED, Color.GREEN, Color.BLUE, Color.BLACK };
    353         Bitmap src = Bitmap.createBitmap(2, 2, Config.ARGB_8888);
    354         assertTrue(src.isMutable());
    355         src.setPixels(colorArray,0, 2, 0, 0, 2, 2);
    356 
    357         // baseline
    358         verify2x2BitmapContents(colorArray, src);
    359 
    360         // null
    361         Bitmap dst = Bitmap.createBitmap(src, 0, 0, 2, 2, null, false);
    362         assertTrue(dst.isMutable());
    363         verify2x2BitmapContents(colorArray, dst);
    364 
    365         // identity matrix
    366         Matrix matrix = new Matrix();
    367         dst = Bitmap.createBitmap(src, 0, 0, 2, 2, matrix, false);
    368         assertTrue(dst.isMutable());
    369         verify2x2BitmapContents(colorArray, dst);
    370 
    371         // big scale - only red visible
    372         matrix.setScale(10, 10);
    373         dst = Bitmap.createBitmap(src, 0, 0, 2, 2, matrix, false);
    374         assertTrue(dst.isMutable());
    375         verify2x2BitmapContents(new int[] { Color.RED, Color.RED, Color.RED, Color.RED }, dst);
    376 
    377         // rotation
    378         matrix.setRotate(90);
    379         dst = Bitmap.createBitmap(src, 0, 0, 2, 2, matrix, false);
    380         assertTrue(dst.isMutable());
    381         verify2x2BitmapContents(
    382                 new int[] { Color.BLUE, Color.RED, Color.BLACK, Color.GREEN }, dst);
    383     }
    384 
    385     @Test(expected=IllegalArgumentException.class)
    386     public void testCreateBitmapFromColorsNegativeWidthHeight() {
    387         int[] colors = createColors(100);
    388 
    389         // abnormal case: width and/or height less than 0
    390         Bitmap.createBitmap(colors, 0, 100, -1, 100, Config.RGB_565);
    391     }
    392 
    393     @Test(expected=IllegalArgumentException.class)
    394     public void testCreateBitmapFromColorsIllegalStride() {
    395         int[] colors = createColors(100);
    396 
    397         // abnormal case: stride less than width and bigger than -width
    398         Bitmap.createBitmap(colors, 10, 10, 100, 100, Config.RGB_565);
    399     }
    400 
    401     @Test(expected=ArrayIndexOutOfBoundsException.class)
    402     public void testCreateBitmapFromColorsNegativeOffset() {
    403         int[] colors = createColors(100);
    404 
    405         // abnormal case: offset less than 0
    406         Bitmap.createBitmap(colors, -10, 100, 100, 100, Config.RGB_565);
    407     }
    408 
    409     @Test(expected=ArrayIndexOutOfBoundsException.class)
    410     public void testCreateBitmapFromColorsOffsetTooLarge() {
    411         int[] colors = createColors(100);
    412 
    413         // abnormal case: (offset + width) bigger than colors' length
    414         Bitmap.createBitmap(colors, 10, 100, 100, 100, Config.RGB_565);
    415     }
    416 
    417     @Test(expected=ArrayIndexOutOfBoundsException.class)
    418     public void testCreateBitmapFromColorsScalnlineTooLarge() {
    419         int[] colors = createColors(100);
    420 
    421         // abnormal case: (lastScanline + width) bigger than colors' length
    422         Bitmap.createBitmap(colors, 10, 100, 50, 100, Config.RGB_565);
    423     }
    424 
    425     @Test
    426     public void testCreateBitmap6() {
    427         int[] colors = createColors(100);
    428 
    429         // normal case
    430         Bitmap ret = Bitmap.createBitmap(colors, 5, 10, 10, 5, Config.RGB_565);
    431         assertNotNull(ret);
    432         assertFalse(ret.isMutable());
    433         assertEquals(10, ret.getWidth());
    434         assertEquals(5, ret.getHeight());
    435         assertEquals(Config.RGB_565, ret.getConfig());
    436     }
    437 
    438     @Test
    439     public void testCreateBitmap_displayMetrics_mutable() {
    440         DisplayMetrics metrics =
    441                 InstrumentationRegistry.getTargetContext().getResources().getDisplayMetrics();
    442 
    443         Bitmap bitmap;
    444         bitmap = Bitmap.createBitmap(metrics, 10, 10, Config.ARGB_8888);
    445         assertTrue(bitmap.isMutable());
    446         assertEquals(metrics.densityDpi, bitmap.getDensity());
    447 
    448         bitmap = Bitmap.createBitmap(metrics, 10, 10, Config.ARGB_8888);
    449         assertTrue(bitmap.isMutable());
    450         assertEquals(metrics.densityDpi, bitmap.getDensity());
    451 
    452         bitmap = Bitmap.createBitmap(metrics, 10, 10, Config.ARGB_8888, true);
    453         assertTrue(bitmap.isMutable());
    454         assertEquals(metrics.densityDpi, bitmap.getDensity());
    455 
    456         bitmap = Bitmap.createBitmap(metrics, 10, 10, Config.ARGB_8888, true, ColorSpace.get(
    457                 ColorSpace.Named.SRGB));
    458 
    459         assertTrue(bitmap.isMutable());
    460         assertEquals(metrics.densityDpi, bitmap.getDensity());
    461 
    462         int[] colors = createColors(100);
    463         bitmap = Bitmap.createBitmap(metrics, colors, 0, 10, 10, 10, Config.ARGB_8888);
    464         assertNotNull(bitmap);
    465         assertFalse(bitmap.isMutable());
    466 
    467         bitmap = Bitmap.createBitmap(metrics, colors, 10, 10, Config.ARGB_8888);
    468         assertNotNull(bitmap);
    469         assertFalse(bitmap.isMutable());
    470     }
    471 
    472     @Test
    473     public void testCreateBitmap_noDisplayMetrics_mutable() {
    474         Bitmap bitmap;
    475         bitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888);
    476         assertTrue(bitmap.isMutable());
    477 
    478         bitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888, true);
    479         assertTrue(bitmap.isMutable());
    480 
    481         bitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888, true, ColorSpace.get(Named.SRGB));
    482         assertTrue(bitmap.isMutable());
    483     }
    484 
    485     @Test
    486     public void testCreateBitmap_displayMetrics_immutable() {
    487         DisplayMetrics metrics =
    488                 InstrumentationRegistry.getTargetContext().getResources().getDisplayMetrics();
    489         int[] colors = createColors(100);
    490 
    491         Bitmap bitmap;
    492         bitmap = Bitmap.createBitmap(metrics, colors, 0, 10, 10, 10, Config.ARGB_8888);
    493         assertFalse(bitmap.isMutable());
    494         assertEquals(metrics.densityDpi, bitmap.getDensity());
    495 
    496         bitmap = Bitmap.createBitmap(metrics, colors, 10, 10, Config.ARGB_8888);
    497         assertFalse(bitmap.isMutable());
    498         assertEquals(metrics.densityDpi, bitmap.getDensity());
    499     }
    500 
    501     @Test
    502     public void testCreateBitmap_noDisplayMetrics_immutable() {
    503         int[] colors = createColors(100);
    504         Bitmap bitmap;
    505         bitmap = Bitmap.createBitmap(colors, 0, 10, 10, 10, Config.ARGB_8888);
    506         assertFalse(bitmap.isMutable());
    507 
    508         bitmap = Bitmap.createBitmap(colors, 10, 10, Config.ARGB_8888);
    509         assertFalse(bitmap.isMutable());
    510     }
    511 
    512     @Test
    513     public void testCreateBitmap_Picture_immutable() {
    514         Picture picture = new Picture();
    515         Canvas canvas = picture.beginRecording(200, 100);
    516 
    517         Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
    518 
    519         p.setColor(0x88FF0000);
    520         canvas.drawCircle(50, 50, 40, p);
    521 
    522         p.setColor(Color.GREEN);
    523         p.setTextSize(30);
    524         canvas.drawText("Pictures", 60, 60, p);
    525         picture.endRecording();
    526 
    527         Bitmap bitmap;
    528         bitmap = Bitmap.createBitmap(picture);
    529         assertFalse(bitmap.isMutable());
    530 
    531         bitmap = Bitmap.createBitmap(picture, 100, 100, Config.HARDWARE);
    532         assertFalse(bitmap.isMutable());
    533         assertNotNull(bitmap.getColorSpace());
    534 
    535         bitmap = Bitmap.createBitmap(picture, 100, 100, Config.ARGB_8888);
    536         assertFalse(bitmap.isMutable());
    537     }
    538 
    539     @Test
    540     public void testCreateScaledBitmap() {
    541         mBitmap = Bitmap.createBitmap(100, 200, Config.RGB_565);
    542         assertTrue(mBitmap.isMutable());
    543         Bitmap ret = Bitmap.createScaledBitmap(mBitmap, 50, 100, false);
    544         assertNotNull(ret);
    545         assertEquals(50, ret.getWidth());
    546         assertEquals(100, ret.getHeight());
    547         assertTrue(ret.isMutable());
    548     }
    549 
    550     @Test
    551     public void testWrapHardwareBufferSucceeds() {
    552         try (HardwareBuffer hwBuffer = createTestBuffer(128, 128, false)) {
    553             Bitmap bitmap = Bitmap.wrapHardwareBuffer(hwBuffer, ColorSpace.get(Named.SRGB));
    554             assertNotNull(bitmap);
    555             bitmap.recycle();
    556         }
    557     }
    558 
    559     @Test(expected = IllegalArgumentException.class)
    560     public void testWrapHardwareBufferWithInvalidUsageFails() {
    561         try (HardwareBuffer hwBuffer = HardwareBuffer.create(512, 512, HardwareBuffer.RGBA_8888, 1,
    562             HardwareBuffer.USAGE_CPU_WRITE_RARELY)) {
    563             Bitmap bitmap = Bitmap.wrapHardwareBuffer(hwBuffer, ColorSpace.get(Named.SRGB));
    564         }
    565     }
    566 
    567     @Test(expected = IllegalArgumentException.class)
    568     public void testWrapHardwareBufferWithRgbBufferButNonRgbColorSpaceFails() {
    569         try (HardwareBuffer hwBuffer = HardwareBuffer.create(512, 512, HardwareBuffer.RGBA_8888, 1,
    570             HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE)) {
    571             Bitmap bitmap = Bitmap.wrapHardwareBuffer(hwBuffer, ColorSpace.get(Named.CIE_LAB));
    572         }
    573     }
    574 
    575     @Test
    576     public void testGenerationId() {
    577         Bitmap bitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888);
    578         int genId = bitmap.getGenerationId();
    579         assertEquals("not expected to change", genId, bitmap.getGenerationId());
    580         bitmap.setDensity(bitmap.getDensity() + 4);
    581         assertEquals("not expected to change", genId, bitmap.getGenerationId());
    582         bitmap.getPixel(0, 0);
    583         assertEquals("not expected to change", genId, bitmap.getGenerationId());
    584 
    585         int beforeGenId = bitmap.getGenerationId();
    586         bitmap.eraseColor(Color.WHITE);
    587         int afterGenId = bitmap.getGenerationId();
    588         assertTrue("expected to increase", afterGenId > beforeGenId);
    589 
    590         beforeGenId = bitmap.getGenerationId();
    591         bitmap.setPixel(4, 4, Color.BLUE);
    592         afterGenId = bitmap.getGenerationId();
    593         assertTrue("expected to increase again", afterGenId > beforeGenId);
    594     }
    595 
    596     @Test
    597     public void testDescribeContents() {
    598         assertEquals(0, mBitmap.describeContents());
    599     }
    600 
    601     @Test(expected=IllegalStateException.class)
    602     public void testEraseColorOnRecycled() {
    603         mBitmap.recycle();
    604 
    605         mBitmap.eraseColor(0);
    606     }
    607 
    608     @Test(expected = IllegalStateException.class)
    609     public void testEraseColorLongOnRecycled() {
    610         mBitmap.recycle();
    611 
    612         mBitmap.eraseColor(Color.pack(0));
    613     }
    614 
    615     @Test(expected=IllegalStateException.class)
    616     public void testEraseColorOnImmutable() {
    617         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
    618 
    619         //abnormal case: bitmap is immutable
    620         mBitmap.eraseColor(0);
    621     }
    622 
    623     @Test(expected = IllegalStateException.class)
    624     public void testEraseColorLongOnImmutable() {
    625         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
    626 
    627         //abnormal case: bitmap is immutable
    628         mBitmap.eraseColor(Color.pack(0));
    629     }
    630 
    631     @Test
    632     public void testEraseColor() {
    633         // normal case
    634         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
    635         mBitmap.eraseColor(0xffff0000);
    636         assertEquals(0xffff0000, mBitmap.getPixel(10, 10));
    637         assertEquals(0xffff0000, mBitmap.getPixel(50, 50));
    638     }
    639 
    640     @Test(expected = IllegalArgumentException.class)
    641     public void testGetColorOOB() {
    642         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
    643         mBitmap.getColor(-1, 0);
    644     }
    645 
    646     @Test(expected = IllegalArgumentException.class)
    647     public void testGetColorOOB2() {
    648         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
    649         mBitmap.getColor(5, -10);
    650     }
    651 
    652     @Test(expected = IllegalArgumentException.class)
    653     public void testGetColorOOB3() {
    654         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
    655         mBitmap.getColor(100, 10);
    656     }
    657 
    658     @Test(expected = IllegalArgumentException.class)
    659     public void testGetColorOOB4() {
    660         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
    661         mBitmap.getColor(99, 1000);
    662     }
    663 
    664     @Test(expected = IllegalStateException.class)
    665     public void testGetColorRecycled() {
    666         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
    667         mBitmap.recycle();
    668         mBitmap.getColor(0, 0);
    669     }
    670 
    671     @Test(expected = IllegalStateException.class)
    672     public void testGetColorHardware() {
    673         BitmapFactory.Options options = new BitmapFactory.Options();
    674         options.inPreferredConfig = Bitmap.Config.HARDWARE;
    675         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, options);
    676         mBitmap.getColor(50, 50);
    677 
    678     }
    679 
    680     private static float clamp(float f) {
    681         return clamp(f, 0.0f, 1.0f);
    682     }
    683 
    684     private static float clamp(float f, float min, float max) {
    685         return Math.min(Math.max(f, min), max);
    686     }
    687 
    688     @Test
    689     public void testGetColor() {
    690         final ColorSpace sRGB = ColorSpace.get(ColorSpace.Named.SRGB);
    691         List<ColorSpace> rgbColorSpaces = getRgbColorSpaces();
    692         for (Config config : new Config[] { Config.ARGB_8888, Config.RGBA_F16, Config.RGB_565 }) {
    693             for (ColorSpace bitmapColorSpace : rgbColorSpaces) {
    694                 mBitmap = Bitmap.createBitmap(1, 1, config, /*hasAlpha*/ false,
    695                         bitmapColorSpace);
    696                 bitmapColorSpace = mBitmap.getColorSpace();
    697                 for (ColorSpace eraseColorSpace : rgbColorSpaces) {
    698                     for (long wideGamutLong : new long[] {
    699                             Color.pack(1.0f, 0.0f, 0.0f, 1.0f, eraseColorSpace),
    700                             Color.pack(0.0f, 1.0f, 0.0f, 1.0f, eraseColorSpace),
    701                             Color.pack(0.0f, 0.0f, 1.0f, 1.0f, eraseColorSpace)}) {
    702                         mBitmap.eraseColor(wideGamutLong);
    703 
    704                         Color result = mBitmap.getColor(0, 0);
    705                         if (mBitmap.getColorSpace().equals(sRGB)) {
    706                             assertEquals(mBitmap.getPixel(0, 0), result.toArgb());
    707                         }
    708                         if (eraseColorSpace.equals(bitmapColorSpace)) {
    709                             final Color wideGamutColor = Color.valueOf(wideGamutLong);
    710                             ColorUtils.verifyColor("Erasing to Bitmap's ColorSpace "
    711                                     + bitmapColorSpace, wideGamutColor, result, .001f);
    712 
    713                         } else {
    714                             Color convertedColor = Color.valueOf(
    715                                     Color.convert(wideGamutLong, bitmapColorSpace));
    716                             if (mBitmap.getConfig() != Config.RGBA_F16) {
    717                                 // It's possible that we have to clip to fit into the Config.
    718                                 convertedColor = Color.valueOf(
    719                                         clamp(convertedColor.red()),
    720                                         clamp(convertedColor.green()),
    721                                         clamp(convertedColor.blue()),
    722                                         convertedColor.alpha(),
    723                                         bitmapColorSpace);
    724                             }
    725                             ColorUtils.verifyColor("Bitmap(Config: " + mBitmap.getConfig()
    726                                     + ", ColorSpace: " + bitmapColorSpace
    727                                     + ") erasing to " + Color.valueOf(wideGamutLong),
    728                                     convertedColor, result, .03f);
    729                         }
    730                     }
    731                 }
    732             }
    733         }
    734     }
    735 
    736     private static class ARGB {
    737         public float alpha;
    738         public float red;
    739         public float green;
    740         public float blue;
    741         ARGB(float alpha, float red, float green, float blue) {
    742             this.alpha = alpha;
    743             this.red = red;
    744             this.green = green;
    745             this.blue = blue;
    746         }
    747     };
    748 
    749     @Test
    750     public void testEraseColorLong() {
    751         List<ColorSpace> rgbColorSpaces = getRgbColorSpaces();
    752         for (Config config : new Config[]{Config.ARGB_8888, Config.RGB_565, Config.RGBA_F16}) {
    753             mBitmap = Bitmap.createBitmap(100, 100, config);
    754             // pack SRGB colors into ColorLongs.
    755             for (int color : new int[]{ Color.RED, Color.BLUE, Color.GREEN, Color.BLACK,
    756                     Color.WHITE, Color.TRANSPARENT }) {
    757                 if (config.equals(Config.RGB_565) && Float.compare(Color.alpha(color), 1.0f) != 0) {
    758                     // 565 doesn't support alpha.
    759                     continue;
    760                 }
    761                 mBitmap.eraseColor(Color.pack(color));
    762                 // The Bitmap is either SRGB or SRGBLinear (F16). getPixel(), which retrieves the
    763                 // color in SRGB, should match exactly.
    764                 ColorUtils.verifyColor("Config " + config + " mismatch at 10, 10 ",
    765                         color, mBitmap.getPixel(10, 10), 0);
    766                 ColorUtils.verifyColor("Config " + config + " mismatch at 50, 50 ",
    767                         color, mBitmap.getPixel(50, 50), 0);
    768             }
    769 
    770             // Use arbitrary colors in various ColorSpaces. getPixel() should approximately match
    771             // the SRGB version of the color.
    772             for (ARGB color : new ARGB[]{ new ARGB(1.0f, .5f, .5f, .5f),
    773                                           new ARGB(1.0f, .3f, .6f, .9f),
    774                                           new ARGB(0.5f, .2f, .8f, .7f) }) {
    775                 if (config.equals(Config.RGB_565) && Float.compare(color.alpha, 1.0f) != 0) {
    776                     continue;
    777                 }
    778                 int srgbColor = Color.argb(color.alpha, color.red, color.green, color.blue);
    779                 for (ColorSpace cs : rgbColorSpaces) {
    780                     long longColor = Color.convert(srgbColor, cs);
    781                     mBitmap.eraseColor(longColor);
    782                     // These tolerances were chosen by trial and error. It is expected that
    783                     // some conversions do not round-trip perfectly.
    784                     int tolerance = 1;
    785                     if (config.equals(Config.RGB_565)) {
    786                         tolerance = 4;
    787                     } else if (cs.equals(ColorSpace.get(ColorSpace.Named.SMPTE_C))) {
    788                         tolerance = 3;
    789                     }
    790 
    791                     ColorUtils.verifyColor("Config " + config + ", ColorSpace " + cs
    792                             + ", mismatch at 10, 10 ", srgbColor, mBitmap.getPixel(10, 10),
    793                             tolerance);
    794                     ColorUtils.verifyColor("Config " + config + ", ColorSpace " + cs
    795                             + ", mismatch at 50, 50 ", srgbColor, mBitmap.getPixel(50, 50),
    796                             tolerance);
    797                 }
    798             }
    799         }
    800     }
    801 
    802     @Test
    803     public void testEraseColorOnP3() {
    804         // Use a ColorLong with a different ColorSpace than the Bitmap. getPixel() should
    805         // approximately match the SRGB version of the color.
    806         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888, true,
    807                 ColorSpace.get(ColorSpace.Named.DISPLAY_P3));
    808         int srgbColor = Color.argb(.5f, .3f, .6f, .7f);
    809         long acesColor = Color.convert(srgbColor, ColorSpace.get(ColorSpace.Named.ACES));
    810         mBitmap.eraseColor(acesColor);
    811         ColorUtils.verifyColor("Mismatch at 15, 15", srgbColor, mBitmap.getPixel(15, 15), 1);
    812     }
    813 
    814     @Test(expected = IllegalArgumentException.class)
    815     public void testEraseColorXYZ() {
    816         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
    817         mBitmap.eraseColor(Color.convert(Color.BLUE, ColorSpace.get(ColorSpace.Named.CIE_XYZ)));
    818     }
    819 
    820     @Test(expected = IllegalArgumentException.class)
    821     public void testEraseColorLAB() {
    822         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
    823         mBitmap.eraseColor(Color.convert(Color.BLUE, ColorSpace.get(ColorSpace.Named.CIE_LAB)));
    824     }
    825 
    826     @Test(expected = IllegalArgumentException.class)
    827     public void testEraseColorUnknown() {
    828         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
    829         mBitmap.eraseColor(-1L);
    830     }
    831 
    832     @Test(expected=IllegalStateException.class)
    833     public void testExtractAlphaFromRecycled() {
    834         mBitmap.recycle();
    835 
    836         mBitmap.extractAlpha();
    837     }
    838 
    839     @Test
    840     public void testExtractAlpha() {
    841         // normal case
    842         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
    843         Bitmap ret = mBitmap.extractAlpha();
    844         assertNotNull(ret);
    845         int source = mBitmap.getPixel(10, 20);
    846         int result = ret.getPixel(10, 20);
    847         assertEquals(Color.alpha(source), Color.alpha(result));
    848         assertEquals(0xFF, Color.alpha(result));
    849     }
    850 
    851     @Test(expected=IllegalStateException.class)
    852     public void testExtractAlphaWithPaintAndOffsetFromRecycled() {
    853         mBitmap.recycle();
    854 
    855         mBitmap.extractAlpha(new Paint(), new int[]{0, 1});
    856     }
    857 
    858     @Test
    859     public void testExtractAlphaWithPaintAndOffset() {
    860         // normal case
    861         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
    862         Bitmap ret = mBitmap.extractAlpha(new Paint(), new int[]{0, 1});
    863         assertNotNull(ret);
    864         int source = mBitmap.getPixel(10, 20);
    865         int result = ret.getPixel(10, 20);
    866         assertEquals(Color.alpha(source), Color.alpha(result));
    867         assertEquals(0xFF, Color.alpha(result));
    868     }
    869 
    870     @Test
    871     public void testGetAllocationByteCount() {
    872         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ALPHA_8);
    873         int alloc = mBitmap.getAllocationByteCount();
    874         assertEquals(mBitmap.getByteCount(), alloc);
    875 
    876         // reconfigure same size
    877         mBitmap.reconfigure(50, 100, Bitmap.Config.ARGB_8888);
    878         assertEquals(mBitmap.getByteCount(), alloc);
    879         assertEquals(mBitmap.getAllocationByteCount(), alloc);
    880 
    881         // reconfigure different size
    882         mBitmap.reconfigure(10, 10, Bitmap.Config.ALPHA_8);
    883         assertEquals(mBitmap.getByteCount(), 100);
    884         assertEquals(mBitmap.getAllocationByteCount(), alloc);
    885     }
    886 
    887     @Test
    888     public void testGetConfig() {
    889         Bitmap bm0 = Bitmap.createBitmap(100, 200, Bitmap.Config.ALPHA_8);
    890         Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
    891         Bitmap bm2 = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
    892         Bitmap bm3 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_4444);
    893 
    894         assertEquals(Bitmap.Config.ALPHA_8, bm0.getConfig());
    895         assertEquals(Bitmap.Config.ARGB_8888, bm1.getConfig());
    896         assertEquals(Bitmap.Config.RGB_565, bm2.getConfig());
    897         // Attempting to create a 4444 bitmap actually creates an 8888 bitmap.
    898         assertEquals(Bitmap.Config.ARGB_8888, bm3.getConfig());
    899 
    900         // Can't call Bitmap.createBitmap with Bitmap.Config.HARDWARE,
    901         // because createBitmap creates mutable bitmap and hardware bitmaps are always immutable,
    902         // so such call will throw an exception.
    903         Bitmap hardwareBitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot,
    904                 HARDWARE_OPTIONS);
    905         assertEquals(Bitmap.Config.HARDWARE, hardwareBitmap.getConfig());
    906     }
    907 
    908     @Test
    909     public void testGetHeight() {
    910         assertEquals(31, mBitmap.getHeight());
    911         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
    912         assertEquals(200, mBitmap.getHeight());
    913     }
    914 
    915     @Test
    916     public void testGetNinePatchChunk() {
    917         assertNull(mBitmap.getNinePatchChunk());
    918     }
    919 
    920     @Test(expected=IllegalStateException.class)
    921     public void testGetPixelFromRecycled() {
    922         mBitmap.recycle();
    923 
    924         mBitmap.getPixel(10, 16);
    925     }
    926 
    927     @Test(expected=IllegalArgumentException.class)
    928     public void testGetPixelXTooLarge() {
    929         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
    930 
    931         // abnormal case: x bigger than the source bitmap's width
    932         mBitmap.getPixel(200, 16);
    933     }
    934 
    935     @Test(expected=IllegalArgumentException.class)
    936     public void testGetPixelYTooLarge() {
    937         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
    938 
    939         // abnormal case: y bigger than the source bitmap's height
    940         mBitmap.getPixel(10, 300);
    941     }
    942 
    943     @Test
    944     public void testGetPixel() {
    945         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
    946 
    947         // normal case 565
    948         mBitmap.setPixel(10, 16, 0xFF << 24);
    949         assertEquals(0xFF << 24, mBitmap.getPixel(10, 16));
    950 
    951         // normal case A_8
    952         mBitmap = Bitmap.createBitmap(10, 10, Config.ALPHA_8);
    953         mBitmap.setPixel(5, 5, 0xFFFFFFFF);
    954         assertEquals(0xFF000000, mBitmap.getPixel(5, 5));
    955         mBitmap.setPixel(5, 5, 0xA8A8A8A8);
    956         assertEquals(0xA8000000, mBitmap.getPixel(5, 5));
    957         mBitmap.setPixel(5, 5, 0x00000000);
    958         assertEquals(0x00000000, mBitmap.getPixel(5, 5));
    959         mBitmap.setPixel(5, 5, 0x1F000000);
    960         assertEquals(0x1F000000, mBitmap.getPixel(5, 5));
    961     }
    962 
    963     @Test
    964     public void testGetRowBytes() {
    965         Bitmap bm0 = Bitmap.createBitmap(100, 200, Bitmap.Config.ALPHA_8);
    966         Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
    967         Bitmap bm2 = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
    968         Bitmap bm3 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_4444);
    969 
    970         assertEquals(100, bm0.getRowBytes());
    971         assertEquals(400, bm1.getRowBytes());
    972         assertEquals(200, bm2.getRowBytes());
    973         // Attempting to create a 4444 bitmap actually creates an 8888 bitmap.
    974         assertEquals(400, bm3.getRowBytes());
    975     }
    976 
    977     @Test
    978     public void testGetWidth() {
    979         assertEquals(31, mBitmap.getWidth());
    980         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
    981         assertEquals(100, mBitmap.getWidth());
    982     }
    983 
    984     @Test
    985     public void testHasAlpha() {
    986         assertFalse(mBitmap.hasAlpha());
    987         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
    988         assertTrue(mBitmap.hasAlpha());
    989     }
    990 
    991     @Test
    992     public void testIsMutable() {
    993         assertFalse(mBitmap.isMutable());
    994         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
    995         assertTrue(mBitmap.isMutable());
    996     }
    997 
    998     @Test
    999     public void testIsRecycled() {
   1000         assertFalse(mBitmap.isRecycled());
   1001         mBitmap.recycle();
   1002         assertTrue(mBitmap.isRecycled());
   1003     }
   1004 
   1005     @Test
   1006     public void testReconfigure() {
   1007         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
   1008         int alloc = mBitmap.getAllocationByteCount();
   1009 
   1010         // test shrinking
   1011         mBitmap.reconfigure(50, 100, Bitmap.Config.ALPHA_8);
   1012         assertEquals(mBitmap.getAllocationByteCount(), alloc);
   1013         assertEquals(mBitmap.getByteCount() * 8, alloc);
   1014     }
   1015 
   1016     @Test(expected=IllegalArgumentException.class)
   1017     public void testReconfigureExpanding() {
   1018         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
   1019         mBitmap.reconfigure(101, 201, Bitmap.Config.ARGB_8888);
   1020     }
   1021 
   1022     @Test(expected=IllegalStateException.class)
   1023     public void testReconfigureMutable() {
   1024         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
   1025         mBitmap.reconfigure(1, 1, Bitmap.Config.ALPHA_8);
   1026     }
   1027 
   1028     // Used by testAlphaAndPremul.
   1029     private static Config[] CONFIGS = new Config[] { Config.ALPHA_8, Config.ARGB_4444,
   1030             Config.ARGB_8888, Config.RGB_565 };
   1031 
   1032     // test that reconfigure, setHasAlpha, and setPremultiplied behave as expected with
   1033     // respect to alpha and premultiplied.
   1034     @Test
   1035     public void testAlphaAndPremul() {
   1036         boolean falseTrue[] = new boolean[] { false, true };
   1037         for (Config fromConfig : CONFIGS) {
   1038             for (Config toConfig : CONFIGS) {
   1039                 for (boolean hasAlpha : falseTrue) {
   1040                     for (boolean isPremul : falseTrue) {
   1041                         Bitmap bitmap = Bitmap.createBitmap(10, 10, fromConfig);
   1042 
   1043                         // 4444 is deprecated, and will convert to 8888. No need to
   1044                         // attempt a reconfigure, which will be tested when fromConfig
   1045                         // is 8888.
   1046                         if (fromConfig == Config.ARGB_4444) {
   1047                             assertEquals(bitmap.getConfig(), Config.ARGB_8888);
   1048                             break;
   1049                         }
   1050 
   1051                         bitmap.setHasAlpha(hasAlpha);
   1052                         bitmap.setPremultiplied(isPremul);
   1053 
   1054                         verifyAlphaAndPremul(bitmap, hasAlpha, isPremul, false);
   1055 
   1056                         // reconfigure to a smaller size so the function will still succeed when
   1057                         // going to a Config that requires more bits.
   1058                         bitmap.reconfigure(1, 1, toConfig);
   1059                         if (toConfig == Config.ARGB_4444) {
   1060                             assertEquals(bitmap.getConfig(), Config.ARGB_8888);
   1061                         } else {
   1062                             assertEquals(bitmap.getConfig(), toConfig);
   1063                         }
   1064 
   1065                         // Check that the alpha and premultiplied state has not changed (unless
   1066                         // we expected it to).
   1067                         verifyAlphaAndPremul(bitmap, hasAlpha, isPremul, fromConfig == Config.RGB_565);
   1068                     }
   1069                 }
   1070             }
   1071         }
   1072     }
   1073 
   1074     /**
   1075      *  Assert that bitmap returns the appropriate values for hasAlpha() and isPremultiplied().
   1076      *  @param bitmap Bitmap to check.
   1077      *  @param expectedAlpha Expected return value from bitmap.hasAlpha(). Note that this is based
   1078      *          on what was set, but may be different from the actual return value depending on the
   1079      *          Config and convertedFrom565.
   1080      *  @param expectedPremul Expected return value from bitmap.isPremultiplied(). Similar to
   1081      *          expectedAlpha, this is based on what was set, but may be different from the actual
   1082      *          return value depending on the Config.
   1083      *  @param convertedFrom565 Whether bitmap was converted to its current Config by being
   1084      *          reconfigured from RGB_565. If true, and bitmap is now a Config that supports alpha,
   1085      *          hasAlpha() is expected to be true even if expectedAlpha is false.
   1086      */
   1087     private void verifyAlphaAndPremul(Bitmap bitmap, boolean expectedAlpha, boolean expectedPremul,
   1088             boolean convertedFrom565) {
   1089         switch (bitmap.getConfig()) {
   1090             case ARGB_4444:
   1091                 // This shouldn't happen, since we don't allow creating or converting
   1092                 // to 4444.
   1093                 assertFalse(true);
   1094                 break;
   1095             case RGB_565:
   1096                 assertFalse(bitmap.hasAlpha());
   1097                 assertFalse(bitmap.isPremultiplied());
   1098                 break;
   1099             case ALPHA_8:
   1100                 // ALPHA_8 behaves mostly the same as 8888, except for premultiplied. Fall through.
   1101             case ARGB_8888:
   1102                 // Since 565 is necessarily opaque, we revert to hasAlpha when switching to a type
   1103                 // that can have alpha.
   1104                 if (convertedFrom565) {
   1105                     assertTrue(bitmap.hasAlpha());
   1106                 } else {
   1107                     assertEquals(bitmap.hasAlpha(), expectedAlpha);
   1108                 }
   1109 
   1110                 if (bitmap.hasAlpha()) {
   1111                     // ALPHA_8's premultiplied status is undefined.
   1112                     if (bitmap.getConfig() != Config.ALPHA_8) {
   1113                         assertEquals(bitmap.isPremultiplied(), expectedPremul);
   1114                     }
   1115                 } else {
   1116                     // Opaque bitmap is never considered premultiplied.
   1117                     assertFalse(bitmap.isPremultiplied());
   1118                 }
   1119                 break;
   1120         }
   1121     }
   1122 
   1123     @Test
   1124     public void testSetColorSpace() {
   1125         // Use arbitrary colors and assign to various ColorSpaces.
   1126         for (ARGB color : new ARGB[]{ new ARGB(1.0f, .5f, .5f, .5f),
   1127                 new ARGB(1.0f, .3f, .6f, .9f),
   1128                 new ARGB(0.5f, .2f, .8f, .7f) }) {
   1129 
   1130             int srgbColor = Color.argb(color.alpha, color.red, color.green, color.blue);
   1131             for (ColorSpace cs : getRgbColorSpaces()) {
   1132                 for (Config config : new Config[] {
   1133                         // F16 is tested elsewhere, since it defaults to EXTENDED_SRGB, and
   1134                         // many of these calls to setColorSpace would reduce the range, resulting
   1135                         // in an Exception.
   1136                         Config.ARGB_8888,
   1137                         Config.RGB_565,
   1138                 }) {
   1139                     mBitmap = Bitmap.createBitmap(10, 10, config);
   1140                     mBitmap.eraseColor(srgbColor);
   1141                     mBitmap.setColorSpace(cs);
   1142                     ColorSpace actual = mBitmap.getColorSpace();
   1143                     if (cs == ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)) {
   1144                         assertSame(ColorSpace.get(ColorSpace.Named.SRGB), actual);
   1145                     } else if (cs == ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB)) {
   1146                         assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_SRGB), actual);
   1147                     } else {
   1148                         assertSame(cs, actual);
   1149                     }
   1150 
   1151                     // This tolerance was chosen by trial and error. It is expected that
   1152                     // some conversions do not round-trip perfectly.
   1153                     int tolerance = 2;
   1154                     Color c = Color.valueOf(color.red, color.green, color.blue, color.alpha, cs);
   1155                     ColorUtils.verifyColor("Mismatch after setting the colorSpace to "
   1156                             + cs.getName(), c.convert(mBitmap.getColorSpace()),
   1157                             mBitmap.getColor(5, 5), tolerance);
   1158                 }
   1159             }
   1160         }
   1161     }
   1162 
   1163     @Test(expected = IllegalStateException.class)
   1164     public void testSetColorSpaceRecycled() {
   1165         mBitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888);
   1166         mBitmap.recycle();
   1167         mBitmap.setColorSpace(ColorSpace.get(Named.DISPLAY_P3));
   1168     }
   1169 
   1170     @Test(expected = IllegalArgumentException.class)
   1171     public void testSetColorSpaceNull() {
   1172         mBitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888);
   1173         mBitmap.setColorSpace(null);
   1174     }
   1175 
   1176     @Test(expected = IllegalArgumentException.class)
   1177     public void testSetColorSpaceXYZ() {
   1178         mBitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888);
   1179         mBitmap.setColorSpace(ColorSpace.get(Named.CIE_XYZ));
   1180     }
   1181 
   1182     @Test(expected = IllegalArgumentException.class)
   1183     public void testSetColorSpaceNoTransferParameters() {
   1184         mBitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888);
   1185         ColorSpace cs = new ColorSpace.Rgb("NoTransferParams",
   1186                 new float[]{ 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f },
   1187                 ColorSpace.ILLUMINANT_D50,
   1188                 x -> Math.pow(x, 1.0f / 2.2f), x -> Math.pow(x, 2.2f),
   1189                 0, 1);
   1190         mBitmap.setColorSpace(cs);
   1191     }
   1192 
   1193     @Test(expected = IllegalArgumentException.class)
   1194     public void testSetColorSpaceAlpha8() {
   1195         mBitmap = Bitmap.createBitmap(10, 10, Config.ALPHA_8);
   1196         assertNull(mBitmap.getColorSpace());
   1197         mBitmap.setColorSpace(ColorSpace.get(ColorSpace.Named.SRGB));
   1198     }
   1199 
   1200     @Test
   1201     public void testSetColorSpaceReducedRange() {
   1202         ColorSpace aces = ColorSpace.get(Named.ACES);
   1203         mBitmap = Bitmap.createBitmap(10, 10, Config.RGBA_F16, true, aces);
   1204         try {
   1205             mBitmap.setColorSpace(ColorSpace.get(Named.SRGB));
   1206             fail("Expected IllegalArgumentException!");
   1207         } catch (IllegalArgumentException e) {
   1208             assertSame(aces, mBitmap.getColorSpace());
   1209         }
   1210     }
   1211 
   1212     @Test
   1213     public void testSetColorSpaceNotReducedRange() {
   1214         ColorSpace extended = ColorSpace.get(Named.EXTENDED_SRGB);
   1215         mBitmap = Bitmap.createBitmap(10, 10, Config.RGBA_F16, true,
   1216                 extended);
   1217         mBitmap.setColorSpace(ColorSpace.get(Named.SRGB));
   1218         assertSame(mBitmap.getColorSpace(), extended);
   1219     }
   1220 
   1221     @Test
   1222     public void testSetColorSpaceNotReducedRangeLinear() {
   1223         ColorSpace linearExtended = ColorSpace.get(Named.LINEAR_EXTENDED_SRGB);
   1224         mBitmap = Bitmap.createBitmap(10, 10, Config.RGBA_F16, true,
   1225                 linearExtended);
   1226         mBitmap.setColorSpace(ColorSpace.get(Named.LINEAR_SRGB));
   1227         assertSame(mBitmap.getColorSpace(), linearExtended);
   1228     }
   1229 
   1230     @Test
   1231     public void testSetColorSpaceIncreasedRange() {
   1232         mBitmap = Bitmap.createBitmap(10, 10, Config.RGBA_F16, true,
   1233                 ColorSpace.get(Named.DISPLAY_P3));
   1234         ColorSpace linearExtended = ColorSpace.get(Named.LINEAR_EXTENDED_SRGB);
   1235         mBitmap.setColorSpace(linearExtended);
   1236         assertSame(mBitmap.getColorSpace(), linearExtended);
   1237     }
   1238 
   1239     @Test
   1240     public void testSetConfig() {
   1241         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
   1242         int alloc = mBitmap.getAllocationByteCount();
   1243 
   1244         // test shrinking
   1245         mBitmap.setConfig(Bitmap.Config.ALPHA_8);
   1246         assertEquals(mBitmap.getAllocationByteCount(), alloc);
   1247         assertEquals(mBitmap.getByteCount() * 2, alloc);
   1248     }
   1249 
   1250     @Test(expected=IllegalArgumentException.class)
   1251     public void testSetConfigExpanding() {
   1252         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
   1253         // test expanding
   1254         mBitmap.setConfig(Bitmap.Config.ARGB_8888);
   1255     }
   1256 
   1257     @Test(expected=IllegalStateException.class)
   1258     public void testSetConfigMutable() {
   1259         // test mutable
   1260         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
   1261         mBitmap.setConfig(Bitmap.Config.ALPHA_8);
   1262     }
   1263 
   1264     @Test
   1265     public void testSetHeight() {
   1266         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
   1267         int alloc = mBitmap.getAllocationByteCount();
   1268 
   1269         // test shrinking
   1270         mBitmap.setHeight(100);
   1271         assertEquals(mBitmap.getAllocationByteCount(), alloc);
   1272         assertEquals(mBitmap.getByteCount() * 2, alloc);
   1273     }
   1274 
   1275     @Test(expected=IllegalArgumentException.class)
   1276     public void testSetHeightExpanding() {
   1277         // test expanding
   1278         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
   1279         mBitmap.setHeight(201);
   1280     }
   1281 
   1282     @Test(expected=IllegalStateException.class)
   1283     public void testSetHeightMutable() {
   1284         // test mutable
   1285         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
   1286         mBitmap.setHeight(1);
   1287     }
   1288 
   1289     @Test(expected=IllegalStateException.class)
   1290     public void testSetPixelOnRecycled() {
   1291         int color = 0xff << 24;
   1292 
   1293         mBitmap.recycle();
   1294         mBitmap.setPixel(10, 16, color);
   1295     }
   1296 
   1297     @Test(expected=IllegalStateException.class)
   1298     public void testSetPixelOnImmutable() {
   1299         int color = 0xff << 24;
   1300         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
   1301 
   1302         mBitmap.setPixel(10, 16, color);
   1303     }
   1304 
   1305     @Test(expected=IllegalArgumentException.class)
   1306     public void testSetPixelXIsTooLarge() {
   1307         int color = 0xff << 24;
   1308         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
   1309 
   1310         // abnormal case: x bigger than the source bitmap's width
   1311         mBitmap.setPixel(200, 16, color);
   1312     }
   1313 
   1314     @Test(expected=IllegalArgumentException.class)
   1315     public void testSetPixelYIsTooLarge() {
   1316         int color = 0xff << 24;
   1317         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
   1318 
   1319         // abnormal case: y bigger than the source bitmap's height
   1320         mBitmap.setPixel(10, 300, color);
   1321     }
   1322 
   1323     @Test
   1324     public void testSetPixel() {
   1325         int color = 0xff << 24;
   1326         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
   1327 
   1328         // normal case
   1329         mBitmap.setPixel(10, 16, color);
   1330         assertEquals(color, mBitmap.getPixel(10, 16));
   1331     }
   1332 
   1333     @Test(expected=IllegalStateException.class)
   1334     public void testSetPixelsOnRecycled() {
   1335         int[] colors = createColors(100);
   1336 
   1337         mBitmap.recycle();
   1338         mBitmap.setPixels(colors, 0, 0, 0, 0, 0, 0);
   1339     }
   1340 
   1341     @Test(expected=IllegalStateException.class)
   1342     public void testSetPixelsOnImmutable() {
   1343         int[] colors = createColors(100);
   1344         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
   1345 
   1346         mBitmap.setPixels(colors, 0, 0, 0, 0, 0, 0);
   1347     }
   1348 
   1349     @Test(expected=IllegalArgumentException.class)
   1350     public void testSetPixelsXYNegative() {
   1351         int[] colors = createColors(100);
   1352         mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
   1353 
   1354         // abnormal case: x and/or y less than 0
   1355         mBitmap.setPixels(colors, 0, 0, -1, -1, 200, 16);
   1356     }
   1357 
   1358     @Test(expected=IllegalArgumentException.class)
   1359     public void testSetPixelsWidthHeightNegative() {
   1360         int[] colors = createColors(100);
   1361         mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
   1362 
   1363         // abnormal case: width and/or height less than 0
   1364         mBitmap.setPixels(colors, 0, 0, 0, 0, -1, -1);
   1365     }
   1366 
   1367     @Test(expected=IllegalArgumentException.class)
   1368     public void testSetPixelsXTooHigh() {
   1369         int[] colors = createColors(100);
   1370         mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
   1371 
   1372         // abnormal case: (x + width) bigger than the source bitmap's width
   1373         mBitmap.setPixels(colors, 0, 0, 10, 10, 95, 50);
   1374     }
   1375 
   1376     @Test(expected=IllegalArgumentException.class)
   1377     public void testSetPixelsYTooHigh() {
   1378         int[] colors = createColors(100);
   1379         mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
   1380 
   1381         // abnormal case: (y + height) bigger than the source bitmap's height
   1382         mBitmap.setPixels(colors, 0, 0, 10, 10, 50, 95);
   1383     }
   1384 
   1385     @Test(expected=IllegalArgumentException.class)
   1386     public void testSetPixelsStrideIllegal() {
   1387         int[] colors = createColors(100);
   1388         mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
   1389 
   1390         // abnormal case: stride less than width and bigger than -width
   1391         mBitmap.setPixels(colors, 0, 10, 10, 10, 50, 50);
   1392     }
   1393 
   1394     @Test(expected=ArrayIndexOutOfBoundsException.class)
   1395     public void testSetPixelsOffsetNegative() {
   1396         int[] colors = createColors(100);
   1397         mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
   1398 
   1399         // abnormal case: offset less than 0
   1400         mBitmap.setPixels(colors, -1, 50, 10, 10, 50, 50);
   1401     }
   1402 
   1403     @Test(expected=ArrayIndexOutOfBoundsException.class)
   1404     public void testSetPixelsOffsetTooBig() {
   1405         int[] colors = createColors(100);
   1406         mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
   1407 
   1408         // abnormal case: (offset + width) bigger than the length of colors
   1409         mBitmap.setPixels(colors, 60, 50, 10, 10, 50, 50);
   1410     }
   1411 
   1412     @Test(expected=ArrayIndexOutOfBoundsException.class)
   1413     public void testSetPixelsLastScanlineNegative() {
   1414         int[] colors = createColors(100);
   1415         mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
   1416 
   1417         // abnormal case: lastScanline less than 0
   1418         mBitmap.setPixels(colors, 10, -50, 10, 10, 50, 50);
   1419     }
   1420 
   1421     @Test(expected=ArrayIndexOutOfBoundsException.class)
   1422     public void testSetPixelsLastScanlineTooBig() {
   1423         int[] colors = createColors(100);
   1424         mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
   1425 
   1426         // abnormal case: (lastScanline + width) bigger than the length of colors
   1427         mBitmap.setPixels(colors, 10, 50, 10, 10, 50, 50);
   1428     }
   1429 
   1430     @Test
   1431     public void testSetPixels() {
   1432         int[] colors = createColors(100 * 100);
   1433         mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
   1434         mBitmap.setPixels(colors, 0, 100, 0, 0, 100, 100);
   1435         int[] ret = new int[100 * 100];
   1436         mBitmap.getPixels(ret, 0, 100, 0, 0, 100, 100);
   1437 
   1438         for(int i = 0; i < 10000; i++){
   1439             assertEquals(ret[i], colors[i]);
   1440         }
   1441     }
   1442 
   1443     private void verifyPremultipliedBitmapConfig(Config config, boolean expectedPremul) {
   1444         Bitmap bitmap = Bitmap.createBitmap(1, 1, config);
   1445         bitmap.setPremultiplied(true);
   1446         bitmap.setPixel(0, 0, Color.TRANSPARENT);
   1447         assertTrue(bitmap.isPremultiplied() == expectedPremul);
   1448 
   1449         bitmap.setHasAlpha(false);
   1450         assertFalse(bitmap.isPremultiplied());
   1451     }
   1452 
   1453     @Test
   1454     public void testSetPremultipliedSimple() {
   1455         verifyPremultipliedBitmapConfig(Bitmap.Config.ALPHA_8, true);
   1456         verifyPremultipliedBitmapConfig(Bitmap.Config.RGB_565, false);
   1457         verifyPremultipliedBitmapConfig(Bitmap.Config.ARGB_4444, true);
   1458         verifyPremultipliedBitmapConfig(Bitmap.Config.ARGB_8888, true);
   1459     }
   1460 
   1461     @Test
   1462     public void testSetPremultipliedData() {
   1463         // with premul, will store 2,2,2,2, so it doesn't get value correct
   1464         Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
   1465         bitmap.setPixel(0, 0, PREMUL_COLOR);
   1466         assertEquals(bitmap.getPixel(0, 0), PREMUL_ROUNDED_COLOR);
   1467 
   1468         // read premultiplied value directly
   1469         bitmap.setPremultiplied(false);
   1470         assertEquals(bitmap.getPixel(0, 0), PREMUL_STORED_COLOR);
   1471 
   1472         // value can now be stored/read correctly
   1473         bitmap.setPixel(0, 0, PREMUL_COLOR);
   1474         assertEquals(bitmap.getPixel(0, 0), PREMUL_COLOR);
   1475 
   1476         // verify with array methods
   1477         int testArray[] = new int[] { PREMUL_COLOR };
   1478         bitmap.setPixels(testArray, 0, 1, 0, 0, 1, 1);
   1479         bitmap.getPixels(testArray, 0, 1, 0, 0, 1, 1);
   1480         assertEquals(bitmap.getPixel(0, 0), PREMUL_COLOR);
   1481     }
   1482 
   1483     @Test
   1484     public void testPremultipliedCanvas() {
   1485         Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
   1486         bitmap.setHasAlpha(true);
   1487         bitmap.setPremultiplied(false);
   1488         assertFalse(bitmap.isPremultiplied());
   1489 
   1490         Canvas c = new Canvas();
   1491         try {
   1492             c.drawBitmap(bitmap, 0, 0, null);
   1493             fail("canvas should fail with exception");
   1494         } catch (RuntimeException e) {
   1495         }
   1496     }
   1497 
   1498     private int getBitmapRawInt(Bitmap bitmap) {
   1499         IntBuffer buffer = IntBuffer.allocate(1);
   1500         bitmap.copyPixelsToBuffer(buffer);
   1501         return buffer.get(0);
   1502     }
   1503 
   1504     private void bitmapStoreRawInt(Bitmap bitmap, int value) {
   1505         IntBuffer buffer = IntBuffer.allocate(1);
   1506         buffer.put(0, value);
   1507         bitmap.copyPixelsFromBuffer(buffer);
   1508     }
   1509 
   1510     @Test
   1511     public void testSetPremultipliedToBuffer() {
   1512         Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
   1513         bitmap.setPixel(0, 0, PREMUL_COLOR);
   1514         int storedPremul = getBitmapRawInt(bitmap);
   1515 
   1516         bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
   1517         bitmap.setPremultiplied(false);
   1518         bitmap.setPixel(0, 0, PREMUL_STORED_COLOR);
   1519 
   1520         assertEquals(getBitmapRawInt(bitmap), storedPremul);
   1521     }
   1522 
   1523     @Test
   1524     public void testSetPremultipliedFromBuffer() {
   1525         Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
   1526         bitmap.setPremultiplied(false);
   1527         bitmap.setPixel(0, 0, PREMUL_COLOR);
   1528         int rawTestColor = getBitmapRawInt(bitmap);
   1529 
   1530         bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
   1531         bitmap.setPremultiplied(false);
   1532         bitmapStoreRawInt(bitmap, rawTestColor);
   1533         assertEquals(bitmap.getPixel(0, 0), PREMUL_COLOR);
   1534     }
   1535 
   1536     @Test
   1537     public void testSetWidth() {
   1538         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
   1539         int alloc = mBitmap.getAllocationByteCount();
   1540 
   1541         // test shrinking
   1542         mBitmap.setWidth(50);
   1543         assertEquals(mBitmap.getAllocationByteCount(), alloc);
   1544         assertEquals(mBitmap.getByteCount() * 2, alloc);
   1545     }
   1546 
   1547     @Test(expected=IllegalArgumentException.class)
   1548     public void testSetWidthExpanding() {
   1549         // test expanding
   1550         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
   1551 
   1552         mBitmap.setWidth(101);
   1553     }
   1554 
   1555     @Test(expected=IllegalStateException.class)
   1556     public void testSetWidthMutable() {
   1557         // test mutable
   1558         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
   1559 
   1560         mBitmap.setWidth(1);
   1561     }
   1562 
   1563     @Test(expected=IllegalStateException.class)
   1564     public void testWriteToParcelRecycled() {
   1565         mBitmap.recycle();
   1566 
   1567         mBitmap.writeToParcel(null, 0);
   1568     }
   1569 
   1570     @Test
   1571     public void testWriteToParcel() {
   1572         // abnormal case: failed to unparcel Bitmap
   1573         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
   1574         Parcel p = Parcel.obtain();
   1575         mBitmap.writeToParcel(p, 0);
   1576 
   1577         try {
   1578             Bitmap.CREATOR.createFromParcel(p);
   1579             fail("shouldn't come to here");
   1580         } catch(RuntimeException e){
   1581         }
   1582 
   1583         p.recycle();
   1584         // normal case
   1585         p = Parcel.obtain();
   1586         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
   1587         mBitmap.writeToParcel(p, 0);
   1588         p.setDataPosition(0);
   1589         assertTrue(mBitmap.sameAs(Bitmap.CREATOR.createFromParcel(p)));
   1590 
   1591         p.recycle();
   1592     }
   1593 
   1594     @Test
   1595     public void testWriteHwBitmapToParcel() {
   1596         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS);
   1597         Parcel p = Parcel.obtain();
   1598         mBitmap.writeToParcel(p, 0);
   1599         p.setDataPosition(0);
   1600         Bitmap expectedBitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot);
   1601         assertTrue(expectedBitmap.sameAs(Bitmap.CREATOR.createFromParcel(p)));
   1602 
   1603         p.recycle();
   1604     }
   1605 
   1606     @Test
   1607     public void testParcelF16ColorSpace() {
   1608         for (ColorSpace.Named e : new ColorSpace.Named[] {
   1609                 ColorSpace.Named.EXTENDED_SRGB,
   1610                 ColorSpace.Named.LINEAR_EXTENDED_SRGB,
   1611                 ColorSpace.Named.PRO_PHOTO_RGB,
   1612                 ColorSpace.Named.DISPLAY_P3
   1613         }) {
   1614             final ColorSpace cs = ColorSpace.get(e);
   1615             Bitmap b = Bitmap.createBitmap(10, 10, Config.RGBA_F16, true, cs);
   1616             assertSame(cs, b.getColorSpace());
   1617 
   1618             Parcel p = Parcel.obtain();
   1619             b.writeToParcel(p, 0);
   1620             p.setDataPosition(0);
   1621             Bitmap unparceled = Bitmap.CREATOR.createFromParcel(p);
   1622             assertSame(cs, unparceled.getColorSpace());
   1623         }
   1624     }
   1625 
   1626     @Test
   1627     public void testGetScaledHeight1() {
   1628         int dummyDensity = 5;
   1629         Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565);
   1630         int scaledHeight = scaleFromDensity(ret.getHeight(), ret.getDensity(), dummyDensity);
   1631         assertNotNull(ret);
   1632         assertEquals(scaledHeight, ret.getScaledHeight(dummyDensity));
   1633     }
   1634 
   1635     @Test
   1636     public void testGetScaledHeight2() {
   1637         Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565);
   1638         DisplayMetrics metrics =
   1639                 InstrumentationRegistry.getTargetContext().getResources().getDisplayMetrics();
   1640         int scaledHeight = scaleFromDensity(ret.getHeight(), ret.getDensity(), metrics.densityDpi);
   1641         assertEquals(scaledHeight, ret.getScaledHeight(metrics));
   1642     }
   1643 
   1644     @Test
   1645     public void testGetScaledHeight3() {
   1646         Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565);
   1647         Bitmap mMutableBitmap = Bitmap.createBitmap(100, 200, Config.ARGB_8888);
   1648         Canvas mCanvas = new Canvas(mMutableBitmap);
   1649         // set Density
   1650         mCanvas.setDensity(DisplayMetrics.DENSITY_HIGH);
   1651         int scaledHeight = scaleFromDensity(
   1652                 ret.getHeight(), ret.getDensity(), mCanvas.getDensity());
   1653         assertEquals(scaledHeight, ret.getScaledHeight(mCanvas));
   1654     }
   1655 
   1656     @Test
   1657     public void testGetScaledWidth1() {
   1658         int dummyDensity = 5;
   1659         Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565);
   1660         int scaledWidth = scaleFromDensity(ret.getWidth(), ret.getDensity(), dummyDensity);
   1661         assertNotNull(ret);
   1662         assertEquals(scaledWidth, ret.getScaledWidth(dummyDensity));
   1663     }
   1664 
   1665     @Test
   1666     public void testGetScaledWidth2() {
   1667         Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565);
   1668         DisplayMetrics metrics =
   1669                 InstrumentationRegistry.getTargetContext().getResources().getDisplayMetrics();
   1670         int scaledWidth = scaleFromDensity(ret.getWidth(), ret.getDensity(), metrics.densityDpi);
   1671         assertEquals(scaledWidth, ret.getScaledWidth(metrics));
   1672     }
   1673 
   1674     @Test
   1675     public void testGetScaledWidth3() {
   1676         Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565);
   1677         Bitmap mMutableBitmap = Bitmap.createBitmap(100, 200, Config.ARGB_8888);
   1678         Canvas mCanvas = new Canvas(mMutableBitmap);
   1679         // set Density
   1680         mCanvas.setDensity(DisplayMetrics.DENSITY_HIGH);
   1681         int scaledWidth = scaleFromDensity(ret.getWidth(), ret.getDensity(),  mCanvas.getDensity());
   1682         assertEquals(scaledWidth, ret.getScaledWidth(mCanvas));
   1683     }
   1684 
   1685     @Test
   1686     public void testSameAs_simpleSuccess() {
   1687         Bitmap bitmap1 = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
   1688         Bitmap bitmap2 = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
   1689         bitmap1.eraseColor(Color.BLACK);
   1690         bitmap2.eraseColor(Color.BLACK);
   1691         assertTrue(bitmap1.sameAs(bitmap2));
   1692         assertTrue(bitmap2.sameAs(bitmap1));
   1693     }
   1694 
   1695     @Test
   1696     public void testSameAs_simpleFail() {
   1697         Bitmap bitmap1 = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
   1698         Bitmap bitmap2 = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
   1699         bitmap1.eraseColor(Color.BLACK);
   1700         bitmap2.eraseColor(Color.BLACK);
   1701         bitmap2.setPixel(20, 10, Color.WHITE);
   1702         assertFalse(bitmap1.sameAs(bitmap2));
   1703         assertFalse(bitmap2.sameAs(bitmap1));
   1704     }
   1705 
   1706     @Test
   1707     public void testSameAs_reconfigure() {
   1708         Bitmap bitmap1 = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
   1709         Bitmap bitmap2 = Bitmap.createBitmap(150, 150, Config.ARGB_8888);
   1710         bitmap2.reconfigure(100, 100, Config.ARGB_8888); // now same size, so should be same
   1711         bitmap1.eraseColor(Color.BLACK);
   1712         bitmap2.eraseColor(Color.BLACK);
   1713         assertTrue(bitmap1.sameAs(bitmap2));
   1714         assertTrue(bitmap2.sameAs(bitmap1));
   1715     }
   1716 
   1717     @Test
   1718     public void testSameAs_config() {
   1719         Bitmap bitmap1 = Bitmap.createBitmap(100, 200, Config.RGB_565);
   1720         Bitmap bitmap2 = Bitmap.createBitmap(100, 200, Config.ARGB_8888);
   1721 
   1722         // both bitmaps can represent black perfectly
   1723         bitmap1.eraseColor(Color.BLACK);
   1724         bitmap2.eraseColor(Color.BLACK);
   1725 
   1726         // but not same due to config
   1727         assertFalse(bitmap1.sameAs(bitmap2));
   1728         assertFalse(bitmap2.sameAs(bitmap1));
   1729     }
   1730 
   1731     @Test
   1732     public void testSameAs_width() {
   1733         Bitmap bitmap1 = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
   1734         Bitmap bitmap2 = Bitmap.createBitmap(101, 100, Config.ARGB_8888);
   1735         bitmap1.eraseColor(Color.BLACK);
   1736         bitmap2.eraseColor(Color.BLACK);
   1737         assertFalse(bitmap1.sameAs(bitmap2));
   1738         assertFalse(bitmap2.sameAs(bitmap1));
   1739     }
   1740 
   1741     @Test
   1742     public void testSameAs_height() {
   1743         Bitmap bitmap1 = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
   1744         Bitmap bitmap2 = Bitmap.createBitmap(102, 100, Config.ARGB_8888);
   1745         bitmap1.eraseColor(Color.BLACK);
   1746         bitmap2.eraseColor(Color.BLACK);
   1747         assertFalse(bitmap1.sameAs(bitmap2));
   1748         assertFalse(bitmap2.sameAs(bitmap1));
   1749     }
   1750 
   1751     @Test
   1752     public void testSameAs_opaque() {
   1753         Bitmap bitmap1 = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
   1754         Bitmap bitmap2 = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
   1755         bitmap1.eraseColor(Color.BLACK);
   1756         bitmap2.eraseColor(Color.BLACK);
   1757         bitmap1.setHasAlpha(true);
   1758         bitmap2.setHasAlpha(false);
   1759         assertFalse(bitmap1.sameAs(bitmap2));
   1760         assertFalse(bitmap2.sameAs(bitmap1));
   1761     }
   1762 
   1763     @Test
   1764     public void testSameAs_hardware() {
   1765         Bitmap bitmap1 = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS);
   1766         Bitmap bitmap2 = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS);
   1767         Bitmap bitmap3 = BitmapFactory.decodeResource(mRes, R.drawable.robot);
   1768         Bitmap bitmap4 = BitmapFactory.decodeResource(mRes, R.drawable.start, HARDWARE_OPTIONS);
   1769         assertTrue(bitmap1.sameAs(bitmap2));
   1770         assertTrue(bitmap2.sameAs(bitmap1));
   1771         assertFalse(bitmap1.sameAs(bitmap3));
   1772         assertFalse(bitmap1.sameAs(bitmap4));
   1773     }
   1774 
   1775     @Test
   1776     public void testSameAs_wrappedHardwareBuffer() {
   1777         try (HardwareBuffer hwBufferA = createTestBuffer(512, 512, true);
   1778              HardwareBuffer hwBufferB = createTestBuffer(512, 512, true);
   1779              HardwareBuffer hwBufferC = createTestBuffer(512, 512, true);) {
   1780             // Fill buffer C with generated data
   1781             nFillRgbaHwBuffer(hwBufferC);
   1782 
   1783             // Create the test bitmaps
   1784             Bitmap bitmap1 = Bitmap.wrapHardwareBuffer(hwBufferA, ColorSpace.get(Named.SRGB));
   1785             Bitmap bitmap2 = Bitmap.wrapHardwareBuffer(hwBufferA, ColorSpace.get(Named.SRGB));
   1786             Bitmap bitmap3 = BitmapFactory.decodeResource(mRes, R.drawable.robot);
   1787             Bitmap bitmap4 = Bitmap.wrapHardwareBuffer(hwBufferB, ColorSpace.get(Named.SRGB));
   1788             Bitmap bitmap5 = Bitmap.wrapHardwareBuffer(hwBufferC, ColorSpace.get(Named.SRGB));
   1789 
   1790             // Run the compare-a-thon
   1791             assertTrue(bitmap1.sameAs(bitmap2));  // SAME UNDERLYING BUFFER
   1792             assertTrue(bitmap2.sameAs(bitmap1));  // SAME UNDERLYING BUFFER
   1793             assertFalse(bitmap1.sameAs(bitmap3)); // HW vs. NON-HW
   1794             assertTrue(bitmap1.sameAs(bitmap4));  // DIFFERENT BUFFERS, SAME CONTENT
   1795             assertFalse(bitmap1.sameAs(bitmap5)); // DIFFERENT BUFFERS, DIFFERENT CONTENT
   1796         }
   1797     }
   1798 
   1799     @Test(expected=IllegalStateException.class)
   1800     public void testHardwareGetPixel() {
   1801         Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS);
   1802         bitmap.getPixel(0, 0);
   1803     }
   1804 
   1805     @Test(expected=IllegalStateException.class)
   1806     public void testHardwareGetPixels() {
   1807         Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS);
   1808         bitmap.getPixels(new int[5], 0, 5, 0, 0, 5, 1);
   1809     }
   1810 
   1811     @Test
   1812     public void testGetConfigOnRecycled() {
   1813         Bitmap bitmap1 = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS);
   1814         bitmap1.recycle();
   1815         assertEquals(Config.HARDWARE, bitmap1.getConfig());
   1816         Bitmap bitmap2 = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
   1817         bitmap2.recycle();
   1818         assertEquals(Config.ARGB_8888, bitmap2.getConfig());
   1819     }
   1820 
   1821     @Test(expected = IllegalStateException.class)
   1822     public void testHardwareSetWidth() {
   1823         Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS);
   1824         bitmap.setWidth(30);
   1825     }
   1826 
   1827     @Test(expected = IllegalStateException.class)
   1828     public void testHardwareSetHeight() {
   1829         Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS);
   1830         bitmap.setHeight(30);
   1831     }
   1832 
   1833     @Test(expected = IllegalStateException.class)
   1834     public void testHardwareSetConfig() {
   1835         Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS);
   1836         bitmap.setConfig(Config.ARGB_8888);
   1837     }
   1838 
   1839     @Test(expected = IllegalStateException.class)
   1840     public void testHardwareReconfigure() {
   1841         Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS);
   1842         bitmap.reconfigure(30, 30, Config.ARGB_8888);
   1843     }
   1844 
   1845     @Test(expected = IllegalStateException.class)
   1846     public void testHardwareSetPixels() {
   1847         Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS);
   1848         bitmap.setPixels(new int[10], 0, 1, 0, 0, 1, 1);
   1849     }
   1850 
   1851     @Test(expected = IllegalStateException.class)
   1852     public void testHardwareSetPixel() {
   1853         Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS);
   1854         bitmap.setPixel(1, 1, 0);
   1855     }
   1856 
   1857     @Test(expected = IllegalStateException.class)
   1858     public void testHardwareEraseColor() {
   1859         Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS);
   1860         bitmap.eraseColor(0);
   1861     }
   1862 
   1863     @Test(expected = IllegalStateException.class)
   1864     public void testHardwareEraseColorLong() {
   1865         Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS);
   1866         bitmap.eraseColor(Color.pack(0));
   1867     }
   1868 
   1869     @Test(expected = IllegalStateException.class)
   1870     public void testHardwareCopyPixelsToBuffer() {
   1871         Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, HARDWARE_OPTIONS);
   1872         ByteBuffer byteBuf = ByteBuffer.allocate(bitmap.getRowBytes() * bitmap.getHeight());
   1873         bitmap.copyPixelsToBuffer(byteBuf);
   1874     }
   1875 
   1876     @Test(expected = IllegalStateException.class)
   1877     public void testHardwareCopyPixelsFromBuffer() {
   1878         IntBuffer intBuf1 = IntBuffer.allocate(mBitmap.getRowBytes() * mBitmap.getHeight());
   1879         assertEquals(0, intBuf1.position());
   1880         mBitmap.copyPixelsToBuffer(intBuf1);
   1881         Bitmap hwBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, HARDWARE_OPTIONS);
   1882         hwBitmap.copyPixelsFromBuffer(intBuf1);
   1883     }
   1884 
   1885     @Test
   1886     public void testUseMetadataAfterRecycle() {
   1887         Bitmap bitmap = Bitmap.createBitmap(10, 20, Config.RGB_565);
   1888         bitmap.recycle();
   1889         assertEquals(10, bitmap.getWidth());
   1890         assertEquals(20, bitmap.getHeight());
   1891         assertEquals(Config.RGB_565, bitmap.getConfig());
   1892     }
   1893 
   1894     @Test
   1895     public void testCopyHWBitmapInStrictMode() {
   1896         strictModeTest(()->{
   1897             Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
   1898             Bitmap hwBitmap = bitmap.copy(Config.HARDWARE, false);
   1899             hwBitmap.copy(Config.ARGB_8888, false);
   1900         });
   1901     }
   1902 
   1903     @Test
   1904     public void testCreateScaledFromHWInStrictMode() {
   1905         strictModeTest(()->{
   1906             Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
   1907             Bitmap hwBitmap = bitmap.copy(Config.HARDWARE, false);
   1908             Bitmap.createScaledBitmap(hwBitmap, 200, 200, false);
   1909         });
   1910     }
   1911 
   1912     @Test
   1913     public void testExtractAlphaFromHWInStrictMode() {
   1914         strictModeTest(()->{
   1915             Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
   1916             Bitmap hwBitmap = bitmap.copy(Config.HARDWARE, false);
   1917             hwBitmap.extractAlpha();
   1918         });
   1919     }
   1920 
   1921     @Test
   1922     public void testCompressInStrictMode() {
   1923         strictModeTest(()->{
   1924             Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
   1925             bitmap.compress(CompressFormat.JPEG, 90, new ByteArrayOutputStream());
   1926         });
   1927     }
   1928 
   1929     @Test
   1930     public void testParcelHWInStrictMode() {
   1931         strictModeTest(()->{
   1932             mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
   1933             Bitmap hwBitmap = mBitmap.copy(Config.HARDWARE, false);
   1934             hwBitmap.writeToParcel(Parcel.obtain(), 0);
   1935         });
   1936     }
   1937 
   1938     @Test
   1939     public void testSameAsFirstHWInStrictMode() {
   1940         strictModeTest(()->{
   1941             Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
   1942             Bitmap hwBitmap = bitmap.copy(Config.HARDWARE, false);
   1943             hwBitmap.sameAs(bitmap);
   1944         });
   1945     }
   1946 
   1947     @Test
   1948     public void testSameAsSecondHWInStrictMode() {
   1949         strictModeTest(()->{
   1950             Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
   1951             Bitmap hwBitmap = bitmap.copy(Config.HARDWARE, false);
   1952             bitmap.sameAs(hwBitmap);
   1953         });
   1954     }
   1955 
   1956     @Test
   1957     public void testNdkAccessAfterRecycle() {
   1958         Bitmap bitmap = Bitmap.createBitmap(10, 20, Config.RGB_565);
   1959         nValidateBitmapInfo(bitmap, 10, 20, true);
   1960         bitmap.recycle();
   1961         nValidateBitmapInfo(bitmap, 10, 20, true);
   1962         nValidateNdkAccessAfterRecycle(bitmap);
   1963     }
   1964 
   1965     @Test
   1966     public void bitmapIsMutable() {
   1967         Bitmap b = Bitmap.createBitmap(10, 10, Config.ARGB_8888);
   1968         assertTrue("CreateBitmap w/ params should be mutable", b.isMutable());
   1969         assertTrue("CreateBitmap from bitmap should be mutable",
   1970                 Bitmap.createBitmap(b).isMutable());
   1971     }
   1972 
   1973     private static void runGcAndFinalizersSync() {
   1974         Runtime.getRuntime().gc();
   1975         Runtime.getRuntime().runFinalization();
   1976 
   1977         final CountDownLatch fence = new CountDownLatch(1);
   1978         new Object() {
   1979             @Override
   1980             protected void finalize() throws Throwable {
   1981                 try {
   1982                     fence.countDown();
   1983                 } finally {
   1984                     super.finalize();
   1985                 }
   1986             }
   1987         };
   1988         try {
   1989             do {
   1990                 Runtime.getRuntime().gc();
   1991                 Runtime.getRuntime().runFinalization();
   1992             } while (!fence.await(100, TimeUnit.MILLISECONDS));
   1993         } catch (InterruptedException ex) {
   1994             throw new RuntimeException(ex);
   1995         }
   1996     }
   1997 
   1998     private static File sProcSelfFd = new File("/proc/self/fd");
   1999     private static int getFdCount() {
   2000         return sProcSelfFd.listFiles().length;
   2001     }
   2002 
   2003     private static void assertNotLeaking(int iteration,
   2004             Debug.MemoryInfo start, Debug.MemoryInfo end) {
   2005         Debug.getMemoryInfo(end);
   2006         assertNotEquals(0, start.getTotalPss());
   2007         assertNotEquals(0, end.getTotalPss());
   2008         if (end.getTotalPss() - start.getTotalPss() > 2000 /* kB */) {
   2009             runGcAndFinalizersSync();
   2010             Debug.getMemoryInfo(end);
   2011             if (end.getTotalPss() - start.getTotalPss() > 4000 /* kB */) {
   2012                 // Guarded by if so we don't continually generate garbage for the
   2013                 // assertion string.
   2014                 assertEquals("Memory leaked, iteration=" + iteration,
   2015                         start.getTotalPss(), end.getTotalPss(),
   2016                         4000 /* kb */);
   2017             }
   2018         }
   2019     }
   2020 
   2021     private static void runNotLeakingTest(Runnable test) {
   2022         Debug.MemoryInfo meminfoStart = new Debug.MemoryInfo();
   2023         Debug.MemoryInfo meminfoEnd = new Debug.MemoryInfo();
   2024         int fdCount = -1;
   2025         for (int i = 0; i < 2000; i++) {
   2026             if (i == 4) {
   2027                 // Not really the "start" but by having done a couple
   2028                 // we've fully initialized any state that may be required,
   2029                 // so memory usage should be stable now
   2030                 runGcAndFinalizersSync();
   2031                 Debug.getMemoryInfo(meminfoStart);
   2032                 fdCount = getFdCount();
   2033             }
   2034             if (i % 100 == 5) {
   2035                 assertNotLeaking(i, meminfoStart, meminfoEnd);
   2036                 final int curFdCount = getFdCount();
   2037                 if (curFdCount - fdCount > 10) {
   2038                     fail(String.format("FDs leaked. Expected=%d, current=%d, iteration=%d",
   2039                             fdCount, curFdCount, i));
   2040                 }
   2041             }
   2042             test.run();
   2043         }
   2044         assertNotLeaking(2000, meminfoStart, meminfoEnd);
   2045         final int curFdCount = getFdCount();
   2046         if (curFdCount - fdCount > 10) {
   2047             fail(String.format("FDs leaked. Expected=%d, current=%d", fdCount, curFdCount));
   2048         }
   2049     }
   2050 
   2051     @Test
   2052     @LargeTest
   2053     public void testHardwareBitmapNotLeaking() {
   2054         BitmapFactory.Options opts = new BitmapFactory.Options();
   2055         opts.inPreferredConfig = Config.HARDWARE;
   2056         opts.inScaled = false;
   2057 
   2058         runNotLeakingTest(() -> {
   2059             Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, opts);
   2060             assertNotNull(bitmap);
   2061             // Make sure nothing messed with the bitmap
   2062             assertEquals(128, bitmap.getWidth());
   2063             assertEquals(128, bitmap.getHeight());
   2064             assertEquals(Config.HARDWARE, bitmap.getConfig());
   2065             bitmap.recycle();
   2066         });
   2067     }
   2068 
   2069     @Test
   2070     @LargeTest
   2071     public void testWrappedHardwareBufferBitmapNotLeaking() {
   2072         final ColorSpace colorSpace = ColorSpace.get(Named.SRGB);
   2073         try (HardwareBuffer hwBuffer = createTestBuffer(1024, 512, false)) {
   2074             runNotLeakingTest(() -> {
   2075                 Bitmap bitmap = Bitmap.wrapHardwareBuffer(hwBuffer, colorSpace);
   2076                 assertNotNull(bitmap);
   2077                 // Make sure nothing messed with the bitmap
   2078                 assertEquals(1024, bitmap.getWidth());
   2079                 assertEquals(512, bitmap.getHeight());
   2080                 assertEquals(Config.HARDWARE, bitmap.getConfig());
   2081                 bitmap.recycle();
   2082             });
   2083         }
   2084     }
   2085 
   2086     @Test
   2087     @LargeTest
   2088     public void testDrawingHardwareBitmapNotLeaking() {
   2089         BitmapFactory.Options opts = new BitmapFactory.Options();
   2090         opts.inPreferredConfig = Config.HARDWARE;
   2091         opts.inScaled = false;
   2092         RenderTarget renderTarget = RenderTarget.create();
   2093         renderTarget.setDefaultSize(128, 128);
   2094         final Surface surface = renderTarget.getSurface();
   2095 
   2096         runNotLeakingTest(() -> {
   2097             Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, opts);
   2098             assertNotNull(bitmap);
   2099             // Make sure nothing messed with the bitmap
   2100             assertEquals(128, bitmap.getWidth());
   2101             assertEquals(128, bitmap.getHeight());
   2102             assertEquals(Config.HARDWARE, bitmap.getConfig());
   2103             Canvas canvas = surface.lockHardwareCanvas();
   2104             canvas.drawBitmap(bitmap, 0, 0, null);
   2105             surface.unlockCanvasAndPost(canvas);
   2106             bitmap.recycle();
   2107         });
   2108     }
   2109 
   2110     @Test
   2111     public void testWrapHardwareBufferHoldsReference() {
   2112         Bitmap bitmap;
   2113         // Create hardware-buffer and wrap it in a Bitmap
   2114         try (HardwareBuffer hwBuffer = createTestBuffer(128, 128, false)) {
   2115             // Fill buffer with colors (x, y, 42, 255)
   2116             nFillRgbaHwBuffer(hwBuffer);
   2117             bitmap = Bitmap.wrapHardwareBuffer(hwBuffer, ColorSpace.get(Named.SRGB));
   2118         }
   2119 
   2120         // Buffer is closed at this point. Ensure bitmap still works by drawing it
   2121         assertEquals(128, bitmap.getWidth());
   2122         assertEquals(128, bitmap.getHeight());
   2123         assertEquals(Config.HARDWARE, bitmap.getConfig());
   2124 
   2125         // Copy bitmap to target bitmap we can read from
   2126         Bitmap dstBitmap = bitmap.copy(Config.ARGB_8888, false);
   2127         bitmap.recycle();
   2128 
   2129         // Ensure that the bitmap has valid contents
   2130         int pixel = dstBitmap.getPixel(0, 0);
   2131         assertEquals(255 << 24 | 42, pixel);
   2132         dstBitmap.recycle();
   2133     }
   2134 
   2135     @Test
   2136     public void testWrapHardwareBufferPreservesColors() {
   2137         try (HardwareBuffer hwBuffer = createTestBuffer(128, 128, true)) {
   2138             // Fill buffer with colors (x, y, 42, 255)
   2139             nFillRgbaHwBuffer(hwBuffer);
   2140 
   2141             // Create HW bitmap from this buffer
   2142             Bitmap srcBitmap = Bitmap.wrapHardwareBuffer(hwBuffer, ColorSpace.get(Named.SRGB));
   2143             assertNotNull(srcBitmap);
   2144 
   2145             // Copy it to target non-HW bitmap
   2146             Bitmap dstBitmap = srcBitmap.copy(Config.ARGB_8888, false);
   2147             srcBitmap.recycle();
   2148 
   2149             // Ensure all colors are as expected (matches the nFillRgbaHwBuffer call used above).
   2150             for (int y = 0; y < 128; ++y) {
   2151                 for (int x = 0; x < 128; ++x) {
   2152                     int pixel = dstBitmap.getPixel(x, y);
   2153                     short a = 255;
   2154                     short r = (short) (x % 255);
   2155                     short g = (short) (y % 255);
   2156                     short b = 42;
   2157                     assertEquals(a << 24 | r << 16 | g << 8 | b, pixel);
   2158                 }
   2159             }
   2160             dstBitmap.recycle();
   2161         }
   2162     }
   2163 
   2164     private void strictModeTest(Runnable runnable) {
   2165         StrictMode.ThreadPolicy originalPolicy = StrictMode.getThreadPolicy();
   2166         StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
   2167                 .detectCustomSlowCalls().penaltyDeath().build());
   2168         try {
   2169             runnable.run();
   2170             fail("Shouldn't reach it");
   2171         } catch (RuntimeException expected){
   2172             // expect to receive StrictModeViolation
   2173         } finally {
   2174             StrictMode.setThreadPolicy(originalPolicy);
   2175         }
   2176     }
   2177 
   2178     private static native void nValidateBitmapInfo(Bitmap bitmap, int width, int height,
   2179             boolean is565);
   2180     private static native void nValidateNdkAccessAfterRecycle(Bitmap bitmap);
   2181 
   2182     private static native void nFillRgbaHwBuffer(HardwareBuffer hwBuffer);
   2183 
   2184     private static final int ANDROID_BITMAP_FORMAT_RGBA_8888 = 1;
   2185     private static final int ANDROID_BITMAP_FORMAT_RGB_565 = 4;
   2186     private static native int nGetFormat(Bitmap bitmap);
   2187 
   2188     private static HardwareBuffer createTestBuffer(int width, int height, boolean cpuAccess) {
   2189         long usage = HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE;
   2190         if (cpuAccess) {
   2191             usage |= HardwareBuffer.USAGE_CPU_WRITE_RARELY;
   2192         }
   2193         // We can assume that RGBA_8888 format is supported for every platform.
   2194         HardwareBuffer hwBuffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888,
   2195                 1, usage);
   2196         return hwBuffer;
   2197     }
   2198 
   2199     private static int scaleFromDensity(int size, int sdensity, int tdensity) {
   2200         if (sdensity == Bitmap.DENSITY_NONE || sdensity == tdensity) {
   2201             return size;
   2202         }
   2203 
   2204         // Scale by tdensity / sdensity, rounding up.
   2205         return ((size * tdensity) + (sdensity >> 1)) / sdensity;
   2206     }
   2207 
   2208     private static int[] createColors(int size) {
   2209         int[] colors = new int[size];
   2210 
   2211         for (int i = 0; i < size; i++) {
   2212             colors[i] = (0xFF << 24) | (i << 16) | (i << 8) | i;
   2213         }
   2214 
   2215         return colors;
   2216     }
   2217 
   2218     private static BitmapFactory.Options createHardwareBitmapOptions() {
   2219         BitmapFactory.Options options = new BitmapFactory.Options();
   2220         options.inPreferredConfig = Config.HARDWARE;
   2221         return options;
   2222     }
   2223 }
   2224