Merge "Fallback to regular XML Drawable if ColorStateList loading fails"
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 77796d9..d8564d5 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -855,13 +855,9 @@
             try {
                 if (file.endsWith(".xml")) {
                     if (file.startsWith("res/color/")) {
-                        ColorStateList csl = loadColorStateList(wrapper, value, id, null);
-                        dr = (csl != null ? new ColorStateListDrawable(csl) : null);
+                        dr = loadColorOrXmlDrawable(wrapper, value, id, density, file);
                     } else {
-                        final XmlResourceParser rp = loadXmlResourceParser(
-                                file, id, value.assetCookie, "drawable");
-                        dr = Drawable.createFromXmlForDensity(wrapper, rp, density, null);
-                        rp.close();
+                        dr = loadXmlDrawable(wrapper, value, id, density, file);
                     }
                 } else {
                     final InputStream is = mAssets.openNonAsset(
@@ -915,6 +911,33 @@
         return dr;
     }
 
+    private Drawable loadColorOrXmlDrawable(@NonNull Resources wrapper, @NonNull TypedValue value,
+            int id, int density, String file) {
+        try {
+            ColorStateList csl = loadColorStateList(wrapper, value, id, null);
+            return new ColorStateListDrawable(csl);
+        } catch (NotFoundException originalException) {
+            // If we fail to load as color, try as normal XML drawable
+            try {
+                return loadXmlDrawable(wrapper, value, id, density, file);
+            } catch (Exception ignored) {
+                // If fallback also fails, throw the original exception
+                throw originalException;
+            }
+        }
+    }
+
+    private Drawable loadXmlDrawable(@NonNull Resources wrapper, @NonNull TypedValue value,
+            int id, int density, String file)
+            throws IOException, XmlPullParserException {
+        try (
+                XmlResourceParser rp =
+                        loadXmlResourceParser(file, id, value.assetCookie, "drawable")
+        ) {
+            return Drawable.createFromXmlForDensity(wrapper, rp, density, null);
+        }
+    }
+
     /**
      * Loads a font from XML or resources stream.
      */
diff --git a/core/tests/coretests/README b/core/tests/coretests/README
index ea282a0..34beb45 100644
--- a/core/tests/coretests/README
+++ b/core/tests/coretests/README
@@ -30,9 +30,9 @@
 
   adb install -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
   adb shell am instrument -w \
-    com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+    com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
 
-To run a tests within a specific package, add the following argument AFTER -w:
+To run a tests within a specific package, add -e AFTER -w and before the runner class:
 
     -e package android.content.pm
 
diff --git a/core/tests/coretests/res/color/drawable_in_color_dir_invalid.xml b/core/tests/coretests/res/color/drawable_in_color_dir_invalid.xml
new file mode 100644
index 0000000..8d630b0
--- /dev/null
+++ b/core/tests/coretests/res/color/drawable_in_color_dir_invalid.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+
+<!-- This drawable is purposely in the color directory to test a backwards compatible fallback. -->
+<layer-list
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@android:id/icon" android:drawable="@string/app_name" />
+</layer-list>
\ No newline at end of file
diff --git a/core/tests/coretests/res/color/drawable_in_color_dir_valid.xml b/core/tests/coretests/res/color/drawable_in_color_dir_valid.xml
new file mode 100644
index 0000000..d140475
--- /dev/null
+++ b/core/tests/coretests/res/color/drawable_in_color_dir_valid.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+
+<!-- This drawable is purposely in the color directory to test a backwards compatible fallback. -->
+<layer-list
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@android:id/background" android:drawable="@drawable/test32x24" />
+    <item android:id="@android:id/icon" android:drawable="@drawable/test16x12" />
+</layer-list>
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/content/res/ResourcesDrawableTest.java b/core/tests/coretests/src/android/content/res/ResourcesDrawableTest.java
new file mode 100644
index 0000000..c4df88b
--- /dev/null
+++ b/core/tests/coretests/src/android/content/res/ResourcesDrawableTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.content.res;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.graphics.drawable.ColorStateListDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ResourcesDrawableTest {
+
+    @Test
+    public void testLoadColorAsDrawable() {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        Resources resources = context.getResources();
+        Drawable drawable = resources.getDrawable(R.color.color1);
+        assertTrue(drawable instanceof ColorStateListDrawable);
+    }
+
+    @Test
+    public void testLoadColorAsDrawableFailureThrowsOriginalException() throws Throwable {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        Resources resources = context.getResources();
+
+        Exception exception = null;
+
+        try {
+            resources.getDrawable(R.color.drawable_in_color_dir_invalid);
+        } catch (Exception e) {
+            exception = e;
+        }
+
+        assertNotNull(
+                "Loading drawable_in_color_dir_invalid should throw an exception",
+                exception
+        );
+
+        assertEquals(
+                "Can't find ColorStateList from drawable resource ID #0x"
+                        + Integer.toHexString(R.color.drawable_in_color_dir_invalid),
+                exception.getCause().getCause().getMessage()
+        );
+    }
+
+    @Test
+    public void testLoadNormalDrawableInColorDir() {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        Resources resources = context.getResources();
+        Drawable drawable = resources.getDrawable(R.color.drawable_in_color_dir_valid);
+        assertTrue(drawable instanceof LayerDrawable);
+    }
+}