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 android.graphics.cts.utils.LeakTest.runNotLeakingTest; 19 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertFalse; 22 import static org.junit.Assert.assertNotEquals; 23 import static org.junit.Assert.assertNotNull; 24 import static org.junit.Assert.assertNull; 25 import static org.junit.Assert.assertSame; 26 import static org.junit.Assert.assertThrows; 27 import static org.junit.Assert.assertTrue; 28 import static org.junit.Assert.fail; 29 import static org.junit.Assume.assumeNoException; 30 import static org.junit.Assume.assumeNotNull; 31 import static org.junit.Assume.assumeTrue; 32 33 import android.content.res.Resources; 34 import android.graphics.Bitmap; 35 import android.graphics.Bitmap.CompressFormat; 36 import android.graphics.Bitmap.Config; 37 import android.graphics.BitmapFactory; 38 import android.graphics.Canvas; 39 import android.graphics.Color; 40 import android.graphics.ColorSpace; 41 import android.graphics.ColorSpace.Named; 42 import android.graphics.ImageDecoder; 43 import android.graphics.ImageFormat; 44 import android.graphics.LinearGradient; 45 import android.graphics.Matrix; 46 import android.graphics.Paint; 47 import android.graphics.Picture; 48 import android.graphics.Shader; 49 import android.hardware.HardwareBuffer; 50 import android.os.Parcel; 51 import android.os.StrictMode; 52 import android.platform.test.annotations.DisabledOnRavenwood; 53 import android.platform.test.annotations.RequiresFlagsDisabled; 54 import android.platform.test.annotations.RequiresFlagsEnabled; 55 import android.platform.test.flag.junit.CheckFlagsRule; 56 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 57 import android.util.DisplayMetrics; 58 import android.view.Surface; 59 60 import androidx.test.InstrumentationRegistry; 61 import androidx.test.filters.LargeTest; 62 import androidx.test.filters.SmallTest; 63 64 import com.android.compatibility.common.util.BitmapUtils; 65 import com.android.compatibility.common.util.ColorUtils; 66 import com.android.compatibility.common.util.WidgetTestUtils; 67 import com.android.graphics.hwui.flags.Flags; 68 69 import junitparams.JUnitParamsRunner; 70 import junitparams.Parameters; 71 72 import org.junit.Before; 73 import org.junit.Rule; 74 import org.junit.Test; 75 import org.junit.runner.RunWith; 76 77 import java.io.ByteArrayOutputStream; 78 import java.io.IOException; 79 import java.io.OutputStream; 80 import java.nio.ByteBuffer; 81 import java.nio.CharBuffer; 82 import java.nio.IntBuffer; 83 import java.nio.ShortBuffer; 84 import java.util.ArrayList; 85 import java.util.Arrays; 86 import java.util.HashSet; 87 import java.util.List; 88 89 @SmallTest 90 @RunWith(JUnitParamsRunner.class) 91 public class BitmapTest { 92 @Rule 93 public final CheckFlagsRule mCheckFlagsRule = 94 DeviceFlagsValueProvider.createCheckFlagsRule(); 95 96 // small alpha values cause color values to be pre-multiplied down, losing accuracy 97 private static final int PREMUL_COLOR = Color.argb(2, 255, 254, 253); 98 private static final int PREMUL_ROUNDED_COLOR = Color.argb(2, 255, 255, 255); 99 private static final int PREMUL_STORED_COLOR = Color.argb(2, 2, 2, 2); 100 101 private static final BitmapFactory.Options HARDWARE_OPTIONS = createHardwareBitmapOptions(); 102 103 static { 104 if (Utils.isNdkSupported()) { 105 System.loadLibrary("ctsgraphics_jni"); 106 } 107 } 108 109 private Resources mRes; 110 private Bitmap mBitmap; 111 private BitmapFactory.Options mOptions; 112 getRgbColorSpaces()113 public static List<ColorSpace> getRgbColorSpaces() { 114 List<ColorSpace> rgbColorSpaces; 115 rgbColorSpaces = new ArrayList<ColorSpace>(); 116 for (ColorSpace.Named e : ColorSpace.Named.values()) { 117 ColorSpace cs = ColorSpace.get(e); 118 if (cs.getModel() != ColorSpace.Model.RGB) { 119 continue; 120 } 121 if (((ColorSpace.Rgb) cs).getTransferParameters() == null) { 122 continue; 123 } 124 rgbColorSpaces.add(cs); 125 } 126 return rgbColorSpaces; 127 } 128 129 @Before setup()130 public void setup() { 131 mRes = InstrumentationRegistry.getTargetContext().getResources(); 132 mOptions = new BitmapFactory.Options(); 133 mOptions.inScaled = false; 134 mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions); 135 } 136 137 @Test(expected=IllegalStateException.class) testCompressRecycled()138 public void testCompressRecycled() { 139 mBitmap.recycle(); 140 mBitmap.compress(CompressFormat.JPEG, 0, null); 141 } 142 143 @Test(expected=NullPointerException.class) testCompressNullStream()144 public void testCompressNullStream() { 145 mBitmap.compress(CompressFormat.JPEG, 0, null); 146 } 147 148 @Test(expected=IllegalArgumentException.class) testCompressQualityTooLow()149 public void testCompressQualityTooLow() { 150 mBitmap.compress(CompressFormat.JPEG, -1, new ByteArrayOutputStream()); 151 } 152 153 @Test(expected=IllegalArgumentException.class) testCompressQualityTooHigh()154 public void testCompressQualityTooHigh() { 155 mBitmap.compress(CompressFormat.JPEG, 101, new ByteArrayOutputStream()); 156 } 157 compressFormats()158 private static Object[] compressFormats() { 159 return CompressFormat.values(); 160 } 161 162 @Test 163 @Parameters(method = "compressFormats") testCompress(CompressFormat format)164 public void testCompress(CompressFormat format) { 165 assertTrue(mBitmap.compress(format, 50, new ByteArrayOutputStream())); 166 } 167 decodeBytes(byte[] bytes)168 private Bitmap decodeBytes(byte[] bytes) { 169 ByteBuffer buffer = ByteBuffer.wrap(bytes); 170 ImageDecoder.Source src = ImageDecoder.createSource(buffer); 171 try { 172 return ImageDecoder.decodeBitmap(src, (decoder, info, s) -> { 173 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); 174 }); 175 } catch (IOException e) { 176 fail("Failed to decode with " + e); 177 return null; 178 } 179 } 180 181 // There are three color components and 182 // each should be within a square difference of 15 * 15. 183 private static final int MSE_MARGIN = 3 * (15 * 15); 184 185 @Test testCompressWebpLossy()186 public void testCompressWebpLossy() { 187 // For qualities < 100, WEBP performs a lossy decode. 188 byte[] last = null; 189 Bitmap lastBitmap = null; 190 for (int quality : new int[] { 25, 50, 80, 99 }) { 191 ByteArrayOutputStream webp = new ByteArrayOutputStream(); 192 assertTrue(mBitmap.compress(CompressFormat.WEBP, quality, webp)); 193 byte[] webpCompressed = webp.toByteArray(); 194 195 196 ByteArrayOutputStream webpLossy = new ByteArrayOutputStream(); 197 assertTrue(mBitmap.compress(CompressFormat.WEBP_LOSSY, quality, webpLossy)); 198 byte[] webpLossyCompressed = webpLossy.toByteArray(); 199 200 assertTrue("Compression did not match at quality " + quality, 201 Arrays.equals(webpCompressed, webpLossyCompressed)); 202 203 Bitmap result = decodeBytes(webpCompressed); 204 if (last != null) { 205 // Higher quality will generally result in a larger file. 206 assertTrue(webpCompressed.length > last.length); 207 if (!BitmapUtils.compareBitmapsMse(lastBitmap, result, MSE_MARGIN, true, false)) { 208 fail("Bad comparison for quality " + quality); 209 } 210 } 211 last = webpCompressed; 212 lastBitmap = result; 213 } 214 } 215 216 @Test 217 @Parameters({ "0", "50", "80", "99", "100" }) testCompressWebpLossless(int quality)218 public void testCompressWebpLossless(int quality) { 219 ByteArrayOutputStream webp = new ByteArrayOutputStream(); 220 assertTrue(mBitmap.compress(CompressFormat.WEBP_LOSSLESS, quality, webp)); 221 byte[] webpCompressed = webp.toByteArray(); 222 Bitmap result = decodeBytes(webpCompressed); 223 224 assertTrue("WEBP_LOSSLESS did not losslessly compress at quality " + quality, 225 BitmapUtils.compareBitmaps(mBitmap, result)); 226 } 227 228 @Test testCompressWebp100MeansLossless()229 public void testCompressWebp100MeansLossless() { 230 ByteArrayOutputStream webp = new ByteArrayOutputStream(); 231 assertTrue(mBitmap.compress(CompressFormat.WEBP, 100, webp)); 232 byte[] webpCompressed = webp.toByteArray(); 233 Bitmap result = decodeBytes(webpCompressed); 234 assertTrue("WEBP_LOSSLESS did not losslessly compress at quality 100", 235 BitmapUtils.compareBitmaps(mBitmap, result)); 236 } 237 238 @Test 239 @Parameters(method = "compressFormats") testCompressAlpha8Fails(CompressFormat format)240 public void testCompressAlpha8Fails(CompressFormat format) { 241 Bitmap bitmap = Bitmap.createBitmap(1, 1, Config.ALPHA_8); 242 assertFalse("Incorrectly compressed ALPHA_8 to " + format, 243 bitmap.compress(format, 50, new ByteArrayOutputStream())); 244 } 245 246 @Test 247 @Parameters(method = "compressFormats") 248 @DisabledOnRavenwood(reason = "Ravenwood does not support NDK APIs yet") testCompressAlpha8NdkFails(CompressFormat format)249 public void testCompressAlpha8NdkFails(CompressFormat format) { 250 if (format == CompressFormat.WEBP) { 251 // Skip the native test, since the NDK just has equivalents for 252 // WEBP_LOSSY and WEBP_LOSSLESS. 253 return; 254 } 255 256 Bitmap bitmap = Bitmap.createBitmap(1, 1, Config.ALPHA_8); 257 byte[] storage = new byte[16 * 1024]; 258 OutputStream stream = new ByteArrayOutputStream(); 259 assertFalse("Incorrectly compressed ALPHA_8 with the NDK to " + format, 260 nCompress(bitmap, nativeCompressFormat(format), 50, stream, storage)); 261 } 262 263 @Test(expected=IllegalStateException.class) testCopyRecycled()264 public void testCopyRecycled() { 265 mBitmap.recycle(); 266 mBitmap.copy(Config.RGB_565, false); 267 } 268 269 @Test testCopy()270 public void testCopy() { 271 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 272 Bitmap bitmap = mBitmap.copy(Config.ARGB_8888, false); 273 WidgetTestUtils.assertEquals(mBitmap, bitmap); 274 } 275 276 @Test testCopyConfigs()277 public void testCopyConfigs() { 278 Config[] supportedConfigs = new Config[] { 279 Config.ALPHA_8, Config.RGB_565, Config.ARGB_8888, Config.RGBA_F16, 280 }; 281 for (Config src : supportedConfigs) { 282 for (Config dst : supportedConfigs) { 283 Bitmap srcBitmap = Bitmap.createBitmap(1, 1, src); 284 srcBitmap.eraseColor(Color.WHITE); 285 Bitmap dstBitmap = srcBitmap.copy(dst, false); 286 assertNotNull("Should support copying from " + src + " to " + dst, 287 dstBitmap); 288 if (Config.ALPHA_8 == dst || Config.ALPHA_8 == src) { 289 // Color will be opaque but color information will be lost. 290 assertEquals("Color should be black when copying from " + src + " to " 291 + dst, Color.BLACK, dstBitmap.getPixel(0, 0)); 292 } else { 293 assertEquals("Color should be preserved when copying from " + src + " to " 294 + dst, Color.WHITE, dstBitmap.getPixel(0, 0)); 295 } 296 } 297 } 298 } 299 300 @Test(expected=IllegalArgumentException.class) testCopyMutableHwBitmap()301 public void testCopyMutableHwBitmap() { 302 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 303 mBitmap.copy(Config.HARDWARE, true); 304 } 305 306 @Test(expected=RuntimeException.class) testCopyPixelsToBufferUnsupportedBufferClass()307 public void testCopyPixelsToBufferUnsupportedBufferClass() { 308 final int pixSize = mBitmap.getRowBytes() * mBitmap.getHeight(); 309 310 mBitmap.copyPixelsToBuffer(CharBuffer.allocate(pixSize)); 311 } 312 313 @Test(expected=RuntimeException.class) testCopyPixelsToBufferBufferTooSmall()314 public void testCopyPixelsToBufferBufferTooSmall() { 315 final int pixSize = mBitmap.getRowBytes() * mBitmap.getHeight(); 316 final int tooSmall = pixSize / 2; 317 318 mBitmap.copyPixelsToBuffer(ByteBuffer.allocate(tooSmall)); 319 } 320 321 @Test testCopyPixelsToBuffer()322 public void testCopyPixelsToBuffer() { 323 final int pixSize = mBitmap.getRowBytes() * mBitmap.getHeight(); 324 325 ByteBuffer byteBuf = ByteBuffer.allocate(pixSize); 326 assertEquals(0, byteBuf.position()); 327 mBitmap.copyPixelsToBuffer(byteBuf); 328 assertEquals(pixSize, byteBuf.position()); 329 330 ShortBuffer shortBuf = ShortBuffer.allocate(pixSize); 331 assertEquals(0, shortBuf.position()); 332 mBitmap.copyPixelsToBuffer(shortBuf); 333 assertEquals(pixSize >> 1, shortBuf.position()); 334 335 IntBuffer intBuf1 = IntBuffer.allocate(pixSize); 336 assertEquals(0, intBuf1.position()); 337 mBitmap.copyPixelsToBuffer(intBuf1); 338 assertEquals(pixSize >> 2, intBuf1.position()); 339 340 Bitmap bitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), 341 mBitmap.getConfig()); 342 intBuf1.position(0); // copyPixelsToBuffer adjusted the position, so rewind to start 343 bitmap.copyPixelsFromBuffer(intBuf1); 344 IntBuffer intBuf2 = IntBuffer.allocate(pixSize); 345 bitmap.copyPixelsToBuffer(intBuf2); 346 347 assertEquals(pixSize >> 2, intBuf2.position()); 348 assertEquals(intBuf1.position(), intBuf2.position()); 349 int size = intBuf1.position(); 350 intBuf1.position(0); 351 intBuf2.position(0); 352 for (int i = 0; i < size; i++) { 353 assertEquals("mismatching pixels at position " + i, intBuf1.get(), intBuf2.get()); 354 } 355 } 356 357 @Test testCreateBitmap1()358 public void testCreateBitmap1() { 359 int[] colors = createColors(100); 360 Bitmap bitmap = Bitmap.createBitmap(colors, 10, 10, Config.RGB_565); 361 assertFalse(bitmap.isMutable()); 362 Bitmap ret = Bitmap.createBitmap(bitmap); 363 assertNotNull(ret); 364 assertFalse(ret.isMutable()); 365 assertEquals(10, ret.getWidth()); 366 assertEquals(10, ret.getHeight()); 367 assertEquals(Config.RGB_565, ret.getConfig()); 368 if (Utils.isNdkSupported()) { 369 assertEquals(ANDROID_BITMAP_FORMAT_RGB_565, nGetFormat(ret)); 370 } 371 } 372 373 @Test(expected=IllegalArgumentException.class) testCreateBitmapNegativeX()374 public void testCreateBitmapNegativeX() { 375 Bitmap.createBitmap(mBitmap, -100, 50, 50, 200); 376 } 377 378 @Test testCreateBitmap2()379 public void testCreateBitmap2() { 380 // special case: output bitmap is equal to the input bitmap 381 mBitmap = Bitmap.createBitmap(new int[100 * 100], 100, 100, Config.ARGB_8888); 382 assertFalse(mBitmap.isMutable()); // createBitmap w/ colors should be immutable 383 Bitmap ret = Bitmap.createBitmap(mBitmap, 0, 0, 100, 100); 384 assertNotNull(ret); 385 assertFalse(ret.isMutable()); // createBitmap from subset should be immutable 386 assertTrue(mBitmap.equals(ret)); 387 388 //normal case 389 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 390 ret = Bitmap.createBitmap(mBitmap, 10, 10, 50, 50); 391 assertNotNull(ret); 392 assertFalse(mBitmap.equals(ret)); 393 assertEquals(Config.ARGB_8888, ret.getConfig()); 394 if (Utils.isNdkSupported()) { 395 assertEquals(ANDROID_BITMAP_FORMAT_RGBA_8888, nGetFormat(mBitmap)); 396 } 397 } 398 399 @Test(expected=IllegalArgumentException.class) testCreateBitmapNegativeXY()400 public void testCreateBitmapNegativeXY() { 401 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 402 403 // abnormal case: x and/or y less than 0 404 Bitmap.createBitmap(mBitmap, -1, -1, 10, 10, null, false); 405 } 406 407 @Test(expected=IllegalArgumentException.class) testCreateBitmapNegativeWidthHeight()408 public void testCreateBitmapNegativeWidthHeight() { 409 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 410 411 // abnormal case: width and/or height less than 0 412 Bitmap.createBitmap(mBitmap, 1, 1, -10, -10, null, false); 413 } 414 415 @Test(expected=IllegalArgumentException.class) testCreateBitmapXRegionTooWide()416 public void testCreateBitmapXRegionTooWide() { 417 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 418 419 // abnormal case: (x + width) bigger than source bitmap's width 420 Bitmap.createBitmap(mBitmap, 10, 10, 95, 50, null, false); 421 } 422 423 @Test(expected=IllegalArgumentException.class) testCreateBitmapYRegionTooTall()424 public void testCreateBitmapYRegionTooTall() { 425 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 426 427 // abnormal case: (y + height) bigger than source bitmap's height 428 Bitmap.createBitmap(mBitmap, 10, 10, 50, 95, null, false); 429 } 430 431 @Test(expected=IllegalArgumentException.class) testCreateMutableBitmapWithHardwareConfig()432 public void testCreateMutableBitmapWithHardwareConfig() { 433 Bitmap.createBitmap(100, 100, Config.HARDWARE); 434 } 435 436 @Test testCreateBitmap3()437 public void testCreateBitmap3() { 438 // special case: output bitmap is equal to the input bitmap 439 mBitmap = Bitmap.createBitmap(new int[100 * 100], 100, 100, Config.ARGB_8888); 440 Bitmap ret = Bitmap.createBitmap(mBitmap, 0, 0, 100, 100, null, false); 441 assertNotNull(ret); 442 assertFalse(ret.isMutable()); // subset should be immutable 443 assertTrue(mBitmap.equals(ret)); 444 445 // normal case 446 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 447 ret = Bitmap.createBitmap(mBitmap, 10, 10, 50, 50, new Matrix(), true); 448 assertTrue(ret.isMutable()); 449 assertNotNull(ret); 450 assertFalse(mBitmap.equals(ret)); 451 } 452 453 @Test 454 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testCreateBitmapFromHardwareBitmap()455 public void testCreateBitmapFromHardwareBitmap() { 456 Bitmap hardwareBitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, 457 HARDWARE_OPTIONS); 458 assertEquals(Config.HARDWARE, hardwareBitmap.getConfig()); 459 460 Bitmap ret = Bitmap.createBitmap(hardwareBitmap, 0, 0, 96, 96, null, false); 461 assertEquals(Config.HARDWARE, ret.getConfig()); 462 assertFalse(ret.isMutable()); 463 } 464 465 @Test testCreateBitmap4()466 public void testCreateBitmap4() { 467 Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565); 468 assertNotNull(ret); 469 assertTrue(ret.isMutable()); 470 assertEquals(100, ret.getWidth()); 471 assertEquals(200, ret.getHeight()); 472 assertEquals(Config.RGB_565, ret.getConfig()); 473 } 474 verify2x2BitmapContents(int[] expected, Bitmap observed)475 private static void verify2x2BitmapContents(int[] expected, Bitmap observed) { 476 ColorUtils.verifyColor(expected[0], observed.getPixel(0, 0)); 477 ColorUtils.verifyColor(expected[1], observed.getPixel(1, 0)); 478 ColorUtils.verifyColor(expected[2], observed.getPixel(0, 1)); 479 ColorUtils.verifyColor(expected[3], observed.getPixel(1, 1)); 480 } 481 482 @Test testCreateBitmap_matrix()483 public void testCreateBitmap_matrix() { 484 int[] colorArray = new int[] { Color.RED, Color.GREEN, Color.BLUE, Color.BLACK }; 485 Bitmap src = Bitmap.createBitmap(2, 2, Config.ARGB_8888); 486 assertTrue(src.isMutable()); 487 src.setPixels(colorArray,0, 2, 0, 0, 2, 2); 488 489 // baseline 490 verify2x2BitmapContents(colorArray, src); 491 492 // null 493 Bitmap dst = Bitmap.createBitmap(src, 0, 0, 2, 2, null, false); 494 assertTrue(dst.isMutable()); 495 verify2x2BitmapContents(colorArray, dst); 496 497 // identity matrix 498 Matrix matrix = new Matrix(); 499 dst = Bitmap.createBitmap(src, 0, 0, 2, 2, matrix, false); 500 assertTrue(dst.isMutable()); 501 verify2x2BitmapContents(colorArray, dst); 502 503 // big scale - only red visible 504 matrix.setScale(10, 10); 505 dst = Bitmap.createBitmap(src, 0, 0, 2, 2, matrix, false); 506 assertTrue(dst.isMutable()); 507 verify2x2BitmapContents(new int[] { Color.RED, Color.RED, Color.RED, Color.RED }, dst); 508 509 // rotation 510 matrix.setRotate(90); 511 dst = Bitmap.createBitmap(src, 0, 0, 2, 2, matrix, false); 512 assertTrue(dst.isMutable()); 513 verify2x2BitmapContents( 514 new int[] { Color.BLUE, Color.RED, Color.BLACK, Color.GREEN }, dst); 515 } 516 517 @Test(expected=IllegalArgumentException.class) testCreateBitmapFromColorsNegativeWidthHeight()518 public void testCreateBitmapFromColorsNegativeWidthHeight() { 519 int[] colors = createColors(100); 520 521 // abnormal case: width and/or height less than 0 522 Bitmap.createBitmap(colors, 0, 100, -1, 100, Config.RGB_565); 523 } 524 525 @Test(expected=IllegalArgumentException.class) testCreateBitmapFromColorsIllegalStride()526 public void testCreateBitmapFromColorsIllegalStride() { 527 int[] colors = createColors(100); 528 529 // abnormal case: stride less than width and bigger than -width 530 Bitmap.createBitmap(colors, 10, 10, 100, 100, Config.RGB_565); 531 } 532 533 @Test(expected=ArrayIndexOutOfBoundsException.class) testCreateBitmapFromColorsNegativeOffset()534 public void testCreateBitmapFromColorsNegativeOffset() { 535 int[] colors = createColors(100); 536 537 // abnormal case: offset less than 0 538 Bitmap.createBitmap(colors, -10, 100, 100, 100, Config.RGB_565); 539 } 540 541 @Test(expected=ArrayIndexOutOfBoundsException.class) testCreateBitmapFromColorsOffsetTooLarge()542 public void testCreateBitmapFromColorsOffsetTooLarge() { 543 int[] colors = createColors(100); 544 545 // abnormal case: (offset + width) bigger than colors' length 546 Bitmap.createBitmap(colors, 10, 100, 100, 100, Config.RGB_565); 547 } 548 549 @Test(expected=ArrayIndexOutOfBoundsException.class) testCreateBitmapFromColorsScalnlineTooLarge()550 public void testCreateBitmapFromColorsScalnlineTooLarge() { 551 int[] colors = createColors(100); 552 553 // abnormal case: (lastScanline + width) bigger than colors' length 554 Bitmap.createBitmap(colors, 10, 100, 50, 100, Config.RGB_565); 555 } 556 557 @Test testCreateBitmap6()558 public void testCreateBitmap6() { 559 int[] colors = createColors(100); 560 561 // normal case 562 Bitmap ret = Bitmap.createBitmap(colors, 5, 10, 10, 5, Config.RGB_565); 563 assertNotNull(ret); 564 assertFalse(ret.isMutable()); 565 assertEquals(10, ret.getWidth()); 566 assertEquals(5, ret.getHeight()); 567 assertEquals(Config.RGB_565, ret.getConfig()); 568 } 569 570 @Test testCreateBitmap_displayMetrics_mutable()571 public void testCreateBitmap_displayMetrics_mutable() { 572 DisplayMetrics metrics = 573 InstrumentationRegistry.getTargetContext().getResources().getDisplayMetrics(); 574 575 Bitmap bitmap; 576 bitmap = Bitmap.createBitmap(metrics, 10, 10, Config.ARGB_8888); 577 assertTrue(bitmap.isMutable()); 578 assertEquals(metrics.densityDpi, bitmap.getDensity()); 579 580 bitmap = Bitmap.createBitmap(metrics, 10, 10, Config.ARGB_8888); 581 assertTrue(bitmap.isMutable()); 582 assertEquals(metrics.densityDpi, bitmap.getDensity()); 583 584 bitmap = Bitmap.createBitmap(metrics, 10, 10, Config.ARGB_8888, true); 585 assertTrue(bitmap.isMutable()); 586 assertEquals(metrics.densityDpi, bitmap.getDensity()); 587 588 bitmap = Bitmap.createBitmap(metrics, 10, 10, Config.ARGB_8888, true, ColorSpace.get( 589 ColorSpace.Named.SRGB)); 590 591 assertTrue(bitmap.isMutable()); 592 assertEquals(metrics.densityDpi, bitmap.getDensity()); 593 594 int[] colors = createColors(100); 595 bitmap = Bitmap.createBitmap(metrics, colors, 0, 10, 10, 10, Config.ARGB_8888); 596 assertNotNull(bitmap); 597 assertFalse(bitmap.isMutable()); 598 599 bitmap = Bitmap.createBitmap(metrics, colors, 10, 10, Config.ARGB_8888); 600 assertNotNull(bitmap); 601 assertFalse(bitmap.isMutable()); 602 } 603 604 @Test testCreateBitmap_noDisplayMetrics_mutable()605 public void testCreateBitmap_noDisplayMetrics_mutable() { 606 Bitmap bitmap; 607 bitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888); 608 assertTrue(bitmap.isMutable()); 609 610 bitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888, true); 611 assertTrue(bitmap.isMutable()); 612 613 bitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888, true, ColorSpace.get(Named.SRGB)); 614 assertTrue(bitmap.isMutable()); 615 } 616 617 @Test testCreateBitmap_displayMetrics_immutable()618 public void testCreateBitmap_displayMetrics_immutable() { 619 DisplayMetrics metrics = 620 InstrumentationRegistry.getTargetContext().getResources().getDisplayMetrics(); 621 int[] colors = createColors(100); 622 623 Bitmap bitmap; 624 bitmap = Bitmap.createBitmap(metrics, colors, 0, 10, 10, 10, Config.ARGB_8888); 625 assertFalse(bitmap.isMutable()); 626 assertEquals(metrics.densityDpi, bitmap.getDensity()); 627 628 bitmap = Bitmap.createBitmap(metrics, colors, 10, 10, Config.ARGB_8888); 629 assertFalse(bitmap.isMutable()); 630 assertEquals(metrics.densityDpi, bitmap.getDensity()); 631 } 632 633 @Test testCreateBitmap_noDisplayMetrics_immutable()634 public void testCreateBitmap_noDisplayMetrics_immutable() { 635 int[] colors = createColors(100); 636 Bitmap bitmap; 637 bitmap = Bitmap.createBitmap(colors, 0, 10, 10, 10, Config.ARGB_8888); 638 assertFalse(bitmap.isMutable()); 639 640 bitmap = Bitmap.createBitmap(colors, 10, 10, Config.ARGB_8888); 641 assertFalse(bitmap.isMutable()); 642 } 643 644 @Test 645 @DisabledOnRavenwood(blockedBy = Picture.class) testCreateBitmap_Picture_immutable()646 public void testCreateBitmap_Picture_immutable() { 647 Picture picture = new Picture(); 648 Canvas canvas = picture.beginRecording(200, 100); 649 650 Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); 651 652 p.setColor(0x88FF0000); 653 canvas.drawCircle(50, 50, 40, p); 654 655 p.setColor(Color.GREEN); 656 p.setTextSize(30); 657 canvas.drawText("Pictures", 60, 60, p); 658 picture.endRecording(); 659 660 Bitmap bitmap; 661 bitmap = Bitmap.createBitmap(picture); 662 assertFalse(bitmap.isMutable()); 663 664 bitmap = Bitmap.createBitmap(picture, 100, 100, Config.HARDWARE); 665 assertFalse(bitmap.isMutable()); 666 assertNotNull(bitmap.getColorSpace()); 667 668 bitmap = Bitmap.createBitmap(picture, 100, 100, Config.ARGB_8888); 669 assertFalse(bitmap.isMutable()); 670 } 671 672 @Test testCreateScaledBitmap()673 public void testCreateScaledBitmap() { 674 mBitmap = Bitmap.createBitmap(100, 200, Config.RGB_565); 675 assertTrue(mBitmap.isMutable()); 676 Bitmap ret = Bitmap.createScaledBitmap(mBitmap, 50, 100, false); 677 assertNotNull(ret); 678 assertEquals(50, ret.getWidth()); 679 assertEquals(100, ret.getHeight()); 680 assertTrue(ret.isMutable()); 681 } 682 683 @Test 684 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testWrapHardwareBufferSucceeds()685 public void testWrapHardwareBufferSucceeds() { 686 try (HardwareBuffer hwBuffer = createTestBuffer(128, 128, false)) { 687 Bitmap bitmap = Bitmap.wrapHardwareBuffer(hwBuffer, ColorSpace.get(Named.SRGB)); 688 assertNotNull(bitmap); 689 bitmap.recycle(); 690 } 691 } 692 693 @Test 694 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testWrapHardwareBufferMissingGpuUsageFails()695 public void testWrapHardwareBufferMissingGpuUsageFails() { 696 try (HardwareBuffer hwBuffer = HardwareBuffer.create(512, 512, HardwareBuffer.RGBA_8888, 1, 697 HardwareBuffer.USAGE_CPU_WRITE_RARELY)) { 698 assertThrows(IllegalArgumentException.class, () -> { 699 Bitmap.wrapHardwareBuffer(hwBuffer, ColorSpace.get(Named.SRGB)); 700 }); 701 } 702 } 703 704 @Test 705 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testWrapHardwareBufferWithProtectedUsageFails()706 public void testWrapHardwareBufferWithProtectedUsageFails() { 707 long usage = HardwareBuffer.USAGE_GPU_COLOR_OUTPUT 708 | HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE 709 | HardwareBuffer.USAGE_COMPOSER_OVERLAY 710 | HardwareBuffer.USAGE_PROTECTED_CONTENT; 711 712 assumeTrue("Creating a protected HW buffer is not supported", 713 HardwareBuffer.isSupported(512, 512, HardwareBuffer.RGBA_8888, 1, usage)); 714 try (HardwareBuffer hwBuffer = 715 HardwareBuffer.create(512, 512, HardwareBuffer.RGBA_8888, 1, usage)) { 716 assertThrows(IllegalArgumentException.class, () -> { 717 Bitmap.wrapHardwareBuffer(hwBuffer, ColorSpace.get(Named.SRGB)); 718 }); 719 } 720 } 721 722 @Test(expected = IllegalArgumentException.class) 723 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testWrapHardwareBufferWithRgbBufferButNonRgbColorSpaceFails()724 public void testWrapHardwareBufferWithRgbBufferButNonRgbColorSpaceFails() { 725 try (HardwareBuffer hwBuffer = HardwareBuffer.create(512, 512, HardwareBuffer.RGBA_8888, 1, 726 HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE)) { 727 Bitmap bitmap = Bitmap.wrapHardwareBuffer(hwBuffer, ColorSpace.get(Named.CIE_LAB)); 728 } 729 } 730 731 @Test 732 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testWrapHardwareBufferFor1010102BufferSucceeds()733 public void testWrapHardwareBufferFor1010102BufferSucceeds() { 734 HardwareBuffer hwBufferMaybe = null; 735 736 try { 737 hwBufferMaybe = HardwareBuffer.create(128, 128, HardwareBuffer.RGBA_1010102, 1, 738 HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE); 739 } catch (IllegalArgumentException e) { 740 assumeNoException("Creating a 1010102 HW buffer was not supported", e); 741 } 742 743 assumeNotNull(hwBufferMaybe); 744 745 try (HardwareBuffer buffer = hwBufferMaybe) { 746 Bitmap bitmap = Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(Named.SRGB)); 747 assertNotNull(bitmap); 748 bitmap.recycle(); 749 } 750 } 751 assertMatches(HardwareBuffer hwBuffer, HardwareBuffer hwBuffer2)752 private void assertMatches(HardwareBuffer hwBuffer, HardwareBuffer hwBuffer2) { 753 assertEquals(hwBuffer, hwBuffer2); 754 assertEquals(hwBuffer.hashCode(), hwBuffer2.hashCode()); 755 assertEquals(hwBuffer.getWidth(), hwBuffer2.getWidth()); 756 assertEquals(hwBuffer.getHeight(), hwBuffer2.getHeight()); 757 assertEquals(hwBuffer.getFormat(), hwBuffer2.getFormat()); 758 assertEquals(hwBuffer.getLayers(), hwBuffer2.getLayers()); 759 assertEquals(hwBuffer.getUsage(), hwBuffer2.getUsage()); 760 } 761 762 @Test 763 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testGetHardwareBufferMatchesWrapped()764 public void testGetHardwareBufferMatchesWrapped() { 765 try (HardwareBuffer hwBuffer = createTestBuffer(128, 128, false)) { 766 Bitmap bitmap = Bitmap.wrapHardwareBuffer(hwBuffer, ColorSpace.get(Named.SRGB)); 767 assertNotNull(bitmap); 768 769 try (HardwareBuffer hwBuffer2 = bitmap.getHardwareBuffer()) { 770 assertNotNull(hwBuffer2); 771 assertMatches(hwBuffer, hwBuffer2); 772 } 773 bitmap.recycle(); 774 } 775 } 776 parametersFor_testGetAllocationSizeWrappedBuffer()777 private static Object[] parametersFor_testGetAllocationSizeWrappedBuffer() { 778 return new Object[] { 779 HardwareBuffer.YCBCR_420_888, 780 HardwareBuffer.YCBCR_P010, 781 ImageFormat.YV12, 782 }; 783 } 784 785 @Test 786 @Parameters(method = "parametersFor_testGetAllocationSizeWrappedBuffer") 787 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testGetAllocationSizeWrappedBuffer(int format)788 public void testGetAllocationSizeWrappedBuffer(int format) { 789 final long usage = HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE; 790 assumeTrue(HardwareBuffer.isSupported(1, 1, format, 1, usage)); 791 HardwareBuffer buffer = HardwareBuffer.create(100, 100, format, 1, usage); 792 assertNotNull("isSupported = true but allocation failed", buffer); 793 Bitmap bitmap = Bitmap.wrapHardwareBuffer(buffer, null); 794 buffer.close(); 795 try { 796 // We can probably assert closer to at least 100 * 100 but maybe someone has super 797 // duper good compression rates, so assume a lower bound of 2kb 798 assertTrue(bitmap.getAllocationByteCount() > 2000); 799 } finally { 800 bitmap.recycle(); 801 } 802 } 803 parametersFor_testGetHardwareBufferConfig()804 private static Object[] parametersFor_testGetHardwareBufferConfig() { 805 return new Object[] {Config.ARGB_8888, Config.RGBA_F16, Config.RGB_565}; 806 } 807 808 @Test 809 @Parameters(method = "parametersFor_testGetHardwareBufferConfig") 810 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testGetHardwareBufferConfig(Config config)811 public void testGetHardwareBufferConfig(Config config) { 812 Bitmap bitmap = Bitmap.createBitmap(10, 10, config); 813 bitmap = bitmap.copy(Config.HARDWARE, false); 814 if (bitmap == null) { 815 fail("Failed to copy to HARDWARE with Config " + config); 816 } 817 try (HardwareBuffer hwBuffer = bitmap.getHardwareBuffer()) { 818 assertNotNull(hwBuffer); 819 assertEquals(hwBuffer.getWidth(), 10); 820 assertEquals(hwBuffer.getHeight(), 10); 821 } 822 } 823 824 @Test 825 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testGetHardwareBufferTwice()826 public void testGetHardwareBufferTwice() { 827 Bitmap bitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888); 828 bitmap = bitmap.copy(Config.HARDWARE, false); 829 try (HardwareBuffer hwBuffer = bitmap.getHardwareBuffer()) { 830 assertNotNull(hwBuffer); 831 try (HardwareBuffer hwBuffer2 = bitmap.getHardwareBuffer()) { 832 assertNotNull(hwBuffer2); 833 assertMatches(hwBuffer, hwBuffer2); 834 } 835 } 836 } 837 838 @Test 839 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testGetHardwareBufferMatches()840 public void testGetHardwareBufferMatches() { 841 Bitmap bitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888); 842 bitmap = bitmap.copy(Config.HARDWARE, false); 843 try (HardwareBuffer hwBuffer = bitmap.getHardwareBuffer()) { 844 HashSet<HardwareBuffer> set = new HashSet<HardwareBuffer>(); 845 set.add(hwBuffer); 846 assertTrue(set.contains(bitmap.getHardwareBuffer())); 847 } 848 } 849 850 @Test(expected = IllegalStateException.class) 851 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testGetHardwareBufferNonHardware()852 public void testGetHardwareBufferNonHardware() { 853 Bitmap bitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888); 854 bitmap.getHardwareBuffer(); 855 } 856 857 @Test(expected = IllegalStateException.class) 858 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testGetHardwareBufferRecycled()859 public void testGetHardwareBufferRecycled() { 860 Bitmap bitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888); 861 bitmap = bitmap.copy(Config.HARDWARE, false); 862 bitmap.recycle(); 863 bitmap.getHardwareBuffer(); 864 } 865 866 @Test 867 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testGetHardwareBufferClosed()868 public void testGetHardwareBufferClosed() { 869 HardwareBuffer hwBuffer = createTestBuffer(128, 128, false); 870 Bitmap bitmap = Bitmap.wrapHardwareBuffer(hwBuffer, ColorSpace.get(Named.SRGB)); 871 assertNotNull(bitmap); 872 873 hwBuffer.close(); 874 875 try (HardwareBuffer hwBuffer2 = bitmap.getHardwareBuffer()) { 876 assertNotNull(hwBuffer2); 877 assertFalse(hwBuffer2.isClosed()); 878 assertNotEquals(hwBuffer, hwBuffer2); 879 } 880 bitmap.recycle(); 881 } 882 883 @Test testGenerationId()884 public void testGenerationId() { 885 Bitmap bitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888); 886 int genId = bitmap.getGenerationId(); 887 assertEquals("not expected to change", genId, bitmap.getGenerationId()); 888 bitmap.setDensity(bitmap.getDensity() + 4); 889 assertEquals("not expected to change", genId, bitmap.getGenerationId()); 890 bitmap.getPixel(0, 0); 891 assertEquals("not expected to change", genId, bitmap.getGenerationId()); 892 893 int beforeGenId = bitmap.getGenerationId(); 894 bitmap.eraseColor(Color.WHITE); 895 int afterGenId = bitmap.getGenerationId(); 896 assertTrue("expected to increase", afterGenId > beforeGenId); 897 898 beforeGenId = bitmap.getGenerationId(); 899 bitmap.setPixel(4, 4, Color.BLUE); 900 afterGenId = bitmap.getGenerationId(); 901 assertTrue("expected to increase again", afterGenId > beforeGenId); 902 } 903 904 @Test testDescribeContents()905 public void testDescribeContents() { 906 assertEquals(0, mBitmap.describeContents()); 907 } 908 909 @Test(expected=IllegalStateException.class) testEraseColorOnRecycled()910 public void testEraseColorOnRecycled() { 911 mBitmap.recycle(); 912 913 mBitmap.eraseColor(0); 914 } 915 916 @Test(expected = IllegalStateException.class) testEraseColorLongOnRecycled()917 public void testEraseColorLongOnRecycled() { 918 mBitmap.recycle(); 919 920 mBitmap.eraseColor(Color.pack(0)); 921 } 922 923 @Test(expected=IllegalStateException.class) testEraseColorOnImmutable()924 public void testEraseColorOnImmutable() { 925 mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions); 926 927 //abnormal case: bitmap is immutable 928 mBitmap.eraseColor(0); 929 } 930 931 @Test(expected = IllegalStateException.class) testEraseColorLongOnImmutable()932 public void testEraseColorLongOnImmutable() { 933 mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions); 934 935 //abnormal case: bitmap is immutable 936 mBitmap.eraseColor(Color.pack(0)); 937 } 938 939 @Test testEraseColor()940 public void testEraseColor() { 941 // normal case 942 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 943 mBitmap.eraseColor(0xffff0000); 944 assertEquals(0xffff0000, mBitmap.getPixel(10, 10)); 945 assertEquals(0xffff0000, mBitmap.getPixel(50, 50)); 946 } 947 948 @Test(expected = IllegalArgumentException.class) testGetColorOOB()949 public void testGetColorOOB() { 950 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 951 mBitmap.getColor(-1, 0); 952 } 953 954 @Test(expected = IllegalArgumentException.class) testGetColorOOB2()955 public void testGetColorOOB2() { 956 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 957 mBitmap.getColor(5, -10); 958 } 959 960 @Test(expected = IllegalArgumentException.class) testGetColorOOB3()961 public void testGetColorOOB3() { 962 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 963 mBitmap.getColor(100, 10); 964 } 965 966 @Test(expected = IllegalArgumentException.class) testGetColorOOB4()967 public void testGetColorOOB4() { 968 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 969 mBitmap.getColor(99, 1000); 970 } 971 972 @Test(expected = IllegalStateException.class) testGetColorRecycled()973 public void testGetColorRecycled() { 974 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 975 mBitmap.recycle(); 976 mBitmap.getColor(0, 0); 977 } 978 979 @Test(expected = IllegalStateException.class) 980 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testGetColorHardware()981 public void testGetColorHardware() { 982 BitmapFactory.Options options = new BitmapFactory.Options(); 983 options.inPreferredConfig = Bitmap.Config.HARDWARE; 984 mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, options); 985 mBitmap.getColor(50, 50); 986 } 987 clamp(float f)988 private static float clamp(float f) { 989 return clamp(f, 0.0f, 1.0f); 990 } 991 clamp(float f, float min, float max)992 private static float clamp(float f, float min, float max) { 993 return Math.min(Math.max(f, min), max); 994 } 995 996 @Test testGetColor()997 public void testGetColor() { 998 final ColorSpace sRGB = ColorSpace.get(ColorSpace.Named.SRGB); 999 List<ColorSpace> rgbColorSpaces = getRgbColorSpaces(); 1000 for (Config config : new Config[] { Config.ARGB_8888, Config.RGBA_F16, Config.RGB_565 }) { 1001 for (ColorSpace bitmapColorSpace : rgbColorSpaces) { 1002 mBitmap = Bitmap.createBitmap(1, 1, config, /*hasAlpha*/ false, 1003 bitmapColorSpace); 1004 bitmapColorSpace = mBitmap.getColorSpace(); 1005 for (ColorSpace eraseColorSpace : rgbColorSpaces) { 1006 for (long wideGamutLong : new long[] { 1007 Color.pack(1.0f, 0.0f, 0.0f, 1.0f, eraseColorSpace), 1008 Color.pack(0.0f, 1.0f, 0.0f, 1.0f, eraseColorSpace), 1009 Color.pack(0.0f, 0.0f, 1.0f, 1.0f, eraseColorSpace)}) { 1010 mBitmap.eraseColor(wideGamutLong); 1011 1012 Color result = mBitmap.getColor(0, 0); 1013 if (mBitmap.getColorSpace().equals(sRGB)) { 1014 assertEquals(mBitmap.getPixel(0, 0), result.toArgb()); 1015 } 1016 if (eraseColorSpace.equals(bitmapColorSpace)) { 1017 final Color wideGamutColor = Color.valueOf(wideGamutLong); 1018 ColorUtils.verifyColor("Erasing to Bitmap's ColorSpace " 1019 + bitmapColorSpace, wideGamutColor, result, .001f); 1020 1021 } else { 1022 Color convertedColor = Color.valueOf( 1023 Color.convert(wideGamutLong, bitmapColorSpace)); 1024 if (mBitmap.getConfig() != Config.RGBA_F16) { 1025 // It's possible that we have to clip to fit into the Config. 1026 convertedColor = Color.valueOf( 1027 clamp(convertedColor.red()), 1028 clamp(convertedColor.green()), 1029 clamp(convertedColor.blue()), 1030 convertedColor.alpha(), 1031 bitmapColorSpace); 1032 } 1033 ColorUtils.verifyColor("Bitmap(Config: " + mBitmap.getConfig() 1034 + ", ColorSpace: " + bitmapColorSpace 1035 + ") erasing to " + Color.valueOf(wideGamutLong), 1036 convertedColor, result, .03f); 1037 } 1038 } 1039 } 1040 } 1041 } 1042 } 1043 1044 private static class ARGB { 1045 public float alpha; 1046 public float red; 1047 public float green; 1048 public float blue; ARGB(float alpha, float red, float green, float blue)1049 ARGB(float alpha, float red, float green, float blue) { 1050 this.alpha = alpha; 1051 this.red = red; 1052 this.green = green; 1053 this.blue = blue; 1054 } 1055 }; 1056 1057 @Test testEraseColorLong()1058 public void testEraseColorLong() { 1059 List<ColorSpace> rgbColorSpaces = getRgbColorSpaces(); 1060 for (Config config : new Config[]{Config.ARGB_8888, Config.RGB_565, Config.RGBA_F16}) { 1061 mBitmap = Bitmap.createBitmap(100, 100, config); 1062 // pack SRGB colors into ColorLongs. 1063 for (int color : new int[]{ Color.RED, Color.BLUE, Color.GREEN, Color.BLACK, 1064 Color.WHITE, Color.TRANSPARENT }) { 1065 if (config.equals(Config.RGB_565) && Float.compare(Color.alpha(color), 1.0f) != 0) { 1066 // 565 doesn't support alpha. 1067 continue; 1068 } 1069 mBitmap.eraseColor(Color.pack(color)); 1070 // The Bitmap is either SRGB or SRGBLinear (F16). getPixel(), which retrieves the 1071 // color in SRGB, should match exactly. 1072 ColorUtils.verifyColor("Config " + config + " mismatch at 10, 10 ", 1073 color, mBitmap.getPixel(10, 10), 0); 1074 ColorUtils.verifyColor("Config " + config + " mismatch at 50, 50 ", 1075 color, mBitmap.getPixel(50, 50), 0); 1076 } 1077 1078 // Use arbitrary colors in various ColorSpaces. getPixel() should approximately match 1079 // the SRGB version of the color. 1080 for (ARGB color : new ARGB[]{ new ARGB(1.0f, .5f, .5f, .5f), 1081 new ARGB(1.0f, .3f, .6f, .9f), 1082 new ARGB(0.5f, .2f, .8f, .7f) }) { 1083 if (config.equals(Config.RGB_565) && Float.compare(color.alpha, 1.0f) != 0) { 1084 continue; 1085 } 1086 int srgbColor = Color.argb(color.alpha, color.red, color.green, color.blue); 1087 for (ColorSpace cs : rgbColorSpaces) { 1088 long longColor = Color.convert(srgbColor, cs); 1089 mBitmap.eraseColor(longColor); 1090 // These tolerances were chosen by trial and error. It is expected that 1091 // some conversions do not round-trip perfectly. 1092 int tolerance = 1; 1093 if (config.equals(Config.RGB_565)) { 1094 tolerance = 4; 1095 } else if (cs.equals(ColorSpace.get(ColorSpace.Named.SMPTE_C))) { 1096 tolerance = 3; 1097 } 1098 1099 ColorUtils.verifyColor("Config " + config + ", ColorSpace " + cs 1100 + ", mismatch at 10, 10 ", srgbColor, mBitmap.getPixel(10, 10), 1101 tolerance); 1102 ColorUtils.verifyColor("Config " + config + ", ColorSpace " + cs 1103 + ", mismatch at 50, 50 ", srgbColor, mBitmap.getPixel(50, 50), 1104 tolerance); 1105 } 1106 } 1107 } 1108 } 1109 1110 @Test testEraseColorOnP3()1111 public void testEraseColorOnP3() { 1112 // Use a ColorLong with a different ColorSpace than the Bitmap. getPixel() should 1113 // approximately match the SRGB version of the color. 1114 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888, true, 1115 ColorSpace.get(ColorSpace.Named.DISPLAY_P3)); 1116 int srgbColor = Color.argb(.5f, .3f, .6f, .7f); 1117 long acesColor = Color.convert(srgbColor, ColorSpace.get(ColorSpace.Named.ACES)); 1118 mBitmap.eraseColor(acesColor); 1119 ColorUtils.verifyColor("Mismatch at 15, 15", srgbColor, mBitmap.getPixel(15, 15), 1); 1120 } 1121 1122 @Test(expected = IllegalArgumentException.class) testEraseColorXYZ()1123 public void testEraseColorXYZ() { 1124 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 1125 mBitmap.eraseColor(Color.convert(Color.BLUE, ColorSpace.get(ColorSpace.Named.CIE_XYZ))); 1126 } 1127 1128 @Test(expected = IllegalArgumentException.class) testEraseColorLAB()1129 public void testEraseColorLAB() { 1130 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 1131 mBitmap.eraseColor(Color.convert(Color.BLUE, ColorSpace.get(ColorSpace.Named.CIE_LAB))); 1132 } 1133 1134 @Test(expected = IllegalArgumentException.class) testEraseColorUnknown()1135 public void testEraseColorUnknown() { 1136 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 1137 mBitmap.eraseColor(-1L); 1138 } 1139 1140 @Test(expected=IllegalStateException.class) testExtractAlphaFromRecycled()1141 public void testExtractAlphaFromRecycled() { 1142 mBitmap.recycle(); 1143 1144 mBitmap.extractAlpha(); 1145 } 1146 1147 @Test testExtractAlpha()1148 public void testExtractAlpha() { 1149 // normal case 1150 mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions); 1151 Bitmap ret = mBitmap.extractAlpha(); 1152 assertNotNull(ret); 1153 int source = mBitmap.getPixel(10, 20); 1154 int result = ret.getPixel(10, 20); 1155 assertEquals(Color.alpha(source), Color.alpha(result)); 1156 assertEquals(0xFF, Color.alpha(result)); 1157 } 1158 1159 @Test(expected=IllegalStateException.class) testExtractAlphaWithPaintAndOffsetFromRecycled()1160 public void testExtractAlphaWithPaintAndOffsetFromRecycled() { 1161 mBitmap.recycle(); 1162 1163 mBitmap.extractAlpha(new Paint(), new int[]{0, 1}); 1164 } 1165 1166 @Test testExtractAlphaWithPaintAndOffset()1167 public void testExtractAlphaWithPaintAndOffset() { 1168 // normal case 1169 mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions); 1170 Bitmap ret = mBitmap.extractAlpha(new Paint(), new int[]{0, 1}); 1171 assertNotNull(ret); 1172 int source = mBitmap.getPixel(10, 20); 1173 int result = ret.getPixel(10, 20); 1174 assertEquals(Color.alpha(source), Color.alpha(result)); 1175 assertEquals(0xFF, Color.alpha(result)); 1176 } 1177 1178 @Test testGetAllocationByteCount()1179 public void testGetAllocationByteCount() { 1180 mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ALPHA_8); 1181 int alloc = mBitmap.getAllocationByteCount(); 1182 assertEquals(mBitmap.getByteCount(), alloc); 1183 1184 // reconfigure same size 1185 mBitmap.reconfigure(50, 100, Bitmap.Config.ARGB_8888); 1186 assertEquals(mBitmap.getByteCount(), alloc); 1187 assertEquals(mBitmap.getAllocationByteCount(), alloc); 1188 1189 // reconfigure different size 1190 mBitmap.reconfigure(10, 10, Bitmap.Config.ALPHA_8); 1191 assertEquals(mBitmap.getByteCount(), 100); 1192 assertEquals(mBitmap.getAllocationByteCount(), alloc); 1193 } 1194 1195 @Test testGetConfig()1196 public void testGetConfig() { 1197 Bitmap bm0 = Bitmap.createBitmap(100, 200, Bitmap.Config.ALPHA_8); 1198 Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); 1199 Bitmap bm2 = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565); 1200 Bitmap bm3 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_4444); 1201 1202 assertEquals(Bitmap.Config.ALPHA_8, bm0.getConfig()); 1203 assertEquals(Bitmap.Config.ARGB_8888, bm1.getConfig()); 1204 assertEquals(Bitmap.Config.RGB_565, bm2.getConfig()); 1205 // Attempting to create a 4444 bitmap actually creates an 8888 bitmap. 1206 assertEquals(Bitmap.Config.ARGB_8888, bm3.getConfig()); 1207 } 1208 1209 @Test 1210 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testGetHardwareConfig()1211 public void testGetHardwareConfig() { 1212 // Can't call Bitmap.createBitmap with Bitmap.Config.HARDWARE, 1213 // because createBitmap creates mutable bitmap and hardware bitmaps are always immutable, 1214 // so such call will throw an exception. 1215 Bitmap hardwareBitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, 1216 HARDWARE_OPTIONS); 1217 assertEquals(Bitmap.Config.HARDWARE, hardwareBitmap.getConfig()); 1218 } 1219 1220 @Test testGetHeight()1221 public void testGetHeight() { 1222 assertEquals(31, mBitmap.getHeight()); 1223 mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); 1224 assertEquals(200, mBitmap.getHeight()); 1225 } 1226 1227 @Test testGetNinePatchChunk()1228 public void testGetNinePatchChunk() { 1229 assertNull(mBitmap.getNinePatchChunk()); 1230 } 1231 1232 @Test(expected=IllegalStateException.class) testGetPixelFromRecycled()1233 public void testGetPixelFromRecycled() { 1234 mBitmap.recycle(); 1235 1236 mBitmap.getPixel(10, 16); 1237 } 1238 1239 @Test(expected=IllegalArgumentException.class) testGetPixelXTooLarge()1240 public void testGetPixelXTooLarge() { 1241 mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565); 1242 1243 // abnormal case: x bigger than the source bitmap's width 1244 mBitmap.getPixel(200, 16); 1245 } 1246 1247 @Test(expected=IllegalArgumentException.class) testGetPixelYTooLarge()1248 public void testGetPixelYTooLarge() { 1249 mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565); 1250 1251 // abnormal case: y bigger than the source bitmap's height 1252 mBitmap.getPixel(10, 300); 1253 } 1254 1255 @Test testGetPixel()1256 public void testGetPixel() { 1257 mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565); 1258 1259 // normal case 565 1260 mBitmap.setPixel(10, 16, 0xFF << 24); 1261 assertEquals(0xFF << 24, mBitmap.getPixel(10, 16)); 1262 1263 // normal case A_8 1264 mBitmap = Bitmap.createBitmap(10, 10, Config.ALPHA_8); 1265 mBitmap.setPixel(5, 5, 0xFFFFFFFF); 1266 assertEquals(0xFF000000, mBitmap.getPixel(5, 5)); 1267 mBitmap.setPixel(5, 5, 0xA8A8A8A8); 1268 assertEquals(0xA8000000, mBitmap.getPixel(5, 5)); 1269 mBitmap.setPixel(5, 5, 0x00000000); 1270 assertEquals(0x00000000, mBitmap.getPixel(5, 5)); 1271 mBitmap.setPixel(5, 5, 0x1F000000); 1272 assertEquals(0x1F000000, mBitmap.getPixel(5, 5)); 1273 } 1274 1275 @Test testGetRowBytes()1276 public void testGetRowBytes() { 1277 Bitmap bm0 = Bitmap.createBitmap(100, 200, Bitmap.Config.ALPHA_8); 1278 Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); 1279 Bitmap bm2 = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565); 1280 Bitmap bm3 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_4444); 1281 1282 assertEquals(100, bm0.getRowBytes()); 1283 assertEquals(400, bm1.getRowBytes()); 1284 assertEquals(200, bm2.getRowBytes()); 1285 // Attempting to create a 4444 bitmap actually creates an 8888 bitmap. 1286 assertEquals(400, bm3.getRowBytes()); 1287 } 1288 1289 @Test testGetWidth()1290 public void testGetWidth() { 1291 assertEquals(31, mBitmap.getWidth()); 1292 mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); 1293 assertEquals(100, mBitmap.getWidth()); 1294 } 1295 1296 @Test testHasAlpha()1297 public void testHasAlpha() { 1298 assertFalse(mBitmap.hasAlpha()); 1299 mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); 1300 assertTrue(mBitmap.hasAlpha()); 1301 } 1302 1303 @Test testIsMutable()1304 public void testIsMutable() { 1305 assertFalse(mBitmap.isMutable()); 1306 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 1307 assertTrue(mBitmap.isMutable()); 1308 } 1309 1310 @Test testIsRecycled()1311 public void testIsRecycled() { 1312 assertFalse(mBitmap.isRecycled()); 1313 mBitmap.recycle(); 1314 assertTrue(mBitmap.isRecycled()); 1315 } 1316 1317 @Test testReconfigure()1318 public void testReconfigure() { 1319 mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565); 1320 int alloc = mBitmap.getAllocationByteCount(); 1321 1322 // test shrinking 1323 mBitmap.reconfigure(50, 100, Bitmap.Config.ALPHA_8); 1324 assertEquals(mBitmap.getAllocationByteCount(), alloc); 1325 assertEquals(mBitmap.getByteCount() * 8, alloc); 1326 } 1327 1328 @Test(expected=IllegalArgumentException.class) testReconfigureExpanding()1329 public void testReconfigureExpanding() { 1330 mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565); 1331 mBitmap.reconfigure(101, 201, Bitmap.Config.ARGB_8888); 1332 } 1333 1334 @Test(expected=IllegalStateException.class) testReconfigureMutable()1335 public void testReconfigureMutable() { 1336 mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions); 1337 mBitmap.reconfigure(1, 1, Bitmap.Config.ALPHA_8); 1338 } 1339 1340 // Used by testAlphaAndPremul. 1341 private static Config[] CONFIGS = new Config[] { Config.ALPHA_8, Config.ARGB_4444, 1342 Config.ARGB_8888, Config.RGB_565 }; 1343 1344 // test that reconfigure, setHasAlpha, and setPremultiplied behave as expected with 1345 // respect to alpha and premultiplied. 1346 @Test testAlphaAndPremul()1347 public void testAlphaAndPremul() { 1348 boolean falseTrue[] = new boolean[] { false, true }; 1349 for (Config fromConfig : CONFIGS) { 1350 for (Config toConfig : CONFIGS) { 1351 for (boolean hasAlpha : falseTrue) { 1352 for (boolean isPremul : falseTrue) { 1353 Bitmap bitmap = Bitmap.createBitmap(10, 10, fromConfig); 1354 1355 // 4444 is deprecated, and will convert to 8888. No need to 1356 // attempt a reconfigure, which will be tested when fromConfig 1357 // is 8888. 1358 if (fromConfig == Config.ARGB_4444) { 1359 assertEquals(bitmap.getConfig(), Config.ARGB_8888); 1360 break; 1361 } 1362 1363 bitmap.setHasAlpha(hasAlpha); 1364 bitmap.setPremultiplied(isPremul); 1365 1366 verifyAlphaAndPremul(bitmap, hasAlpha, isPremul, false); 1367 1368 // reconfigure to a smaller size so the function will still succeed when 1369 // going to a Config that requires more bits. 1370 bitmap.reconfigure(1, 1, toConfig); 1371 if (toConfig == Config.ARGB_4444) { 1372 assertEquals(bitmap.getConfig(), Config.ARGB_8888); 1373 } else { 1374 assertEquals(bitmap.getConfig(), toConfig); 1375 } 1376 1377 // Check that the alpha and premultiplied state has not changed (unless 1378 // we expected it to). 1379 verifyAlphaAndPremul(bitmap, hasAlpha, isPremul, fromConfig == Config.RGB_565); 1380 } 1381 } 1382 } 1383 } 1384 } 1385 1386 /** 1387 * Assert that bitmap returns the appropriate values for hasAlpha() and isPremultiplied(). 1388 * @param bitmap Bitmap to check. 1389 * @param expectedAlpha Expected return value from bitmap.hasAlpha(). Note that this is based 1390 * on what was set, but may be different from the actual return value depending on the 1391 * Config and convertedFrom565. 1392 * @param expectedPremul Expected return value from bitmap.isPremultiplied(). Similar to 1393 * expectedAlpha, this is based on what was set, but may be different from the actual 1394 * return value depending on the Config. 1395 * @param convertedFrom565 Whether bitmap was converted to its current Config by being 1396 * reconfigured from RGB_565. If true, and bitmap is now a Config that supports alpha, 1397 * hasAlpha() is expected to be true even if expectedAlpha is false. 1398 */ verifyAlphaAndPremul(Bitmap bitmap, boolean expectedAlpha, boolean expectedPremul, boolean convertedFrom565)1399 private void verifyAlphaAndPremul(Bitmap bitmap, boolean expectedAlpha, boolean expectedPremul, 1400 boolean convertedFrom565) { 1401 switch (bitmap.getConfig()) { 1402 case ARGB_4444: 1403 // This shouldn't happen, since we don't allow creating or converting 1404 // to 4444. 1405 assertFalse(true); 1406 break; 1407 case RGB_565: 1408 assertFalse(bitmap.hasAlpha()); 1409 assertFalse(bitmap.isPremultiplied()); 1410 break; 1411 case ALPHA_8: 1412 // ALPHA_8 behaves mostly the same as 8888, except for premultiplied. Fall through. 1413 case ARGB_8888: 1414 // Since 565 is necessarily opaque, we revert to hasAlpha when switching to a type 1415 // that can have alpha. 1416 if (convertedFrom565) { 1417 assertTrue(bitmap.hasAlpha()); 1418 } else { 1419 assertEquals(bitmap.hasAlpha(), expectedAlpha); 1420 } 1421 1422 if (bitmap.hasAlpha()) { 1423 // ALPHA_8's premultiplied status is undefined. 1424 if (bitmap.getConfig() != Config.ALPHA_8) { 1425 assertEquals(bitmap.isPremultiplied(), expectedPremul); 1426 } 1427 } else { 1428 // Opaque bitmap is never considered premultiplied. 1429 assertFalse(bitmap.isPremultiplied()); 1430 } 1431 break; 1432 } 1433 } 1434 1435 @Test testSetColorSpace()1436 public void testSetColorSpace() { 1437 // Use arbitrary colors and assign to various ColorSpaces. 1438 for (ARGB color : new ARGB[]{ new ARGB(1.0f, .5f, .5f, .5f), 1439 new ARGB(1.0f, .3f, .6f, .9f), 1440 new ARGB(0.5f, .2f, .8f, .7f) }) { 1441 1442 int srgbColor = Color.argb(color.alpha, color.red, color.green, color.blue); 1443 for (ColorSpace cs : getRgbColorSpaces()) { 1444 for (Config config : new Config[] { 1445 // F16 is tested elsewhere, since it defaults to EXTENDED_SRGB, and 1446 // many of these calls to setColorSpace would reduce the range, resulting 1447 // in an Exception. 1448 Config.ARGB_8888, 1449 Config.RGB_565, 1450 }) { 1451 mBitmap = Bitmap.createBitmap(10, 10, config); 1452 mBitmap.eraseColor(srgbColor); 1453 mBitmap.setColorSpace(cs); 1454 ColorSpace actual = mBitmap.getColorSpace(); 1455 if (cs == ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)) { 1456 assertSame(ColorSpace.get(ColorSpace.Named.SRGB), actual); 1457 } else if (cs == ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB)) { 1458 assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_SRGB), actual); 1459 } else { 1460 assertSame(cs, actual); 1461 } 1462 1463 // This tolerance was chosen by trial and error. It is expected that 1464 // some conversions do not round-trip perfectly. 1465 int tolerance = 2; 1466 Color c = Color.valueOf(color.red, color.green, color.blue, color.alpha, cs); 1467 ColorUtils.verifyColor("Mismatch after setting the colorSpace to " 1468 + cs.getName(), c.convert(mBitmap.getColorSpace()), 1469 mBitmap.getColor(5, 5), tolerance); 1470 } 1471 } 1472 } 1473 } 1474 1475 @Test(expected = IllegalStateException.class) testSetColorSpaceRecycled()1476 public void testSetColorSpaceRecycled() { 1477 mBitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888); 1478 mBitmap.recycle(); 1479 mBitmap.setColorSpace(ColorSpace.get(Named.DISPLAY_P3)); 1480 } 1481 1482 @Test(expected = IllegalArgumentException.class) testSetColorSpaceNull()1483 public void testSetColorSpaceNull() { 1484 mBitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888); 1485 mBitmap.setColorSpace(null); 1486 } 1487 1488 @Test(expected = IllegalArgumentException.class) testSetColorSpaceXYZ()1489 public void testSetColorSpaceXYZ() { 1490 mBitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888); 1491 mBitmap.setColorSpace(ColorSpace.get(Named.CIE_XYZ)); 1492 } 1493 1494 @Test(expected = IllegalArgumentException.class) testSetColorSpaceNoTransferParameters()1495 public void testSetColorSpaceNoTransferParameters() { 1496 mBitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888); 1497 ColorSpace cs = new ColorSpace.Rgb("NoTransferParams", 1498 new float[]{ 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f }, 1499 ColorSpace.ILLUMINANT_D50, 1500 x -> Math.pow(x, 1.0f / 2.2f), x -> Math.pow(x, 2.2f), 1501 0, 1); 1502 mBitmap.setColorSpace(cs); 1503 } 1504 1505 @Test(expected = IllegalArgumentException.class) testSetColorSpaceAlpha8()1506 public void testSetColorSpaceAlpha8() { 1507 mBitmap = Bitmap.createBitmap(10, 10, Config.ALPHA_8); 1508 assertNull(mBitmap.getColorSpace()); 1509 mBitmap.setColorSpace(ColorSpace.get(ColorSpace.Named.SRGB)); 1510 } 1511 1512 @Test testSetColorSpaceReducedRange()1513 public void testSetColorSpaceReducedRange() { 1514 ColorSpace aces = ColorSpace.get(Named.ACES); 1515 mBitmap = Bitmap.createBitmap(10, 10, Config.RGBA_F16, true, aces); 1516 try { 1517 mBitmap.setColorSpace(ColorSpace.get(Named.SRGB)); 1518 fail("Expected IllegalArgumentException!"); 1519 } catch (IllegalArgumentException e) { 1520 assertSame(aces, mBitmap.getColorSpace()); 1521 } 1522 } 1523 1524 @Test testSetColorSpaceNotReducedRange()1525 public void testSetColorSpaceNotReducedRange() { 1526 ColorSpace extended = ColorSpace.get(Named.EXTENDED_SRGB); 1527 mBitmap = Bitmap.createBitmap(10, 10, Config.RGBA_F16, true, 1528 extended); 1529 mBitmap.setColorSpace(ColorSpace.get(Named.SRGB)); 1530 assertSame(mBitmap.getColorSpace(), extended); 1531 } 1532 1533 @Test testSetColorSpaceNotReducedRangeLinear()1534 public void testSetColorSpaceNotReducedRangeLinear() { 1535 ColorSpace linearExtended = ColorSpace.get(Named.LINEAR_EXTENDED_SRGB); 1536 mBitmap = Bitmap.createBitmap(10, 10, Config.RGBA_F16, true, 1537 linearExtended); 1538 mBitmap.setColorSpace(ColorSpace.get(Named.LINEAR_SRGB)); 1539 assertSame(mBitmap.getColorSpace(), linearExtended); 1540 } 1541 1542 @Test testSetColorSpaceIncreasedRange()1543 public void testSetColorSpaceIncreasedRange() { 1544 mBitmap = Bitmap.createBitmap(10, 10, Config.RGBA_F16, true, 1545 ColorSpace.get(Named.DISPLAY_P3)); 1546 ColorSpace linearExtended = ColorSpace.get(Named.LINEAR_EXTENDED_SRGB); 1547 mBitmap.setColorSpace(linearExtended); 1548 assertSame(mBitmap.getColorSpace(), linearExtended); 1549 } 1550 1551 @Test testSetConfig()1552 public void testSetConfig() { 1553 mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565); 1554 int alloc = mBitmap.getAllocationByteCount(); 1555 1556 // test shrinking 1557 mBitmap.setConfig(Bitmap.Config.ALPHA_8); 1558 assertEquals(mBitmap.getAllocationByteCount(), alloc); 1559 assertEquals(mBitmap.getByteCount() * 2, alloc); 1560 } 1561 1562 @Test(expected=IllegalArgumentException.class) testSetConfigExpanding()1563 public void testSetConfigExpanding() { 1564 mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565); 1565 // test expanding 1566 mBitmap.setConfig(Bitmap.Config.ARGB_8888); 1567 } 1568 1569 @Test(expected=IllegalStateException.class) testSetConfigMutable()1570 public void testSetConfigMutable() { 1571 // test mutable 1572 mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions); 1573 mBitmap.setConfig(Bitmap.Config.ALPHA_8); 1574 } 1575 1576 @Test testSetHeight()1577 public void testSetHeight() { 1578 mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); 1579 int alloc = mBitmap.getAllocationByteCount(); 1580 1581 // test shrinking 1582 mBitmap.setHeight(100); 1583 assertEquals(mBitmap.getAllocationByteCount(), alloc); 1584 assertEquals(mBitmap.getByteCount() * 2, alloc); 1585 } 1586 1587 @Test(expected=IllegalArgumentException.class) testSetHeightExpanding()1588 public void testSetHeightExpanding() { 1589 // test expanding 1590 mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); 1591 mBitmap.setHeight(201); 1592 } 1593 1594 @Test(expected=IllegalStateException.class) testSetHeightMutable()1595 public void testSetHeightMutable() { 1596 // test mutable 1597 mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions); 1598 mBitmap.setHeight(1); 1599 } 1600 1601 @Test(expected=IllegalStateException.class) testSetPixelOnRecycled()1602 public void testSetPixelOnRecycled() { 1603 int color = 0xff << 24; 1604 1605 mBitmap.recycle(); 1606 mBitmap.setPixel(10, 16, color); 1607 } 1608 1609 @Test(expected=IllegalStateException.class) testSetPixelOnImmutable()1610 public void testSetPixelOnImmutable() { 1611 int color = 0xff << 24; 1612 mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions); 1613 1614 mBitmap.setPixel(10, 16, color); 1615 } 1616 1617 @Test(expected=IllegalArgumentException.class) testSetPixelXIsTooLarge()1618 public void testSetPixelXIsTooLarge() { 1619 int color = 0xff << 24; 1620 mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565); 1621 1622 // abnormal case: x bigger than the source bitmap's width 1623 mBitmap.setPixel(200, 16, color); 1624 } 1625 1626 @Test(expected=IllegalArgumentException.class) testSetPixelYIsTooLarge()1627 public void testSetPixelYIsTooLarge() { 1628 int color = 0xff << 24; 1629 mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565); 1630 1631 // abnormal case: y bigger than the source bitmap's height 1632 mBitmap.setPixel(10, 300, color); 1633 } 1634 1635 @Test testSetPixel()1636 public void testSetPixel() { 1637 int color = 0xff << 24; 1638 mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565); 1639 1640 // normal case 1641 mBitmap.setPixel(10, 16, color); 1642 assertEquals(color, mBitmap.getPixel(10, 16)); 1643 } 1644 1645 @Test(expected=IllegalStateException.class) testSetPixelsOnRecycled()1646 public void testSetPixelsOnRecycled() { 1647 int[] colors = createColors(100); 1648 1649 mBitmap.recycle(); 1650 mBitmap.setPixels(colors, 0, 0, 0, 0, 0, 0); 1651 } 1652 1653 @Test(expected=IllegalStateException.class) testSetPixelsOnImmutable()1654 public void testSetPixelsOnImmutable() { 1655 int[] colors = createColors(100); 1656 mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions); 1657 1658 mBitmap.setPixels(colors, 0, 0, 0, 0, 0, 0); 1659 } 1660 1661 @Test(expected=IllegalArgumentException.class) testSetPixelsXYNegative()1662 public void testSetPixelsXYNegative() { 1663 int[] colors = createColors(100); 1664 mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 1665 1666 // abnormal case: x and/or y less than 0 1667 mBitmap.setPixels(colors, 0, 0, -1, -1, 200, 16); 1668 } 1669 1670 @Test(expected=IllegalArgumentException.class) testSetPixelsWidthHeightNegative()1671 public void testSetPixelsWidthHeightNegative() { 1672 int[] colors = createColors(100); 1673 mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 1674 1675 // abnormal case: width and/or height less than 0 1676 mBitmap.setPixels(colors, 0, 0, 0, 0, -1, -1); 1677 } 1678 1679 @Test(expected=IllegalArgumentException.class) testSetPixelsXTooHigh()1680 public void testSetPixelsXTooHigh() { 1681 int[] colors = createColors(100); 1682 mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 1683 1684 // abnormal case: (x + width) bigger than the source bitmap's width 1685 mBitmap.setPixels(colors, 0, 0, 10, 10, 95, 50); 1686 } 1687 1688 @Test(expected=IllegalArgumentException.class) testSetPixelsYTooHigh()1689 public void testSetPixelsYTooHigh() { 1690 int[] colors = createColors(100); 1691 mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 1692 1693 // abnormal case: (y + height) bigger than the source bitmap's height 1694 mBitmap.setPixels(colors, 0, 0, 10, 10, 50, 95); 1695 } 1696 1697 @Test(expected=IllegalArgumentException.class) testSetPixelsStrideIllegal()1698 public void testSetPixelsStrideIllegal() { 1699 int[] colors = createColors(100); 1700 mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 1701 1702 // abnormal case: stride less than width and bigger than -width 1703 mBitmap.setPixels(colors, 0, 10, 10, 10, 50, 50); 1704 } 1705 1706 @Test(expected=ArrayIndexOutOfBoundsException.class) testSetPixelsOffsetNegative()1707 public void testSetPixelsOffsetNegative() { 1708 int[] colors = createColors(100); 1709 mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 1710 1711 // abnormal case: offset less than 0 1712 mBitmap.setPixels(colors, -1, 50, 10, 10, 50, 50); 1713 } 1714 1715 @Test(expected=ArrayIndexOutOfBoundsException.class) testSetPixelsOffsetTooBig()1716 public void testSetPixelsOffsetTooBig() { 1717 int[] colors = createColors(100); 1718 mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 1719 1720 // abnormal case: (offset + width) bigger than the length of colors 1721 mBitmap.setPixels(colors, 60, 50, 10, 10, 50, 50); 1722 } 1723 1724 @Test(expected=ArrayIndexOutOfBoundsException.class) testSetPixelsLastScanlineNegative()1725 public void testSetPixelsLastScanlineNegative() { 1726 int[] colors = createColors(100); 1727 mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 1728 1729 // abnormal case: lastScanline less than 0 1730 mBitmap.setPixels(colors, 10, -50, 10, 10, 50, 50); 1731 } 1732 1733 @Test(expected=ArrayIndexOutOfBoundsException.class) testSetPixelsLastScanlineTooBig()1734 public void testSetPixelsLastScanlineTooBig() { 1735 int[] colors = createColors(100); 1736 mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 1737 1738 // abnormal case: (lastScanline + width) bigger than the length of colors 1739 mBitmap.setPixels(colors, 10, 50, 10, 10, 50, 50); 1740 } 1741 1742 @Test testSetPixels()1743 public void testSetPixels() { 1744 int[] colors = createColors(100 * 100); 1745 mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 1746 mBitmap.setPixels(colors, 0, 100, 0, 0, 100, 100); 1747 int[] ret = new int[100 * 100]; 1748 mBitmap.getPixels(ret, 0, 100, 0, 0, 100, 100); 1749 1750 for(int i = 0; i < 10000; i++){ 1751 assertEquals(ret[i], colors[i]); 1752 } 1753 } 1754 verifyPremultipliedBitmapConfig(Config config, boolean expectedPremul)1755 private void verifyPremultipliedBitmapConfig(Config config, boolean expectedPremul) { 1756 Bitmap bitmap = Bitmap.createBitmap(1, 1, config); 1757 bitmap.setPremultiplied(true); 1758 bitmap.setPixel(0, 0, Color.TRANSPARENT); 1759 assertTrue(bitmap.isPremultiplied() == expectedPremul); 1760 1761 bitmap.setHasAlpha(false); 1762 assertFalse(bitmap.isPremultiplied()); 1763 } 1764 1765 @Test testSetPremultipliedSimple()1766 public void testSetPremultipliedSimple() { 1767 verifyPremultipliedBitmapConfig(Bitmap.Config.ALPHA_8, true); 1768 verifyPremultipliedBitmapConfig(Bitmap.Config.RGB_565, false); 1769 verifyPremultipliedBitmapConfig(Bitmap.Config.ARGB_4444, true); 1770 verifyPremultipliedBitmapConfig(Bitmap.Config.ARGB_8888, true); 1771 } 1772 1773 @Test testSetPremultipliedData()1774 public void testSetPremultipliedData() { 1775 // with premul, will store 2,2,2,2, so it doesn't get value correct 1776 Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); 1777 bitmap.setPixel(0, 0, PREMUL_COLOR); 1778 assertEquals(bitmap.getPixel(0, 0), PREMUL_ROUNDED_COLOR); 1779 1780 // read premultiplied value directly 1781 bitmap.setPremultiplied(false); 1782 assertEquals(bitmap.getPixel(0, 0), PREMUL_STORED_COLOR); 1783 1784 // value can now be stored/read correctly 1785 bitmap.setPixel(0, 0, PREMUL_COLOR); 1786 assertEquals(bitmap.getPixel(0, 0), PREMUL_COLOR); 1787 1788 // verify with array methods 1789 int testArray[] = new int[] { PREMUL_COLOR }; 1790 bitmap.setPixels(testArray, 0, 1, 0, 0, 1, 1); 1791 bitmap.getPixels(testArray, 0, 1, 0, 0, 1, 1); 1792 assertEquals(bitmap.getPixel(0, 0), PREMUL_COLOR); 1793 } 1794 1795 @Test testPremultipliedCanvas()1796 public void testPremultipliedCanvas() { 1797 Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); 1798 bitmap.setHasAlpha(true); 1799 bitmap.setPremultiplied(false); 1800 assertFalse(bitmap.isPremultiplied()); 1801 1802 Canvas c = new Canvas(); 1803 try { 1804 c.drawBitmap(bitmap, 0, 0, null); 1805 fail("canvas should fail with exception"); 1806 } catch (RuntimeException e) { 1807 } 1808 } 1809 getBitmapRawInt(Bitmap bitmap)1810 private int getBitmapRawInt(Bitmap bitmap) { 1811 IntBuffer buffer = IntBuffer.allocate(1); 1812 bitmap.copyPixelsToBuffer(buffer); 1813 return buffer.get(0); 1814 } 1815 bitmapStoreRawInt(Bitmap bitmap, int value)1816 private void bitmapStoreRawInt(Bitmap bitmap, int value) { 1817 IntBuffer buffer = IntBuffer.allocate(1); 1818 buffer.put(0, value); 1819 bitmap.copyPixelsFromBuffer(buffer); 1820 } 1821 1822 @Test testSetPremultipliedToBuffer()1823 public void testSetPremultipliedToBuffer() { 1824 Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); 1825 bitmap.setPixel(0, 0, PREMUL_COLOR); 1826 int storedPremul = getBitmapRawInt(bitmap); 1827 1828 bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); 1829 bitmap.setPremultiplied(false); 1830 bitmap.setPixel(0, 0, PREMUL_STORED_COLOR); 1831 1832 assertEquals(getBitmapRawInt(bitmap), storedPremul); 1833 } 1834 1835 @Test testSetPremultipliedFromBuffer()1836 public void testSetPremultipliedFromBuffer() { 1837 Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); 1838 bitmap.setPremultiplied(false); 1839 bitmap.setPixel(0, 0, PREMUL_COLOR); 1840 int rawTestColor = getBitmapRawInt(bitmap); 1841 1842 bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); 1843 bitmap.setPremultiplied(false); 1844 bitmapStoreRawInt(bitmap, rawTestColor); 1845 assertEquals(bitmap.getPixel(0, 0), PREMUL_COLOR); 1846 } 1847 1848 @Test testSetWidth()1849 public void testSetWidth() { 1850 mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); 1851 int alloc = mBitmap.getAllocationByteCount(); 1852 1853 // test shrinking 1854 mBitmap.setWidth(50); 1855 assertEquals(mBitmap.getAllocationByteCount(), alloc); 1856 assertEquals(mBitmap.getByteCount() * 2, alloc); 1857 } 1858 1859 @Test(expected=IllegalArgumentException.class) testSetWidthExpanding()1860 public void testSetWidthExpanding() { 1861 // test expanding 1862 mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); 1863 1864 mBitmap.setWidth(101); 1865 } 1866 1867 @Test(expected=IllegalStateException.class) testSetWidthMutable()1868 public void testSetWidthMutable() { 1869 // test mutable 1870 mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions); 1871 1872 mBitmap.setWidth(1); 1873 } 1874 1875 @Test(expected=IllegalStateException.class) testWriteToParcelRecycled()1876 public void testWriteToParcelRecycled() { 1877 mBitmap.recycle(); 1878 1879 mBitmap.writeToParcel(null, 0); 1880 } 1881 1882 @Test testWriteToParcel()1883 public void testWriteToParcel() { 1884 // abnormal case: failed to unparcel Bitmap 1885 mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions); 1886 Parcel p = Parcel.obtain(); 1887 mBitmap.writeToParcel(p, 0); 1888 1889 try { 1890 Bitmap.CREATOR.createFromParcel(p); 1891 fail("shouldn't come to here"); 1892 } catch(RuntimeException e){ 1893 } 1894 1895 p.recycle(); 1896 // normal case 1897 p = Parcel.obtain(); 1898 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 1899 mBitmap.writeToParcel(p, 0); 1900 p.setDataPosition(0); 1901 assertTrue(mBitmap.sameAs(Bitmap.CREATOR.createFromParcel(p))); 1902 1903 p.recycle(); 1904 } 1905 1906 /** 1907 * Although not specified as required behavior, it's something that some apps appear 1908 * to rely upon when sending bitmaps between themselves 1909 */ 1910 @Test 1911 @RequiresFlagsDisabled(Flags.FLAG_BITMAP_PARCEL_ASHMEM_AS_IMMUTABLE) testWriteToParcelPreserveMutability()1912 public void testWriteToParcelPreserveMutability() { 1913 Bitmap source = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 1914 assertTrue(source.isMutable()); 1915 Parcel p = Parcel.obtain(); 1916 source.writeToParcel(p, 0); 1917 p.setDataPosition(0); 1918 Bitmap result = Bitmap.CREATOR.createFromParcel(p); 1919 p.recycle(); 1920 assertTrue(result.isMutable()); 1921 } 1922 1923 /** 1924 * If we copy a bitmap to ashmem and write that to the parcel, then we should parcel as 1925 * immutable, since we won't be mutating the bitmap after writing it to the parcel. 1926 */ 1927 @Test 1928 @RequiresFlagsEnabled(Flags.FLAG_BITMAP_PARCEL_ASHMEM_AS_IMMUTABLE) testWriteToParcelImplicitAshmemCopyIsImmutable()1929 public void testWriteToParcelImplicitAshmemCopyIsImmutable() { 1930 // A sufficiently large Bitmap so that it's implicitly copied to ashmem. 1931 Bitmap chonkySource = Bitmap.createBitmap(1000, 1000, Config.ARGB_8888); 1932 assertTrue(chonkySource.isMutable()); 1933 Parcel p = Parcel.obtain(); 1934 // This will copy the bitmap to ashmem and write that to the parcel. 1935 chonkySource.writeToParcel(p, 0); 1936 p.setDataPosition(0); 1937 Bitmap result = Bitmap.CREATOR.createFromParcel(p); 1938 p.recycle(); 1939 // The parceled Bitmap should be immutable even though the original was mutable. 1940 assertFalse(result.isMutable()); 1941 1942 // A Bitmap small enough to not be copied to ashmem for parceling. 1943 Bitmap smolSource = Bitmap.createBitmap(10, 10, Config.ARGB_8888); 1944 assertTrue(smolSource.isMutable()); 1945 p = Parcel.obtain(); 1946 // This will copy the bitmap to ashmem and write that to the parcel. 1947 smolSource.writeToParcel(p, 0); 1948 p.setDataPosition(0); 1949 result = Bitmap.CREATOR.createFromParcel(p); 1950 p.recycle(); 1951 // The parceled Bitmap should be mutable, same as the source. 1952 assertTrue(result.isMutable()); 1953 } 1954 1955 @Test testWriteToParcelPreserveImmutability()1956 public void testWriteToParcelPreserveImmutability() { 1957 // Kinda silly way to create an immutable bitmap but it works 1958 Bitmap source = Bitmap.createBitmap(100, 100, Config.ARGB_8888) 1959 .copy(Config.ARGB_8888, false); 1960 assertFalse(source.isMutable()); 1961 Parcel p = Parcel.obtain(); 1962 source.writeToParcel(p, 0); 1963 p.setDataPosition(0); 1964 Bitmap result = Bitmap.CREATOR.createFromParcel(p); 1965 p.recycle(); 1966 assertFalse(result.isMutable()); 1967 } 1968 1969 @Test 1970 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testWriteHwBitmapToParcel()1971 public void testWriteHwBitmapToParcel() { 1972 mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS); 1973 Parcel p = Parcel.obtain(); 1974 mBitmap.writeToParcel(p, 0); 1975 p.setDataPosition(0); 1976 Bitmap expectedBitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot); 1977 assertTrue(expectedBitmap.sameAs(Bitmap.CREATOR.createFromParcel(p))); 1978 1979 p.recycle(); 1980 } 1981 1982 @Test testParcelF16ColorSpace()1983 public void testParcelF16ColorSpace() { 1984 for (ColorSpace.Named e : new ColorSpace.Named[] { 1985 ColorSpace.Named.EXTENDED_SRGB, 1986 ColorSpace.Named.LINEAR_EXTENDED_SRGB, 1987 ColorSpace.Named.PRO_PHOTO_RGB, 1988 ColorSpace.Named.DISPLAY_P3 1989 }) { 1990 final ColorSpace cs = ColorSpace.get(e); 1991 Bitmap b = Bitmap.createBitmap(10, 10, Config.RGBA_F16, true, cs); 1992 assertSame(cs, b.getColorSpace()); 1993 1994 Parcel p = Parcel.obtain(); 1995 b.writeToParcel(p, 0); 1996 p.setDataPosition(0); 1997 Bitmap unparceled = Bitmap.CREATOR.createFromParcel(p); 1998 assertSame(cs, unparceled.getColorSpace()); 1999 } 2000 } 2001 2002 @Test testGetScaledHeight1()2003 public void testGetScaledHeight1() { 2004 int dummyDensity = 5; 2005 Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565); 2006 int scaledHeight = scaleFromDensity(ret.getHeight(), ret.getDensity(), dummyDensity); 2007 assertNotNull(ret); 2008 assertEquals(scaledHeight, ret.getScaledHeight(dummyDensity)); 2009 } 2010 2011 @Test testGetScaledHeight2()2012 public void testGetScaledHeight2() { 2013 Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565); 2014 DisplayMetrics metrics = 2015 InstrumentationRegistry.getTargetContext().getResources().getDisplayMetrics(); 2016 int scaledHeight = scaleFromDensity(ret.getHeight(), ret.getDensity(), metrics.densityDpi); 2017 assertEquals(scaledHeight, ret.getScaledHeight(metrics)); 2018 } 2019 2020 @Test testGetScaledHeight3()2021 public void testGetScaledHeight3() { 2022 Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565); 2023 Bitmap mMutableBitmap = Bitmap.createBitmap(100, 200, Config.ARGB_8888); 2024 Canvas mCanvas = new Canvas(mMutableBitmap); 2025 // set Density 2026 mCanvas.setDensity(DisplayMetrics.DENSITY_HIGH); 2027 int scaledHeight = scaleFromDensity( 2028 ret.getHeight(), ret.getDensity(), mCanvas.getDensity()); 2029 assertEquals(scaledHeight, ret.getScaledHeight(mCanvas)); 2030 } 2031 2032 @Test testGetScaledWidth1()2033 public void testGetScaledWidth1() { 2034 int dummyDensity = 5; 2035 Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565); 2036 int scaledWidth = scaleFromDensity(ret.getWidth(), ret.getDensity(), dummyDensity); 2037 assertNotNull(ret); 2038 assertEquals(scaledWidth, ret.getScaledWidth(dummyDensity)); 2039 } 2040 2041 @Test testGetScaledWidth2()2042 public void testGetScaledWidth2() { 2043 Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565); 2044 DisplayMetrics metrics = 2045 InstrumentationRegistry.getTargetContext().getResources().getDisplayMetrics(); 2046 int scaledWidth = scaleFromDensity(ret.getWidth(), ret.getDensity(), metrics.densityDpi); 2047 assertEquals(scaledWidth, ret.getScaledWidth(metrics)); 2048 } 2049 2050 @Test testGetScaledWidth3()2051 public void testGetScaledWidth3() { 2052 Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565); 2053 Bitmap mMutableBitmap = Bitmap.createBitmap(100, 200, Config.ARGB_8888); 2054 Canvas mCanvas = new Canvas(mMutableBitmap); 2055 // set Density 2056 mCanvas.setDensity(DisplayMetrics.DENSITY_HIGH); 2057 int scaledWidth = scaleFromDensity(ret.getWidth(), ret.getDensity(), mCanvas.getDensity()); 2058 assertEquals(scaledWidth, ret.getScaledWidth(mCanvas)); 2059 } 2060 2061 @Test testSameAs_simpleSuccess()2062 public void testSameAs_simpleSuccess() { 2063 Bitmap bitmap1 = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 2064 Bitmap bitmap2 = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 2065 bitmap1.eraseColor(Color.BLACK); 2066 bitmap2.eraseColor(Color.BLACK); 2067 assertTrue(bitmap1.sameAs(bitmap2)); 2068 assertTrue(bitmap2.sameAs(bitmap1)); 2069 } 2070 2071 @Test testSameAs_simpleFail()2072 public void testSameAs_simpleFail() { 2073 Bitmap bitmap1 = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 2074 Bitmap bitmap2 = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 2075 bitmap1.eraseColor(Color.BLACK); 2076 bitmap2.eraseColor(Color.BLACK); 2077 bitmap2.setPixel(20, 10, Color.WHITE); 2078 assertFalse(bitmap1.sameAs(bitmap2)); 2079 assertFalse(bitmap2.sameAs(bitmap1)); 2080 } 2081 2082 @Test testSameAs_reconfigure()2083 public void testSameAs_reconfigure() { 2084 Bitmap bitmap1 = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 2085 Bitmap bitmap2 = Bitmap.createBitmap(150, 150, Config.ARGB_8888); 2086 bitmap2.reconfigure(100, 100, Config.ARGB_8888); // now same size, so should be same 2087 bitmap1.eraseColor(Color.BLACK); 2088 bitmap2.eraseColor(Color.BLACK); 2089 assertTrue(bitmap1.sameAs(bitmap2)); 2090 assertTrue(bitmap2.sameAs(bitmap1)); 2091 } 2092 2093 @Test testSameAs_config()2094 public void testSameAs_config() { 2095 Bitmap bitmap1 = Bitmap.createBitmap(100, 200, Config.RGB_565); 2096 Bitmap bitmap2 = Bitmap.createBitmap(100, 200, Config.ARGB_8888); 2097 2098 // both bitmaps can represent black perfectly 2099 bitmap1.eraseColor(Color.BLACK); 2100 bitmap2.eraseColor(Color.BLACK); 2101 2102 // but not same due to config 2103 assertFalse(bitmap1.sameAs(bitmap2)); 2104 assertFalse(bitmap2.sameAs(bitmap1)); 2105 } 2106 2107 @Test testSameAs_width()2108 public void testSameAs_width() { 2109 Bitmap bitmap1 = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 2110 Bitmap bitmap2 = Bitmap.createBitmap(101, 100, Config.ARGB_8888); 2111 bitmap1.eraseColor(Color.BLACK); 2112 bitmap2.eraseColor(Color.BLACK); 2113 assertFalse(bitmap1.sameAs(bitmap2)); 2114 assertFalse(bitmap2.sameAs(bitmap1)); 2115 } 2116 2117 @Test testSameAs_height()2118 public void testSameAs_height() { 2119 Bitmap bitmap1 = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 2120 Bitmap bitmap2 = Bitmap.createBitmap(102, 100, Config.ARGB_8888); 2121 bitmap1.eraseColor(Color.BLACK); 2122 bitmap2.eraseColor(Color.BLACK); 2123 assertFalse(bitmap1.sameAs(bitmap2)); 2124 assertFalse(bitmap2.sameAs(bitmap1)); 2125 } 2126 2127 @Test testSameAs_opaque()2128 public void testSameAs_opaque() { 2129 Bitmap bitmap1 = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 2130 Bitmap bitmap2 = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 2131 bitmap1.eraseColor(Color.BLACK); 2132 bitmap2.eraseColor(Color.BLACK); 2133 bitmap1.setHasAlpha(true); 2134 bitmap2.setHasAlpha(false); 2135 assertFalse(bitmap1.sameAs(bitmap2)); 2136 assertFalse(bitmap2.sameAs(bitmap1)); 2137 } 2138 2139 @Test 2140 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testSameAs_hardware()2141 public void testSameAs_hardware() { 2142 Bitmap bitmap1 = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS); 2143 Bitmap bitmap2 = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS); 2144 Bitmap bitmap3 = BitmapFactory.decodeResource(mRes, R.drawable.robot); 2145 Bitmap bitmap4 = BitmapFactory.decodeResource(mRes, R.drawable.start, HARDWARE_OPTIONS); 2146 assertTrue(bitmap1.sameAs(bitmap2)); 2147 assertTrue(bitmap2.sameAs(bitmap1)); 2148 assertFalse(bitmap1.sameAs(bitmap3)); 2149 assertFalse(bitmap1.sameAs(bitmap4)); 2150 } 2151 2152 @Test 2153 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testSameAs_wrappedHardwareBuffer()2154 public void testSameAs_wrappedHardwareBuffer() { 2155 try (HardwareBuffer hwBufferA = createTestBuffer(512, 512, true); 2156 HardwareBuffer hwBufferB = createTestBuffer(512, 512, true); 2157 HardwareBuffer hwBufferC = createTestBuffer(512, 512, true);) { 2158 // Fill buffer C with generated data 2159 nFillRgbaHwBuffer(hwBufferC); 2160 2161 // Create the test bitmaps 2162 Bitmap bitmap1 = Bitmap.wrapHardwareBuffer(hwBufferA, ColorSpace.get(Named.SRGB)); 2163 Bitmap bitmap2 = Bitmap.wrapHardwareBuffer(hwBufferA, ColorSpace.get(Named.SRGB)); 2164 Bitmap bitmap3 = BitmapFactory.decodeResource(mRes, R.drawable.robot); 2165 Bitmap bitmap4 = Bitmap.wrapHardwareBuffer(hwBufferB, ColorSpace.get(Named.SRGB)); 2166 Bitmap bitmap5 = Bitmap.wrapHardwareBuffer(hwBufferC, ColorSpace.get(Named.SRGB)); 2167 2168 // Run the compare-a-thon 2169 assertTrue(bitmap1.sameAs(bitmap2)); // SAME UNDERLYING BUFFER 2170 assertTrue(bitmap2.sameAs(bitmap1)); // SAME UNDERLYING BUFFER 2171 assertFalse(bitmap1.sameAs(bitmap3)); // HW vs. NON-HW 2172 assertTrue(bitmap1.sameAs(bitmap4)); // DIFFERENT BUFFERS, SAME CONTENT 2173 assertFalse(bitmap1.sameAs(bitmap5)); // DIFFERENT BUFFERS, DIFFERENT CONTENT 2174 } 2175 } 2176 2177 @Test(expected = IllegalStateException.class) 2178 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testHardwareGetPixel()2179 public void testHardwareGetPixel() { 2180 Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS); 2181 bitmap.getPixel(0, 0); 2182 } 2183 2184 @Test(expected = IllegalStateException.class) 2185 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testHardwareGetPixels()2186 public void testHardwareGetPixels() { 2187 Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS); 2188 bitmap.getPixels(new int[5], 0, 5, 0, 0, 5, 1); 2189 } 2190 2191 @Test testGetConfigOnRecycled()2192 public void testGetConfigOnRecycled() { 2193 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 2194 bitmap.recycle(); 2195 assertEquals(Config.ARGB_8888, bitmap.getConfig()); 2196 } 2197 2198 @Test 2199 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testHardwareGetConfigOnRecycled()2200 public void testHardwareGetConfigOnRecycled() { 2201 Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS); 2202 bitmap.recycle(); 2203 assertEquals(Config.HARDWARE, bitmap.getConfig()); 2204 } 2205 2206 @Test(expected = IllegalStateException.class) 2207 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testHardwareSetWidth()2208 public void testHardwareSetWidth() { 2209 Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS); 2210 bitmap.setWidth(30); 2211 } 2212 2213 @Test(expected = IllegalStateException.class) 2214 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testHardwareSetHeight()2215 public void testHardwareSetHeight() { 2216 Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS); 2217 bitmap.setHeight(30); 2218 } 2219 2220 @Test(expected = IllegalStateException.class) 2221 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testHardwareSetConfig()2222 public void testHardwareSetConfig() { 2223 Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS); 2224 bitmap.setConfig(Config.ARGB_8888); 2225 } 2226 2227 @Test(expected = IllegalStateException.class) 2228 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testHardwareReconfigure()2229 public void testHardwareReconfigure() { 2230 Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS); 2231 bitmap.reconfigure(30, 30, Config.ARGB_8888); 2232 } 2233 2234 @Test(expected = IllegalStateException.class) 2235 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testHardwareSetPixels()2236 public void testHardwareSetPixels() { 2237 Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS); 2238 bitmap.setPixels(new int[10], 0, 1, 0, 0, 1, 1); 2239 } 2240 2241 @Test(expected = IllegalStateException.class) 2242 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testHardwareSetPixel()2243 public void testHardwareSetPixel() { 2244 Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS); 2245 bitmap.setPixel(1, 1, 0); 2246 } 2247 2248 @Test(expected = IllegalStateException.class) 2249 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testHardwareEraseColor()2250 public void testHardwareEraseColor() { 2251 Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS); 2252 bitmap.eraseColor(0); 2253 } 2254 2255 @Test(expected = IllegalStateException.class) 2256 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testHardwareEraseColorLong()2257 public void testHardwareEraseColorLong() { 2258 Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, HARDWARE_OPTIONS); 2259 bitmap.eraseColor(Color.pack(0)); 2260 } 2261 2262 @Test(expected = IllegalStateException.class) 2263 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testHardwareCopyPixelsToBuffer()2264 public void testHardwareCopyPixelsToBuffer() { 2265 Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, HARDWARE_OPTIONS); 2266 ByteBuffer byteBuf = ByteBuffer.allocate(bitmap.getRowBytes() * bitmap.getHeight()); 2267 bitmap.copyPixelsToBuffer(byteBuf); 2268 } 2269 2270 @Test(expected = IllegalStateException.class) 2271 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testHardwareCopyPixelsFromBuffer()2272 public void testHardwareCopyPixelsFromBuffer() { 2273 IntBuffer intBuf1 = IntBuffer.allocate(mBitmap.getRowBytes() * mBitmap.getHeight()); 2274 assertEquals(0, intBuf1.position()); 2275 mBitmap.copyPixelsToBuffer(intBuf1); 2276 Bitmap hwBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, HARDWARE_OPTIONS); 2277 hwBitmap.copyPixelsFromBuffer(intBuf1); 2278 } 2279 2280 @Test testUseMetadataAfterRecycle()2281 public void testUseMetadataAfterRecycle() { 2282 Bitmap bitmap = Bitmap.createBitmap(10, 20, Config.RGB_565); 2283 bitmap.recycle(); 2284 assertEquals(10, bitmap.getWidth()); 2285 assertEquals(20, bitmap.getHeight()); 2286 assertEquals(Config.RGB_565, bitmap.getConfig()); 2287 } 2288 2289 @Test 2290 @DisabledOnRavenwood(blockedBy = StrictMode.class) testCopyHWBitmapInStrictMode()2291 public void testCopyHWBitmapInStrictMode() { 2292 strictModeTest(()->{ 2293 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 2294 Bitmap hwBitmap = bitmap.copy(Config.HARDWARE, false); 2295 hwBitmap.copy(Config.ARGB_8888, false); 2296 }); 2297 } 2298 2299 @Test 2300 @DisabledOnRavenwood(blockedBy = StrictMode.class) testCreateScaledFromHWInStrictMode()2301 public void testCreateScaledFromHWInStrictMode() { 2302 strictModeTest(()->{ 2303 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 2304 Bitmap hwBitmap = bitmap.copy(Config.HARDWARE, false); 2305 Bitmap.createScaledBitmap(hwBitmap, 200, 200, false); 2306 }); 2307 } 2308 2309 @Test 2310 @DisabledOnRavenwood(blockedBy = StrictMode.class) testExtractAlphaFromHWInStrictMode()2311 public void testExtractAlphaFromHWInStrictMode() { 2312 strictModeTest(()->{ 2313 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 2314 Bitmap hwBitmap = bitmap.copy(Config.HARDWARE, false); 2315 hwBitmap.extractAlpha(); 2316 }); 2317 } 2318 2319 @Test 2320 @DisabledOnRavenwood(blockedBy = StrictMode.class) testCompressInStrictMode()2321 public void testCompressInStrictMode() { 2322 strictModeTest(()->{ 2323 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 2324 bitmap.compress(CompressFormat.JPEG, 90, new ByteArrayOutputStream()); 2325 }); 2326 } 2327 2328 @Test 2329 @DisabledOnRavenwood(blockedBy = StrictMode.class) testParcelHWInStrictMode()2330 public void testParcelHWInStrictMode() { 2331 strictModeTest(()->{ 2332 mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 2333 Bitmap hwBitmap = mBitmap.copy(Config.HARDWARE, false); 2334 hwBitmap.writeToParcel(Parcel.obtain(), 0); 2335 }); 2336 } 2337 2338 @Test 2339 @DisabledOnRavenwood(blockedBy = StrictMode.class) testSameAsFirstHWInStrictMode()2340 public void testSameAsFirstHWInStrictMode() { 2341 strictModeTest(()->{ 2342 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 2343 Bitmap hwBitmap = bitmap.copy(Config.HARDWARE, false); 2344 hwBitmap.sameAs(bitmap); 2345 }); 2346 } 2347 2348 @Test 2349 @DisabledOnRavenwood(blockedBy = StrictMode.class) testSameAsSecondHWInStrictMode()2350 public void testSameAsSecondHWInStrictMode() { 2351 strictModeTest(()->{ 2352 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 2353 Bitmap hwBitmap = bitmap.copy(Config.HARDWARE, false); 2354 bitmap.sameAs(hwBitmap); 2355 }); 2356 } 2357 2358 @Test 2359 @DisabledOnRavenwood(reason = "Ravenwood does not support NDK APIs yet") testNdkAccessAfterRecycle()2360 public void testNdkAccessAfterRecycle() { 2361 Bitmap bitmap = Bitmap.createBitmap(10, 20, Config.RGB_565); 2362 Bitmap hardware = bitmap.copy(Config.HARDWARE, false); 2363 nValidateBitmapInfo(bitmap, 10, 20, true); 2364 nValidateBitmapInfo(hardware, 10, 20, true); 2365 2366 bitmap.recycle(); 2367 hardware.recycle(); 2368 2369 nValidateBitmapInfo(bitmap, 10, 20, true); 2370 nValidateBitmapInfo(hardware, 10, 20, true); 2371 nValidateNdkAccessFails(bitmap); 2372 } 2373 2374 @Test bitmapIsMutable()2375 public void bitmapIsMutable() { 2376 Bitmap b = Bitmap.createBitmap(10, 10, Config.ARGB_8888); 2377 assertTrue("CreateBitmap w/ params should be mutable", b.isMutable()); 2378 assertTrue("CreateBitmap from bitmap should be mutable", 2379 Bitmap.createBitmap(b).isMutable()); 2380 } 2381 2382 @Test 2383 @LargeTest 2384 @DisabledOnRavenwood(reason = "Timeout") testHardwareBitmapNotLeaking()2385 public void testHardwareBitmapNotLeaking() { 2386 BitmapFactory.Options opts = new BitmapFactory.Options(); 2387 opts.inPreferredConfig = Config.HARDWARE; 2388 opts.inScaled = false; 2389 2390 runNotLeakingTest(() -> { 2391 Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, opts); 2392 assertNotNull(bitmap); 2393 // Make sure nothing messed with the bitmap 2394 assertEquals(128, bitmap.getWidth()); 2395 assertEquals(128, bitmap.getHeight()); 2396 assertEquals(Config.HARDWARE, bitmap.getConfig()); 2397 bitmap.recycle(); 2398 }); 2399 } 2400 2401 @Test 2402 @LargeTest 2403 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testWrappedHardwareBufferBitmapNotLeaking()2404 public void testWrappedHardwareBufferBitmapNotLeaking() { 2405 final ColorSpace colorSpace = ColorSpace.get(Named.SRGB); 2406 try (HardwareBuffer hwBuffer = createTestBuffer(1024, 512, false)) { 2407 runNotLeakingTest(() -> { 2408 Bitmap bitmap = Bitmap.wrapHardwareBuffer(hwBuffer, colorSpace); 2409 assertNotNull(bitmap); 2410 // Make sure nothing messed with the bitmap 2411 assertEquals(1024, bitmap.getWidth()); 2412 assertEquals(512, bitmap.getHeight()); 2413 assertEquals(Config.HARDWARE, bitmap.getConfig()); 2414 bitmap.recycle(); 2415 }); 2416 } 2417 } 2418 2419 @Test 2420 @LargeTest 2421 @DisabledOnRavenwood(reason = "Timeout") testDrawingHardwareBitmapNotLeaking()2422 public void testDrawingHardwareBitmapNotLeaking() { 2423 BitmapFactory.Options opts = new BitmapFactory.Options(); 2424 opts.inPreferredConfig = Config.HARDWARE; 2425 opts.inScaled = false; 2426 RenderTarget renderTarget = RenderTarget.create(); 2427 renderTarget.setDefaultSize(128, 128); 2428 final Surface surface = renderTarget.getSurface(); 2429 2430 runNotLeakingTest(() -> { 2431 Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, opts); 2432 assertNotNull(bitmap); 2433 // Make sure nothing messed with the bitmap 2434 assertEquals(128, bitmap.getWidth()); 2435 assertEquals(128, bitmap.getHeight()); 2436 assertEquals(Config.HARDWARE, bitmap.getConfig()); 2437 Canvas canvas = surface.lockHardwareCanvas(); 2438 canvas.drawBitmap(bitmap, 0, 0, null); 2439 surface.unlockCanvasAndPost(canvas); 2440 bitmap.recycle(); 2441 }); 2442 2443 surface.release(); 2444 renderTarget.destroy(); 2445 } 2446 2447 @Test 2448 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testWrapHardwareBufferHoldsReference()2449 public void testWrapHardwareBufferHoldsReference() { 2450 Bitmap bitmap; 2451 // Create hardware-buffer and wrap it in a Bitmap 2452 try (HardwareBuffer hwBuffer = createTestBuffer(128, 128, true)) { 2453 // Fill buffer with colors (x, y, 42, 255) 2454 nFillRgbaHwBuffer(hwBuffer); 2455 bitmap = Bitmap.wrapHardwareBuffer(hwBuffer, ColorSpace.get(Named.SRGB)); 2456 } 2457 2458 // Buffer is closed at this point. Ensure bitmap still works by drawing it 2459 assertEquals(128, bitmap.getWidth()); 2460 assertEquals(128, bitmap.getHeight()); 2461 assertEquals(Config.HARDWARE, bitmap.getConfig()); 2462 2463 // Copy bitmap to target bitmap we can read from 2464 Bitmap dstBitmap = bitmap.copy(Config.ARGB_8888, false); 2465 bitmap.recycle(); 2466 2467 // Ensure that the bitmap has valid contents 2468 int pixel = dstBitmap.getPixel(0, 0); 2469 assertEquals(255 << 24 | 42, pixel); 2470 dstBitmap.recycle(); 2471 } 2472 2473 @Test 2474 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testWrapHardwareBufferPreservesColors()2475 public void testWrapHardwareBufferPreservesColors() { 2476 try (HardwareBuffer hwBuffer = createTestBuffer(128, 128, true)) { 2477 // Fill buffer with colors (x, y, 42, 255) 2478 nFillRgbaHwBuffer(hwBuffer); 2479 2480 // Create HW bitmap from this buffer 2481 Bitmap srcBitmap = Bitmap.wrapHardwareBuffer(hwBuffer, ColorSpace.get(Named.SRGB)); 2482 assertNotNull(srcBitmap); 2483 2484 // Copy it to target non-HW bitmap 2485 Bitmap dstBitmap = srcBitmap.copy(Config.ARGB_8888, false); 2486 srcBitmap.recycle(); 2487 2488 // Ensure all colors are as expected (matches the nFillRgbaHwBuffer call used above). 2489 for (int y = 0; y < 128; ++y) { 2490 for (int x = 0; x < 128; ++x) { 2491 int pixel = dstBitmap.getPixel(x, y); 2492 short a = 255; 2493 short r = (short) (x % 255); 2494 short g = (short) (y % 255); 2495 short b = 42; 2496 assertEquals(a << 24 | r << 16 | g << 8 | b, pixel); 2497 } 2498 } 2499 dstBitmap.recycle(); 2500 } 2501 } 2502 compressToPng(Bitmap bitmap)2503 private static byte[] compressToPng(Bitmap bitmap) { 2504 try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) { 2505 assertTrue("Failed to encode a Bitmap with Config " + bitmap.getConfig() 2506 + " and ColorSpace " + bitmap.getColorSpace() + "!", 2507 bitmap.compress(CompressFormat.PNG, 100, stream)); 2508 return stream.toByteArray(); 2509 } catch (IOException e) { 2510 fail("Failed to compress with " + e); 2511 return null; 2512 } 2513 } 2514 parametersForTestAsShared()2515 private static Object[] parametersForTestAsShared() { 2516 return Utils.crossProduct(Config.values(), getRgbColorSpaces().toArray(new Object[0])); 2517 } 2518 2519 @Test 2520 @Parameters(method = "parametersForTestAsShared") 2521 @DisabledOnRavenwood(reason = "Ashmem unsupported") testAsShared(Config config, ColorSpace colorSpace)2522 public void testAsShared(Config config, ColorSpace colorSpace) { 2523 Bitmap original = Bitmap.createBitmap(10, 10, 2524 config == Config.HARDWARE ? Config.ARGB_8888 : config, true /*hasAlpha*/, 2525 colorSpace); 2526 drawGradient(original); 2527 2528 if (config == Config.HARDWARE) { 2529 original = original.copy(Config.HARDWARE, false /*mutable*/); 2530 } 2531 2532 // There's no visible way to test that the memory is allocated in shared memory, but we can 2533 // verify that the Bitmaps look the same. 2534 Bitmap shared = original.asShared(); 2535 assertNotNull(shared); 2536 2537 if (config == Config.HARDWARE) { 2538 int expectedFormat = nGetFormat(original); 2539 assertEquals(expectedFormat, configToFormat(shared.getConfig())); 2540 2541 // There's no public way to look at the pixels in the HARDWARE Bitmap, but if we 2542 // compress each as a lossless PNG, they should look identical. 2543 byte[] origBytes = compressToPng(original); 2544 byte[] sharedBytes = compressToPng(shared); 2545 assertTrue(Arrays.equals(origBytes, sharedBytes)); 2546 } else { 2547 assertSame(original.getConfig(), shared.getConfig()); 2548 assertTrue(shared.sameAs(original)); 2549 } 2550 assertSame(original.getColorSpace(), shared.getColorSpace()); 2551 2552 // The Bitmap is already in shared memory, so no work is done. 2553 Bitmap shared2 = shared.asShared(); 2554 assertSame(shared, shared2); 2555 2556 original.recycle(); 2557 shared.recycle(); 2558 shared2.recycle(); 2559 } 2560 2561 @Test 2562 @DisabledOnRavenwood(reason = "Ashmem unsupported") testAsSharedRecycled()2563 public void testAsSharedRecycled() { 2564 Bitmap bitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888); 2565 bitmap.recycle(); 2566 assertThrows(IllegalStateException.class, bitmap::asShared); 2567 } 2568 2569 @Test 2570 @DisabledOnRavenwood(reason = "Ashmem unsupported") testAsSharedDensity()2571 public void testAsSharedDensity() { 2572 DisplayMetrics metrics = 2573 InstrumentationRegistry.getTargetContext().getResources().getDisplayMetrics(); 2574 Bitmap bitmap = Bitmap.createBitmap(10, 10, Config.ARGB_8888); 2575 for (int density : new int[] { Bitmap.DENSITY_NONE, metrics.densityDpi, 2576 DisplayMetrics.DENSITY_HIGH, DisplayMetrics.DENSITY_DEVICE_STABLE, 2577 DisplayMetrics.DENSITY_MEDIUM }) { 2578 bitmap.setDensity(density); 2579 Bitmap shared = bitmap.asShared(); 2580 assertEquals(density, shared.getDensity()); 2581 shared.recycle(); 2582 } 2583 } 2584 2585 @Test 2586 @Parameters({"true", "false"}) 2587 @DisabledOnRavenwood(reason = "Ashmem unsupported") testAsSharedImageDecoder(boolean mutable)2588 public void testAsSharedImageDecoder(boolean mutable) { 2589 Resources res = InstrumentationRegistry.getTargetContext().getResources(); 2590 ImageDecoder.Source source = ImageDecoder.createSource(res.getAssets(), 2591 "grayscale-16bit-linearSrgb.png"); 2592 try { 2593 Bitmap bitmap = ImageDecoder.decodeBitmap(source, (decoder, info, s) -> { 2594 decoder.setAllocator(ImageDecoder.ALLOCATOR_SHARED_MEMORY); 2595 if (mutable) decoder.setMutableRequired(true); 2596 }); 2597 2598 Bitmap shared = bitmap.asShared(); 2599 if (mutable) { 2600 // bitmap is mutable, so asShared must make a copy. 2601 assertNotEquals(bitmap, shared); 2602 assertTrue(bitmap.sameAs(shared)); 2603 } else { 2604 // bitmap is already immutable and in shared memory, so asShared will return 2605 // itself. 2606 assertSame(bitmap, shared); 2607 } 2608 } catch (IOException e) { 2609 fail("Failed to decode with " + e); 2610 } 2611 } 2612 2613 @Test 2614 @DisabledOnRavenwood(reason = "Ravenwood does not support NDK APIs yet") testNdkFormats()2615 public void testNdkFormats() { 2616 for (ConfigToFormat pair : CONFIG_TO_FORMAT) { 2617 Bitmap bm = Bitmap.createBitmap(10, 10, pair.config); 2618 assertNotNull(bm); 2619 int nativeFormat = nGetFormat(bm); 2620 assertEquals("Config: " + pair.config, pair.format, nativeFormat); 2621 } 2622 } 2623 2624 @Test 2625 @DisabledOnRavenwood(reason = "Ravenwood does not support NDK APIs yet") testNdkFormatsHardware()2626 public void testNdkFormatsHardware() { 2627 for (ConfigToFormat pair : CONFIG_TO_FORMAT) { 2628 Bitmap bm = Bitmap.createBitmap(10, 10, pair.config); 2629 bm = bm.copy(Bitmap.Config.HARDWARE, false); 2630 2631 // ALPHA_8 may not be supported in HARDWARE. 2632 if (bm == null) { 2633 assertEquals(Bitmap.Config.ALPHA_8, pair.config); 2634 continue; 2635 } 2636 2637 int nativeFormat = nGetFormat(bm); 2638 // We allow everything to fall back to 8888 2639 if (nativeFormat != ANDROID_BITMAP_FORMAT_RGBA_8888) { 2640 assertEquals("Config: " + pair.config, pair.format, nativeFormat); 2641 } 2642 } 2643 } 2644 2645 @Test 2646 @DisabledOnRavenwood(reason = "Ravenwood does not support NDK APIs yet") testNullBitmapNdk()2647 public void testNullBitmapNdk() { 2648 Bitmap bitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888); 2649 nTestNullBitmap(bitmap); 2650 } 2651 parametersForTestNdkInfo()2652 private Object[] parametersForTestNdkInfo() { 2653 return new Object[] { 2654 new Object[] { Config.ALPHA_8, ANDROID_BITMAP_FORMAT_A_8 }, 2655 new Object[] { Config.ARGB_8888, ANDROID_BITMAP_FORMAT_RGBA_8888 }, 2656 new Object[] { Config.RGB_565, ANDROID_BITMAP_FORMAT_RGB_565 }, 2657 new Object[] { Config.RGBA_F16, ANDROID_BITMAP_FORMAT_RGBA_F16 }, 2658 new Object[] { Config.RGBA_1010102, ANDROID_BITMAP_FORMAT_RGBA_1010102 }, 2659 }; 2660 } 2661 2662 @Test 2663 @Parameters(method = "parametersForTestNdkInfo") 2664 @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) testNdkInfo(Config config, final int expectedFormat)2665 public void testNdkInfo(Config config, final int expectedFormat) { 2666 // Arbitrary width and height. 2667 final int width = 13; 2668 final int height = 7; 2669 boolean[] trueFalse = new boolean[] { true, false }; 2670 for (boolean hasAlpha : trueFalse) { 2671 for (boolean premultiplied : trueFalse) { 2672 Bitmap bm = Bitmap.createBitmap(width, height, config, hasAlpha); 2673 bm.setPremultiplied(premultiplied); 2674 nTestInfo(bm, expectedFormat, width, height, bm.hasAlpha(), 2675 bm.isPremultiplied(), false); 2676 Bitmap hwBitmap = bm.copy(Bitmap.Config.HARDWARE, false); 2677 assertNotNull(hwBitmap); 2678 // Formats that are not supported by gralloc fall back to 8888. 2679 // Check what the HWB format is and compare against that 2680 int tempExpectedFormat = expectedFormat; 2681 HardwareBuffer buffer = hwBitmap.getHardwareBuffer(); 2682 if (buffer.getFormat() == HardwareBuffer.RGBA_8888) { 2683 tempExpectedFormat = ANDROID_BITMAP_FORMAT_RGBA_8888; 2684 } 2685 nTestInfo(hwBitmap, tempExpectedFormat, width, height, hwBitmap.hasAlpha(), 2686 hwBitmap.isPremultiplied(), true); 2687 hwBitmap.recycle(); 2688 bm.recycle(); 2689 } 2690 } 2691 } 2692 2693 @Test 2694 @DisabledOnRavenwood(reason = "Ravenwood does not support NDK APIs yet") testNdkDataSpaceF16Extended()2695 public void testNdkDataSpaceF16Extended() { 2696 // In RGBA_F16 we force EXTENDED in these cases. 2697 for (ColorSpace colorSpace : new ColorSpace[] { 2698 ColorSpace.get(Named.SRGB), 2699 ColorSpace.get(Named.EXTENDED_SRGB), 2700 }) { 2701 Bitmap bm = Bitmap.createBitmap(10, 10, Config.RGBA_F16, false, colorSpace); 2702 assertNotNull(bm); 2703 2704 assertEquals(ColorSpace.get(Named.EXTENDED_SRGB), bm.getColorSpace()); 2705 assertEquals(DataSpace.ADATASPACE_SCRGB, nGetDataSpace(bm)); 2706 } 2707 2708 for (ColorSpace colorSpace : new ColorSpace[] { 2709 ColorSpace.get(Named.LINEAR_SRGB), 2710 ColorSpace.get(Named.LINEAR_EXTENDED_SRGB), 2711 }) { 2712 Bitmap bm = Bitmap.createBitmap(10, 10, Config.RGBA_F16, false, colorSpace); 2713 assertNotNull(bm); 2714 2715 assertEquals(ColorSpace.get(Named.LINEAR_EXTENDED_SRGB), bm.getColorSpace()); 2716 assertEquals(DataSpace.ADATASPACE_SCRGB_LINEAR, nGetDataSpace(bm)); 2717 } 2718 } 2719 2720 @Test 2721 @DisabledOnRavenwood(reason = "Ravenwood does not support NDK APIs yet") testNdkDataSpaceNonExtended()2722 public void testNdkDataSpaceNonExtended() { 2723 // In 565 and 8888, these force non-extended. 2724 for (ColorSpace colorSpace : new ColorSpace[] { 2725 ColorSpace.get(Named.SRGB), 2726 ColorSpace.get(Named.EXTENDED_SRGB), 2727 }) { 2728 for (Config c: new Config[] { Config.ARGB_8888, Config.RGB_565 }) { 2729 Bitmap bm = Bitmap.createBitmap(10, 10, c, false, colorSpace); 2730 assertNotNull(bm); 2731 2732 assertEquals(ColorSpace.get(Named.SRGB), bm.getColorSpace()); 2733 assertEquals(DataSpace.ADATASPACE_SRGB, nGetDataSpace(bm)); 2734 } 2735 } 2736 2737 for (ColorSpace colorSpace : new ColorSpace[] { 2738 ColorSpace.get(Named.LINEAR_SRGB), 2739 ColorSpace.get(Named.LINEAR_EXTENDED_SRGB), 2740 }) { 2741 for (Config c: new Config[] { Config.ARGB_8888, Config.RGB_565 }) { 2742 Bitmap bm = Bitmap.createBitmap(10, 10, c, false, colorSpace); 2743 assertNotNull(bm); 2744 2745 assertEquals(ColorSpace.get(Named.LINEAR_SRGB), bm.getColorSpace()); 2746 assertEquals(DataSpace.ADATASPACE_SRGB_LINEAR, nGetDataSpace(bm)); 2747 } 2748 } 2749 } 2750 2751 @Test 2752 @DisabledOnRavenwood(reason = "Ravenwood does not support NDK APIs yet") testNdkDataSpace()2753 public void testNdkDataSpace() { 2754 // DataSpace.ADATASPACEs that do not depend on the Config. 2755 for (ColorSpace colorSpace : new ColorSpace[] { 2756 // These have corresponding DataSpace.ADATASPACEs that are independent of the Config 2757 ColorSpace.get(Named.DISPLAY_P3), 2758 ColorSpace.get(Named.BT2020), 2759 ColorSpace.get(Named.ADOBE_RGB), 2760 ColorSpace.get(Named.BT709), 2761 ColorSpace.get(Named.DCI_P3), 2762 2763 // These have no public ADATASPACE. 2764 ColorSpace.get(Named.ACES), 2765 ColorSpace.get(Named.ACESCG), 2766 ColorSpace.get(Named.NTSC_1953), 2767 ColorSpace.get(Named.PRO_PHOTO_RGB), 2768 ColorSpace.get(Named.SMPTE_C), 2769 }) { 2770 for (Config c: new Config[] { Config.ARGB_8888, Config.RGB_565, Config.RGBA_F16 }) { 2771 Bitmap bm = Bitmap.createBitmap(10, 10, c, false, colorSpace); 2772 assertNotNull(bm); 2773 2774 int dataSpace = nGetDataSpace(bm); 2775 assertEquals("Bitmap with " + c + " and " + bm.getColorSpace() 2776 + " has unexpected data space", colorSpace.getDataSpace(), 2777 dataSpace); 2778 } 2779 } 2780 } 2781 2782 @Test 2783 @DisabledOnRavenwood(reason = "Ravenwood does not support NDK APIs yet") testNdkDataSpaceAlpha8()2784 public void testNdkDataSpaceAlpha8() { 2785 // ALPHA_8 doesn't support ColorSpaces 2786 Bitmap bm = Bitmap.createBitmap(10, 10, Config.ALPHA_8); 2787 assertNotNull(bm); 2788 assertNull(bm.getColorSpace()); 2789 int dataSpace = nGetDataSpace(bm); 2790 assertEquals(DataSpace.ADATASPACE_UNKNOWN, dataSpace); 2791 } 2792 2793 @Test 2794 @DisabledOnRavenwood(reason = "Ravenwood does not support NDK APIs yet") testNdkDataSpaceNullBitmap()2795 public void testNdkDataSpaceNullBitmap() { 2796 assertEquals(DataSpace.ADATASPACE_UNKNOWN, nGetDataSpace(null)); 2797 } 2798 nGetDataSpace(Bitmap bm)2799 private static native int nGetDataSpace(Bitmap bm); 2800 2801 // These match the NDK APIs. 2802 private static final int ANDROID_BITMAP_COMPRESS_FORMAT_JPEG = 0; 2803 private static final int ANDROID_BITMAP_COMPRESS_FORMAT_PNG = 1; 2804 private static final int ANDROID_BITMAP_COMPRESS_FORMAT_WEBP_LOSSY = 3; 2805 private static final int ANDROID_BITMAP_COMPRESS_FORMAT_WEBP_LOSSLESS = 4; 2806 nativeCompressFormat(CompressFormat format)2807 private int nativeCompressFormat(CompressFormat format) { 2808 switch (format) { 2809 case JPEG: 2810 return ANDROID_BITMAP_COMPRESS_FORMAT_JPEG; 2811 case PNG: 2812 return ANDROID_BITMAP_COMPRESS_FORMAT_PNG; 2813 case WEBP_LOSSY: 2814 return ANDROID_BITMAP_COMPRESS_FORMAT_WEBP_LOSSY; 2815 case WEBP_LOSSLESS: 2816 return ANDROID_BITMAP_COMPRESS_FORMAT_WEBP_LOSSLESS; 2817 default: 2818 fail("format " + format + " has no corresponding native compress format!"); 2819 return -1; 2820 } 2821 } 2822 parametersForNdkCompress()2823 private static Object[] parametersForNdkCompress() { 2824 // Skip WEBP, which has no corresponding native compress format. 2825 Object[] formats = new Object[] { 2826 CompressFormat.JPEG, 2827 CompressFormat.PNG, 2828 CompressFormat.WEBP_LOSSY, 2829 CompressFormat.WEBP_LOSSLESS, 2830 }; 2831 // These are the ColorSpaces with corresponding ADataSpaces 2832 Object[] colorSpaces = new Object[] { 2833 ColorSpace.get(Named.SRGB), 2834 ColorSpace.get(Named.EXTENDED_SRGB), 2835 ColorSpace.get(Named.LINEAR_SRGB), 2836 ColorSpace.get(Named.LINEAR_EXTENDED_SRGB), 2837 2838 ColorSpace.get(Named.DISPLAY_P3), 2839 ColorSpace.get(Named.DCI_P3), 2840 ColorSpace.get(Named.BT2020), 2841 ColorSpace.get(Named.BT709), 2842 ColorSpace.get(Named.ADOBE_RGB), 2843 }; 2844 2845 Object[] configs = new Object[] { 2846 Config.ARGB_8888, 2847 Config.RGB_565, 2848 Config.RGBA_F16, 2849 }; 2850 2851 return crossProduct(formats, colorSpaces, configs); 2852 } 2853 crossProduct(Object[] a, Object[] b, Object[] c)2854 private static Object[] crossProduct(Object[] a, Object[] b, Object[] c) { 2855 final int length = a.length * b.length * c.length; 2856 Object[] ret = new Object[length]; 2857 for (int i = 0; i < a.length; i++) { 2858 for (int j = 0; j < b.length; j++) { 2859 for (int k = 0; k < c.length; k++) { 2860 int index = i * (b.length * c.length) + j * c.length + k; 2861 assertNull(ret[index]); 2862 ret[index] = new Object[] { a[i], b[j], c[k] }; 2863 } 2864 } 2865 } 2866 return ret; 2867 } 2868 isSrgb(ColorSpace cs)2869 private static boolean isSrgb(ColorSpace cs) { 2870 return cs == ColorSpace.get(Named.SRGB) 2871 || cs == ColorSpace.get(Named.EXTENDED_SRGB) 2872 || cs == ColorSpace.get(Named.LINEAR_SRGB) 2873 || cs == ColorSpace.get(Named.LINEAR_EXTENDED_SRGB); 2874 } 2875 2876 // Helper method for populating a Bitmap with interesting pixels for comparison. drawGradient(Bitmap bitmap)2877 private static void drawGradient(Bitmap bitmap) { 2878 // Use different colors and alphas. 2879 Canvas canvas = new Canvas(bitmap); 2880 ColorSpace cs = bitmap.getColorSpace(); 2881 if (cs == null) { 2882 assertSame(Config.ALPHA_8, bitmap.getConfig()); 2883 cs = ColorSpace.get(ColorSpace.Named.SRGB); 2884 } 2885 long color0 = Color.pack(0, 0, 1, 1, cs); 2886 long color1 = Color.pack(1, 0, 0, 0, cs); 2887 LinearGradient gradient = new LinearGradient(0, 0, 10, 10, color0, color1, 2888 Shader.TileMode.CLAMP); 2889 Paint paint = new Paint(); 2890 paint.setShader(gradient); 2891 canvas.drawPaint(paint); 2892 } 2893 2894 @Test 2895 @Parameters(method = "parametersForNdkCompress") 2896 @DisabledOnRavenwood(reason = "Ravenwood does not support NDK APIs yet") testNdkCompress(CompressFormat format, ColorSpace cs, Config config)2897 public void testNdkCompress(CompressFormat format, ColorSpace cs, Config config) 2898 throws IOException { 2899 // Verify that ndk compress behaves the same as Bitmap#compress 2900 Bitmap bitmap = Bitmap.createBitmap(10, 10, config, true /* hasAlpha */, cs); 2901 assertNotNull(bitmap); 2902 2903 { 2904 drawGradient(bitmap); 2905 } 2906 2907 byte[] storage = new byte[16 * 1024]; 2908 for (int quality : new int[] { 50, 80, 100 }) { 2909 byte[] expected = null; 2910 try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) { 2911 assertTrue("Failed to encode a Bitmap with " + cs + " to " + format + " at quality " 2912 + quality + " from Java API", bitmap.compress(format, quality, stream)); 2913 expected = stream.toByteArray(); 2914 } 2915 2916 try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) { 2917 boolean success = nCompress(bitmap, nativeCompressFormat(format), 2918 quality, stream, storage); 2919 assertTrue("Failed to encode pixels with " + cs + " to " + format + " at quality " 2920 + quality + " from NDK API", success); 2921 byte[] actual = stream.toByteArray(); 2922 2923 if (isSrgb(cs)) { 2924 if (!Arrays.equals(expected, actual)) { 2925 fail("NDK compression did not match for " + cs + " and format " + format 2926 + " at quality " + quality); 2927 } 2928 } else { 2929 // The byte arrays will match exactly for SRGB and its variants, because those 2930 // are treated specially. For the others, there are some small differences 2931 // between Skia's and ColorSpace's values that result in the ICC profiles being 2932 // written slightly differently. They should still look the same, though. 2933 Bitmap expectedBitmap = decodeBytes(expected); 2934 Bitmap actualBitmap = decodeBytes(actual); 2935 boolean matched = BitmapUtils.compareBitmapsMse(expectedBitmap, actualBitmap, 2936 5, true, false); 2937 expectedBitmap.recycle(); 2938 actualBitmap.recycle(); 2939 assertTrue("NDK compression did not match for " + cs + " and format " + format 2940 + " at quality " + quality, matched); 2941 } 2942 } 2943 } 2944 } 2945 2946 @Test 2947 @DisabledOnRavenwood(reason = "Ravenwood does not support NDK APIs yet") testNdkCompressBadParameter()2948 public void testNdkCompressBadParameter() throws IOException { 2949 try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) { 2950 nTestNdkCompressBadParameter(mBitmap, stream, new byte[16 * 1024]); 2951 } 2952 } 2953 nCompress(Bitmap bitmap, int format, int quality, OutputStream stream, byte[] storage)2954 private static native boolean nCompress(Bitmap bitmap, int format, int quality, 2955 OutputStream stream, byte[] storage); nTestNdkCompressBadParameter(Bitmap bitmap, OutputStream stream, byte[] storage)2956 private static native void nTestNdkCompressBadParameter(Bitmap bitmap, 2957 OutputStream stream, byte[] storage); 2958 strictModeTest(Runnable runnable)2959 private void strictModeTest(Runnable runnable) { 2960 StrictMode.ThreadPolicy originalPolicy = StrictMode.getThreadPolicy(); 2961 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() 2962 .detectCustomSlowCalls().penaltyDeath().build()); 2963 try { 2964 runnable.run(); 2965 fail("Shouldn't reach it"); 2966 } catch (RuntimeException expected){ 2967 // expect to receive StrictModeViolation 2968 } finally { 2969 StrictMode.setThreadPolicy(originalPolicy); 2970 } 2971 } 2972 nValidateBitmapInfo(Bitmap bitmap, int width, int height, boolean is565)2973 private static native void nValidateBitmapInfo(Bitmap bitmap, int width, int height, 2974 boolean is565); nValidateNdkAccessFails(Bitmap bitmap)2975 private static native void nValidateNdkAccessFails(Bitmap bitmap); 2976 nFillRgbaHwBuffer(HardwareBuffer hwBuffer)2977 private static native void nFillRgbaHwBuffer(HardwareBuffer hwBuffer); nTestNullBitmap(Bitmap bitmap)2978 private static native void nTestNullBitmap(Bitmap bitmap); 2979 2980 private static final int ANDROID_BITMAP_FORMAT_NONE = 0; 2981 static final int ANDROID_BITMAP_FORMAT_RGBA_8888 = 1; 2982 private static final int ANDROID_BITMAP_FORMAT_RGB_565 = 4; 2983 private static final int ANDROID_BITMAP_FORMAT_A_8 = 8; 2984 private static final int ANDROID_BITMAP_FORMAT_RGBA_F16 = 9; 2985 private static final int ANDROID_BITMAP_FORMAT_RGBA_1010102 = 10; 2986 2987 private static class ConfigToFormat { 2988 public final Config config; 2989 public final int format; 2990 ConfigToFormat(Config c, int f)2991 ConfigToFormat(Config c, int f) { 2992 this.config = c; 2993 this.format = f; 2994 } 2995 } 2996 configToFormat(Config config)2997 private static int configToFormat(Config config) { 2998 for (ConfigToFormat pair : CONFIG_TO_FORMAT) { 2999 if (config == pair.config) { 3000 return pair.format; 3001 } 3002 } 3003 return ANDROID_BITMAP_FORMAT_NONE; 3004 } 3005 3006 private static final ConfigToFormat[] CONFIG_TO_FORMAT = new ConfigToFormat[] { 3007 new ConfigToFormat(Bitmap.Config.ARGB_8888, ANDROID_BITMAP_FORMAT_RGBA_8888), 3008 // ARGB_4444 is deprecated, and createBitmap converts to 8888. 3009 new ConfigToFormat(Bitmap.Config.ARGB_4444, ANDROID_BITMAP_FORMAT_RGBA_8888), 3010 new ConfigToFormat(Bitmap.Config.RGB_565, ANDROID_BITMAP_FORMAT_RGB_565), 3011 new ConfigToFormat(Bitmap.Config.ALPHA_8, ANDROID_BITMAP_FORMAT_A_8), 3012 new ConfigToFormat(Bitmap.Config.RGBA_F16, ANDROID_BITMAP_FORMAT_RGBA_F16), 3013 new ConfigToFormat(Bitmap.Config.RGBA_1010102, ANDROID_BITMAP_FORMAT_RGBA_1010102), 3014 }; 3015 nGetFormat(Bitmap bitmap)3016 static native int nGetFormat(Bitmap bitmap); 3017 nTestInfo(Bitmap bm, int androidBitmapFormat, int width, int height, boolean hasAlpha, boolean premultiplied, boolean hardware)3018 private static native void nTestInfo(Bitmap bm, int androidBitmapFormat, int width, int height, 3019 boolean hasAlpha, boolean premultiplied, boolean hardware); 3020 createTestBuffer(int width, int height, boolean cpuAccess)3021 private static HardwareBuffer createTestBuffer(int width, int height, boolean cpuAccess) { 3022 long usage = HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE; 3023 if (cpuAccess) { 3024 usage |= HardwareBuffer.USAGE_CPU_WRITE_RARELY; 3025 } 3026 // We can assume that RGBA_8888 format is supported for every platform. 3027 HardwareBuffer hwBuffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888, 3028 1, usage); 3029 return hwBuffer; 3030 } 3031 scaleFromDensity(int size, int sdensity, int tdensity)3032 private static int scaleFromDensity(int size, int sdensity, int tdensity) { 3033 if (sdensity == Bitmap.DENSITY_NONE || sdensity == tdensity) { 3034 return size; 3035 } 3036 3037 // Scale by tdensity / sdensity, rounding up. 3038 return ((size * tdensity) + (sdensity >> 1)) / sdensity; 3039 } 3040 createColors(int size)3041 private static int[] createColors(int size) { 3042 int[] colors = new int[size]; 3043 3044 for (int i = 0; i < size; i++) { 3045 colors[i] = (0xFF << 24) | (i << 16) | (i << 8) | i; 3046 } 3047 3048 return colors; 3049 } 3050 createHardwareBitmapOptions()3051 private static BitmapFactory.Options createHardwareBitmapOptions() { 3052 BitmapFactory.Options options = new BitmapFactory.Options(); 3053 options.inPreferredConfig = Config.HARDWARE; 3054 return options; 3055 } 3056 3057 @Test testCopyAlpha8ToHardware()3058 public void testCopyAlpha8ToHardware() { 3059 Bitmap bm = Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8); 3060 assertNotNull(bm); 3061 Bitmap hwBitmap = bm.copy(Bitmap.Config.HARDWARE, false /* mutable */); 3062 // Some devices may not support ALPHA_8 + HARDWARE 3063 if (hwBitmap != null) { 3064 assertNull(hwBitmap.getColorSpace()); 3065 } 3066 3067 bm.recycle(); 3068 } 3069 } 3070