Add support for GradientColor in layoutlib
Change-Id: Ia9a55a9e00d7ddb5263f3dbe46b5da8dde457526
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<option name="MAIN_CLASS_NAME" value="com.android.tools.layoutlib.create.Main" />
|
||||
<option name="VM_PARAMETERS" value="-ea" />
|
||||
<option name="PROGRAM_PARAMETERS" value="out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar out/target/common/obj/JAVA_LIBRARIES/core-libart_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/icu4j-icudata-jarjar_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/icu4j-icutzdata-jarjar_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/javalib.jar" />
|
||||
<option name="PROGRAM_PARAMETERS" value="out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar out/target/common/obj/JAVA_LIBRARIES/core-libart_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar out/host/common/obj/JAVA_LIBRARIES/icu4j-icudata-host-jarjar_intermediates/classes-jarjar.jar out/host/common/obj/JAVA_LIBRARIES/icu4j-icutzdata-host-jarjar_intermediates/classes-jarjar.jar out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/javalib.jar" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/../../../../" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="" />
|
||||
|
||||
@@ -25,14 +25,9 @@ import com.android.ide.common.rendering.api.StyleResourceValue;
|
||||
import com.android.internal.util.XmlUtils;
|
||||
import com.android.layoutlib.bridge.Bridge;
|
||||
import com.android.layoutlib.bridge.android.BridgeContext;
|
||||
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
|
||||
import com.android.layoutlib.bridge.impl.ParserFactory;
|
||||
import com.android.layoutlib.bridge.impl.ResourceHelper;
|
||||
import com.android.resources.ResourceType;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.res.Resources.NotFoundException;
|
||||
import android.content.res.Resources.Theme;
|
||||
@@ -42,7 +37,6 @@ import android.util.TypedValue;
|
||||
import android.view.LayoutInflater_Delegate;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
@@ -305,77 +299,22 @@ public final class BridgeTypedArray extends TypedArray {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComplexColor getComplexColor(int index) {
|
||||
// TODO: Support GradientColor
|
||||
return getColorStateList(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the ColorStateList for the attribute at <var>index</var>.
|
||||
* The value may be either a single solid color or a reference to
|
||||
* a color or complex {@link android.content.res.ColorStateList} description.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
*
|
||||
* @return ColorStateList for the attribute, or null if not defined.
|
||||
*/
|
||||
@Override
|
||||
public ColorStateList getColorStateList(int index) {
|
||||
if (!hasValue(index)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ResourceValue resValue = mResourceData[index];
|
||||
String value = resValue.getValue();
|
||||
return ResourceHelper.getColorStateList(mResourceData[index], mContext);
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
@Override
|
||||
public ComplexColor getComplexColor(int index) {
|
||||
if (!hasValue(index)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
// Get the state list file content from callback to parse PSI file
|
||||
XmlPullParser parser = mContext.getLayoutlibCallback().getXmlFileParser(value);
|
||||
if (parser == null) {
|
||||
// If used with a version of Android Studio that does not implement getXmlFileParser
|
||||
// fall back to reading the file from disk
|
||||
File f = new File(value);
|
||||
if (f.isFile()) {
|
||||
parser = ParserFactory.create(f);
|
||||
}
|
||||
}
|
||||
if (parser != null) {
|
||||
BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
|
||||
parser, mContext, resValue.isFramework());
|
||||
try {
|
||||
return ColorStateList.createFromXml(mContext.getResources(), blockParser,
|
||||
mContext.getTheme());
|
||||
} finally {
|
||||
blockParser.ensurePopped();
|
||||
}
|
||||
}
|
||||
} catch (XmlPullParserException e) {
|
||||
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
|
||||
"Failed to configure parser for " + value, e, null);
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
// this is an error and not warning since the file existence is checked before
|
||||
// attempting to parse it.
|
||||
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
|
||||
"Failed to parse file " + value, e, null);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
int color = ResourceHelper.getColor(value);
|
||||
return ColorStateList.valueOf(color);
|
||||
} catch (NumberFormatException e) {
|
||||
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, e.getMessage(), e, null);
|
||||
}
|
||||
|
||||
return null;
|
||||
return ResourceHelper.getComplexColor(mResourceData[index], mContext);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package android.content.res;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.res.Resources.Theme;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Class that provides access to the {@link GradientColor#createFromXmlInner(Resources,
|
||||
* XmlPullParser, AttributeSet, Theme)} and {@link ColorStateList#createFromXmlInner(Resources,
|
||||
* XmlPullParser, AttributeSet, Theme)} methods
|
||||
*/
|
||||
public class ComplexColor_Accessor {
|
||||
public static GradientColor createGradientColorFromXmlInner(@NonNull Resources r,
|
||||
@NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)
|
||||
throws IOException, XmlPullParserException {
|
||||
return GradientColor.createFromXmlInner(r, parser, attrs, theme);
|
||||
}
|
||||
|
||||
public static ColorStateList createColorStateListFromXmlInner(@NonNull Resources r,
|
||||
@NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)
|
||||
throws IOException, XmlPullParserException {
|
||||
return ColorStateList.createFromXmlInner(r, parser, attrs, theme);
|
||||
}
|
||||
}
|
||||
@@ -227,6 +227,10 @@ public class Paint_Delegate {
|
||||
mColorFilter = ColorFilter_Delegate.getDelegate(colorFilterPtr);
|
||||
}
|
||||
|
||||
public void setShader(long shaderPtr) {
|
||||
mShader = Shader_Delegate.getDelegate(shaderPtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Shader} delegate or null if none have been set
|
||||
*
|
||||
|
||||
@@ -211,12 +211,16 @@ public class VectorDrawable_Delegate {
|
||||
|
||||
@LayoutlibDelegate
|
||||
static void nUpdateFullPathFillGradient(long pathPtr, long fillGradientPtr) {
|
||||
VFullPath_Delegate path = getDelegate(pathPtr);
|
||||
|
||||
path.setFillGradient(fillGradientPtr);
|
||||
}
|
||||
|
||||
@LayoutlibDelegate
|
||||
static void nUpdateFullPathStrokeGradient(long pathPtr, long strokeGradientPtr) {
|
||||
VFullPath_Delegate path = getDelegate(pathPtr);
|
||||
|
||||
path.setStrokeGradient(strokeGradientPtr);
|
||||
}
|
||||
|
||||
@LayoutlibDelegate
|
||||
@@ -540,6 +544,8 @@ public class VectorDrawable_Delegate {
|
||||
float mStrokeWidth = 0;
|
||||
|
||||
int mFillColor = Color.TRANSPARENT;
|
||||
long mStrokeGradient = 0;
|
||||
long mFillGradient = 0;
|
||||
float mStrokeAlpha = 1.0f;
|
||||
float mFillAlpha = 1.0f;
|
||||
float mTrimPathStart = 0;
|
||||
@@ -569,6 +575,9 @@ public class VectorDrawable_Delegate {
|
||||
mStrokeLineCap = copy.mStrokeLineCap;
|
||||
mStrokeLineJoin = copy.mStrokeLineJoin;
|
||||
mStrokeMiterlimit = copy.mStrokeMiterlimit;
|
||||
|
||||
mStrokeGradient = copy.mStrokeGradient;
|
||||
mFillGradient = copy.mFillGradient;
|
||||
}
|
||||
|
||||
private int getStrokeLineCap() {
|
||||
@@ -637,7 +646,7 @@ public class VectorDrawable_Delegate {
|
||||
return mStrokeColor;
|
||||
}
|
||||
|
||||
private void setStrokeColor(int strokeColor) {
|
||||
private void setStrokeColor(int strokeColor) {
|
||||
mStrokeColor = strokeColor;
|
||||
}
|
||||
|
||||
@@ -704,6 +713,14 @@ public class VectorDrawable_Delegate {
|
||||
private float getStrokeMiterlimit() {
|
||||
return mStrokeMiterlimit;
|
||||
}
|
||||
|
||||
private void setStrokeGradient(long gradientPtr) {
|
||||
mStrokeGradient = gradientPtr;
|
||||
}
|
||||
|
||||
private void setFillGradient(long gradientPtr) {
|
||||
mFillGradient = gradientPtr;
|
||||
}
|
||||
}
|
||||
|
||||
private static class VGroup_Delegate implements VNativeObject {
|
||||
@@ -1046,11 +1063,11 @@ public class VectorDrawable_Delegate {
|
||||
final Paint fillPaint = mFillPaint;
|
||||
fillPaint.setColor(applyAlpha(fullPath.mFillColor, fullPath.mFillAlpha));
|
||||
Paint_Delegate fillPaintDelegate = Paint_Delegate.getDelegate(fillPaint
|
||||
.getNativeInstance
|
||||
());
|
||||
.getNativeInstance());
|
||||
// mFillPaint can not be null at this point so we will have a delegate
|
||||
assert fillPaintDelegate != null;
|
||||
fillPaintDelegate.setColorFilter(filterPtr);
|
||||
fillPaintDelegate.setShader(fullPath.mFillGradient);
|
||||
Canvas_Delegate.native_drawPath(canvasPtr, mRenderPath.mNativePath, fillPaint
|
||||
.getNativeInstance());
|
||||
}
|
||||
@@ -1080,6 +1097,7 @@ public class VectorDrawable_Delegate {
|
||||
strokePaintDelegate.setColorFilter(filterPtr);
|
||||
final float finalStrokeScale = minScale * matrixScale;
|
||||
strokePaint.setStrokeWidth(fullPath.mStrokeWidth * finalStrokeScale);
|
||||
strokePaintDelegate.setShader(fullPath.mStrokeGradient);
|
||||
Canvas_Delegate.native_drawPath(canvasPtr, mRenderPath.mNativePath, strokePaint
|
||||
.getNativeInstance());
|
||||
}
|
||||
|
||||
@@ -33,7 +33,11 @@ import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.ComplexColor;
|
||||
import android.content.res.ComplexColor_Accessor;
|
||||
import android.content.res.GradientColor;
|
||||
import android.content.res.Resources.Theme;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap_Delegate;
|
||||
@@ -47,6 +51,7 @@ import android.util.TypedValue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
@@ -119,53 +124,127 @@ public final class ResourceHelper {
|
||||
throw new NumberFormatException();
|
||||
}
|
||||
|
||||
public static ColorStateList getColorStateList(ResourceValue resValue, BridgeContext context) {
|
||||
/**
|
||||
* Returns a {@link ComplexColor} from the given {@link ResourceValue}
|
||||
*
|
||||
* @param resValue the value containing a color value or a file path to a complex color
|
||||
* definition
|
||||
* @param context the current context
|
||||
* @param theme the theme to use when resolving the complex color
|
||||
* @param allowGradients when false, only {@link ColorStateList} will be returned. If a {@link
|
||||
* GradientColor} is found, null will be returned.
|
||||
*/
|
||||
@Nullable
|
||||
private static ComplexColor getInternalComplexColor(@NonNull ResourceValue resValue,
|
||||
@NonNull BridgeContext context, @Nullable Theme theme, boolean allowGradients) {
|
||||
String value = resValue.getValue();
|
||||
if (value != null && !RenderResources.REFERENCE_NULL.equals(value)) {
|
||||
// first check if the value is a file (xml most likely)
|
||||
if (value == null || RenderResources.REFERENCE_NULL.equals(value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// first check if the value is a file (xml most likely)
|
||||
XmlPullParser parser = context.getLayoutlibCallback().getXmlFileParser(value);
|
||||
if (parser == null) {
|
||||
File f = new File(value);
|
||||
if (f.isFile()) {
|
||||
// let the framework inflate the color from the XML file, by
|
||||
// providing an XmlPullParser
|
||||
try {
|
||||
// let the framework inflate the ColorStateList from the XML file, by
|
||||
// providing an XmlPullParser
|
||||
XmlPullParser parser = ParserFactory.create(f);
|
||||
|
||||
BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
|
||||
parser, context, resValue.isFramework());
|
||||
try {
|
||||
return ColorStateList.createFromXml(context.getResources(), blockParser);
|
||||
} finally {
|
||||
blockParser.ensurePopped();
|
||||
}
|
||||
} catch (XmlPullParserException e) {
|
||||
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
|
||||
"Failed to configure parser for " + value, e, null /*data*/);
|
||||
// we'll return null below.
|
||||
} catch (Exception e) {
|
||||
// this is an error and not warning since the file existence is
|
||||
// checked before attempting to parse it.
|
||||
parser = ParserFactory.create(f);
|
||||
} catch (XmlPullParserException | FileNotFoundException e) {
|
||||
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
|
||||
"Failed to parse file " + value, e, null /*data*/);
|
||||
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
// try to load the color state list from an int
|
||||
try {
|
||||
int color = ResourceHelper.getColor(value);
|
||||
return ColorStateList.valueOf(color);
|
||||
} catch (NumberFormatException e) {
|
||||
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
|
||||
"Failed to convert " + value + " into a ColorStateList", e,
|
||||
null /*data*/);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parser != null) {
|
||||
try {
|
||||
BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
|
||||
parser, context, resValue.isFramework());
|
||||
try {
|
||||
// Advance the parser to the first element so we can detect if it's a
|
||||
// color list or a gradient color
|
||||
int type;
|
||||
//noinspection StatementWithEmptyBody
|
||||
while ((type = blockParser.next()) != XmlPullParser.START_TAG
|
||||
&& type != XmlPullParser.END_DOCUMENT) {
|
||||
// Seek parser to start tag.
|
||||
}
|
||||
|
||||
if (type != XmlPullParser.START_TAG) {
|
||||
throw new XmlPullParserException("No start tag found");
|
||||
}
|
||||
|
||||
final String name = blockParser.getName();
|
||||
if (allowGradients && "gradient".equals(name)) {
|
||||
return ComplexColor_Accessor.createGradientColorFromXmlInner(
|
||||
context.getResources(),
|
||||
blockParser, blockParser,
|
||||
theme);
|
||||
} else if ("selector".equals(name)) {
|
||||
return ComplexColor_Accessor.createColorStateListFromXmlInner(
|
||||
context.getResources(),
|
||||
blockParser, blockParser,
|
||||
theme);
|
||||
}
|
||||
} finally {
|
||||
blockParser.ensurePopped();
|
||||
}
|
||||
} catch (XmlPullParserException e) {
|
||||
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
|
||||
"Failed to configure parser for " + value, e, null /*data*/);
|
||||
// we'll return null below.
|
||||
} catch (Exception e) {
|
||||
// this is an error and not warning since the file existence is
|
||||
// checked before attempting to parse it.
|
||||
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
|
||||
"Failed to parse file " + value, e, null /*data*/);
|
||||
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
// try to load the color state list from an int
|
||||
try {
|
||||
int color = getColor(value);
|
||||
return ColorStateList.valueOf(color);
|
||||
} catch (NumberFormatException e) {
|
||||
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
|
||||
"Failed to convert " + value + " into a ColorStateList", e,
|
||||
null /*data*/);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link ColorStateList} from the given {@link ResourceValue}
|
||||
*
|
||||
* @param resValue the value containing a color value or a file path to a complex color
|
||||
* definition
|
||||
* @param context the current context
|
||||
*/
|
||||
@Nullable
|
||||
public static ColorStateList getColorStateList(@NonNull ResourceValue resValue,
|
||||
@NonNull BridgeContext context) {
|
||||
return (ColorStateList) getInternalComplexColor(resValue, context, context.getTheme(),
|
||||
false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link ComplexColor} from the given {@link ResourceValue}
|
||||
*
|
||||
* @param resValue the value containing a color value or a file path to a complex color
|
||||
* definition
|
||||
* @param context the current context
|
||||
*/
|
||||
@Nullable
|
||||
public static ComplexColor getComplexColor(@NonNull ResourceValue resValue,
|
||||
@NonNull BridgeContext context) {
|
||||
return getInternalComplexColor(resValue, context, context.getTheme(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a drawable from the given value.
|
||||
* @param value The value that contains a path to a 9 patch, a bitmap or a xml based drawable,
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 5.5 KiB |
@@ -0,0 +1,24 @@
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
|
||||
<gradient xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:startX="10"
|
||||
android:startY="10"
|
||||
android:endX="50"
|
||||
android:endY="50"
|
||||
android:startColor="#ffff0000"
|
||||
android:endColor="#ff00ff00" />
|
||||
@@ -53,6 +53,16 @@
|
||||
android:trimPathStart="0.2"
|
||||
android:trimPathEnd="0.8"
|
||||
/>
|
||||
|
||||
<!--
|
||||
Draw a line with gradient stroke color
|
||||
-->
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#FF00FF"
|
||||
android:fillColor="@color/gradient"
|
||||
android:pathData="M-20,-20 l0, 10 l10, 0 l0, -10 l-10,0 "
|
||||
/>
|
||||
</group>
|
||||
|
||||
</vector>
|
||||
Reference in New Issue
Block a user