CTS test for changing GradientDrawable density

Bug: 25081461
Change-Id: I75e211d5d745f2f10fc05ae2ac078eb2c1bad09e
diff --git a/tests/tests/graphics/res/drawable/gradient_drawable_density.xml b/tests/tests/graphics/res/drawable/gradient_drawable_density.xml
new file mode 100644
index 0000000..ad3a3be
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/gradient_drawable_density.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="ring"
+    android:innerRadius="10dp"
+    android:thickness="4dp">
+    <gradient
+        android:gradientRadius="10dp" />
+    <corners
+        android:topLeftRadius="8dp"
+        android:topRightRadius="9dp"
+        android:bottomLeftRadius="10dp"
+        android:bottomRightRadius="11dp" />
+    <padding
+        android:left="11dp"
+        android:top="12dp"
+        android:right="13dp"
+        android:bottom="14dp" />
+    <stroke
+        android:color="@android:color/black"
+        android:dashGap="4dp"
+        android:dashWidth="4dp"
+        android:width="2dp" />
+    <size
+        android:width="200dp"
+        android:height="200dp" />
+</shape>
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTestUtils.java b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTestUtils.java
index a0fa634..53bc987 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTestUtils.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTestUtils.java
@@ -16,15 +16,17 @@
 
 package android.graphics.drawable.cts;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.util.AttributeSet;
 import android.util.Xml;
 
 import java.io.IOException;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 /**
  * The useful methods for graphics.drawable test.
  */
@@ -85,4 +87,22 @@
         }
         return attrs;
     }
+
+    public static XmlResourceParser getResourceParser(Resources res, int resId)
+            throws XmlPullParserException, IOException {
+        final XmlResourceParser parser = res.getXml(resId);
+        int type;
+        while ((type = parser.next()) != XmlPullParser.START_TAG
+                && type != XmlPullParser.END_DOCUMENT) {
+            // Empty loop
+        }
+        return parser;
+    }
+
+    public static void setResourcesDensity(Resources res, int densityDpi) {
+        final Configuration config = new Configuration();
+        config.setTo(res.getConfiguration());
+        config.densityDpi = densityDpi;
+        res.updateConfiguration(config, null);
+    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
index 1cecd5d..97def25 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
@@ -16,6 +16,8 @@
 
 package android.graphics.drawable.cts;
 
+import android.content.res.Resources.Theme;
+import android.content.res.XmlResourceParser;
 import android.graphics.cts.R;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -320,4 +322,70 @@
         assertEquals(50, d3.getIntrinsicHeight());
         assertEquals(40, d3.getIntrinsicWidth());
     }
+
+    public void testPreloadDensity() throws XmlPullParserException, IOException {
+        final Resources res = getContext().getResources();
+        final int densityDpi = res.getConfiguration().densityDpi;
+        final Rect tempPadding = new Rect();
+
+        // Capture initial state at default density.
+        final XmlResourceParser parser = DrawableTestUtils.getResourceParser(
+                res, R.drawable.gradient_drawable_density);
+        final GradientDrawable preloadedDrawable = new GradientDrawable();
+        preloadedDrawable.inflate(res, parser, Xml.asAttributeSet(parser));
+        final ConstantState preloadedConstantState = preloadedDrawable.getConstantState();
+        final int origWidth = preloadedDrawable.getIntrinsicWidth();
+        final int origHeight = preloadedDrawable.getIntrinsicHeight();
+        final Rect origPadding = new Rect();
+        preloadedDrawable.getPadding(origPadding);
+
+        // Set density to half of original. Unlike offsets, which are
+        // truncated, dimensions are rounded to the nearest pixel.
+        DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
+        final GradientDrawable halfDrawable =
+                (GradientDrawable) preloadedConstantState.newDrawable(res);
+        assertEquals(Math.round(origWidth / 2f), halfDrawable.getIntrinsicWidth());
+        assertEquals(Math.round(origHeight / 2f), halfDrawable.getIntrinsicHeight());
+        assertTrue(halfDrawable.getPadding(tempPadding));
+        assertEquals(Math.round(origPadding.left / 2f), tempPadding.left);
+
+        // Set density to double original.
+        DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
+        final GradientDrawable doubleDrawable =
+                (GradientDrawable) preloadedConstantState.newDrawable(res);
+        assertEquals(origWidth * 2, doubleDrawable.getIntrinsicWidth());
+        assertEquals(origHeight * 2, doubleDrawable.getIntrinsicHeight());
+        assertTrue(doubleDrawable.getPadding(tempPadding));
+        assertEquals(origPadding.left * 2, tempPadding.left);
+
+        // Restore original density.
+        DrawableTestUtils.setResourcesDensity(res, densityDpi);
+        final GradientDrawable origDrawable =
+                (GradientDrawable) preloadedConstantState.newDrawable();
+        assertEquals(origWidth, origDrawable.getIntrinsicWidth());
+        assertEquals(origHeight, origDrawable.getIntrinsicHeight());
+        assertTrue(origDrawable.getPadding(tempPadding));
+        assertEquals(origPadding, tempPadding);
+
+        // Some precision is lost when scaling the half-density
+        // drawable back up to the original density.
+        final Rect sloppyOrigPadding = new Rect();
+        sloppyOrigPadding.left = 2 * Math.round(origPadding.left / 2f);
+        sloppyOrigPadding.top = 2 * Math.round(origPadding.top / 2f);
+        sloppyOrigPadding.right = 2 * Math.round(origPadding.right / 2f);
+        sloppyOrigPadding.bottom = 2 * Math.round(origPadding.bottom / 2f);
+
+        // Ensure theme density is applied correctly.
+        final Theme t = res.newTheme();
+        halfDrawable.applyTheme(t);
+        assertEquals(2 * Math.round(origWidth / 2f), halfDrawable.getIntrinsicWidth());
+        assertEquals(2 * Math.round(origHeight / 2f), halfDrawable.getIntrinsicHeight());
+        assertTrue(halfDrawable.getPadding(tempPadding));
+        assertEquals(sloppyOrigPadding, tempPadding);
+        doubleDrawable.applyTheme(t);
+        assertEquals(origWidth, doubleDrawable.getIntrinsicWidth());
+        assertEquals(origHeight, doubleDrawable.getIntrinsicHeight());
+        assertTrue(doubleDrawable.getPadding(tempPadding));
+        assertEquals(origPadding, tempPadding);
+    }
 }