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);
+ }
+}