Merge "Update layoutlib following platform change in VectorDrawable"
diff --git a/bridge/src/android/graphics/Path_Delegate.java b/bridge/src/android/graphics/Path_Delegate.java
index 265ebd1..219c487 100644
--- a/bridge/src/android/graphics/Path_Delegate.java
+++ b/bridge/src/android/graphics/Path_Delegate.java
@@ -86,6 +86,8 @@
public void reset() {
mPath.reset();
+ mLastX = 0;
+ mLastY = 0;
}
public void setPathIterator(PathIterator iterator) {
@@ -124,7 +126,7 @@
return;
}
- pathDelegate.mPath.reset();
+ pathDelegate.reset();
}
@LayoutlibDelegate
diff --git a/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java b/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
index 34db24e..2b969cc 100644
--- a/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
+++ b/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
@@ -1149,7 +1149,8 @@
}
final Paint fillPaint = mFillPaint;
- fillPaint.setColor(applyAlpha(fullPath.mFillColor, fullPath.mFillAlpha));
+ fillPaint.setColor(applyAlpha(applyAlpha(fullPath.mFillColor, fullPath
+ .mFillAlpha), getRootAlpha()));
Paint_Delegate fillPaintDelegate = Paint_Delegate.getDelegate(fillPaint
.getNativeInstance());
// mFillPaint can not be null at this point so we will have a delegate
@@ -1178,7 +1179,8 @@
}
strokePaint.setStrokeMiter(fullPath.mStrokeMiterlimit);
- strokePaint.setColor(applyAlpha(fullPath.mStrokeColor, fullPath.mStrokeAlpha));
+ strokePaint.setColor(applyAlpha(applyAlpha(fullPath.mStrokeColor, fullPath
+ .mStrokeAlpha), getRootAlpha()));
Paint_Delegate strokePaintDelegate = Paint_Delegate.getDelegate(strokePaint
.getNativeInstance());
// mStrokePaint can not be null at this point so we will have a delegate
diff --git a/bridge/src/android/view/BridgeInflater.java b/bridge/src/android/view/BridgeInflater.java
index bdddfd8..f38fb19 100644
--- a/bridge/src/android/view/BridgeInflater.java
+++ b/bridge/src/android/view/BridgeInflater.java
@@ -39,6 +39,7 @@
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import android.widget.NumberPicker;
import java.io.File;
import java.util.HashMap;
@@ -144,9 +145,26 @@
@Override
public View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
boolean ignoreThemeAttr) {
- View view;
+ View view = null;
+ if (name.equals("view")) {
+ // This is usually done by the superclass but this allows us catching the error and
+ // reporting something useful.
+ name = attrs.getAttributeValue(null, "class");
+
+ if (name == null) {
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Unable to inflate view tag without " +
+ "class attribute", null);
+ // We weren't able to resolve the view so we just pass a mock View to be able to
+ // continue rendering.
+ view = new MockView(context, attrs);
+ ((MockView) view).setText("view");
+ }
+ }
+
try {
- view = super.createViewFromTag(parent, name, context, attrs, ignoreThemeAttr);
+ if (view == null) {
+ view = super.createViewFromTag(parent, name, context, attrs, ignoreThemeAttr);
+ }
} catch (InflateException e) {
// Creation of ContextThemeWrapper code is same as in the super method.
// Apply a theme wrapper, if allowed and one is specified.
@@ -240,6 +258,9 @@
// first get the classname in case it's not the node name
if (name.equals("view")) {
name = attrs.getAttributeValue(null, "class");
+ if (name == null) {
+ return null;
+ }
}
mConstructorArgs[1] = attrs;
@@ -300,6 +321,17 @@
getDrawerLayoutMap().put(view, attrVal);
}
}
+ else if (view instanceof NumberPicker) {
+ NumberPicker numberPicker = (NumberPicker) view;
+ String minValue = attrs.getAttributeValue(BridgeConstants.NS_TOOLS_URI, "minValue");
+ if (minValue != null) {
+ numberPicker.setMinValue(Integer.parseInt(minValue));
+ }
+ String maxValue = attrs.getAttributeValue(BridgeConstants.NS_TOOLS_URI, "maxValue");
+ if (maxValue != null) {
+ numberPicker.setMaxValue(Integer.parseInt(maxValue));
+ }
+ }
}
}
diff --git a/bridge/src/android/view/RectShadowPainter.java b/bridge/src/android/view/RectShadowPainter.java
index ea9a255..d15cb48 100644
--- a/bridge/src/android/view/RectShadowPainter.java
+++ b/bridge/src/android/view/RectShadowPainter.java
@@ -54,12 +54,18 @@
if (saved == -1) {
return;
}
+
+ float radius = viewOutline.getRadius();
+ if (radius <= 0) {
+ // We can not paint a shadow with radius 0
+ return;
+ }
+
try {
Paint cornerPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
cornerPaint.setStyle(Style.FILL);
Paint edgePaint = new Paint(cornerPaint);
edgePaint.setAntiAlias(false);
- float radius = viewOutline.getRadius();
float outerArcRadius = radius + shadowSize;
int[] colors = {START_COLOR, START_COLOR, END_COLOR};
cornerPaint.setShader(new RadialGradient(0, 0, outerArcRadius, colors,
diff --git a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index f87269b..194eecc 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -831,45 +831,55 @@
}
}
- // if there's no direct value for this attribute in the XML, we look for default
- // values in the widget defStyle, and then in the theme.
- if (value == null) {
- ResourceValue resValue = null;
-
+ // Calculate the default value from the Theme in two cases:
+ // - If defaultPropMap is not null, get the default value to add it to the list
+ // of default values of properties.
+ // - If value is null, it means that the attribute is not directly set as an
+ // attribute in the XML so try to get the default value.
+ ResourceValue defaultValue = null;
+ if (defaultPropMap != null || value == null) {
// look for the value in the custom style first (and its parent if needed)
if (customStyleValues != null) {
- resValue = mRenderResources.findItemInStyle(customStyleValues,
- attrName, frameworkAttr);
+ defaultValue = mRenderResources.findItemInStyle(customStyleValues, attrName,
+ frameworkAttr);
}
// then look for the value in the default Style (and its parent if needed)
- if (resValue == null && defStyleValues != null) {
- resValue = mRenderResources.findItemInStyle(defStyleValues,
- attrName, frameworkAttr);
+ if (defaultValue == null && defStyleValues != null) {
+ defaultValue = mRenderResources.findItemInStyle(defStyleValues, attrName,
+ frameworkAttr);
}
// if the item is not present in the defStyle, we look in the main theme (and
// its parent themes)
- if (resValue == null) {
- resValue = mRenderResources.findItemInTheme(attrName, frameworkAttr);
+ if (defaultValue == null) {
+ defaultValue = mRenderResources.findItemInTheme(attrName, frameworkAttr);
}
// if we found a value, we make sure this doesn't reference another value.
// So we resolve it.
- if (resValue != null) {
- String preResolve = resValue.getValue();
- resValue = mRenderResources.resolveResValue(resValue);
+ if (defaultValue != null) {
+ String preResolve = defaultValue.getValue();
+ defaultValue = mRenderResources.resolveResValue(defaultValue);
if (defaultPropMap != null) {
defaultPropMap.put(
frameworkAttr ? SdkConstants.PREFIX_ANDROID + attrName :
- attrName,
- new Property(preResolve, resValue.getValue()));
+ attrName, new Property(preResolve, defaultValue.getValue()));
}
+ }
+ }
+ // Done calculating the defaultValue
+ // if there's no direct value for this attribute in the XML, we look for default
+ // values in the widget defStyle, and then in the theme.
+ if (value == null) {
+ // if we found a value, we make sure this doesn't reference another value.
+ // So we resolve it.
+ if (defaultValue != null) {
// If the value is a reference to another theme attribute that doesn't
// exist, we should log a warning and omit it.
- String val = resValue.getValue();
+ String val = defaultValue.getValue();
if (val != null && val.startsWith(SdkConstants.PREFIX_THEME_REF)) {
if (!attrName.equals(RTL_ATTRS.get(val)) ||
getApplicationInfo().targetSdkVersion <
@@ -880,11 +890,11 @@
String.format("Failed to find '%s' in current theme.", val),
val);
}
- resValue = null;
+ defaultValue = null;
}
}
- ta.bridgeSetValue(index, attrName, frameworkAttr, resValue);
+ ta.bridgeSetValue(index, attrName, frameworkAttr, defaultValue);
} else {
// there is a value in the XML, but we need to resolve it in case it's
// referencing another resource or a theme value.
@@ -1799,6 +1809,12 @@
}
@Override
+ public Display getDisplay() {
+ // pass
+ return null;
+ }
+
+ @Override
public int getUserId() {
return 0; // not used
}
diff --git a/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
index 3f276c9..ab73a8b 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
@@ -16,11 +16,13 @@
package com.android.layoutlib.bridge.android;
+import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
import com.android.internal.view.IInputMethodManager;
import com.android.internal.view.InputBindResult;
+import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -239,4 +241,11 @@
// TODO Auto-generated method stub
return null;
}
+
+ @Override
+ public IInputContentUriToken createInputContentUriToken(IBinder token, Uri contentUri,
+ String packageName) {
+ // TODO Auto-generated method stub
+ return null;
+ }
}
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java b/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
index e273b2c..1ae9cb6 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
@@ -39,8 +39,6 @@
public final static boolean LOG_PARSER = false;
- private final static String ENCODING = "UTF-8"; //$NON-NLS-1$
-
// Used to get a new XmlPullParser from the client.
@Nullable
private static com.android.ide.common.rendering.api.ParserFactory sParserFactory;
@@ -74,7 +72,7 @@
stream = readAndClose(stream, name, size);
- parser.setInput(stream, ENCODING);
+ parser.setInput(stream, null);
if (isLayout) {
try {
return new LayoutParserWrapper(parser).peekTillLayoutStart();
diff --git a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png
index 55d6a20..466eca8 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.png b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.png
new file mode 100644
index 0000000..940fe5b
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/android.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/android.xml
new file mode 100644
index 0000000..42e3beb
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/android.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:viewportWidth="1102"
+ android:viewportHeight="642"
+ android:width="1102px"
+ android:height="642px">
+
+ <group
+ android:translateX="-126.347"
+ android:translateY="6.7928655e-4">
+
+
+ <path
+ android:fillColor="#94c147"
+ android:pathData="
+ m 552.777,147.57
+ c -14.147,0 -25.622,11.652 -25.622,26.02
+ v 101.68
+ c 0,14.372 11.475,26.019 25.622,26.019 14.147,0 25.61,-11.646 25.61,-26.019
+ V 173.59
+ c 0.001,-14.368 -11.462,-26.02 -25.61,-26.02
+ z
+
+ m -309.011,0
+ c -14.155,0 -25.618,11.652 -25.618,26.02
+ v 101.68
+ c 0,14.372 11.462,26.019 25.618,26.019 14.153,0 25.623,-11.646 25.623,-26.019
+ V 173.59
+ c -0.008,-14.368 -11.475,-26.02 -25.623,-26.02
+ z" />
+
+
+ <path
+ android:fillColor="#94c147"
+ android:pathData="m 284.799,148.364 v 185.768 c 0,11.035 8.948,19.98 19.983,19.98 h 22.815 v 56.567 c 0,14.37 11.47,26.016 25.623,26.016 14.148,0 25.623,-11.646 25.623,-26.016 v -56.567 h 39.878 v 56.567 c 0,14.37 11.463,26.016 25.61,26.016 14.147,0 25.622,-11.646 25.622,-26.016 v -56.567 h 22.828 c 11.022,0 19.971,-8.953 19.971,-19.98 V 148.364 H 284.799 l 0,0 z" />
+
+ <group
+ android:name="head"
+ android:pivotX="400"
+ android:pivotY="131.105">
+
+ <path
+ android:fillColor="#94c147"
+ android:pathData="m 452.302,52.105 21.057,-30.572 c 1.245,-1.819 0.939,-4.199 -0.695,-5.329 -1.637,-1.123 -3.968,-0.568 -5.225,1.251 l -21.875,31.75 c -14.404,-5.682 -30.418,-8.844 -47.293,-8.844 -16.87,0 -32.893,3.162 -47.297,8.844 l -21.875,-31.75 c -1.257,-1.819 -3.589,-2.375 -5.225,-1.251 -1.636,1.124 -1.946,3.509 -0.696,5.329 l 21.057,30.572 c -33.464,15.57 -56.951,45.166 -59.941,79.706 H 512.25 C 509.259,97.271 485.772,67.676 452.302,52.105 z M 350.187,100.28 c -6.965,0 -12.617,-5.646 -12.617,-12.616 0,-6.958 5.647,-12.61 12.617,-12.61 6.97,0 12.603,5.652 12.603,12.61 0,6.965 -5.64,12.616 -12.603,12.616 z m 97.744,0 c -6.97,0 -12.609,-5.646 -12.609,-12.616 0,-6.958 5.64,-12.61 12.609,-12.61 6.971,0 12.61,5.652 12.61,12.61 0,6.965 -5.64,12.616 -12.61,12.616 z" />
+ </group>
+
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/headset.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/headset.xml
new file mode 100644
index 0000000..897c411
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/headset.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2016 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="150dp"
+ android:height="150dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="m12,1c-4.97,0 -9,4.03 -9,9v7c0,1.66 1.34,3 3,3h3v-8H5v-2c0,-3.87 3.13,-7 7,-7s7,3.13 7,7v2h-4v8h4v1h-7v2h6c1.66,0 3,-1.34 3,-3V10c0,-4.97 -4.03,-9 -9,-9z"/>
+</vector>
\ No newline at end of file
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/multi_path.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/multi_path.xml
index 32e6e73..0998b25 100644
--- a/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/multi_path.xml
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/multi_path.xml
@@ -4,7 +4,8 @@
android:height="76dp"
android:width="76dp"
android:viewportHeight="48"
- android:viewportWidth="48">
+ android:viewportWidth="48"
+ android:alpha="0.6">
<group
android:name="root"
@@ -79,7 +80,7 @@
android:fillType="nonZero"
android:strokeWidth="1"
android:strokeColor="#AABBCC"
- android:fillColor="#AAEFCC"
+ android:fillColor="#40AAEFCC"
android:pathData="M0,-40 l0, 10 l10, 0 l0, -10 l-10,0 m5,0 l0, 10 l10, 0 l0, -10 l-10,0"
/>
</group>
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/empty.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/empty.xml
new file mode 100644
index 0000000..5322411
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/empty.xml
@@ -0,0 +1,16 @@
+<!--
+ ~ Copyright (C) 2016 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.
+ -->
+
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/vector_drawable_android.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/vector_drawable_android.xml
new file mode 100644
index 0000000..3b01ea0
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/vector_drawable_android.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2016 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:padding="16dp"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:src="@drawable/android"/>
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:src="@drawable/headset"/>
+
+</LinearLayout>
+
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index 8f570ae..88ac72d 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -116,7 +116,7 @@
private static ArrayList<String> sRenderMessages = Lists.newArrayList();
@Rule
- public static TestWatcher sRenderMessageWatcher = new TestWatcher() {
+ public TestWatcher sRenderMessageWatcher = new TestWatcher() {
@Override
protected void succeeded(Description description) {
// We only check error messages if the rest of the test case was successful.
@@ -433,6 +433,24 @@
renderAndVerify(params, "vector_drawable.png", TimeUnit.SECONDS.toNanos(2));
}
+ /**
+ * Regression test for http://b.android.com/91383 and http://b.android.com/203797
+ */
+ @Test
+ public void testVectorDrawable91383() throws ClassNotFoundException {
+ // Create the layout pull parser.
+ LayoutPullParser parser = createLayoutPullParser("vector_drawable_android.xml");
+ // Create LayoutLibCallback.
+ LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
+ layoutLibCallback.initResources();
+
+ SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5,
+ layoutLibCallback, "Theme.Material.NoActionBar.Fullscreen", false,
+ RenderingMode.V_SCROLL, 22);
+
+ renderAndVerify(params, "vector_drawable_91383.png", TimeUnit.SECONDS.toNanos(2));
+ }
+
/** Test activity.xml */
@Test
public void testScrolling() throws ClassNotFoundException {
@@ -469,7 +487,7 @@
@Test
public void testGetResourceNameVariants() throws Exception {
// Setup
- SessionParams params = createSessionParams("", ConfigGenerator.NEXUS_4);
+ SessionParams params = createSessionParams("empty.xml", ConfigGenerator.NEXUS_4);
AssetManager assetManager = AssetManager.getSystem();
DisplayMetrics metrics = new DisplayMetrics();
Configuration configuration = RenderAction.getConfiguration(params);