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