Fix support for enum attributes in BridgeContext
Test: Updated BridgeXmlPullAttributesTest Bug: http://b.android.com/231347 Change-Id: I5fd8b46155ccea6c9b65787f311a0887fa4b4806
This commit is contained in:
9
tools/layoutlib/.idea/libraries/mockito.xml
generated
Normal file
9
tools/layoutlib/.idea/libraries/mockito.xml
generated
Normal 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>
|
||||
9
tools/layoutlib/.idea/libraries/objenesis.xml
generated
Normal file
9
tools/layoutlib/.idea/libraries/objenesis.xml
generated
Normal 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>
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -31,7 +31,8 @@ LOCAL_JAVA_LIBRARIES := layoutlib \
|
||||
tools-common-prebuilt \
|
||||
sdk-common \
|
||||
junit-host \
|
||||
guavalib
|
||||
guavalib \
|
||||
mockito-host
|
||||
|
||||
include $(BUILD_HOST_JAVA_LIBRARY)
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user