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
17package android.graphics.drawable;
18
19import android.graphics.Bitmap;
20import android.graphics.Canvas;
21import android.os.Handler;
22import android.os.HandlerThread;
23import android.os.Parcel;
24import android.test.AndroidTestCase;
25import android.test.suitebuilder.annotation.SmallTest;
26import android.util.Log;
27
28import java.io.ByteArrayOutputStream;
29import java.io.File;
30import java.io.FileOutputStream;
31import java.lang.Override;
32import java.util.Arrays;
33import java.util.ArrayList;
34
35import com.android.frameworks.graphicstests.R;
36
37public 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 testWithBitmapResource() throws Exception {
112        final Bitmap res1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape))
113                .getBitmap();
114
115        final Icon im1 = Icon.createWithResource(getContext(), R.drawable.landscape);
116        final Drawable draw1 = im1.loadDrawable(mContext);
117        final Bitmap test1 = Bitmap.createBitmap(draw1.getIntrinsicWidth(),
118                draw1.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
119        draw1.setBounds(0, 0, test1.getWidth(), test1.getHeight());
120        draw1.draw(new Canvas(test1));
121
122        final File dir = getContext().getExternalFilesDir(null);
123        res1.compress(Bitmap.CompressFormat.PNG, 100,
124                new FileOutputStream(new File(dir, "res1-original.png")));
125        test1.compress(Bitmap.CompressFormat.PNG, 100,
126                new FileOutputStream(new File(dir, "res1-test.png")));
127        if (!equalBitmaps(res1, test1)) {
128            findBitmapDifferences(res1, test1);
129            fail("res1 differs, check " + dir);
130        }
131    }
132
133    @SmallTest
134    public void testWithFile() throws Exception {
135        final Bitmap bit1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape))
136                .getBitmap();
137        final File dir = getContext().getExternalFilesDir(null);
138        final File file1 = new File(dir, "file1-original.png");
139        bit1.compress(Bitmap.CompressFormat.PNG, 100,
140                new FileOutputStream(file1));
141
142        final Icon im1 = Icon.createWithFilePath(file1.toString());
143        final Drawable draw1 = im1.loadDrawable(mContext);
144        final Bitmap test1 = Bitmap.createBitmap(draw1.getIntrinsicWidth(),
145                draw1.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
146        draw1.setBounds(0, 0, test1.getWidth(), test1.getHeight());
147        draw1.draw(new Canvas(test1));
148
149        test1.compress(Bitmap.CompressFormat.PNG, 100,
150                new FileOutputStream(new File(dir, "file1-test.png")));
151        if (!equalBitmaps(bit1, test1)) {
152            findBitmapDifferences(bit1, test1);
153            fail("testWithFile: file1 differs, check " + dir);
154        }
155    }
156
157    @SmallTest
158    public void testAsync() throws Exception {
159        final Bitmap bit1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape))
160                .getBitmap();
161        final File dir = getContext().getExternalFilesDir(null);
162        final File file1 = new File(dir, "async-original.png");
163        bit1.compress(Bitmap.CompressFormat.PNG, 100,
164                new FileOutputStream(file1));
165
166        final Icon im1 = Icon.createWithFilePath(file1.toString());
167        final HandlerThread thd = new HandlerThread("testAsync");
168        thd.start();
169        final Handler h = new Handler(thd.getLooper());
170        L(TAG, "asyncTest: dispatching load to thread: " + thd);
171        im1.loadDrawableAsync(mContext, new Icon.OnDrawableLoadedListener() {
172            @Override
173            public void onDrawableLoaded(Drawable draw1) {
174                L(TAG, "asyncTest: thread: loading drawable");
175                L(TAG, "asyncTest: thread: loaded: %dx%d", draw1.getIntrinsicWidth(),
176                    draw1.getIntrinsicHeight());
177                final Bitmap test1 = Bitmap.createBitmap(draw1.getIntrinsicWidth(),
178                        draw1.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
179                draw1.setBounds(0, 0, test1.getWidth(), test1.getHeight());
180                draw1.draw(new Canvas(test1));
181
182                try {
183                    test1.compress(Bitmap.CompressFormat.PNG, 100,
184                            new FileOutputStream(new File(dir, "async-test.png")));
185                } catch (java.io.FileNotFoundException ex) {
186                    fail("couldn't create test file: " + ex);
187                }
188                if (!equalBitmaps(bit1, test1)) {
189                    findBitmapDifferences(bit1, test1);
190                    fail("testAsync: file1 differs, check " + dir);
191                }
192            }
193        }, h);
194        L(TAG, "asyncTest: awaiting result");
195        Thread.sleep(500); // ;_;
196        assertTrue("async-test.png does not exist!", new File(dir, "async-test.png").exists());
197        L(TAG, "asyncTest: done");
198    }
199
200    @SmallTest
201    public void testParcel() throws Exception {
202        final Bitmap originalbits = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape))
203                .getBitmap();
204
205        final ByteArrayOutputStream ostream = new ByteArrayOutputStream(
206                originalbits.getWidth() * originalbits.getHeight() * 2); // guess 50% compression
207        originalbits.compress(Bitmap.CompressFormat.PNG, 100, ostream);
208        final byte[] pngdata = ostream.toByteArray();
209
210        L("starting testParcel; bitmap: %d bytes, PNG: %d bytes",
211                originalbits.getByteCount(),
212                pngdata.length);
213
214        final File dir = getContext().getExternalFilesDir(null);
215        final File originalfile = new File(dir, "parcel-original.png");
216        new FileOutputStream(originalfile).write(pngdata);
217
218        ArrayList<Icon> imgs = new ArrayList<>();
219        final Icon file1 = Icon.createWithFilePath(originalfile.getAbsolutePath());
220        imgs.add(file1);
221        final Icon bit1 = Icon.createWithBitmap(originalbits);
222        imgs.add(bit1);
223        final Icon data1 = Icon.createWithData(pngdata, 0, pngdata.length);
224        imgs.add(data1);
225        final Icon res1 = Icon.createWithResource(getContext(), R.drawable.landscape);
226        imgs.add(res1);
227
228        ArrayList<Icon> test = new ArrayList<>();
229        final Parcel parcel = Parcel.obtain();
230        int pos = 0;
231        parcel.writeInt(imgs.size());
232        for (Icon img : imgs) {
233            img.writeToParcel(parcel, 0);
234            L("used %d bytes parceling: %s", parcel.dataPosition() - pos, img);
235            pos = parcel.dataPosition();
236        }
237
238        parcel.setDataPosition(0); // rewind
239        final int N = parcel.readInt();
240        for (int i=0; i<N; i++) {
241            Icon img = Icon.CREATOR.createFromParcel(parcel);
242            L("test %d: read from parcel: %s", i, img);
243            final File testfile = new File(dir,
244                    String.format("parcel-test%02d.png", i));
245
246            final Drawable draw1 = img.loadDrawable(mContext);
247            if (draw1 == null) {
248                fail("null drawable from img: " + img);
249            }
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            try {
256                test1.compress(Bitmap.CompressFormat.PNG, 100,
257                        new FileOutputStream(testfile));
258            } catch (java.io.FileNotFoundException ex) {
259                fail("couldn't create test file " + testfile + ": " + ex);
260            }
261            if (!equalBitmaps(originalbits, test1)) {
262                findBitmapDifferences(originalbits, test1);
263                fail(testfile + " differs from original: " + originalfile);
264            }
265
266        }
267    }
268
269
270    // ======== utils ========
271
272    static final char[] GRADIENT = " .:;+=xX$#".toCharArray();
273    static float[] hsv = new float[3];
274    static char colorToChar(int color) {
275        int sum = ((color >> 16) & 0xff)
276                + ((color >> 8)  & 0xff)
277                + ((color)       & 0xff);
278        return GRADIENT[sum * (GRADIENT.length-1) / (3*0xff)];
279    }
280    static void printBits(int[] a, int w, int h) {
281        final StringBuilder sb = new StringBuilder();
282        for (int i=0; i<w; i++) {
283            for (int j=0; j<h; j++) {
284                sb.append(colorToChar(a[i+w*j]));
285            }
286            sb.append('\n');
287        }
288        L(sb.toString());
289    }
290    static void printBits(Bitmap a) {
291        final int w = a.getWidth();
292        final int h = a.getHeight();
293        int[] aPix = new int[w * h];
294        printBits(aPix, w, h);
295    }
296    boolean equalBitmaps(Bitmap a, Bitmap b) {
297        if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) return false;
298
299        final int w = a.getWidth();
300        final int h = a.getHeight();
301        int[] aPix = new int[w * h];
302        int[] bPix = new int[w * h];
303
304        a.getPixels(aPix, 0, w, 0, 0, w, h);
305        b.getPixels(bPix, 0, w, 0, 0, w, h);
306
307        return Arrays.equals(aPix, bPix);
308    }
309
310    void findBitmapDifferences(Bitmap a, Bitmap b) {
311        if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) {
312            L("different sizes: %dx%d vs %dx%d",
313                        a.getWidth(), a.getHeight(), b.getWidth(), b.getHeight());
314            return;
315        }
316
317        final int w = a.getWidth();
318        final int h = a.getHeight();
319        int[] aPix = new int[w * h];
320        int[] bPix = new int[w * h];
321
322        a.getPixels(aPix, 0, w, 0, 0, w, h);
323        b.getPixels(bPix, 0, w, 0, 0, w, h);
324
325        L("bitmap a (%dx%d)", w, h);
326        printBits(aPix, w, h);
327        L("bitmap b (%dx%d)", w, h);
328        printBits(bPix, w, h);
329
330        StringBuffer sb = new StringBuffer("Different pixels: ");
331        for (int i=0; i<w; i++) {
332            for (int j=0; j<h; j++) {
333                if (aPix[i+w*j] != bPix[i+w*j]) {
334                    sb.append(" ").append(i).append(",").append(j);
335                }
336            }
337        }
338        L(sb.toString());
339    }
340}
341