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 getRgbColorSpaces()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 setup()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) testCompressRecycled()112 public void testCompressRecycled() { 113 mBitmap.recycle(); 114 mBitmap.compress(CompressFormat.JPEG, 0, null); 115 } 116 117 @Test(expected=NullPointerException.class) testCompressNullStream()118 public void testCompressNullStream() { 119 mBitmap.compress(CompressFormat.JPEG, 0, null); 120 } 121 122 @Test(expected=IllegalArgumentException.class) testCompressQualityTooLow()123 public void testCompressQualityTooLow() { 124 mBitmap.compress(CompressFormat.JPEG, -1, new ByteArrayOutputStream()); 125 } 126 127 @Test(expected=IllegalArgumentException.class) testCompressQualityTooHigh()128 public void testCompressQualityTooHigh() { 129 mBitmap.compress(CompressFormat.JPEG, 101, new ByteArrayOutputStream()); 130 } 131 132 @Test testCompress()133 public void testCompress() { 134 assertTrue(mBitmap.compress(CompressFormat.JPEG, 50, new ByteArrayOutputStream())); 135 } 136 137 @Test(expected=IllegalStateException.class) testCopyRecycled()138 public void testCopyRecycled() { 139 mBitmap.recycle(); 140 mBitmap.copy(Config.RGB_565, false); 141 } 142 143 @Test testCopy()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 testCopyConfigs()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) testCopyMutableHwBitmap()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) testCopyPixelsToBufferUnsupportedBufferClass()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) testCopyPixelsToBufferBufferTooSmall()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 testCopyPixelsToBuffer()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 testCreateBitmap1()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) testCreateBitmapNegativeX()246 public void testCreateBitmapNegativeX() { 247 Bitmap.createBitmap(mBitmap, -100, 50, 50, 200); 248 } 249 250 @Test testCreateBitmap2()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) testCreateBitmapNegativeXY()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) testCreateBitmapNegativeWidthHeight()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) testCreateBitmapXRegionTooWide()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) testCreateBitmapYRegionTooTall()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) testCreateMutableBitmapWithHardwareConfig()301 public void testCreateMutableBitmapWithHardwareConfig() { 302 Bitmap.createBitmap(100, 100, Config.HARDWARE); 303 } 304 305 @Test testCreateBitmap3()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 testCreateBitmapFromHardwareBitmap()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 testCreateBitmap4()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 verify2x2BitmapContents(int[] expected, Bitmap observed)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 testCreateBitmap_matrix()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) testCreateBitmapFromColorsNegativeWidthHeight()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) testCreateBitmapFromColorsIllegalStride()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) testCreateBitmapFromColorsNegativeOffset()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) testCreateBitmapFromColorsOffsetTooLarge()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) testCreateBitmapFromColorsScalnlineTooLarge()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 testCreateBitmap6()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 testCreateBitmap_displayMetrics_mutable()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 testCreateBitmap_noDisplayMetrics_mutable()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 testCreateBitmap_displayMetrics_immutable()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 testCreateBitmap_noDisplayMetrics_immutable()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 testCreateBitmap_Picture_immutable()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 testCreateScaledBitmap()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 testWrapHardwareBufferSucceeds()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) testWrapHardwareBufferWithInvalidUsageFails()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) testWrapHardwareBufferWithRgbBufferButNonRgbColorSpaceFails()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 testGenerationId()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 testDescribeContents()597 public void testDescribeContents() { 598 assertEquals(0, mBitmap.describeContents()); 599 } 600 601 @Test(expected=IllegalStateException.class) testEraseColorOnRecycled()602 public void testEraseColorOnRecycled() { 603 mBitmap.recycle(); 604 605 mBitmap.eraseColor(0); 606 } 607 608 @Test(expected = IllegalStateException.class) testEraseColorLongOnRecycled()609 public void testEraseColorLongOnRecycled() { 610 mBitmap.recycle(); 611 612 mBitmap.eraseColor(Color.pack(0)); 613 } 614 615 @Test(expected=IllegalStateException.class) testEraseColorOnImmutable()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) testEraseColorLongOnImmutable()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 testEraseColor()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) testGetColorOOB()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) testGetColorOOB2()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) testGetColorOOB3()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) testGetColorOOB4()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) testGetColorRecycled()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) testGetColorHardware()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 clamp(float f)680 private static float clamp(float f) { 681 return clamp(f, 0.0f, 1.0f); 682 } 683 clamp(float f, float min, float max)684 private static float clamp(float f, float min, float max) { 685 return Math.min(Math.max(f, min), max); 686 } 687 688 @Test testGetColor()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; ARGB(float alpha, float red, float green, 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 testEraseColorLong()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 testEraseColorOnP3()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) testEraseColorXYZ()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) testEraseColorLAB()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) testEraseColorUnknown()827 public void testEraseColorUnknown() { 828 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 829 mBitmap.eraseColor(-1L); 830 } 831 832 @Test(expected=IllegalStateException.class) testExtractAlphaFromRecycled()833 public void testExtractAlphaFromRecycled() { 834 mBitmap.recycle(); 835 836 mBitmap.extractAlpha(); 837 } 838 839 @Test testExtractAlpha()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) testExtractAlphaWithPaintAndOffsetFromRecycled()852 public void testExtractAlphaWithPaintAndOffsetFromRecycled() { 853 mBitmap.recycle(); 854 855 mBitmap.extractAlpha(new Paint(), new int[]{0, 1}); 856 } 857 858 @Test testExtractAlphaWithPaintAndOffset()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 testGetAllocationByteCount()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 testGetConfig()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 testGetHeight()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 testGetNinePatchChunk()916 public void testGetNinePatchChunk() { 917 assertNull(mBitmap.getNinePatchChunk()); 918 } 919 920 @Test(expected=IllegalStateException.class) testGetPixelFromRecycled()921 public void testGetPixelFromRecycled() { 922 mBitmap.recycle(); 923 924 mBitmap.getPixel(10, 16); 925 } 926 927 @Test(expected=IllegalArgumentException.class) testGetPixelXTooLarge()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) testGetPixelYTooLarge()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 testGetPixel()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 testGetRowBytes()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 testGetWidth()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 testHasAlpha()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 testIsMutable()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 testIsRecycled()999 public void testIsRecycled() { 1000 assertFalse(mBitmap.isRecycled()); 1001 mBitmap.recycle(); 1002 assertTrue(mBitmap.isRecycled()); 1003 } 1004 1005 @Test testReconfigure()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) testReconfigureExpanding()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) testReconfigureMutable()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 testAlphaAndPremul()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 */ verifyAlphaAndPremul(Bitmap bitmap, boolean expectedAlpha, boolean expectedPremul, boolean convertedFrom565)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 testSetColorSpace()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) testSetColorSpaceRecycled()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) testSetColorSpaceNull()1171 public void testSetColorSpaceNull() { 1172 mBitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888); 1173 mBitmap.setColorSpace(null); 1174 } 1175 1176 @Test(expected = IllegalArgumentException.class) testSetColorSpaceXYZ()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) testSetColorSpaceNoTransferParameters()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) testSetColorSpaceAlpha8()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 testSetColorSpaceReducedRange()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 testSetColorSpaceNotReducedRange()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 testSetColorSpaceNotReducedRangeLinear()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 testSetColorSpaceIncreasedRange()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 testSetConfig()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) testSetConfigExpanding()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) testSetConfigMutable()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 testSetHeight()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) testSetHeightExpanding()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) testSetHeightMutable()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) testSetPixelOnRecycled()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) testSetPixelOnImmutable()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) testSetPixelXIsTooLarge()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) testSetPixelYIsTooLarge()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 testSetPixel()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) testSetPixelsOnRecycled()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) testSetPixelsOnImmutable()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) testSetPixelsXYNegative()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) testSetPixelsWidthHeightNegative()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) testSetPixelsXTooHigh()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) testSetPixelsYTooHigh()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) testSetPixelsStrideIllegal()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) testSetPixelsOffsetNegative()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) testSetPixelsOffsetTooBig()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) testSetPixelsLastScanlineNegative()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) testSetPixelsLastScanlineTooBig()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 testSetPixels()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 verifyPremultipliedBitmapConfig(Config config, boolean expectedPremul)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 testSetPremultipliedSimple()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 testSetPremultipliedData()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 testPremultipliedCanvas()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 getBitmapRawInt(Bitmap bitmap)1498 private int getBitmapRawInt(Bitmap bitmap) { 1499 IntBuffer buffer = IntBuffer.allocate(1); 1500 bitmap.copyPixelsToBuffer(buffer); 1501 return buffer.get(0); 1502 } 1503 bitmapStoreRawInt(Bitmap bitmap, int value)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 testSetPremultipliedToBuffer()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 testSetPremultipliedFromBuffer()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 testSetWidth()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) testSetWidthExpanding()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) testSetWidthMutable()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) testWriteToParcelRecycled()1564 public void testWriteToParcelRecycled() { 1565 mBitmap.recycle(); 1566 1567 mBitmap.writeToParcel(null, 0); 1568 } 1569 1570 @Test testWriteToParcel()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 testWriteHwBitmapToParcel()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 testParcelF16ColorSpace()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 testGetScaledHeight1()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 testGetScaledHeight2()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 testGetScaledHeight3()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 testGetScaledWidth1()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 testGetScaledWidth2()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 testGetScaledWidth3()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 testSameAs_simpleSuccess()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 testSameAs_simpleFail()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 testSameAs_reconfigure()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 testSameAs_config()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 testSameAs_width()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 testSameAs_height()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 testSameAs_opaque()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 testSameAs_hardware()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 testSameAs_wrappedHardwareBuffer()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) testHardwareGetPixel()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) testHardwareGetPixels()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 testGetConfigOnRecycled()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) testHardwareSetWidth()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) testHardwareSetHeight()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) testHardwareSetConfig()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) testHardwareReconfigure()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) testHardwareSetPixels()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) testHardwareSetPixel()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) testHardwareEraseColor()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) testHardwareEraseColorLong()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) testHardwareCopyPixelsToBuffer()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) testHardwareCopyPixelsFromBuffer()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 testUseMetadataAfterRecycle()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 testCopyHWBitmapInStrictMode()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 testCreateScaledFromHWInStrictMode()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 testExtractAlphaFromHWInStrictMode()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 testCompressInStrictMode()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 testParcelHWInStrictMode()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 testSameAsFirstHWInStrictMode()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 testSameAsSecondHWInStrictMode()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 testNdkAccessAfterRecycle()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 bitmapIsMutable()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 runGcAndFinalizersSync()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"); getFdCount()1999 private static int getFdCount() { 2000 return sProcSelfFd.listFiles().length; 2001 } 2002 assertNotLeaking(int iteration, Debug.MemoryInfo start, Debug.MemoryInfo end)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 runNotLeakingTest(Runnable test)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 testHardwareBitmapNotLeaking()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 testWrappedHardwareBufferBitmapNotLeaking()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 testDrawingHardwareBitmapNotLeaking()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 testWrapHardwareBufferHoldsReference()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 testWrapHardwareBufferPreservesColors()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 strictModeTest(Runnable runnable)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 nValidateBitmapInfo(Bitmap bitmap, int width, int height, boolean is565)2178 private static native void nValidateBitmapInfo(Bitmap bitmap, int width, int height, 2179 boolean is565); nValidateNdkAccessAfterRecycle(Bitmap bitmap)2180 private static native void nValidateNdkAccessAfterRecycle(Bitmap bitmap); 2181 nFillRgbaHwBuffer(HardwareBuffer hwBuffer)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; nGetFormat(Bitmap bitmap)2186 private static native int nGetFormat(Bitmap bitmap); 2187 createTestBuffer(int width, int height, boolean cpuAccess)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 scaleFromDensity(int size, int sdensity, int tdensity)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 createColors(int size)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 createHardwareBitmapOptions()2218 private static BitmapFactory.Options createHardwareBitmapOptions() { 2219 BitmapFactory.Options options = new BitmapFactory.Options(); 2220 options.inPreferredConfig = Config.HARDWARE; 2221 return options; 2222 } 2223 } 2224