1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.graphics.drawable; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import android.graphics.Bitmap; 22 import android.graphics.Canvas; 23 import android.graphics.RecordingCanvas; 24 import android.graphics.Region; 25 import android.os.Handler; 26 import android.os.HandlerThread; 27 import android.os.Parcel; 28 import android.test.AndroidTestCase; 29 import android.util.Log; 30 31 import androidx.test.filters.SmallTest; 32 33 import com.android.frameworks.coretests.R; 34 35 import java.io.ByteArrayOutputStream; 36 import java.io.File; 37 import java.io.FileOutputStream; 38 import java.util.ArrayList; 39 import java.util.Arrays; 40 41 public class IconTest extends AndroidTestCase { 42 public static final String TAG = IconTest.class.getSimpleName(); L(String s, Object... parts)43 public static void L(String s, Object... parts) { 44 Log.d(TAG, (parts.length == 0) ? s : String.format(s, parts)); 45 } 46 47 @SmallTest testWithBitmap()48 public void testWithBitmap() throws Exception { 49 final Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); 50 final Bitmap bm2 = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565); 51 final Bitmap bm3 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape)) 52 .getBitmap(); 53 54 final Canvas can1 = new Canvas(bm1); 55 can1.drawColor(0xFFFF0000); 56 final Canvas can2 = new Canvas(bm2); 57 can2.drawColor(0xFF00FF00); 58 59 final Icon im1 = Icon.createWithBitmap(bm1); 60 final Icon im2 = Icon.createWithBitmap(bm2); 61 final Icon im3 = Icon.createWithBitmap(bm3); 62 63 final Drawable draw1 = im1.loadDrawable(mContext); 64 final Drawable draw2 = im2.loadDrawable(mContext); 65 final Drawable draw3 = im3.loadDrawable(mContext); 66 67 final Bitmap test1 = Bitmap.createBitmap(draw1.getIntrinsicWidth(), 68 draw1.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 69 final Bitmap test2 = Bitmap.createBitmap(draw2.getIntrinsicWidth(), 70 draw2.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 71 final Bitmap test3 = Bitmap.createBitmap(draw3.getIntrinsicWidth(), 72 draw3.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 73 74 draw1.setBounds(0, 0, draw1.getIntrinsicWidth(), draw1.getIntrinsicHeight()); 75 draw1.draw(new Canvas(test1)); 76 77 draw2.setBounds(0, 0, draw2.getIntrinsicWidth(), draw2.getIntrinsicHeight()); 78 draw2.draw(new Canvas(test2)); 79 80 draw3.setBounds(0, 0, draw3.getIntrinsicWidth(), draw3.getIntrinsicHeight()); 81 draw3.draw(new Canvas(test3)); 82 83 final File dir = getContext().getExternalFilesDir(null); 84 L("writing temp bitmaps to %s...", dir); 85 86 bm1.compress(Bitmap.CompressFormat.PNG, 100, 87 new FileOutputStream(new File(dir, "bitmap1-original.png"))); 88 test1.compress(Bitmap.CompressFormat.PNG, 100, 89 new FileOutputStream(new File(dir, "bitmap1-test.png"))); 90 if (!equalBitmaps(bm1, test1)) { 91 findBitmapDifferences(bm1, test1); 92 fail("bitmap1 differs, check " + dir); 93 } 94 95 bm2.compress(Bitmap.CompressFormat.PNG, 100, 96 new FileOutputStream(new File(dir, "bitmap2-original.png"))); 97 test2.compress(Bitmap.CompressFormat.PNG, 100, 98 new FileOutputStream(new File(dir, "bitmap2-test.png"))); 99 if (!equalBitmaps(bm2, test2)) { 100 findBitmapDifferences(bm2, test2); 101 fail("bitmap2 differs, check " + dir); 102 } 103 104 bm3.compress(Bitmap.CompressFormat.PNG, 100, 105 new FileOutputStream(new File(dir, "bitmap3-original.png"))); 106 test3.compress(Bitmap.CompressFormat.PNG, 100, 107 new FileOutputStream(new File(dir, "bitmap3-test.png"))); 108 if (!equalBitmaps(bm3, test3)) { 109 findBitmapDifferences(bm3, test3); 110 fail("bitmap3 differs, check " + dir); 111 } 112 } 113 114 @SmallTest testScaleDownIfNecessary()115 public void testScaleDownIfNecessary() throws Exception { 116 final Bitmap bm = Bitmap.createBitmap(4321, 78, Bitmap.Config.ARGB_8888); 117 final Icon ic = Icon.createWithBitmap(bm); 118 ic.scaleDownIfNecessary(40, 20); 119 120 assertThat(bm.getWidth()).isEqualTo(4321); 121 assertThat(bm.getHeight()).isEqualTo(78); 122 123 assertThat(ic.getBitmap().getWidth()).isLessThan(41); 124 assertThat(ic.getBitmap().getHeight()).isLessThan(21); 125 } 126 127 @SmallTest testWithAdaptiveBitmap()128 public void testWithAdaptiveBitmap() throws Exception { 129 final Bitmap bm1 = Bitmap.createBitmap(150, 150, Bitmap.Config.ARGB_8888); 130 131 final Canvas can1 = new Canvas(bm1); 132 can1.drawColor(0xFFFF0000); 133 134 final Icon im1 = Icon.createWithAdaptiveBitmap(bm1); 135 136 final AdaptiveIconDrawable draw1 = (AdaptiveIconDrawable) im1.loadDrawable(mContext); 137 138 final Bitmap test1 = Bitmap.createBitmap( 139 (int)(draw1.getIntrinsicWidth() * (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction())), 140 (int)(draw1.getIntrinsicHeight() * (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction())), 141 Bitmap.Config.ARGB_8888); 142 143 draw1.setBounds(0, 0, 144 (int) (draw1.getIntrinsicWidth() * (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction())), 145 (int) (draw1.getIntrinsicHeight() * (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction()))); 146 draw1.draw(new Canvas(test1)); 147 148 final File dir = getContext().getExternalFilesDir(null); 149 L("writing temp bitmaps to %s...", dir); 150 151 bm1.compress(Bitmap.CompressFormat.PNG, 100, 152 new FileOutputStream(new File(dir, "adaptive-bitmap1-original.png"))); 153 test1.compress(Bitmap.CompressFormat.PNG, 100, 154 new FileOutputStream(new File(dir, "adaptive-bitmap1-test.png"))); 155 if (!equalBitmaps(bm1, test1, draw1.getSafeZone())) { 156 findBitmapDifferences(bm1, test1); 157 fail("adaptive bitmap1 differs, check " + dir); 158 } 159 } 160 161 @SmallTest testWithBitmapResource()162 public void testWithBitmapResource() throws Exception { 163 final Bitmap res1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape)) 164 .getBitmap(); 165 166 final Icon im1 = Icon.createWithResource(getContext(), R.drawable.landscape); 167 final Drawable draw1 = im1.loadDrawable(mContext); 168 final Bitmap test1 = Bitmap.createBitmap(draw1.getIntrinsicWidth(), 169 draw1.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 170 draw1.setBounds(0, 0, test1.getWidth(), test1.getHeight()); 171 draw1.draw(new Canvas(test1)); 172 173 final File dir = getContext().getExternalFilesDir(null); 174 res1.compress(Bitmap.CompressFormat.PNG, 100, 175 new FileOutputStream(new File(dir, "res1-original.png"))); 176 test1.compress(Bitmap.CompressFormat.PNG, 100, 177 new FileOutputStream(new File(dir, "res1-test.png"))); 178 if (!equalBitmaps(res1, test1)) { 179 findBitmapDifferences(res1, test1); 180 fail("res1 differs, check " + dir); 181 } 182 } 183 184 /** 185 * Icon resource test that ensures we can load and draw non-bitmaps. (In this case, 186 * stat_sys_adb is assumed, and asserted, to be a vector drawable.) 187 */ 188 @SmallTest testWithStatSysAdbResource()189 public void testWithStatSysAdbResource() throws Exception { 190 // establish reference bitmap 191 final float dp = getContext().getResources().getDisplayMetrics().density; 192 final int stat_sys_adb_width = (int) (24 * dp); 193 final int stat_sys_adb_height = (int) (24 * dp); 194 195 final Drawable stat_sys_adb = getContext() 196 .getDrawable(com.android.internal.R.drawable.stat_sys_adb); 197 if (!(stat_sys_adb instanceof VectorDrawable)) { 198 fail("stat_sys_adb is a " + stat_sys_adb.toString() 199 + ", not a VectorDrawable; stat_sys_adb malformed"); 200 } 201 202 if (stat_sys_adb.getIntrinsicWidth() != stat_sys_adb_width) { 203 fail("intrinsic width of stat_sys_adb is not 24dp; stat_sys_adb malformed"); 204 } 205 if (stat_sys_adb.getIntrinsicHeight() != stat_sys_adb_height) { 206 fail("intrinsic height of stat_sys_adb is not 24dp; stat_sys_adb malformed"); 207 } 208 final Bitmap referenceBitmap = Bitmap.createBitmap( 209 stat_sys_adb_width, 210 stat_sys_adb_height, 211 Bitmap.Config.ARGB_8888); 212 stat_sys_adb.setBounds(0, 0, stat_sys_adb_width, stat_sys_adb_height); 213 stat_sys_adb.draw(new Canvas(referenceBitmap)); 214 215 final Icon im1 = Icon.createWithResource(getContext(), 216 com.android.internal.R.drawable.stat_sys_adb); 217 final Drawable draw1 = im1.loadDrawable(getContext()); 218 219 assertEquals(stat_sys_adb.getIntrinsicWidth(), draw1.getIntrinsicWidth()); 220 assertEquals(stat_sys_adb.getIntrinsicHeight(), draw1.getIntrinsicHeight()); 221 assertEquals(im1.getResId(), com.android.internal.R.drawable.stat_sys_adb); 222 223 final Bitmap test1 = Bitmap.createBitmap( 224 draw1.getIntrinsicWidth(), 225 draw1.getIntrinsicHeight(), 226 Bitmap.Config.ARGB_8888); 227 draw1.setBounds(0, 0, test1.getWidth(), test1.getHeight()); 228 draw1.draw(new Canvas(test1)); 229 230 final File dir = getContext().getExternalFilesDir(null); 231 test1.compress(Bitmap.CompressFormat.PNG, 100, 232 new FileOutputStream(new File(dir, "testWithVectorDrawableResource-test.png"))); 233 if (!equalBitmaps(referenceBitmap, test1)) { 234 findBitmapDifferences(referenceBitmap, test1); 235 fail("testWithFile: file1 differs, check " + dir); 236 } 237 } 238 239 @SmallTest testWithFile()240 public void testWithFile() throws Exception { 241 final Bitmap bit1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape)) 242 .getBitmap(); 243 final File dir = getContext().getExternalFilesDir(null); 244 final File file1 = new File(dir, "file1-original.png"); 245 bit1.compress(Bitmap.CompressFormat.PNG, 100, 246 new FileOutputStream(file1)); 247 248 final Icon im1 = Icon.createWithFilePath(file1.toString()); 249 final Drawable draw1 = im1.loadDrawable(mContext); 250 final Bitmap test1 = Bitmap.createBitmap(draw1.getIntrinsicWidth(), 251 draw1.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 252 draw1.setBounds(0, 0, test1.getWidth(), test1.getHeight()); 253 draw1.draw(new Canvas(test1)); 254 255 test1.compress(Bitmap.CompressFormat.PNG, 100, 256 new FileOutputStream(new File(dir, "file1-test.png"))); 257 if (!equalBitmaps(bit1, test1)) { 258 findBitmapDifferences(bit1, test1); 259 fail("testWithFile: file1 differs, check " + dir); 260 } 261 } 262 263 @SmallTest testAsync()264 public void testAsync() throws Exception { 265 final Bitmap bit1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape)) 266 .getBitmap(); 267 final File dir = getContext().getExternalFilesDir(null); 268 final File file1 = new File(dir, "async-original.png"); 269 bit1.compress(Bitmap.CompressFormat.PNG, 100, 270 new FileOutputStream(file1)); 271 272 final Icon im1 = Icon.createWithFilePath(file1.toString()); 273 final HandlerThread thd = new HandlerThread("testAsync"); 274 thd.start(); 275 final Handler h = new Handler(thd.getLooper()); 276 L(TAG, "asyncTest: dispatching load to thread: " + thd); 277 im1.loadDrawableAsync(mContext, new Icon.OnDrawableLoadedListener() { 278 @Override 279 public void onDrawableLoaded(Drawable draw1) { 280 L(TAG, "asyncTest: thread: loading drawable"); 281 L(TAG, "asyncTest: thread: loaded: %dx%d", draw1.getIntrinsicWidth(), 282 draw1.getIntrinsicHeight()); 283 final Bitmap test1 = Bitmap.createBitmap(draw1.getIntrinsicWidth(), 284 draw1.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 285 draw1.setBounds(0, 0, test1.getWidth(), test1.getHeight()); 286 draw1.draw(new Canvas(test1)); 287 288 try { 289 test1.compress(Bitmap.CompressFormat.PNG, 100, 290 new FileOutputStream(new File(dir, "async-test.png"))); 291 } catch (java.io.FileNotFoundException ex) { 292 fail("couldn't create test file: " + ex); 293 } 294 if (!equalBitmaps(bit1, test1)) { 295 findBitmapDifferences(bit1, test1); 296 fail("testAsync: file1 differs, check " + dir); 297 } 298 } 299 }, h); 300 L(TAG, "asyncTest: awaiting result"); 301 Thread.sleep(500); // ;_; 302 assertTrue("async-test.png does not exist!", new File(dir, "async-test.png").exists()); 303 L(TAG, "asyncTest: done"); 304 } 305 306 @SmallTest testParcel()307 public void testParcel() throws Exception { 308 final Bitmap originalbits = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape)) 309 .getBitmap(); 310 311 final ByteArrayOutputStream ostream = new ByteArrayOutputStream( 312 originalbits.getWidth() * originalbits.getHeight() * 2); // guess 50% compression 313 originalbits.compress(Bitmap.CompressFormat.PNG, 100, ostream); 314 final byte[] pngdata = ostream.toByteArray(); 315 316 L("starting testParcel; bitmap: %d bytes, PNG: %d bytes", 317 originalbits.getByteCount(), 318 pngdata.length); 319 320 final File dir = getContext().getExternalFilesDir(null); 321 final File originalfile = new File(dir, "parcel-original.png"); 322 new FileOutputStream(originalfile).write(pngdata); 323 324 ArrayList<Icon> imgs = new ArrayList<>(); 325 final Icon file1 = Icon.createWithFilePath(originalfile.getAbsolutePath()); 326 imgs.add(file1); 327 final Icon bit1 = Icon.createWithBitmap(originalbits); 328 imgs.add(bit1); 329 final Icon data1 = Icon.createWithData(pngdata, 0, pngdata.length); 330 imgs.add(data1); 331 final Icon res1 = Icon.createWithResource(getContext(), R.drawable.landscape); 332 imgs.add(res1); 333 334 ArrayList<Icon> test = new ArrayList<>(); 335 final Parcel parcel = Parcel.obtain(); 336 int pos = 0; 337 parcel.writeInt(imgs.size()); 338 for (Icon img : imgs) { 339 img.writeToParcel(parcel, 0); 340 L("used %d bytes parceling: %s", parcel.dataPosition() - pos, img); 341 pos = parcel.dataPosition(); 342 } 343 344 parcel.setDataPosition(0); // rewind 345 final int N = parcel.readInt(); 346 for (int i=0; i<N; i++) { 347 Icon img = Icon.CREATOR.createFromParcel(parcel); 348 L("test %d: read from parcel: %s", i, img); 349 final File testfile = new File(dir, 350 String.format("parcel-test%02d.png", i)); 351 352 final Drawable draw1 = img.loadDrawable(mContext); 353 if (draw1 == null) { 354 fail("null drawable from img: " + img); 355 } 356 final Bitmap test1 = Bitmap.createBitmap(draw1.getIntrinsicWidth(), 357 draw1.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 358 draw1.setBounds(0, 0, test1.getWidth(), test1.getHeight()); 359 draw1.draw(new Canvas(test1)); 360 361 try { 362 test1.compress(Bitmap.CompressFormat.PNG, 100, 363 new FileOutputStream(testfile)); 364 } catch (java.io.FileNotFoundException ex) { 365 fail("couldn't create test file " + testfile + ": " + ex); 366 } 367 if (!equalBitmaps(originalbits, test1)) { 368 findBitmapDifferences(originalbits, test1); 369 fail(testfile + " differs from original: " + originalfile); 370 } 371 372 } 373 } 374 getMaxWidth(int origWidth, int origHeight, int maxNumPixels)375 private int getMaxWidth(int origWidth, int origHeight, int maxNumPixels) { 376 float aspRatio = (float) origWidth / (float) origHeight; 377 int newHeight = (int) Math.sqrt(maxNumPixels / aspRatio); 378 return (int) (newHeight * aspRatio); 379 } 380 getMaxHeight(int origWidth, int origHeight, int maxNumPixels)381 private int getMaxHeight(int origWidth, int origHeight, int maxNumPixels) { 382 float aspRatio = (float) origWidth / (float) origHeight; 383 return (int) Math.sqrt(maxNumPixels / aspRatio); 384 } 385 386 @SmallTest testScaleDownMaxSizeWithBitmap()387 public void testScaleDownMaxSizeWithBitmap() throws Exception { 388 final int bmpWidth = 13_000; 389 final int bmpHeight = 10_000; 390 final int bmpBpp = 4; 391 final int maxNumPixels = RecordingCanvas.MAX_BITMAP_SIZE / bmpBpp; 392 final int maxWidth = getMaxWidth(bmpWidth, bmpHeight, maxNumPixels); 393 final int maxHeight = getMaxHeight(bmpWidth, bmpHeight, maxNumPixels); 394 395 final Bitmap bm = Bitmap.createBitmap(bmpWidth, bmpHeight, Bitmap.Config.ARGB_8888); 396 final Icon ic = Icon.createWithBitmap(bm); 397 final Drawable drawable = ic.loadDrawable(mContext); 398 399 assertThat(drawable.getIntrinsicWidth()).isEqualTo(maxWidth); 400 assertThat(drawable.getIntrinsicHeight()).isEqualTo(maxHeight); 401 } 402 403 @SmallTest testScaleDownMaxSizeWithAdaptiveBitmap()404 public void testScaleDownMaxSizeWithAdaptiveBitmap() throws Exception { 405 final int bmpWidth = 20_000; 406 final int bmpHeight = 10_000; 407 final int bmpBpp = 4; 408 final int maxNumPixels = RecordingCanvas.MAX_BITMAP_SIZE / bmpBpp; 409 final int maxWidth = getMaxWidth(bmpWidth, bmpHeight, maxNumPixels); 410 final int maxHeight = getMaxHeight(bmpWidth, bmpHeight, maxNumPixels); 411 412 final Bitmap bm = Bitmap.createBitmap(bmpWidth, bmpHeight, Bitmap.Config.ARGB_8888); 413 final Icon ic = Icon.createWithAdaptiveBitmap(bm); 414 final AdaptiveIconDrawable adaptiveDrawable = (AdaptiveIconDrawable) ic.loadDrawable( 415 mContext); 416 final Drawable drawable = adaptiveDrawable.getForeground(); 417 418 assertThat(drawable.getIntrinsicWidth()).isEqualTo(maxWidth); 419 assertThat(drawable.getIntrinsicHeight()).isEqualTo(maxHeight); 420 } 421 422 @SmallTest testScaleDownMaxSizeWithResource()423 public void testScaleDownMaxSizeWithResource() throws Exception { 424 final Icon ic = Icon.createWithResource(getContext(), R.drawable.test_too_big); 425 final BitmapDrawable drawable = (BitmapDrawable) ic.loadDrawable(mContext); 426 427 assertThat(drawable.getBitmap().getByteCount()).isAtMost(RecordingCanvas.MAX_BITMAP_SIZE); 428 } 429 430 @SmallTest testScaleDownMaxSizeWithFile()431 public void testScaleDownMaxSizeWithFile() throws Exception { 432 final Bitmap bit1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.test_too_big)) 433 .getBitmap(); 434 final File dir = getContext().getExternalFilesDir(null); 435 final File file1 = new File(dir, "file1-too-big.png"); 436 bit1.compress(Bitmap.CompressFormat.PNG, 100, 437 new FileOutputStream(file1)); 438 439 final Icon ic = Icon.createWithFilePath(file1.toString()); 440 final BitmapDrawable drawable = (BitmapDrawable) ic.loadDrawable(mContext); 441 442 assertThat(drawable.getBitmap().getByteCount()).isAtMost(RecordingCanvas.MAX_BITMAP_SIZE); 443 } 444 445 @SmallTest testScaleDownMaxSizeWithData()446 public void testScaleDownMaxSizeWithData() throws Exception { 447 final int bmpBpp = 4; 448 final Bitmap originalBits = ((BitmapDrawable) getContext().getDrawable( 449 R.drawable.test_too_big)).getBitmap(); 450 final ByteArrayOutputStream ostream = new ByteArrayOutputStream( 451 originalBits.getWidth() * originalBits.getHeight() * bmpBpp); 452 originalBits.compress(Bitmap.CompressFormat.PNG, 100, ostream); 453 final byte[] pngdata = ostream.toByteArray(); 454 final Icon ic = Icon.createWithData(pngdata, 0, pngdata.length); 455 final BitmapDrawable drawable = (BitmapDrawable) ic.loadDrawable(mContext); 456 457 assertThat(drawable.getBitmap().getByteCount()).isAtMost(RecordingCanvas.MAX_BITMAP_SIZE); 458 } 459 460 // ======== utils ======== 461 462 static final char[] GRADIENT = " .:;+=xX$#".toCharArray(); 463 static float[] hsv = new float[3]; colorToChar(int color)464 static char colorToChar(int color) { 465 int sum = ((color >> 16) & 0xff) 466 + ((color >> 8) & 0xff) 467 + ((color) & 0xff); 468 return GRADIENT[sum * (GRADIENT.length-1) / (3*0xff)]; 469 } printBits(int[] a, int w, int h)470 static void printBits(int[] a, int w, int h) { 471 final StringBuilder sb = new StringBuilder(); 472 for (int i=0; i<w; i++) { 473 for (int j=0; j<h; j++) { 474 sb.append(colorToChar(a[i+w*j])); 475 } 476 sb.append('\n'); 477 } 478 L(sb.toString()); 479 } printBits(Bitmap a)480 static void printBits(Bitmap a) { 481 final int w = a.getWidth(); 482 final int h = a.getHeight(); 483 int[] aPix = new int[w * h]; 484 printBits(aPix, w, h); 485 } equalBitmaps(Bitmap a, Bitmap b)486 boolean equalBitmaps(Bitmap a, Bitmap b) { 487 return equalBitmaps(a, b, null); 488 } 489 equalBitmaps(Bitmap a, Bitmap b, Region region)490 boolean equalBitmaps(Bitmap a, Bitmap b, Region region) { 491 if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) return false; 492 493 final int w = a.getWidth(); 494 final int h = a.getHeight(); 495 int[] aPix = new int[w * h]; 496 int[] bPix = new int[w * h]; 497 498 if (region != null) { 499 for (int i = 0; i < w; i++) { 500 for (int j = 0; j < h; j++) { 501 if (region.contains(i, j) && a.getPixel(i, j) != b.getPixel(i, j)) { 502 return false; 503 } 504 } 505 } 506 return true; 507 } else { 508 a.getPixels(aPix, 0, w, 0, 0, w, h); 509 b.getPixels(bPix, 0, w, 0, 0, w, h); 510 return Arrays.equals(aPix, bPix); 511 } 512 } 513 findBitmapDifferences(Bitmap a, Bitmap b)514 void findBitmapDifferences(Bitmap a, Bitmap b) { 515 if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) { 516 L("different sizes: %dx%d vs %dx%d", 517 a.getWidth(), a.getHeight(), b.getWidth(), b.getHeight()); 518 return; 519 } 520 521 final int w = a.getWidth(); 522 final int h = a.getHeight(); 523 int[] aPix = new int[w * h]; 524 int[] bPix = new int[w * h]; 525 526 a.getPixels(aPix, 0, w, 0, 0, w, h); 527 b.getPixels(bPix, 0, w, 0, 0, w, h); 528 529 L("bitmap a (%dx%d)", w, h); 530 printBits(aPix, w, h); 531 L("bitmap b (%dx%d)", w, h); 532 printBits(bPix, w, h); 533 534 StringBuffer sb = new StringBuffer("Different pixels: "); 535 for (int i=0; i<w; i++) { 536 for (int j=0; j<h; j++) { 537 if (aPix[i+w*j] != bPix[i+w*j]) { 538 sb.append(" ").append(i).append(",").append(j); 539 } 540 } 541 } 542 L(sb.toString()); 543 } 544 } 545