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 android.graphics.Bitmap; 20 import android.graphics.Canvas; 21 import android.graphics.Region; 22 import android.os.Handler; 23 import android.os.HandlerThread; 24 import android.os.Parcel; 25 import android.test.AndroidTestCase; 26 import android.test.suitebuilder.annotation.SmallTest; 27 import android.util.Log; 28 29 import com.android.frameworks.coretests.R; 30 31 import java.io.ByteArrayOutputStream; 32 import java.io.File; 33 import java.io.FileOutputStream; 34 import java.util.ArrayList; 35 import java.util.Arrays; 36 37 public class IconTest extends AndroidTestCase { 38 public static final String TAG = IconTest.class.getSimpleName(); 39 public static void L(String s, Object... parts) { 40 Log.d(TAG, (parts.length == 0) ? s : String.format(s, parts)); 41 } 42 43 @SmallTest 44 public void testWithBitmap() throws Exception { 45 final Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); 46 final Bitmap bm2 = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565); 47 final Bitmap bm3 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape)) 48 .getBitmap(); 49 50 final Canvas can1 = new Canvas(bm1); 51 can1.drawColor(0xFFFF0000); 52 final Canvas can2 = new Canvas(bm2); 53 can2.drawColor(0xFF00FF00); 54 55 final Icon im1 = Icon.createWithBitmap(bm1); 56 final Icon im2 = Icon.createWithBitmap(bm2); 57 final Icon im3 = Icon.createWithBitmap(bm3); 58 59 final Drawable draw1 = im1.loadDrawable(mContext); 60 final Drawable draw2 = im2.loadDrawable(mContext); 61 final Drawable draw3 = im3.loadDrawable(mContext); 62 63 final Bitmap test1 = Bitmap.createBitmap(draw1.getIntrinsicWidth(), 64 draw1.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 65 final Bitmap test2 = Bitmap.createBitmap(draw2.getIntrinsicWidth(), 66 draw2.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 67 final Bitmap test3 = Bitmap.createBitmap(draw3.getIntrinsicWidth(), 68 draw3.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 69 70 draw1.setBounds(0, 0, draw1.getIntrinsicWidth(), draw1.getIntrinsicHeight()); 71 draw1.draw(new Canvas(test1)); 72 73 draw2.setBounds(0, 0, draw2.getIntrinsicWidth(), draw2.getIntrinsicHeight()); 74 draw2.draw(new Canvas(test2)); 75 76 draw3.setBounds(0, 0, draw3.getIntrinsicWidth(), draw3.getIntrinsicHeight()); 77 draw3.draw(new Canvas(test3)); 78 79 final File dir = getContext().getExternalFilesDir(null); 80 L("writing temp bitmaps to %s...", dir); 81 82 bm1.compress(Bitmap.CompressFormat.PNG, 100, 83 new FileOutputStream(new File(dir, "bitmap1-original.png"))); 84 test1.compress(Bitmap.CompressFormat.PNG, 100, 85 new FileOutputStream(new File(dir, "bitmap1-test.png"))); 86 if (!equalBitmaps(bm1, test1)) { 87 findBitmapDifferences(bm1, test1); 88 fail("bitmap1 differs, check " + dir); 89 } 90 91 bm2.compress(Bitmap.CompressFormat.PNG, 100, 92 new FileOutputStream(new File(dir, "bitmap2-original.png"))); 93 test2.compress(Bitmap.CompressFormat.PNG, 100, 94 new FileOutputStream(new File(dir, "bitmap2-test.png"))); 95 if (!equalBitmaps(bm2, test2)) { 96 findBitmapDifferences(bm2, test2); 97 fail("bitmap2 differs, check " + dir); 98 } 99 100 bm3.compress(Bitmap.CompressFormat.PNG, 100, 101 new FileOutputStream(new File(dir, "bitmap3-original.png"))); 102 test3.compress(Bitmap.CompressFormat.PNG, 100, 103 new FileOutputStream(new File(dir, "bitmap3-test.png"))); 104 if (!equalBitmaps(bm3, test3)) { 105 findBitmapDifferences(bm3, test3); 106 fail("bitmap3 differs, check " + dir); 107 } 108 } 109 110 @SmallTest 111 public void testWithAdaptiveBitmap() throws Exception { 112 final Bitmap bm1 = Bitmap.createBitmap(150, 150, Bitmap.Config.ARGB_8888); 113 114 final Canvas can1 = new Canvas(bm1); 115 can1.drawColor(0xFFFF0000); 116 117 final Icon im1 = Icon.createWithAdaptiveBitmap(bm1); 118 119 final AdaptiveIconDrawable draw1 = (AdaptiveIconDrawable) im1.loadDrawable(mContext); 120 121 final Bitmap test1 = Bitmap.createBitmap( 122 (int)(draw1.getIntrinsicWidth() * (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction())), 123 (int)(draw1.getIntrinsicHeight() * (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction())), 124 Bitmap.Config.ARGB_8888); 125 126 draw1.setBounds(0, 0, 127 (int) (draw1.getIntrinsicWidth() * (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction())), 128 (int) (draw1.getIntrinsicHeight() * (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction()))); 129 draw1.draw(new Canvas(test1)); 130 131 final File dir = getContext().getExternalFilesDir(null); 132 L("writing temp bitmaps to %s...", dir); 133 134 bm1.compress(Bitmap.CompressFormat.PNG, 100, 135 new FileOutputStream(new File(dir, "adaptive-bitmap1-original.png"))); 136 test1.compress(Bitmap.CompressFormat.PNG, 100, 137 new FileOutputStream(new File(dir, "adaptive-bitmap1-test.png"))); 138 if (!equalBitmaps(bm1, test1, draw1.getSafeZone())) { 139 findBitmapDifferences(bm1, test1); 140 fail("adaptive bitmap1 differs, check " + dir); 141 } 142 } 143 144 @SmallTest 145 public void testWithBitmapResource() throws Exception { 146 final Bitmap res1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape)) 147 .getBitmap(); 148 149 final Icon im1 = Icon.createWithResource(getContext(), R.drawable.landscape); 150 final Drawable draw1 = im1.loadDrawable(mContext); 151 final Bitmap test1 = Bitmap.createBitmap(draw1.getIntrinsicWidth(), 152 draw1.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 153 draw1.setBounds(0, 0, test1.getWidth(), test1.getHeight()); 154 draw1.draw(new Canvas(test1)); 155 156 final File dir = getContext().getExternalFilesDir(null); 157 res1.compress(Bitmap.CompressFormat.PNG, 100, 158 new FileOutputStream(new File(dir, "res1-original.png"))); 159 test1.compress(Bitmap.CompressFormat.PNG, 100, 160 new FileOutputStream(new File(dir, "res1-test.png"))); 161 if (!equalBitmaps(res1, test1)) { 162 findBitmapDifferences(res1, test1); 163 fail("res1 differs, check " + dir); 164 } 165 } 166 167 @SmallTest 168 public void testWithFile() throws Exception { 169 final Bitmap bit1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape)) 170 .getBitmap(); 171 final File dir = getContext().getExternalFilesDir(null); 172 final File file1 = new File(dir, "file1-original.png"); 173 bit1.compress(Bitmap.CompressFormat.PNG, 100, 174 new FileOutputStream(file1)); 175 176 final Icon im1 = Icon.createWithFilePath(file1.toString()); 177 final Drawable draw1 = im1.loadDrawable(mContext); 178 final Bitmap test1 = Bitmap.createBitmap(draw1.getIntrinsicWidth(), 179 draw1.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 180 draw1.setBounds(0, 0, test1.getWidth(), test1.getHeight()); 181 draw1.draw(new Canvas(test1)); 182 183 test1.compress(Bitmap.CompressFormat.PNG, 100, 184 new FileOutputStream(new File(dir, "file1-test.png"))); 185 if (!equalBitmaps(bit1, test1)) { 186 findBitmapDifferences(bit1, test1); 187 fail("testWithFile: file1 differs, check " + dir); 188 } 189 } 190 191 @SmallTest 192 public void testAsync() throws Exception { 193 final Bitmap bit1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape)) 194 .getBitmap(); 195 final File dir = getContext().getExternalFilesDir(null); 196 final File file1 = new File(dir, "async-original.png"); 197 bit1.compress(Bitmap.CompressFormat.PNG, 100, 198 new FileOutputStream(file1)); 199 200 final Icon im1 = Icon.createWithFilePath(file1.toString()); 201 final HandlerThread thd = new HandlerThread("testAsync"); 202 thd.start(); 203 final Handler h = new Handler(thd.getLooper()); 204 L(TAG, "asyncTest: dispatching load to thread: " + thd); 205 im1.loadDrawableAsync(mContext, new Icon.OnDrawableLoadedListener() { 206 @Override 207 public void onDrawableLoaded(Drawable draw1) { 208 L(TAG, "asyncTest: thread: loading drawable"); 209 L(TAG, "asyncTest: thread: loaded: %dx%d", draw1.getIntrinsicWidth(), 210 draw1.getIntrinsicHeight()); 211 final Bitmap test1 = Bitmap.createBitmap(draw1.getIntrinsicWidth(), 212 draw1.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 213 draw1.setBounds(0, 0, test1.getWidth(), test1.getHeight()); 214 draw1.draw(new Canvas(test1)); 215 216 try { 217 test1.compress(Bitmap.CompressFormat.PNG, 100, 218 new FileOutputStream(new File(dir, "async-test.png"))); 219 } catch (java.io.FileNotFoundException ex) { 220 fail("couldn't create test file: " + ex); 221 } 222 if (!equalBitmaps(bit1, test1)) { 223 findBitmapDifferences(bit1, test1); 224 fail("testAsync: file1 differs, check " + dir); 225 } 226 } 227 }, h); 228 L(TAG, "asyncTest: awaiting result"); 229 Thread.sleep(500); // ;_; 230 assertTrue("async-test.png does not exist!", new File(dir, "async-test.png").exists()); 231 L(TAG, "asyncTest: done"); 232 } 233 234 @SmallTest 235 public void testParcel() throws Exception { 236 final Bitmap originalbits = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape)) 237 .getBitmap(); 238 239 final ByteArrayOutputStream ostream = new ByteArrayOutputStream( 240 originalbits.getWidth() * originalbits.getHeight() * 2); // guess 50% compression 241 originalbits.compress(Bitmap.CompressFormat.PNG, 100, ostream); 242 final byte[] pngdata = ostream.toByteArray(); 243 244 L("starting testParcel; bitmap: %d bytes, PNG: %d bytes", 245 originalbits.getByteCount(), 246 pngdata.length); 247 248 final File dir = getContext().getExternalFilesDir(null); 249 final File originalfile = new File(dir, "parcel-original.png"); 250 new FileOutputStream(originalfile).write(pngdata); 251 252 ArrayList<Icon> imgs = new ArrayList<>(); 253 final Icon file1 = Icon.createWithFilePath(originalfile.getAbsolutePath()); 254 imgs.add(file1); 255 final Icon bit1 = Icon.createWithBitmap(originalbits); 256 imgs.add(bit1); 257 final Icon data1 = Icon.createWithData(pngdata, 0, pngdata.length); 258 imgs.add(data1); 259 final Icon res1 = Icon.createWithResource(getContext(), R.drawable.landscape); 260 imgs.add(res1); 261 262 ArrayList<Icon> test = new ArrayList<>(); 263 final Parcel parcel = Parcel.obtain(); 264 int pos = 0; 265 parcel.writeInt(imgs.size()); 266 for (Icon img : imgs) { 267 img.writeToParcel(parcel, 0); 268 L("used %d bytes parceling: %s", parcel.dataPosition() - pos, img); 269 pos = parcel.dataPosition(); 270 } 271 272 parcel.setDataPosition(0); // rewind 273 final int N = parcel.readInt(); 274 for (int i=0; i<N; i++) { 275 Icon img = Icon.CREATOR.createFromParcel(parcel); 276 L("test %d: read from parcel: %s", i, img); 277 final File testfile = new File(dir, 278 String.format("parcel-test%02d.png", i)); 279 280 final Drawable draw1 = img.loadDrawable(mContext); 281 if (draw1 == null) { 282 fail("null drawable from img: " + img); 283 } 284 final Bitmap test1 = Bitmap.createBitmap(draw1.getIntrinsicWidth(), 285 draw1.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 286 draw1.setBounds(0, 0, test1.getWidth(), test1.getHeight()); 287 draw1.draw(new Canvas(test1)); 288 289 try { 290 test1.compress(Bitmap.CompressFormat.PNG, 100, 291 new FileOutputStream(testfile)); 292 } catch (java.io.FileNotFoundException ex) { 293 fail("couldn't create test file " + testfile + ": " + ex); 294 } 295 if (!equalBitmaps(originalbits, test1)) { 296 findBitmapDifferences(originalbits, test1); 297 fail(testfile + " differs from original: " + originalfile); 298 } 299 300 } 301 } 302 303 304 // ======== utils ======== 305 306 static final char[] GRADIENT = " .:;+=xX$#".toCharArray(); 307 static float[] hsv = new float[3]; 308 static char colorToChar(int color) { 309 int sum = ((color >> 16) & 0xff) 310 + ((color >> 8) & 0xff) 311 + ((color) & 0xff); 312 return GRADIENT[sum * (GRADIENT.length-1) / (3*0xff)]; 313 } 314 static void printBits(int[] a, int w, int h) { 315 final StringBuilder sb = new StringBuilder(); 316 for (int i=0; i<w; i++) { 317 for (int j=0; j<h; j++) { 318 sb.append(colorToChar(a[i+w*j])); 319 } 320 sb.append('\n'); 321 } 322 L(sb.toString()); 323 } 324 static void printBits(Bitmap a) { 325 final int w = a.getWidth(); 326 final int h = a.getHeight(); 327 int[] aPix = new int[w * h]; 328 printBits(aPix, w, h); 329 } 330 boolean equalBitmaps(Bitmap a, Bitmap b) { 331 return equalBitmaps(a, b, null); 332 } 333 334 boolean equalBitmaps(Bitmap a, Bitmap b, Region region) { 335 if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) return false; 336 337 final int w = a.getWidth(); 338 final int h = a.getHeight(); 339 int[] aPix = new int[w * h]; 340 int[] bPix = new int[w * h]; 341 342 if (region != null) { 343 for (int i = 0; i < w; i++) { 344 for (int j = 0; j < h; j++) { 345 if (region.contains(i, j) && a.getPixel(i, j) != b.getPixel(i, j)) { 346 return false; 347 } 348 } 349 } 350 return true; 351 } else { 352 a.getPixels(aPix, 0, w, 0, 0, w, h); 353 b.getPixels(bPix, 0, w, 0, 0, w, h); 354 return Arrays.equals(aPix, bPix); 355 } 356 } 357 358 void findBitmapDifferences(Bitmap a, Bitmap b) { 359 if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) { 360 L("different sizes: %dx%d vs %dx%d", 361 a.getWidth(), a.getHeight(), b.getWidth(), b.getHeight()); 362 return; 363 } 364 365 final int w = a.getWidth(); 366 final int h = a.getHeight(); 367 int[] aPix = new int[w * h]; 368 int[] bPix = new int[w * h]; 369 370 a.getPixels(aPix, 0, w, 0, 0, w, h); 371 b.getPixels(bPix, 0, w, 0, 0, w, h); 372 373 L("bitmap a (%dx%d)", w, h); 374 printBits(aPix, w, h); 375 L("bitmap b (%dx%d)", w, h); 376 printBits(bPix, w, h); 377 378 StringBuffer sb = new StringBuffer("Different pixels: "); 379 for (int i=0; i<w; i++) { 380 for (int j=0; j<h; j++) { 381 if (aPix[i+w*j] != bPix[i+w*j]) { 382 sb.append(" ").append(i).append(",").append(j); 383 } 384 } 385 } 386 L(sb.toString()); 387 } 388 } 389