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 
17 package android.graphics.drawable.cts;
18 
19 import android.graphics.Canvas;
20 import android.graphics.drawable.Drawable;
21 import junit.framework.Assert;
22 
23 import org.xmlpull.v1.XmlPullParser;
24 import org.xmlpull.v1.XmlPullParserException;
25 
26 import android.content.res.Configuration;
27 import android.content.res.Resources;
28 import android.content.res.XmlResourceParser;
29 import android.graphics.Bitmap;
30 import android.graphics.Color;
31 import android.util.AttributeSet;
32 import android.util.Xml;
33 
34 import java.io.IOException;
35 
36 /**
37  * The useful methods for graphics.drawable test.
38  */
39 public class DrawableTestUtils {
40 
skipCurrentTag(XmlPullParser parser)41     public static void skipCurrentTag(XmlPullParser parser)
42             throws XmlPullParserException, IOException {
43         int outerDepth = parser.getDepth();
44         int type;
45         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
46                && (type != XmlPullParser.END_TAG
47                        || parser.getDepth() > outerDepth)) {
48         }
49     }
50 
51     /**
52      * Retrieve an AttributeSet from a XML.
53      *
54      * @param parser the XmlPullParser to use for the xml parsing.
55      * @param searchedNodeName the name of the target node.
56      * @return the AttributeSet retrieved from specified node.
57      * @throws IOException
58      * @throws XmlPullParserException
59      */
getAttributeSet(XmlResourceParser parser, String searchedNodeName)60     public static AttributeSet getAttributeSet(XmlResourceParser parser, String searchedNodeName)
61             throws XmlPullParserException, IOException {
62         AttributeSet attrs = null;
63         int type;
64         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
65                 && type != XmlPullParser.START_TAG) {
66         }
67         String nodeName = parser.getName();
68         if (!"alias".equals(nodeName)) {
69             throw new RuntimeException();
70         }
71         int outerDepth = parser.getDepth();
72         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
73                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
74             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
75                 continue;
76             }
77             nodeName = parser.getName();
78             if (searchedNodeName.equals(nodeName)) {
79                 outerDepth = parser.getDepth();
80                 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
81                         && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
82                     if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
83                         continue;
84                     }
85                     nodeName = parser.getName();
86                     attrs = Xml.asAttributeSet(parser);
87                     break;
88                 }
89                 break;
90             } else {
91                 skipCurrentTag(parser);
92             }
93         }
94         return attrs;
95     }
96 
getResourceParser(Resources res, int resId)97     public static XmlResourceParser getResourceParser(Resources res, int resId)
98             throws XmlPullParserException, IOException {
99         final XmlResourceParser parser = res.getXml(resId);
100         int type;
101         while ((type = parser.next()) != XmlPullParser.START_TAG
102                 && type != XmlPullParser.END_DOCUMENT) {
103             // Empty loop
104         }
105         return parser;
106     }
107 
setResourcesDensity(Resources res, int densityDpi)108     public static void setResourcesDensity(Resources res, int densityDpi) {
109         final Configuration config = new Configuration();
110         config.setTo(res.getConfiguration());
111         config.densityDpi = densityDpi;
112         res.updateConfiguration(config, null);
113     }
114 
115     /**
116      * Implements scaling as used by the Bitmap class. Resulting values are
117      * rounded up (as distinct from resource scaling, which truncates or rounds
118      * to the nearest pixel).
119      *
120      * @param size the pixel size to scale
121      * @param sdensity the source density that corresponds to the size
122      * @param tdensity the target density
123      * @return the pixel size scaled for the target density
124      */
scaleBitmapFromDensity(int size, int sdensity, int tdensity)125     public static int scaleBitmapFromDensity(int size, int sdensity, int tdensity) {
126         if (sdensity == 0 || tdensity == 0 || sdensity == tdensity) {
127             return size;
128         }
129 
130         // Scale by tdensity / sdensity, rounding up.
131         return ((size * tdensity) + (sdensity >> 1)) / sdensity;
132     }
133 
134     /**
135      * Asserts that two images are similar within the given thresholds.
136      *
137      * @param message Error message
138      * @param expected Expected bitmap
139      * @param actual Actual bitmap
140      * @param pixelThreshold The total difference threshold for a single pixel
141      * @param pixelCountThreshold The total different pixel count threshold
142      * @param pixelDiffTolerance The pixel value difference tolerance
143      *
144      */
compareImages(String message, Bitmap expected, Bitmap actual, float pixelThreshold, float pixelCountThreshold, int pixelDiffTolerance)145     public static void compareImages(String message, Bitmap expected, Bitmap actual,
146             float pixelThreshold, float pixelCountThreshold, int pixelDiffTolerance) {
147         int idealWidth = expected.getWidth();
148         int idealHeight = expected.getHeight();
149 
150         Assert.assertTrue(idealWidth == actual.getWidth());
151         Assert.assertTrue(idealHeight == actual.getHeight());
152 
153         int totalDiffPixelCount = 0;
154         float totalPixelCount = idealWidth * idealHeight;
155         for (int x = 0; x < idealWidth; x++) {
156             for (int y = 0; y < idealHeight; y++) {
157                 int idealColor = expected.getPixel(x, y);
158                 int givenColor = actual.getPixel(x, y);
159                 if (idealColor == givenColor)
160                     continue;
161 
162                 float totalError = 0;
163                 totalError += Math.abs(Color.red(idealColor) - Color.red(givenColor));
164                 totalError += Math.abs(Color.green(idealColor) - Color.green(givenColor));
165                 totalError += Math.abs(Color.blue(idealColor) - Color.blue(givenColor));
166                 totalError += Math.abs(Color.alpha(idealColor) - Color.alpha(givenColor));
167 
168                 if ((totalError / 1024.0f) >= pixelThreshold) {
169                     Assert.fail((message + ": totalError is " + totalError));
170                 }
171 
172                 if (totalError > pixelDiffTolerance) {
173                     totalDiffPixelCount++;
174                 }
175             }
176         }
177         if ((totalDiffPixelCount / totalPixelCount) >= pixelCountThreshold) {
178             Assert.fail((message +": totalDiffPixelCount is " + totalDiffPixelCount));
179         }
180     }
181 
182     /**
183      * Returns the {@link Color} at the specified location in the {@link Drawable}.
184      */
getPixel(Drawable d, int x, int y)185     public static int getPixel(Drawable d, int x, int y) {
186         final int w = Math.max(d.getIntrinsicWidth(), x + 1);
187         final int h = Math.max(d.getIntrinsicHeight(), y + 1);
188         final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
189         final Canvas c = new Canvas(b);
190         d.setBounds(0, 0, w, h);
191         d.draw(c);
192 
193         final int pixel = b.getPixel(x, y);
194         b.recycle();
195         return pixel;
196     }
197 }
198