1/*
2 * Copyright (C) 2016 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.support.design.testutils;
18
19import android.content.Context;
20import android.content.res.TypedArray;
21import android.graphics.Bitmap;
22import android.graphics.Canvas;
23import android.graphics.Color;
24import android.graphics.Rect;
25import android.graphics.drawable.Drawable;
26import android.support.annotation.ColorInt;
27import android.support.annotation.NonNull;
28
29import junit.framework.Assert;
30
31public class TestUtils {
32    /**
33     * Checks whether all the pixels in the specified drawable are of the same specified color.
34     *
35     * In case there is a color mismatch, the behavior of this method depends on the
36     * <code>throwExceptionIfFails</code> parameter. If it is <code>true</code>, this method will
37     * throw an <code>Exception</code> describing the mismatch. Otherwise this method will call
38     * <code>Assert.fail</code> with detailed description of the mismatch.
39     */
40    public static void assertAllPixelsOfColor(String failMessagePrefix, @NonNull Drawable drawable,
41            int drawableWidth, int drawableHeight, boolean callSetBounds, @ColorInt int color,
42            int allowedComponentVariance, boolean throwExceptionIfFails) {
43        assertAllPixelsOfColor(failMessagePrefix, drawable, drawableWidth, drawableHeight,
44                callSetBounds, color, null, allowedComponentVariance, throwExceptionIfFails);
45    }
46
47    public static void assertAllPixelsOfColor(String failMessagePrefix, @NonNull Drawable drawable,
48            int drawableWidth, int drawableHeight, boolean callSetBounds, @ColorInt int color,
49            Rect checkArea, int allowedComponentVariance, boolean throwExceptionIfFails) {
50
51        // Create a bitmap
52        Bitmap bitmap = Bitmap.createBitmap(drawableWidth, drawableHeight, Bitmap.Config.ARGB_8888);
53        // Create a canvas that wraps the bitmap
54        Canvas canvas = new Canvas(bitmap);
55        if (callSetBounds) {
56            // Configure the drawable to have bounds that match the passed size
57            drawable.setBounds(0, 0, drawableWidth, drawableHeight);
58        }
59
60        // And ask the drawable to draw itself to the canvas / bitmap
61        drawable.draw(canvas);
62
63        try {
64            int[] rowPixels = new int[drawableWidth];
65
66            final int firstRow = checkArea != null ? checkArea.top : 0;
67            final int lastRow = checkArea != null ? checkArea.bottom : drawableHeight - 1;
68            final int firstCol = checkArea != null ? checkArea.left : 0;
69            final int lastCol = checkArea != null ? checkArea.right : drawableWidth - 1;
70
71            final int expectedAlpha = Color.alpha(color);
72            final int expectedRed = Color.red(color);
73            final int expectedGreen = Color.green(color);
74            final int expectedBlue = Color.blue(color);
75
76            for (int row = firstRow; row <= lastRow; row++) {
77                bitmap.getPixels(rowPixels, 0, drawableWidth, 0, row, drawableWidth, 1);
78
79                for (int column = firstCol; column <= lastCol; column++) {
80                    int sourceAlpha = Color.alpha(rowPixels[column]);
81                    int sourceRed = Color.red(rowPixels[column]);
82                    int sourceGreen = Color.green(rowPixels[column]);
83                    int sourceBlue = Color.blue(rowPixels[column]);
84
85                    int varianceAlpha = Math.abs(sourceAlpha - expectedAlpha);
86                    int varianceRed = Math.abs(sourceRed - expectedRed);
87                    int varianceGreen = Math.abs(sourceGreen - expectedGreen);
88                    int varianceBlue = Math.abs(sourceBlue - expectedBlue);
89
90                    boolean isColorMatch = (varianceAlpha <= allowedComponentVariance)
91                            && (varianceRed <= allowedComponentVariance)
92                            && (varianceGreen <= allowedComponentVariance)
93                            && (varianceBlue <= allowedComponentVariance);
94
95                    if (!isColorMatch) {
96                        String mismatchDescription = failMessagePrefix
97                                + ": expected all drawable colors to be ["
98                                + expectedAlpha + "," + expectedRed + ","
99                                + expectedGreen + "," + expectedBlue
100                                + "] but at position (" + row + "," + column + ") found ["
101                                + sourceAlpha + "," + sourceRed + ","
102                                + sourceGreen + "," + sourceBlue + "]";
103                        if (throwExceptionIfFails) {
104                            throw new RuntimeException(mismatchDescription);
105                        } else {
106                            Assert.fail(mismatchDescription);
107                        }
108                    }
109                }
110            }
111        } finally {
112            bitmap.recycle();
113        }
114    }
115
116    public static int getThemeAttrColor(Context context, final int attr) {
117        TypedArray a = null;
118        try {
119            a = context.obtainStyledAttributes(new int[]{attr});
120            return a.getColor(0, 0);
121        } finally {
122            if (a != null) {
123                a.recycle();
124            }
125        }
126    }
127}