Fix support for enum attributes in BridgeContext

Test: Updated BridgeXmlPullAttributesTest
Bug: http://b.android.com/231347
Change-Id: I5fd8b46155ccea6c9b65787f311a0887fa4b4806
This commit is contained in:
Diego Perez
2017-01-18 14:54:04 +00:00
parent 6c149326d8
commit abb080d749
7 changed files with 193 additions and 36 deletions

View File

@@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="mockito">
<CLASSES>
<root url="jar://$PROJECT_DIR$/../../../../out/host/common/obj/JAVA_LIBRARIES/mockito-host_intermediates/javalib.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="objenesis">
<CLASSES>
<root url="jar://$PROJECT_DIR$/../../../../out/host/common/obj/JAVA_LIBRARIES/objenesis-host_intermediates/javalib.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@@ -86,5 +86,7 @@
</library>
</orderEntry>
<orderEntry type="library" scope="TEST" name="junit" level="project" />
<orderEntry type="library" scope="TEST" name="mockito" level="project" />
<orderEntry type="library" scope="TEST" name="objenesis" level="project" />
</component>
</module>

View File

@@ -16,6 +16,7 @@
package android.util;
import com.android.ide.common.rendering.api.AttrResourceValue;
import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.internal.util.XmlUtils;
@@ -27,6 +28,11 @@ import com.android.resources.ResourceType;
import org.xmlpull.v1.XmlPullParser;
import android.annotation.NonNull;
import java.util.Map;
import java.util.function.Function;
/**
* A correct implementation of the {@link AttributeSet} interface on top of a XmlPullParser
*/
@@ -34,12 +40,30 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes {
private final BridgeContext mContext;
private final boolean mPlatformFile;
private final Function<String, Map<String, Integer>> mFrameworkEnumValueSupplier;
private final Function<String, Map<String, Integer>> mProjectEnumValueSupplier;
public BridgeXmlPullAttributes(XmlPullParser parser, BridgeContext context,
boolean platformFile) {
// VisibleForTesting
BridgeXmlPullAttributes(@NonNull XmlPullParser parser, @NonNull BridgeContext context,
boolean platformFile,
@NonNull Function<String, Map<String, Integer>> frameworkEnumValueSupplier,
@NonNull Function<String, Map<String, Integer>> projectEnumValueSupplier) {
super(parser);
mContext = context;
mPlatformFile = platformFile;
mFrameworkEnumValueSupplier = frameworkEnumValueSupplier;
mProjectEnumValueSupplier = projectEnumValueSupplier;
}
public BridgeXmlPullAttributes(@NonNull XmlPullParser parser, @NonNull BridgeContext context,
boolean platformFile) {
this(parser, context, platformFile, Bridge::getEnumValues, attrName -> {
// get the styleable matching the resolved name
RenderResources res = context.getRenderResources();
ResourceValue attr = res.getProjectResource(ResourceType.ATTR, attrName);
return attr instanceof AttrResourceValue ?
((AttrResourceValue) attr).getAttributeValues() : null;
});
}
/*
@@ -59,12 +83,8 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes {
String ns = mParser.getAttributeNamespace(index);
if (BridgeConstants.NS_RESOURCES.equals(ns)) {
Integer v = Bridge.getResourceId(ResourceType.ATTR, name);
if (v != null) {
return v.intValue();
}
return Bridge.getResourceId(ResourceType.ATTR, name);
return 0;
}
// this is not an attribute in the android namespace, we query the customviewloader, if
@@ -72,7 +92,7 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes {
if (mContext.getLayoutlibCallback().getNamespace().equals(ns)) {
Integer v = mContext.getLayoutlibCallback().getResourceId(ResourceType.ATTR, name);
if (v != null) {
return v.intValue();
return v;
}
}
@@ -121,20 +141,38 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes {
}
@Override
public int getAttributeIntValue(String namespace, String attribute,
int defaultValue) {
public int getAttributeIntValue(String namespace, String attribute, int defaultValue) {
String value = getAttributeValue(namespace, attribute);
if (value != null) {
ResourceValue r = getResourceValue(value);
if (r != null) {
value = r.getValue();
}
return XmlUtils.convertValueToInt(value, defaultValue);
if (value == null) {
return defaultValue;
}
return defaultValue;
ResourceValue r = getResourceValue(value);
if (r != null) {
value = r.getValue();
}
if (value.charAt(0) == '#') {
return ResourceHelper.getColor(value);
}
try {
return XmlUtils.convertValueToInt(value, defaultValue);
} catch (NumberFormatException e) {
// This is probably an enum
Map<String, Integer> enumValues = BridgeConstants.NS_RESOURCES.equals(namespace) ?
mFrameworkEnumValueSupplier.apply(attribute) :
mProjectEnumValueSupplier.apply(attribute);
Integer enumValue = enumValues != null ? enumValues.get(value) : null;
if (enumValue != null) {
return enumValue;
}
// We weren't able to find the enum int value
throw e;
}
}
@Override
@@ -203,21 +241,9 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes {
@Override
public int getAttributeIntValue(int index, int defaultValue) {
String value = getAttributeValue(index);
if (value != null) {
ResourceValue r = getResourceValue(value);
if (r != null) {
value = r.getValue();
}
if (value.charAt(0) == '#') {
return ResourceHelper.getColor(value);
}
return XmlUtils.convertValueToInt(value, defaultValue);
}
return defaultValue;
return getAttributeIntValue(mParser.getAttributeNamespace(index),
getAttributeName(index)
, defaultValue);
}
@Override

View File

@@ -111,7 +111,7 @@ import static com.android.layoutlib.bridge.android.RenderParamsFlags.FLAG_KEY_AP
* Custom implementation of Context/Activity to handle non compiled resources.
*/
@SuppressWarnings("deprecation") // For use of Pair.
public final class BridgeContext extends Context {
public class BridgeContext extends Context {
private static final String PREFIX_THEME_APPCOMPAT = "Theme.AppCompat";
private static final Map<String, ResourceValue> FRAMEWORK_PATCHED_VALUES = new HashMap<>(2);

View File

@@ -31,7 +31,8 @@ LOCAL_JAVA_LIBRARIES := layoutlib \
tools-common-prebuilt \
sdk-common \
junit-host \
guavalib
guavalib \
mockito-host
include $(BUILD_HOST_JAVA_LIBRARY)

View File

@@ -0,0 +1,110 @@
/*
* Copyright (C) 2017 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.util;
import com.android.ide.common.rendering.api.RenderResources;
import com.android.layoutlib.bridge.BridgeConstants;
import com.android.layoutlib.bridge.android.BridgeContext;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParser;
import com.google.common.collect.ImmutableMap;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class BridgeXmlPullAttributesTest {
@Test
public void testGetAttributeIntValueForEnums() {
RenderResources renderResources = new RenderResources();
XmlPullParser parser = mock(XmlPullParser.class);
when(parser.getAttributeValue(BridgeConstants.NS_RESOURCES, "layout_width"))
.thenReturn("match_parent");
when(parser.getAttributeName(0)).thenReturn("layout_width");
when(parser.getAttributeNamespace(0)).thenReturn(BridgeConstants.NS_RESOURCES);
// Return every value twice since there is one test using name and other using index
when(parser.getAttributeValue("http://custom", "my_custom_attr"))
.thenReturn("a", "a", "b", "b", "invalid", "invalid");
when(parser.getAttributeName(1)).thenReturn("my_custom_attr");
when(parser.getAttributeNamespace(1)).thenReturn("http://custom");
BridgeContext context = mock(BridgeContext.class);
when(context.getRenderResources()).thenReturn(renderResources);
BridgeXmlPullAttributes attributes = new BridgeXmlPullAttributes(
parser,
context,
false,
attrName -> {
if ("layout_width".equals(attrName)) {
return ImmutableMap.of(
"match_parent", 123);
}
return ImmutableMap.of();
},
attrName -> {
if ("my_custom_attr".equals(attrName)) {
return ImmutableMap.of(
"a", 1,
"b", 2
);
}
return ImmutableMap.of();
});
// Test a framework defined enum attribute
assertEquals(123, attributes.getAttributeIntValue(BridgeConstants.NS_RESOURCES,
"layout_width", 500));
assertEquals(123, attributes.getAttributeIntValue(0, 500));
// Test non existing attribute (it should return the default value)
assertEquals(500, attributes.getAttributeIntValue(BridgeConstants.NS_RESOURCES,
"layout_height", 500));
assertEquals(500, attributes.getAttributeIntValue(2, 500));
// Test project defined enum attribute
assertEquals(1, attributes.getAttributeIntValue("http://custom",
"my_custom_attr", 500));
assertEquals(1, attributes.getAttributeIntValue(1, 500));
assertEquals(2, attributes.getAttributeIntValue("http://custom",
"my_custom_attr", 500));
assertEquals(2, attributes.getAttributeIntValue(1, 500));
// Test an invalid enum
boolean exception = false;
try {
attributes.getAttributeIntValue("http://custom", "my_custom_attr", 500);
} catch(NumberFormatException e) {
exception = true;
}
assertTrue(exception);
exception = false;
try {
attributes.getAttributeIntValue(1, 500);
} catch(NumberFormatException e) {
exception = true;
}
assertTrue(exception);
// Test non existing project attribute
assertEquals(500, attributes.getAttributeIntValue("http://custom",
"my_other_attr", 500));
}
}