package org.commcare.android.tests; import android.graphics.Bitmap; import android.util.DisplayMetrics; import org.commcare.CommCareApplication; import org.commcare.android.CommCareTestRunner; import org.commcare.utils.MediaUtil; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.annotation.Config; @Config(application = CommCareApplication.class) @RunWith(CommCareTestRunner.class) public class ImageInflationTest { private String imageFilepath; private DisplayMetrics lowDensityDevice; private DisplayMetrics mediumDensityDevice; private DisplayMetrics highDensityDevice; private static final int[] boundingDimens_RESTRICTIVE = {50, 50}; private static final int[] boundingDimens_LESS_RESTRICTIVE = {80, 80}; private static final int[] boundingDimens_UNRESTRICTIVE = {200, 200}; private static final int[] boundingDimens_LESS_UNRESTRICTIVE = {150, 150}; private DisplayMetrics createFakeDisplayMetrics(int screenDensity) { DisplayMetrics metrics = new DisplayMetrics(); metrics.densityDpi = screenDensity; metrics.density = (float)screenDensity / DisplayMetrics.DENSITY_DEFAULT; return metrics; } private void testCorrectInflationWithoutDensity(int[] boundingDimens, int expectedNewDimen) { Bitmap b = MediaUtil.getBitmapScaledToContainer(imageFilepath, boundingDimens[0], boundingDimens[1], true); Assert.assertNotNull(b); Assert.assertEquals(expectedNewDimen, b.getWidth()); Assert.assertEquals(expectedNewDimen, b.getHeight()); } private void testCorrectInflationWithDensity(int targetDensity, DisplayMetrics mockDevice, int[] boundingDimens, int expectedNewDimen) { Bitmap b = MediaUtil.getBitmapScaledForNativeDensity(mockDevice, imageFilepath, boundingDimens[0], boundingDimens[1], targetDensity); Assert.assertNotNull(b); Assert.assertEquals(expectedNewDimen, b.getWidth()); Assert.assertEquals(expectedNewDimen, b.getHeight()); } @Before public void init() { imageFilepath = "/images/100x100.png"; lowDensityDevice = createFakeDisplayMetrics(DisplayMetrics.DENSITY_LOW); mediumDensityDevice = createFakeDisplayMetrics(DisplayMetrics.DENSITY_MEDIUM); highDensityDevice = createFakeDisplayMetrics(DisplayMetrics.DENSITY_HIGH); } @Test public void testScaleFactorComputationSimple() { Assert.assertEquals((double)160 / 280, MediaUtil.computeInflationScaleFactor(mediumDensityDevice, DisplayMetrics.DENSITY_280), .1); } // When the device's native density is something other than the standard value of // (device_density / default_density), our custom scale factor should be adjusted by the // same proportions @Test public void testScaleFactorComputationComplex1() { // the expected value of density for a 160 dpi device is 160/160 = 1, so this is 10% larger mediumDensityDevice.density = (float)1.1; Assert.assertEquals((double)160 / 280 * 1.1, MediaUtil.computeInflationScaleFactor(mediumDensityDevice, DisplayMetrics.DENSITY_280), .1); } @Test public void testScaleFactorComputationComplex2() { // the expected value of density for 120dpi device is 120/160 = .75, so this is 33% smaller lowDensityDevice.density = (float)0.5; Assert.assertEquals((double)120 / 280 * ((double)2 / 3), MediaUtil.computeInflationScaleFactor(lowDensityDevice, DisplayMetrics.DENSITY_280), .1); } @Test public void testInflationWithoutDensity_noChange() { testCorrectInflationWithoutDensity(boundingDimens_UNRESTRICTIVE, 100); } @Test public void testInflationWithoutDensity_shouldChange() { testCorrectInflationWithoutDensity(boundingDimens_RESTRICTIVE, 50); } @Test public void testDoNoScaling() { // Low density device with low density target should result in no size change int targetDensity = DisplayMetrics.DENSITY_LOW; testCorrectInflationWithDensity(targetDensity, lowDensityDevice, boundingDimens_UNRESTRICTIVE, 100); } @Test public void testScaleUpDueToDensity() { // Medium density device with low density target should result in image being scaled up // by a factor of 160/120 = 1.33 int targetDensity = DisplayMetrics.DENSITY_LOW; testCorrectInflationWithDensity(targetDensity, mediumDensityDevice, boundingDimens_UNRESTRICTIVE, 133); } @Test public void testScaleDownDueToDensity() { // Low density device with medium density target should result in image being scaled down // by a factor of 120/160 = .75 int targetDensity = DisplayMetrics.DENSITY_MEDIUM; testCorrectInflationWithDensity(targetDensity, lowDensityDevice, boundingDimens_UNRESTRICTIVE, 75); } @Test public void testScaleUpLimitedByContainer() { // High density device with low density target should result in image being scaled up by a // factor of 240 / 120 = 2, which would mean a final size of 200. However, the actual // scale-up should be bounded to 150 by the container int targetDensity = DisplayMetrics.DENSITY_LOW; testCorrectInflationWithDensity(targetDensity, highDensityDevice, boundingDimens_LESS_UNRESTRICTIVE, 150); } @Test public void testScaleDownDueToContainer_noDensityEffect() { // Low density device with low density target means no change based on density, but // restrictive container causes scale down int targetDensity = DisplayMetrics.DENSITY_MEDIUM; testCorrectInflationWithDensity(targetDensity, mediumDensityDevice, boundingDimens_RESTRICTIVE, 50); } @Test public void testScaleDownDueToContainer_densityWouldIncrease() { // Medium density device with low density target would cause an upscale based on density, // but the scale down imposed by a restrictive container should be what actual takes effect int targetDensity = DisplayMetrics.DENSITY_LOW; testCorrectInflationWithDensity(targetDensity, mediumDensityDevice, boundingDimens_RESTRICTIVE, 50); } @Test public void testScaleDownDueToBoth_densityDominant() { // Both the container size and the relative densities impose scale down requirements, // but the density factor imposes a larger scale down, so we scale to those dimens int targetDensity = DisplayMetrics.DENSITY_MEDIUM; testCorrectInflationWithDensity(targetDensity, lowDensityDevice, boundingDimens_LESS_RESTRICTIVE, 75); } @Test public void testScaleDownDueToBoth_containerDominant() { // Both the container size and the relative densities impose scale down requirements, // but the container restrictions impose a larger scale down, so we scale to those dimens int targetDensity = DisplayMetrics.DENSITY_MEDIUM; testCorrectInflationWithDensity(targetDensity, lowDensityDevice, boundingDimens_RESTRICTIVE, 50); } }