blob: 49d5bd0cf799046831b04f0470a4cbb483a8cfc6 [file] [log] [blame]
package android.graphics.drawable.cts;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.cts.R;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable.ConstantState;
import android.graphics.drawable.StateListDrawable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.xmlpull.v1.XmlPullParser;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Arrays;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class AdaptiveIconDrawableTest {
public static final String TAG = AdaptiveIconDrawableTest.class.getSimpleName();
public static final boolean DEBUG = false;
public static void L(String s, Object... parts) {
Log.d(TAG, (parts.length == 0) ? s : String.format(s, parts));
}
@Test
public void testConstructor() {
new AdaptiveIconDrawable(null, null);
new AdaptiveIconDrawable(null, null, null);
}
@Test
public void testInflate() throws Throwable {
AdaptiveIconDrawable dr = new AdaptiveIconDrawable(null, null);
Resources r = InstrumentationRegistry.getTargetContext().getResources();
XmlPullParser parser = r.getXml(R.layout.framelayout_layout);
AttributeSet attrs = Xml.asAttributeSet(parser);
// Should not throw inflate exception
dr.inflate(r, parser, attrs);
}
@Test(expected=NullPointerException.class)
public void testInflateNull() throws Throwable {
AdaptiveIconDrawable dr = new AdaptiveIconDrawable(null, null);
dr.inflate(null, null, null);
}
@Test
public void testDraw() {
Canvas c = new Canvas();
AdaptiveIconDrawable dr = new AdaptiveIconDrawable(null, null);
dr.draw(c);
}
@Test(expected=NullPointerException.class)
public void testDrawNull() {
AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
iconDrawable.setBounds(0, 0, 100, 100);
iconDrawable.draw(null);
}
@Test
public void testInvalidateDrawable() {
AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
iconDrawable.invalidateDrawable(
InstrumentationRegistry.getTargetContext().getDrawable(R.drawable.pass));
}
@Test
public void testScheduleDrawable() {
AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
iconDrawable.scheduleDrawable(
InstrumentationRegistry.getTargetContext().getDrawable(R.drawable.pass),
() -> {}, 10);
// input null as params
iconDrawable.scheduleDrawable(null, null, -1);
// expected, no Exception thrown out, test success
}
@Test
public void testUnscheduleDrawable() {
AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
iconDrawable.unscheduleDrawable(
InstrumentationRegistry.getTargetContext().getDrawable(R.drawable.pass), () -> {});
// input null as params
iconDrawable.unscheduleDrawable(null, null);
// expected, no Exception thrown out, test success
}
@Test
public void testGetChangingConfigurations() {
AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
iconDrawable.setChangingConfigurations(11);
assertEquals(11, iconDrawable.getChangingConfigurations());
iconDrawable.setChangingConfigurations(-21);
assertEquals(-21, iconDrawable.getChangingConfigurations());
}
@Test
public void testGetAlpha() {
ColorDrawable drawable = new ColorDrawable(Color.RED);
AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(null, drawable);
iconDrawable.setAlpha(128);
assertEquals(128, iconDrawable.getAlpha());
}
@Test
public void testGetMonochrome() {
ColorDrawable drawable = new ColorDrawable(Color.RED);
AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(null, null, drawable);
assertEquals(drawable, iconDrawable.getMonochrome());
}
@Test
public void testMonochromeInflated() {
Resources r = InstrumentationRegistry.getTargetContext().getResources();
AdaptiveIconDrawable iconDrawable = (AdaptiveIconDrawable) r.getDrawable(
R.drawable.adaptiveicondrawable);
assertNotNull(iconDrawable.getMonochrome());
}
/**
* When setBound isn't called before draw method is called.
* Nothing is drawn.
*/
@Test
public void testDrawWithoutSetBounds() throws Exception {
Drawable backgroundDrawable = new ColorDrawable(Color.BLUE);
Drawable foregroundDrawable = new ColorDrawable(Color.RED);
AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(backgroundDrawable, foregroundDrawable);
Context context = InstrumentationRegistry.getTargetContext();
File dir = context.getExternalFilesDir(null);
L("writing temp bitmaps to %s...", dir);
final Bitmap bm_test = Bitmap.createBitmap(150, 150, Bitmap.Config.ARGB_8888);
final Bitmap bm_org = bm_test.copy(Config.ARGB_8888, false);
final Canvas can1 = new Canvas(bm_test);
// Even when setBounds is not called, should not crash
iconDrawable.draw(can1);
// Draws nothing! Hence same as original.
if (!equalBitmaps(bm_test, bm_org)) {
findBitmapDifferences(bm_test, bm_org);
fail("bm differs, check " + dir);
}
}
/**
* When setBound is called, translate accordingly.
*/
@Test
public void testDrawSetBounds() throws Exception {
int dpi = 4 ;
int top = 18 * dpi;
int left = 18 * dpi;
int right = 90 * dpi;
int bottom = 90 * dpi;
int width = right - left;
int height = bottom - top;
Context context = InstrumentationRegistry.getTargetContext();
AdaptiveIconDrawable iconDrawable = (AdaptiveIconDrawable) context.getResources().getDrawable(android.R.drawable.sym_def_app_icon);
File dir = context.getExternalFilesDir(null);
L("writing temp bitmaps to %s...", dir);
final Bitmap bm_org = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
final Canvas can_org = new Canvas(bm_org);
iconDrawable.setBounds(0, 0, width, height);
iconDrawable.draw(can_org);
// Tested bitmap is drawn from the adaptive icon drawable.
final Bitmap bm_test = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
final Canvas can_test = new Canvas(bm_test);
iconDrawable.setBounds(left, top, right, bottom);
can_test.translate(-left, -top);
iconDrawable.draw(can_test);
can_test.translate(left, top);
if (DEBUG) {
bm_org.compress(Bitmap.CompressFormat.PNG, 100,
new FileOutputStream(new File(dir, "adaptive-bm-original.png")));
bm_test.compress(Bitmap.CompressFormat.PNG, 100,
new FileOutputStream(new File(dir, "adaptive-bm-test.png")));
}
Region region = new Region(new Rect(0, 0, width, height));
Path circle = new Path();
circle.addCircle(width / 2, height / 2, (right - left)/2 -10 /* room for anti-alias */, Direction.CW);
region.setPath(circle, region);
if (!equalBitmaps(bm_test, bm_org, region)) {
findBitmapDifferences(bm_test, bm_org);
fail("bm differs, check " + dir);
}
}
@Test
public void testSetVisible() {
AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
assertFalse(iconDrawable.setVisible(true, true)); /* unchanged */
assertTrue(iconDrawable.setVisible(false, true)); /* changed */
assertFalse(iconDrawable.setVisible(false, true)); /* unchanged */
}
@Test
public void testSetAlpha() {
Bitmap b = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
Drawable bg = new BitmapDrawable(b);
Drawable fg = new BitmapDrawable(b);
AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(bg, fg);
iconDrawable.setBounds(0, 0, 100, 100);
Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
iconDrawable.draw(canvas);
assertEquals(255, Color.alpha(bitmap.getPixel(50, 50)));
iconDrawable.setAlpha(200);
bitmap.eraseColor(Color.TRANSPARENT);
iconDrawable.draw(canvas);
assertEquals(200, Color.alpha(bitmap.getPixel(50, 50)));
assertEquals(200, bg.getAlpha());
assertEquals(200, fg.getAlpha());
iconDrawable.setAlpha(100);
bitmap.eraseColor(Color.TRANSPARENT);
iconDrawable.draw(canvas);
assertEquals(100, Color.alpha(bitmap.getPixel(50, 50)));
assertEquals(100, bg.getAlpha());
assertEquals(100, fg.getAlpha());
}
@Test
public void testSetColorFilter() {
AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
ColorFilter cf = new ColorFilter();
iconDrawable.setColorFilter(cf);
// input null as param
iconDrawable.setColorFilter(null);
// expected, no Exception thrown out, test success
}
@Test
public void testGetOpacity() {
AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
// Drawable#getOpacity is deprecated, AdaptiveIconDrawable
// should return PixelFormat.TRANSLUCENT always
iconDrawable.setOpacity(PixelFormat.OPAQUE);
assertEquals(PixelFormat.TRANSLUCENT, iconDrawable.getOpacity());
iconDrawable.setOpacity(PixelFormat.TRANSPARENT);
assertEquals(PixelFormat.TRANSLUCENT, iconDrawable.getOpacity());
}
@Test
public void testIsStateful() {
AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
assertFalse(iconDrawable.isStateful());
iconDrawable = new AdaptiveIconDrawable(new StateListDrawable(), new ColorDrawable(Color.RED));
assertTrue(iconDrawable.isStateful());
}
@Test
public void testGetConstantState() {
AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
ConstantState constantState = iconDrawable.getConstantState();
assertNotNull(constantState);
}
@Test
public void testMutate() {
// Obtain the first instance, then mutate and modify a property held by
// constant state. If mutate() works correctly, the property should not
// be modified on the second or third instances.
Resources res = InstrumentationRegistry.getTargetContext().getResources();
AdaptiveIconDrawable first = (AdaptiveIconDrawable) res.getDrawable(R.drawable.adaptive_icon_drawable, null);
AdaptiveIconDrawable pre = (AdaptiveIconDrawable) res.getDrawable(R.drawable.adaptive_icon_drawable, null);
first.mutate().setBounds(0, 0, 100, 100);
assertEquals("Modified first loaded instance", 100, first.getBounds().width());
assertEquals("Did not modify pre-mutate() instance", 0, pre.getBounds().width());
AdaptiveIconDrawable post = (AdaptiveIconDrawable) res.getDrawable(R.drawable.adaptive_icon_drawable, null);
assertEquals("Did not modify post-mutate() instance", 0, post.getBounds().width());
}
@Test
public void testGetForegroundBackground() {
Context context = InstrumentationRegistry.getTargetContext();
AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
new ColorDrawable(Color.RED), new ColorDrawable(Color.BLUE));
Drawable fgDrawable = iconDrawable.getForeground();
Drawable bgDrawable = iconDrawable.getBackground();
assertTrue("Foreground layer is color drawable.", fgDrawable instanceof ColorDrawable);
assertTrue("Backgroud layer is color drawable.", bgDrawable instanceof ColorDrawable);
AdaptiveIconDrawable iconDrawableInflated =
(AdaptiveIconDrawable) context.getDrawable(R.drawable.adaptive_icon_drawable);
fgDrawable = iconDrawableInflated.getForeground();
bgDrawable = iconDrawableInflated.getBackground();
assertTrue("Foreground layer is color drawable.", fgDrawable instanceof BitmapDrawable);
assertTrue("Backgroud layer is color drawable.", bgDrawable instanceof BitmapDrawable);
}
@Test
public void testGetIntrinsicWidth() {
Context context = InstrumentationRegistry.getTargetContext();
AdaptiveIconDrawable iconDrawableInflated =
(AdaptiveIconDrawable) context.getDrawable(R.drawable.adaptive_icon_drawable);
int fgWidth = iconDrawableInflated.getForeground().getIntrinsicWidth();
int bgWidth = iconDrawableInflated.getBackground().getIntrinsicWidth();
float iconIntrinsicWidth = Math.max(fgWidth, bgWidth) / (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction());
assertEquals("Max intrinsic width of the layers should be icon's intrinsic width",
(int) iconIntrinsicWidth, iconDrawableInflated.getIntrinsicWidth());
}
@Test
public void testGetIntrinsicHeight() {
Context context = InstrumentationRegistry.getTargetContext();
AdaptiveIconDrawable iconDrawableInflated =
(AdaptiveIconDrawable) context.getDrawable(R.drawable.adaptive_icon_drawable);
int fgWidth = iconDrawableInflated.getForeground().getIntrinsicHeight();
int bgWidth = iconDrawableInflated.getBackground().getIntrinsicHeight();
float iconIntrinsicHeight = Math.max(fgWidth, bgWidth) / (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction());
assertEquals("Max intrinsic height of the layers should be icon's intrinsic height",
(int) iconIntrinsicHeight, iconDrawableInflated.getIntrinsicHeight());
}
//
// Utils
//
boolean equalBitmaps(Bitmap a, Bitmap b) {
return equalBitmaps(a, b, null);
}
boolean equalBitmaps(Bitmap a, Bitmap b, Region region) {
if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) return false;
final int w = a.getWidth();
final int h = a.getHeight();
int[] aPix = new int[w * h];
int[] bPix = new int[w * h];
if (region != null) {
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
int ra = (a.getPixel(i, j) >> 16) & 0xff;
int ga = (a.getPixel(i, j) >> 8) & 0xff;
int ba = a.getPixel(i, j) & 0xff;
int rb = (b.getPixel(i, j) >> 16) & 0xff;
int gb = (b.getPixel(i, j) >> 8) & 0xff;
int bb = b.getPixel(i, j) & 0xff;
if (region.contains(i, j) && a.getPixel(i, j) != b.getPixel(i, j) ) {
return false;
}
}
}
return true;
} else {
a.getPixels(aPix, 0, w, 0, 0, w, h);
b.getPixels(bPix, 0, w, 0, 0, w, h);
return Arrays.equals(aPix, bPix);
}
}
void findBitmapDifferences(Bitmap a, Bitmap b) {
if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) {
L("different sizes: %dx%d vs %dx%d",
a.getWidth(), a.getHeight(), b.getWidth(), b.getHeight());
return;
}
final int w = a.getWidth();
final int h = a.getHeight();
int[] aPix = new int[w * h];
int[] bPix = new int[w * h];
a.getPixels(aPix, 0, w, 0, 0, w, h);
b.getPixels(bPix, 0, w, 0, 0, w, h);
L("bitmap a (%dx%d)", w, h);
printBits(aPix, w, h);
L("bitmap b (%dx%d)", w, h);
printBits(bPix, w, h);
StringBuffer sb = new StringBuffer("Different pixels: ");
for (int i=0; i<w; i++) {
for (int j=0; j<h; j++) {
if (aPix[i+w*j] != bPix[i+w*j]) {
sb.append(" ").append(i).append(",").append(j).append("<")
.append(aPix[i+w*j]).append(",").append(bPix[i+w*j]).append(">");
}
}
}
L(sb.toString());
}
static void printBits(int[] a, int w, int h) {
final StringBuilder sb = new StringBuilder();
for (int i=0; i<w; i++) {
for (int j=0; j<h; j++) {
sb.append(colorToChar(a[i+w*j]));
}
sb.append('\n');
}
L(sb.toString());
}
static char colorToChar(int color) {
int sum = ((color >> 16) & 0xff)
+ ((color >> 8) & 0xff)
+ ((color) & 0xff);
return GRADIENT[sum * (GRADIENT.length-1) / (3*0xff)];
}
static final char[] GRADIENT = " .:;+=xX$#".toCharArray();
}