diff options
Diffstat (limited to 'graphics')
57 files changed, 5061 insertions, 0 deletions
diff --git a/graphics/Android.mk b/graphics/Android.mk new file mode 100644 index 0000000000..365b3b1b9f --- /dev/null +++ b/graphics/Android.mk @@ -0,0 +1,16 @@ +# Copyright (C) 2015 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. + +LOCAL_PATH:= $(call my-dir) +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/graphics/drawable/Android.mk b/graphics/drawable/Android.mk new file mode 100644 index 0000000000..63e93b7d01 --- /dev/null +++ b/graphics/drawable/Android.mk @@ -0,0 +1,41 @@ +# Copyright (C) 2015 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. + +LOCAL_PATH := $(call my-dir) + +#static vector drawable library +include $(CLEAR_VARS) +LOCAL_MODULE := android-support-v7-vectordrawable +LOCAL_SDK_VERSION := 7 +LOCAL_SRC_FILES := $(call all-java-files-under, static) + +LOCAL_JAVA_LIBRARIES := android-support-v4 + +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \ + +include $(BUILD_STATIC_JAVA_LIBRARY) + +#Animated vector drawable library +include $(CLEAR_VARS) +LOCAL_MODULE := android-support-v11-animatedvectordrawable +LOCAL_SDK_VERSION := 11 +LOCAL_SRC_FILES := $(call all-java-files-under, animated) + +LOCAL_JAVA_LIBRARIES := android-support-v4 + +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \ + +LOCAL_STATIC_JAVA_LIBRARIES := android-support-v7-vectordrawable + +include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file diff --git a/graphics/drawable/AndroidManifest.xml b/graphics/drawable/AndroidManifest.xml new file mode 100644 index 0000000000..83124c76cf --- /dev/null +++ b/graphics/drawable/AndroidManifest.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.support.graphics.drawable"> + <application /> +</manifest> diff --git a/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java b/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java new file mode 100644 index 0000000000..78ef62d1d6 --- /dev/null +++ b/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java @@ -0,0 +1,504 @@ +/* + * Copyright (C) 2015 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.support.graphics.drawable; + +import android.animation.Animator; +import android.animation.AnimatorInflater; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.content.res.Resources.Theme; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.PorterDuff.Mode; +import android.graphics.Rect; +import android.graphics.drawable.Animatable; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.DrawableRes; +import android.support.v4.util.ArrayMap; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Xml; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.ArrayList; + +/** + * This class uses {@link android.animation.ObjectAnimator} and + * {@link android.animation.AnimatorSet} to animate the properties of a + * {@link android.graphics.drawable.VectorDrawableCompat} to create an animated drawable. + * <p> + * AnimatedVectorDrawableCompat are normally defined as 3 separate XML files. + * </p> + * <p> + * First is the XML file for {@link android.graphics.drawable.VectorDrawableCompat}. Note that we + * allow the animation to happen on the group's attributes and path's attributes, which requires they + * are uniquely named in this XML file. Groups and paths without animations do not need names. + * </p> + * <li>Here is a simple VectorDrawable in this vectordrawable.xml file. + * <pre> + * <vector xmlns:android="http://schemas.android.com/apk/res/android" + * android:height="64dp" + * android:width="64dp" + * android:viewportHeight="600" + * android:viewportWidth="600" > + * <group + * android:name="rotationGroup" + * android:pivotX="300.0" + * android:pivotY="300.0" + * android:rotation="45.0" > + * <path + * android:name="v" + * android:fillColor="#000000" + * android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /> + * </group> + * </vector> + * </pre></li> + * <p> + * Second is the AnimatedVectorDrawableCompat's XML file, which defines the target + * VectorDrawableCompat, the target paths and groups to animate, the properties of the path and + * group to animate and the animations defined as the ObjectAnimators or AnimatorSets. + * </p> + * <li>Here is a simple AnimatedVectorDrawable defined in this avd.xml file. + * Note how we use the names to refer to the groups and paths in the vectordrawable.xml. + * <pre> + * <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + * android:drawable="@drawable/vectordrawable" > + * <target + * android:name="rotationGroup" + * android:animation="@anim/rotation" /> + * <target + * android:name="v" + * android:animation="@anim/path_morph" /> + * </animated-vector> + * </pre></li> + * <p> + * Last is the Animator XML file, which is the same as a normal ObjectAnimator or AnimatorSet. To + * complete this example, here are the 2 animator files used in avd.xml: rotation.xml and + * path_morph.xml. + * </p> + * <li>Here is the rotation.xml, which will rotate the target group for 360 degrees. + * <pre> + * <objectAnimator + * android:duration="6000" + * android:propertyName="rotation" + * android:valueFrom="0" + * android:valueTo="360" /> + * </pre></li> + * <li>Here is the path_morph.xml, which will morph the path from one shape to + * the other. Note that the paths must be compatible for morphing. + * In more details, the paths should have exact same length of commands, and + * exact same length of parameters for each commands. + * Note that the path strings are better stored in strings.xml for reusing. + * <pre> + * <set xmlns:android="http://schemas.android.com/apk/res/android"> + * <objectAnimator + * android:duration="3000" + * android:propertyName="pathData" + * android:valueFrom="M300,70 l 0,-70 70,70 0,0 -70,70z" + * android:valueTo="M300,70 l 0,-70 70,0 0,140 -70,0 z" + * android:valueType="pathType"/> + * </set> + * </pre></li> + * + * @attr ref android.R.styleable#AnimatedVectorDrawableCompat_drawable + * @attr ref android.R.styleable#AnimatedVectorDrawableCompatTarget_name + * @attr ref android.R.styleable#AnimatedVectorDrawableCompatTarget_animation + */ +public class AnimatedVectorDrawableCompat extends Drawable implements Animatable { + private static final String LOGTAG = "AnimatedVectorDrawableCompat"; + + private static final String ANIMATED_VECTOR = "animated-vector"; + private static final String TARGET = "target"; + + private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false; + + private AnimatedVectorDrawableCompatState mAnimatedVectorState; + + private boolean mMutated; + + private Context mContext; + + // Currently the only useful ctor. + public AnimatedVectorDrawableCompat(Context context) { + this(context, null, null); + } + + private AnimatedVectorDrawableCompat(Context context, AnimatedVectorDrawableCompatState state, + Resources res) { + mContext = context; + if (state != null) { + mAnimatedVectorState = state; + } else { + mAnimatedVectorState = new AnimatedVectorDrawableCompatState(context, state, mCallback, + res); + } + } + + @Override + public Drawable mutate() { + if (!mMutated && super.mutate() == this) { + mAnimatedVectorState = + new AnimatedVectorDrawableCompatState(null, mAnimatedVectorState, mCallback, + null); + mMutated = true; + } + return this; + } + + + /** + * Create a AnimatedVectorDrawableCompat object. + * + * @param context the context for creating the animators. + * @param resId the resource ID for AnimatedVectorDrawableCompat object. + * @return a new AnimatedVectorDrawableCompat or null if parsing error is found. + */ + @Nullable + public static AnimatedVectorDrawableCompat create(@NonNull Context context, + @DrawableRes int resId) { + Resources resources = context.getResources(); + try { + final XmlPullParser parser = resources.getXml(resId); + final AttributeSet attrs = Xml.asAttributeSet(parser); + int type; + while ((type = parser.next()) != XmlPullParser.START_TAG + && type != XmlPullParser.END_DOCUMENT) { + // Empty loop + } + if (type != XmlPullParser.START_TAG) { + throw new XmlPullParserException("No start tag found"); + } + + final AnimatedVectorDrawableCompat drawable = new AnimatedVectorDrawableCompat(context); + drawable.inflate(resources, parser, attrs, context.getTheme()); + + return drawable; + } catch (XmlPullParserException e) { + Log.e(LOGTAG, "parser error", e); + } catch (IOException e) { + Log.e(LOGTAG, "parser error", e); + } + return null; + } + + @Override + public ConstantState getConstantState() { + mAnimatedVectorState.mChangingConfigurations = getChangingConfigurations(); + return mAnimatedVectorState; + } + + @Override + public int getChangingConfigurations() { + return super.getChangingConfigurations() | mAnimatedVectorState.mChangingConfigurations; + } + + @Override + public void draw(Canvas canvas) { + mAnimatedVectorState.mVectorDrawable.draw(canvas); + if (isStarted()) { + invalidateSelf(); + } + } + + @Override + protected void onBoundsChange(Rect bounds) { + mAnimatedVectorState.mVectorDrawable.setBounds(bounds); + } + + @Override + protected boolean onStateChange(int[] state) { + return mAnimatedVectorState.mVectorDrawable.setState(state); + } + + @Override + protected boolean onLevelChange(int level) { + return mAnimatedVectorState.mVectorDrawable.setLevel(level); + } + + // @Override + public int getAlpha() { + return mAnimatedVectorState.mVectorDrawable.getAlpha(); + } + + // @Override + public void setAlpha(int alpha) { + mAnimatedVectorState.mVectorDrawable.setAlpha(alpha); + } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + mAnimatedVectorState.mVectorDrawable.setColorFilter(colorFilter); + } + + public void setTintList(ColorStateList tint) { + mAnimatedVectorState.mVectorDrawable.setTintList(tint); + } + + public void setTintMode(Mode tintMode) { + mAnimatedVectorState.mVectorDrawable.setTintMode(tintMode); + } + + @Override + public boolean setVisible(boolean visible, boolean restart) { + mAnimatedVectorState.mVectorDrawable.setVisible(visible, restart); + return super.setVisible(visible, restart); + } + + @Override + public boolean isStateful() { + return mAnimatedVectorState.mVectorDrawable.isStateful(); + } + + @Override + public int getOpacity() { + return mAnimatedVectorState.mVectorDrawable.getOpacity(); + } + + public int getIntrinsicWidth() { + return mAnimatedVectorState.mVectorDrawable.getIntrinsicWidth(); + } + + public int getIntrinsicHeight() { + return mAnimatedVectorState.mVectorDrawable.getIntrinsicHeight(); + } + + /** + * Obtains styled attributes from the theme, if available, or unstyled + * resources if the theme is null. + */ + static TypedArray obtainAttributes( + Resources res, Theme theme, AttributeSet set, int[] attrs) { + if (theme == null) { + return res.obtainAttributes(set, attrs); + } + return theme.obtainStyledAttributes(set, attrs, 0, 0); + } + + public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme) + throws XmlPullParserException, IOException { + int eventType = parser.getEventType(); + float pathErrorScale = 1; + while (eventType != XmlPullParser.END_DOCUMENT) { + if (eventType == XmlPullParser.START_TAG) { + final String tagName = parser.getName(); + if (DBG_ANIMATION_VECTOR_DRAWABLE) { + Log.v(LOGTAG, "tagName is " + tagName); + } + if (ANIMATED_VECTOR.equals(tagName)) { + final TypedArray a = + obtainAttributes(res, theme, attrs, R.styleable.AnimatedVectorDrawable); + + int drawableRes = a.getResourceId(R.styleable.AnimatedVectorDrawable_drawable, + 0); + if (DBG_ANIMATION_VECTOR_DRAWABLE) { + Log.v(LOGTAG, "drawableRes is " + drawableRes); + } + if (drawableRes != 0) { + VectorDrawableCompat vectorDrawable = VectorDrawableCompat.create(res, + drawableRes, theme); + vectorDrawable.setAllowCaching(false); + vectorDrawable.setCallback(mCallback); + pathErrorScale = vectorDrawable.getPixelSize(); + if (mAnimatedVectorState.mVectorDrawable != null) { + mAnimatedVectorState.mVectorDrawable.setCallback(null); + } + mAnimatedVectorState.mVectorDrawable = vectorDrawable; + } + a.recycle(); + } else if (TARGET.equals(tagName)) { + final TypedArray a = + res.obtainAttributes(attrs, R.styleable.AnimatedVectorDrawableTarget); + final String target = a.getString( + R.styleable.AnimatedVectorDrawableTarget_name); + + int id = a.getResourceId(R.styleable.AnimatedVectorDrawableTarget_animation, 0); + if (id != 0) { + Animator objectAnimator = AnimatorInflater.loadAnimator(mContext, id); + setupAnimatorsForTarget(target, objectAnimator); + } + a.recycle(); + } + } + + eventType = parser.next(); + } + } + + @Override + public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs) + throws XmlPullParserException, IOException { + inflate(res, parser, attrs, null); + } + + public boolean canApplyTheme() { + return false; + } + + private static class AnimatedVectorDrawableCompatState extends ConstantState { + int mChangingConfigurations; + VectorDrawableCompat mVectorDrawable; + ArrayList<Animator> mAnimators; + ArrayMap<Animator, String> mTargetNameMap; + Context mContext; + + public AnimatedVectorDrawableCompatState(Context context, + AnimatedVectorDrawableCompatState copy, Callback owner, Resources res) { + if (copy != null) { + mChangingConfigurations = copy.mChangingConfigurations; + if (copy.mVectorDrawable != null) { + final ConstantState cs = copy.mVectorDrawable.getConstantState(); + if (res != null) { + mVectorDrawable = (VectorDrawableCompat) cs.newDrawable(res); + } else { + mVectorDrawable = (VectorDrawableCompat) cs.newDrawable(); + } + mVectorDrawable = (VectorDrawableCompat) mVectorDrawable.mutate(); + mVectorDrawable.setCallback(owner); + mVectorDrawable.setBounds(copy.mVectorDrawable.getBounds()); + mVectorDrawable.setAllowCaching(false); + } + if (copy.mAnimators != null) { + final int numAnimators = copy.mAnimators.size(); + mAnimators = new ArrayList<Animator>(numAnimators); + mTargetNameMap = new ArrayMap<Animator, String>(numAnimators); + for (int i = 0; i < numAnimators; ++i) { + Animator anim = copy.mAnimators.get(i); + Animator animClone = anim.clone(); + String targetName = copy.mTargetNameMap.get(anim); + Object targetObject = mVectorDrawable.getTargetByName(targetName); + animClone.setTarget(targetObject); + mAnimators.add(animClone); + mTargetNameMap.put(animClone, targetName); + } + } + } + + if (context != null) { + mContext = context; + } else { + mContext = copy.mContext; + } + + } + + @Override + public Drawable newDrawable() { + return new AnimatedVectorDrawableCompat(mContext, this, null); + } + + @Override + public Drawable newDrawable(Resources res) { + return new AnimatedVectorDrawableCompat(mContext, this, res); + } + + @Override + public int getChangingConfigurations() { + return mChangingConfigurations; + } + } + + private void setupAnimatorsForTarget(String name, Animator animator) { + Object target = mAnimatedVectorState.mVectorDrawable.getTargetByName(name); + animator.setTarget(target); + if (mAnimatedVectorState.mAnimators == null) { + mAnimatedVectorState.mAnimators = new ArrayList<Animator>(); + mAnimatedVectorState.mTargetNameMap = new ArrayMap<Animator, String>(); + } + mAnimatedVectorState.mAnimators.add(animator); + mAnimatedVectorState.mTargetNameMap.put(animator, name); + if (DBG_ANIMATION_VECTOR_DRAWABLE) { + Log.v(LOGTAG, "add animator for target " + name + " " + animator); + } + } + + @Override + public boolean isRunning() { + final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators; + final int size = animators.size(); + for (int i = 0; i < size; i++) { + final Animator animator = animators.get(i); + if (animator.isRunning()) { + return true; + } + } + return false; + } + + private boolean isStarted() { + final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators; + if (animators == null) { + return false; + } + final int size = animators.size(); + for (int i = 0; i < size; i++) { + final Animator animator = animators.get(i); + if (animator.isRunning()) { + return true; + } + } + return false; + } + + @Override + public void start() { + // If any one of the animator has not ended, do nothing. + if (isStarted()) { + return; + } + // Otherwise, kick off every animator. + final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators; + final int size = animators.size(); + for (int i = 0; i < size; i++) { + final Animator animator = animators.get(i); + animator.start(); + } + invalidateSelf(); + } + + @Override + public void stop() { + final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators; + final int size = animators.size(); + for (int i = 0; i < size; i++) { + final Animator animator = animators.get(i); + animator.end(); + } + } + + private final Callback mCallback = new Callback() { + @Override + public void invalidateDrawable(Drawable who) { + invalidateSelf(); + } + + @Override + public void scheduleDrawable(Drawable who, Runnable what, long when) { + scheduleSelf(what, when); + } + + @Override + public void unscheduleDrawable(Drawable who, Runnable what) { + unscheduleSelf(what); + } + }; +} diff --git a/graphics/drawable/res/values/attrs.xml b/graphics/drawable/res/values/attrs.xml new file mode 100644 index 0000000000..b54c9a69c1 --- /dev/null +++ b/graphics/drawable/res/values/attrs.xml @@ -0,0 +1,183 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 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. +--> +<resources> + <!-- If set, specifies the color to apply to the drawable as a tint. By default, + no tint is applied. May be a color state list. --> + <attr name="tint" format="color" /> + <!-- When a tint color is set, specifies its Porter-Duff blending mode. The + default value is src_in, which treats the drawable as an alpha mask. --> + <attr name="tintMode"> + <!-- The tint is drawn on top of the drawable. + [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] --> + <enum name="src_over" value="3" /> + <!-- The tint is masked by the alpha channel of the drawable. The drawable’s + color channels are thrown out. [Sa * Da, Sc * Da] --> + <enum name="src_in" value="5" /> + <!-- The tint is drawn above the drawable, but with the drawable’s alpha + channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] --> + <enum name="src_atop" value="9" /> + <!-- Multiplies the color and alpha channels of the drawable with those of + the tint. [Sa * Da, Sc * Dc] --> + <enum name="multiply" value="14" /> + <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] --> + <enum name="screen" value="15" /> + <!-- Combines the tint and drawable color and alpha channels, clamping the + result to valid color values. Saturate(S + D) --> + <enum name="add" value="16" /> + </attr> + <!-- Animation to use on each child. --> + <attr name="animation" format="reference" /> + <!-- alpha property of the view, as a value between 0 (completely transparent) and 1 + (completely opaque). --> + <attr name="alpha" format="float" /> + <attr name="pivotX" format="float|fraction" /> + <attr name="pivotY" format="float|fraction" /> + <!-- rotation of the view, in degrees. --> + <attr name="rotation" format="float" /> + + <!-- scale of the view in the x direction. --> + <attr name="scaleX" format="float" /> + + <!-- scale of the view in the y direction. --> + <attr name="scaleY" format="float" /> + <!-- Makes the TextView be exactly this many pixels tall. + You could get the same effect by specifying this number in the + layout parameters. --> + <attr name="height" format="dimension" /> + <!-- Makes the TextView be exactly this many pixels wide. + You could get the same effect by specifying this number in the + layout parameters. --> + <attr name="width" format="dimension" /> + <!-- A unique name for the given item. This must use a Java-style naming + convention to ensure the name is unique, for example + "com.mycompany.MyName". --> + <attr name="name" format="string" /> + + <!-- ========================== --> + <!-- VectorDrawable class --> + <!-- ========================== --> + <eat-comment /> + + <!-- Drawable used to draw vector paths. --> + <declare-styleable name="VectorDrawable"> + <!-- If set, specifies the color to apply to the drawable as a tint. By default, + no tint is applied. May be a color state list. --> + <attr name="tint" /> + <!-- When a tint color is set, specifies its Porter-Duff blending mode. The + default value is src_in, which treats the drawable as an alpha mask. --> + <attr name="tintMode" /> + <!-- Indicates if the drawable needs to be mirrored when its layout direction is + RTL (right-to-left). --> + <attr name="autoMirrored" format="boolean" /> + <!-- The intrinsic width of the Vector Drawable. --> + <attr name="width" /> + <!-- The intrinsic height of the Vector Drawable. --> + <attr name="height" /> + <!-- The width of the canvas the drawing is on. --> + <attr name="viewportWidth" format="float"/> + <!-- The height of the canvas the drawing is on. --> + <attr name="viewportHeight" format="float"/> + <!-- The name of this vector drawable --> + <attr name="name" /> + <!-- The opacity of the whole vector drawable, as a value between 0 + (completely transparent) and 1 (completely opaque). --> + <attr name="alpha" /> + </declare-styleable> + + <!-- Defines the group used in VectorDrawables. --> + <declare-styleable name="VectorDrawableGroup"> + <!-- The name of this group --> + <attr name="name" /> + <!-- The amount to rotate the group --> + <attr name="rotation" /> + <!-- The X coordinate of the center of rotation of a group --> + <attr name="pivotX" /> + <!-- The Y coordinate of the center of rotation of a group --> + <attr name="pivotY" /> + <!-- The amount to translate the group on X coordinate --> + <attr name="translateX" format="float"/> + <!-- The amount to translate the group on Y coordinate --> + <attr name="translateY" format="float"/> + <!-- The amount to scale the group on X coordinate --> + <attr name="scaleX" /> + <!-- The amount to scale the group on X coordinate --> + <attr name="scaleY" /> + </declare-styleable> + + <!-- Defines the path used in VectorDrawables. --> + <declare-styleable name="VectorDrawablePath"> + <!-- The name of this path --> + <attr name="name" /> + <!-- The width a path stroke --> + <attr name="strokeWidth" format="float" /> + <!-- The color to stroke the path if not defined implies no stroke--> + <attr name="strokeColor" format="color" /> + <!-- The opacity of a path stroke, as a value between 0 (completely transparent) + and 1 (completely opaque) --> + <attr name="strokeAlpha" format="float" /> + <!-- The color to fill the path if not defined implies no fill--> + <attr name="fillColor" format="color" /> + <!-- The alpha of the path fill, as a value between 0 (completely transparent) + and 1 (completely opaque)--> + <attr name="fillAlpha" format="float" /> + <!-- The specification of the operations that define the path --> + <attr name="pathData" format="string" /> + <!-- The fraction of the path to trim from the start from 0 to 1 --> + <attr name="trimPathStart" format="float" /> + <!-- The fraction of the path to trim from the end from 0 to 1 --> + <attr name="trimPathEnd" format="float" /> + <!-- Shift trim region (allows visible region to include the start and end) from 0 to 1 --> + <attr name="trimPathOffset" format="float" /> + <!-- The linecap for a stroked path --> + <attr name="strokeLineCap" format="enum"> + <enum name="butt" value="0"/> + <enum name="round" value="1"/> + <enum name="square" value="2"/> + </attr> + <!-- The lineJoin for a stroked path --> + <attr name="strokeLineJoin" format="enum"> + <enum name="miter" value="0"/> + <enum name="round" value="1"/> + <enum name="bevel" value="2"/> + </attr> + <!-- The Miter limit for a stroked path --> + <attr name="strokeMiterLimit" format="float"/> + </declare-styleable> + + <!-- Defines the clip path used in VectorDrawables. --> + <declare-styleable name="VectorDrawableClipPath"> + <!-- The Name of this path --> + <attr name="name" /> + <!-- The specification of the operations that define the path --> + <attr name="pathData"/> + </declare-styleable> + + <!-- ========================== --> + <!-- AnimatedVectorDrawable class --> + <!-- ========================== --> + <eat-comment /> + + <!-- Define the AnimatedVectorDrawable. --> + <declare-styleable name="AnimatedVectorDrawable"> + <!-- The static vector drawable. --> + <attr name="drawable" format="reference" /> + </declare-styleable> + + <!-- Defines the target used in the AnimatedVectorDrawable. --> + <declare-styleable name="AnimatedVectorDrawableTarget"> + <!-- The name of the target path, group or vector drawable --> + <attr name="name" /> + <!-- The animation for the target path, group or vector drawable --> + <attr name="animation" /> + </declare-styleable> +</resources> diff --git a/graphics/drawable/runavdtest.sh b/graphics/drawable/runavdtest.sh new file mode 100755 index 0000000000..023ad3e8e9 --- /dev/null +++ b/graphics/drawable/runavdtest.sh @@ -0,0 +1,5 @@ +. ../../../../build/envsetup.sh +mmm -j20 . && mmm -j20 ./testanimated/ && \ +adb install -r $OUT/data/app/AndroidAnimatedVectorDrawableTests/AndroidAnimatedVectorDrawableTests.apk && \ +adb shell am start -n android.support.test.vectordrawable/android.support.test.vectordrawable.TestAVDActivity + diff --git a/graphics/drawable/runtest.sh b/graphics/drawable/runtest.sh new file mode 100755 index 0000000000..6f697801ba --- /dev/null +++ b/graphics/drawable/runtest.sh @@ -0,0 +1,5 @@ +. ../../../../build/envsetup.sh +mmm -j20 . && mmm -j20 ./teststatic/ && \ +adb install -r $OUT/data/app/AndroidVectorDrawableTests/AndroidVectorDrawableTests.apk && \ +adb shell am start -n android.support.test.vectordrawable/android.support.test.vectordrawable.TestActivity + diff --git a/graphics/drawable/static/src/android/support/graphics/drawable/PathParser.java b/graphics/drawable/static/src/android/support/graphics/drawable/PathParser.java new file mode 100644 index 0000000000..a92c3e578d --- /dev/null +++ b/graphics/drawable/static/src/android/support/graphics/drawable/PathParser.java @@ -0,0 +1,718 @@ +/* + * Copyright (C) 2015 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.support.graphics.drawable; + +import android.graphics.Path; +import android.util.Log; + +import java.util.ArrayList; + +// This class is a duplicate from the PathParser.java of frameworks/base, with slight +// update on incompatible API like copyOfRange(). +class PathParser { + private static final String LOGTAG = "PathParser"; + + // Copy from Arrays.copyOfRange() which is only available from API level 9. + /** + * Copies elements from {@code original} into a new array, from indexes start (inclusive) to + * end (exclusive). The original order of elements is preserved. + * If {@code end} is greater than {@code original.length}, the result is padded + * with the value {@code 0.0f}. + * + * @param original the original array + * @param start the start index, inclusive + * @param end the end index, exclusive + * @return the new array + * @throws ArrayIndexOutOfBoundsException if {@code start < 0 || start > original.length} + * @throws IllegalArgumentException if {@code start > end} + * @throws NullPointerException if {@code original == null} + */ + private static float[] copyOfRange(float[] original, int start, int end) { + if (start > end) { + throw new IllegalArgumentException(); + } + int originalLength = original.length; + if (start < 0 || start > originalLength) { + throw new ArrayIndexOutOfBoundsException(); + } + int resultLength = end - start; + int copyLength = Math.min(resultLength, originalLength - start); + float[] result = new float[resultLength]; + System.arraycopy(original, start, result, 0, copyLength); + return result; + } + + /** + * @param pathData The string representing a path, the same as "d" string in svg file. + * @return the generated Path object. + */ + public static Path createPathFromPathData(String pathData) { + Path path = new Path(); + PathDataNode[] nodes = createNodesFromPathData(pathData); + if (nodes != null) { + try { + PathDataNode.nodesToPath(nodes, path); + } catch (RuntimeException e) { + throw new RuntimeException("Error in parsing " + pathData, e); + } + return path; + } + return null; + } + + /** + * @param pathData The string representing a path, the same as "d" string in svg file. + * @return an array of the PathDataNode. + */ + public static PathDataNode[] createNodesFromPathData(String pathData) { + if (pathData == null) { + return null; + } + int start = 0; + int end = 1; + + ArrayList<PathDataNode> list = new ArrayList<PathDataNode>(); + while (end < pathData.length()) { + end = nextStart(pathData, end); + String s = pathData.substring(start, end).trim(); + if (s.length() > 0) { + float[] val = getFloats(s); + addNode(list, s.charAt(0), val); + } + + start = end; + end++; + } + if ((end - start) == 1 && start < pathData.length()) { + addNode(list, pathData.charAt(start), new float[0]); + } + return list.toArray(new PathDataNode[list.size()]); + } + + /** + * @param source The array of PathDataNode to be duplicated. + * @return a deep copy of the <code>source</code>. + */ + public static PathDataNode[] deepCopyNodes(PathDataNode[] source) { + if (source == null) { + return null; + } + PathDataNode[] copy = new PathParser.PathDataNode[source.length]; + for (int i = 0; i < source.length; i ++) { + copy[i] = new PathDataNode(source[i]); + } + return copy; + } + + /** + * @param nodesFrom The source path represented in an array of PathDataNode + * @param nodesTo The target path represented in an array of PathDataNode + * @return whether the <code>nodesFrom</code> can morph into <code>nodesTo</code> + */ + public static boolean canMorph(PathDataNode[] nodesFrom, PathDataNode[] nodesTo) { + if (nodesFrom == null || nodesTo == null) { + return false; + } + + if (nodesFrom.length != nodesTo.length) { + return false; + } + + for (int i = 0; i < nodesFrom.length; i ++) { + if (nodesFrom[i].mType != nodesTo[i].mType + || nodesFrom[i].mParams.length != nodesTo[i].mParams.length) { + return false; + } + } + return true; + } + + /** + * Update the target's data to match the source. + * Before calling this, make sure canMorph(target, source) is true. + * + * @param target The target path represented in an array of PathDataNode + * @param source The source path represented in an array of PathDataNode + */ + public static void updateNodes(PathDataNode[] target, PathDataNode[] source) { + for (int i = 0; i < source.length; i ++) { + target[i].mType = source[i].mType; + for (int j = 0; j < source[i].mParams.length; j ++) { + target[i].mParams[j] = source[i].mParams[j]; + } + } + } + + private static int nextStart(String s, int end) { + char c; + + while (end < s.length()) { + c = s.charAt(end); + // Note that 'e' or 'E' are not valid path commands, but could be + // used for floating point numbers' scientific notation. + // Therefore, when searching for next command, we should ignore 'e' + // and 'E'. + if ((((c - 'A') * (c - 'Z') <= 0) || ((c - 'a') * (c - 'z') <= 0)) + && c != 'e' && c != 'E') { + return end; + } + end++; + } + return end; + } + + private static void addNode(ArrayList<PathDataNode> list, char cmd, float[] val) { + list.add(new PathDataNode(cmd, val)); + } + + private static class ExtractFloatResult { + // We need to return the position of the next separator and whether the + // next float starts with a '-' or a '.'. + int mEndPosition; + boolean mEndWithNegOrDot; + } + + /** + * Parse the floats in the string. + * This is an optimized version of parseFloat(s.split(",|\\s")); + * + * @param s the string containing a command and list of floats + * @return array of floats + */ + private static float[] getFloats(String s) { + if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') { + return new float[0]; + } + try { + float[] results = new float[s.length()]; + int count = 0; + int startPosition = 1; + int endPosition = 0; + + ExtractFloatResult result = new ExtractFloatResult(); + int totalLength = s.length(); + + // The startPosition should always be the first character of the + // current number, and endPosition is the character after the current + // number. + while (startPosition < totalLength) { + extract(s, startPosition, result); + endPosition = result.mEndPosition; + + if (startPosition < endPosition) { + results[count++] = Float.parseFloat( + s.substring(startPosition, endPosition)); + } + + if (result.mEndWithNegOrDot) { + // Keep the '-' or '.' sign with next number. + startPosition = endPosition; + } else { + startPosition = endPosition + 1; + } + } + return copyOfRange(results, 0, count); + } catch (NumberFormatException e) { + throw new RuntimeException("error in parsing \"" + s + "\"", e); + } + } + + /** + * Calculate the position of the next comma or space or negative sign + * @param s the string to search + * @param start the position to start searching + * @param result the result of the extraction, including the position of the + * the starting position of next number, whether it is ending with a '-'. + */ + private static void extract(String s, int start, ExtractFloatResult result) { + // Now looking for ' ', ',', '.' or '-' from the start. + int currentIndex = start; + boolean foundSeparator = false; + result.mEndWithNegOrDot = false; + boolean secondDot = false; + boolean isExponential = false; + for (; currentIndex < s.length(); currentIndex++) { + boolean isPrevExponential = isExponential; + isExponential = false; + char currentChar = s.charAt(currentIndex); + switch (currentChar) { + case ' ': + case ',': + foundSeparator = true; + break; + case '-': + // The negative sign following a 'e' or 'E' is not a separator. + if (currentIndex != start && !isPrevExponential) { + foundSeparator = true; + result.mEndWithNegOrDot = true; + } + break; + case '.': + if (!secondDot) { + secondDot = true; + } else { + // This is the second dot, and it is considered as a separator. + foundSeparator = true; + result.mEndWithNegOrDot = true; + } + break; + case 'e': + case 'E': + isExponential = true; + break; + } + if (foundSeparator) { + break; + } + } + // When there is nothing found, then we put the end position to the end + // of the string. + result.mEndPosition = currentIndex; + } + + /** + * Each PathDataNode represents one command in the "d" attribute of the svg + * file. + * An array of PathDataNode can represent the whole "d" attribute. + */ + public static class PathDataNode { + private char mType; + private float[] mParams; + + private PathDataNode(char type, float[] params) { + mType = type; + mParams = params; + } + + private PathDataNode(PathDataNode n) { + mType = n.mType; + mParams = copyOfRange(n.mParams, 0, n.mParams.length); + } + + /** + * Convert an array of PathDataNode to Path. + * + * @param node The source array of PathDataNode. + * @param path The target Path object. + */ + public static void nodesToPath(PathDataNode[] node, Path path) { + float[] current = new float[6]; + char previousCommand = 'm'; + for (int i = 0; i < node.length; i++) { + addCommand(path, current, previousCommand, node[i].mType, node[i].mParams); + previousCommand = node[i].mType; + } + } + + /** + * The current PathDataNode will be interpolated between the + * <code>nodeFrom</code> and <code>nodeTo</code> according to the + * <code>fraction</code>. + * + * @param nodeFrom The start value as a PathDataNode. + * @param nodeTo The end value as a PathDataNode + * @param fraction The fraction to interpolate. + */ + public void interpolatePathDataNode(PathDataNode nodeFrom, + PathDataNode nodeTo, float fraction) { + for (int i = 0; i < nodeFrom.mParams.length; i++) { + mParams[i] = nodeFrom.mParams[i] * (1 - fraction) + + nodeTo.mParams[i] * fraction; + } + } + + private static void addCommand(Path path, float[] current, + char previousCmd, char cmd, float[] val) { + + int incr = 2; + float currentX = current[0]; + float currentY = current[1]; + float ctrlPointX = current[2]; + float ctrlPointY = current[3]; + float currentSegmentStartX = current[4]; + float currentSegmentStartY = current[5]; + float reflectiveCtrlPointX; + float reflectiveCtrlPointY; + + switch (cmd) { + case 'z': + case 'Z': + path.close(); + // Path is closed here, but we need to move the pen to the + // closed position. So we cache the segment's starting position, + // and restore it here. + currentX = currentSegmentStartX; + currentY = currentSegmentStartY; + ctrlPointX = currentSegmentStartX; + ctrlPointY = currentSegmentStartY; + path.moveTo(currentX, currentY); + break; + case 'm': + case 'M': + case 'l': + case 'L': + case 't': + case 'T': + incr = 2; + break; + case 'h': + case 'H': + case 'v': + case 'V': + incr = 1; + break; + case 'c': + case 'C': + incr = 6; + break; + case 's': + case 'S': + case 'q': + case 'Q': + incr = 4; + break; + case 'a': + case 'A': + incr = 7; + break; + } + + for (int k = 0; k < val.length; k += incr) { + switch (cmd) { + case 'm': // moveto - Start a new sub-path (relative) + path.rMoveTo(val[k + 0], val[k + 1]); + currentX += val[k + 0]; + currentY += val[k + 1]; + currentSegmentStartX = currentX; + currentSegmentStartY = currentY; + break; + case 'M': // moveto - Start a new sub-path + path.moveTo(val[k + 0], val[k + 1]); + currentX = val[k + 0]; + currentY = val[k + 1]; + currentSegmentStartX = currentX; + currentSegmentStartY = currentY; + break; + case 'l': // lineto - Draw a line from the current point (relative) + path.rLineTo(val[k + 0], val[k + 1]); + currentX += val[k + 0]; + currentY += val[k + 1]; + break; + case 'L': // lineto - Draw a line from the current point + path.lineTo(val[k + 0], val[k + 1]); + currentX = val[k + 0]; + currentY = val[k + 1]; + break; + case 'h': // horizontal lineto - Draws a horizontal line (relative) + path.rLineTo(val[k + 0], 0); + currentX += val[k + 0]; + break; + case 'H': // horizontal lineto - Draws a horizontal line + path.lineTo(val[k + 0], currentY); + currentX = val[k + 0]; + break; + case 'v': // vertical lineto - Draws a vertical line from the current point (r) + path.rLineTo(0, val[k + 0]); + currentY += val[k + 0]; + break; + case 'V': // vertical lineto - Draws a vertical line from the current point + path.lineTo(currentX, val[k + 0]); + currentY = val[k + 0]; + break; + case 'c': // curveto - Draws a cubic Bézier curve (relative) + path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], + val[k + 4], val[k + 5]); + + ctrlPointX = currentX + val[k + 2]; + ctrlPointY = currentY + val[k + 3]; + currentX += val[k + 4]; + currentY += val[k + 5]; + + break; + case 'C': // curveto - Draws a cubic Bézier curve + path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], + val[k + 4], val[k + 5]); + currentX = val[k + 4]; + currentY = val[k + 5]; + ctrlPointX = val[k + 2]; + ctrlPointY = val[k + 3]; + break; + case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp) + reflectiveCtrlPointX = 0; + reflectiveCtrlPointY = 0; + if (previousCmd == 'c' || previousCmd == 's' + || previousCmd == 'C' || previousCmd == 'S') { + reflectiveCtrlPointX = currentX - ctrlPointX; + reflectiveCtrlPointY = currentY - ctrlPointY; + } + path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, + val[k + 0], val[k + 1], + val[k + 2], val[k + 3]); + + ctrlPointX = currentX + val[k + 0]; + ctrlPointY = currentY + val[k + 1]; + currentX += val[k + 2]; + currentY += val[k + 3]; + break; + case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp) + reflectiveCtrlPointX = currentX; + reflectiveCtrlPointY = currentY; + if (previousCmd == 'c' || previousCmd == 's' + || previousCmd == 'C' || previousCmd == 'S') { + reflectiveCtrlPointX = 2 * currentX - ctrlPointX; + reflectiveCtrlPointY = 2 * currentY - ctrlPointY; + } + path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, + val[k + 0], val[k + 1], val[k + 2], val[k + 3]); + ctrlPointX = val[k + 0]; + ctrlPointY = val[k + 1]; + currentX = val[k + 2]; + currentY = val[k + 3]; + break; + case 'q': // Draws a quadratic Bézier (relative) + path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); + ctrlPointX = currentX + val[k + 0]; + ctrlPointY = currentY + val[k + 1]; + currentX += val[k + 2]; + currentY += val[k + 3]; + break; + case 'Q': // Draws a quadratic Bézier + path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); + ctrlPointX = val[k + 0]; + ctrlPointY = val[k + 1]; + currentX = val[k + 2]; + currentY = val[k + 3]; + break; + case 't': // Draws a quadratic Bézier curve(reflective control point)(relative) + reflectiveCtrlPointX = 0; + reflectiveCtrlPointY = 0; + if (previousCmd == 'q' || previousCmd == 't' + || previousCmd == 'Q' || previousCmd == 'T') { + reflectiveCtrlPointX = currentX - ctrlPointX; + reflectiveCtrlPointY = currentY - ctrlPointY; + } + path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, + val[k + 0], val[k + 1]); + ctrlPointX = currentX + reflectiveCtrlPointX; + ctrlPointY = currentY + reflectiveCtrlPointY; + currentX += val[k + 0]; + currentY += val[k + 1]; + break; + case 'T': // Draws a quadratic Bézier curve (reflective control point) + reflectiveCtrlPointX = currentX; + reflectiveCtrlPointY = currentY; + if (previousCmd == 'q' || previousCmd == 't' + || previousCmd == 'Q' || previousCmd == 'T') { + reflectiveCtrlPointX = 2 * currentX - ctrlPointX; + reflectiveCtrlPointY = 2 * currentY - ctrlPointY; + } + path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, + val[k + 0], val[k + 1]); + ctrlPointX = reflectiveCtrlPointX; + ctrlPointY = reflectiveCtrlPointY; + currentX = val[k + 0]; + currentY = val[k + 1]; + break; + case 'a': // Draws an elliptical arc + // (rx ry x-axis-rotation large-arc-flag sweep-flag x y) + drawArc(path, + currentX, + currentY, + val[k + 5] + currentX, + val[k + 6] + currentY, + val[k + 0], + val[k + 1], + val[k + 2], + val[k + 3] != 0, + val[k + 4] != 0); + currentX += val[k + 5]; + currentY += val[k + 6]; + ctrlPointX = currentX; + ctrlPointY = currentY; + break; + case 'A': // Draws an elliptical arc + drawArc(path, + currentX, + currentY, + val[k + 5], + val[k + 6], + val[k + 0], + val[k + 1], + val[k + 2], + val[k + 3] != 0, + val[k + 4] != 0); + currentX = val[k + 5]; + currentY = val[k + 6]; + ctrlPointX = currentX; + ctrlPointY = currentY; + break; + } + previousCmd = cmd; + } + current[0] = currentX; + current[1] = currentY; + current[2] = ctrlPointX; + current[3] = ctrlPointY; + current[4] = currentSegmentStartX; + current[5] = currentSegmentStartY; + } + + private static void drawArc(Path p, + float x0, + float y0, + float x1, + float y1, + float a, + float b, + float theta, + boolean isMoreThanHalf, + boolean isPositiveArc) { + + /* Convert rotation angle from degrees to radians */ + double thetaD = Math.toRadians(theta); + /* Pre-compute rotation matrix entries */ + double cosTheta = Math.cos(thetaD); + double sinTheta = Math.sin(thetaD); + /* Transform (x0, y0) and (x1, y1) into unit space */ + /* using (inverse) rotation, followed by (inverse) scale */ + double x0p = (x0 * cosTheta + y0 * sinTheta) / a; + double y0p = (-x0 * sinTheta + y0 * cosTheta) / b; + double x1p = (x1 * cosTheta + y1 * sinTheta) / a; + double y1p = (-x1 * sinTheta + y1 * cosTheta) / b; + + /* Compute differences and averages */ + double dx = x0p - x1p; + double dy = y0p - y1p; + double xm = (x0p + x1p) / 2; + double ym = (y0p + y1p) / 2; + /* Solve for intersecting unit circles */ + double dsq = dx * dx + dy * dy; + if (dsq == 0.0) { + Log.w(LOGTAG, " Points are coincident"); + return; /* Points are coincident */ + } + double disc = 1.0 / dsq - 1.0 / 4.0; + if (disc < 0.0) { + Log.w(LOGTAG, "Points are too far apart " + dsq); + float adjust = (float) (Math.sqrt(dsq) / 1.99999); + drawArc(p, x0, y0, x1, y1, a * adjust, + b * adjust, theta, isMoreThanHalf, isPositiveArc); + return; /* Points are too far apart */ + } + double s = Math.sqrt(disc); + double sdx = s * dx; + double sdy = s * dy; + double cx; + double cy; + if (isMoreThanHalf == isPositiveArc) { + cx = xm - sdy; + cy = ym + sdx; + } else { + cx = xm + sdy; + cy = ym - sdx; + } + + double eta0 = Math.atan2((y0p - cy), (x0p - cx)); + + double eta1 = Math.atan2((y1p - cy), (x1p - cx)); + + double sweep = (eta1 - eta0); + if (isPositiveArc != (sweep >= 0)) { + if (sweep > 0) { + sweep -= 2 * Math.PI; + } else { + sweep += 2 * Math.PI; + } + } + + cx *= a; + cy *= b; + double tcx = cx; + cx = cx * cosTheta - cy * sinTheta; + cy = tcx * sinTheta + cy * cosTheta; + + arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep); + } + + /** + * Converts an arc to cubic Bezier segments and records them in p. + * + * @param p The target for the cubic Bezier segments + * @param cx The x coordinate center of the ellipse + * @param cy The y coordinate center of the ellipse + * @param a The radius of the ellipse in the horizontal direction + * @param b The radius of the ellipse in the vertical direction + * @param e1x E(eta1) x coordinate of the starting point of the arc + * @param e1y E(eta2) y coordinate of the starting point of the arc + * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane + * @param start The start angle of the arc on the ellipse + * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse + */ + private static void arcToBezier(Path p, + double cx, + double cy, + double a, + double b, + double e1x, + double e1y, + double theta, + double start, + double sweep) { + // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html + // and http://www.spaceroots.org/documents/ellipse/node22.html + + // Maximum of 45 degrees per cubic Bezier segment + int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI)); + + double eta1 = start; + double cosTheta = Math.cos(theta); + double sinTheta = Math.sin(theta); + double cosEta1 = Math.cos(eta1); + double sinEta1 = Math.sin(eta1); + double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1); + double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1); + + double anglePerSegment = sweep / numSegments; + for (int i = 0; i < numSegments; i++) { + double eta2 = eta1 + anglePerSegment; + double sinEta2 = Math.sin(eta2); + double cosEta2 = Math.cos(eta2); + double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2); + double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2); + double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2; + double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2; + double tanDiff2 = Math.tan((eta2 - eta1) / 2); + double alpha = + Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3; + double q1x = e1x + alpha * ep1x; + double q1y = e1y + alpha * ep1y; + double q2x = e2x - alpha * ep2x; + double q2y = e2y - alpha * ep2y; + + p.cubicTo((float) q1x, + (float) q1y, + (float) q2x, + (float) q2y, + (float) e2x, + (float) e2y); + eta1 = eta2; + e1x = e2x; + e1y = e2y; + ep1x = ep2x; + ep1y = ep2y; + } + } + } +} diff --git a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java new file mode 100644 index 0000000000..d33c20496c --- /dev/null +++ b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java @@ -0,0 +1,1470 @@ +/* + * Copyright (C) 2015 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.support.graphics.drawable; + +import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.content.res.Resources.Theme; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PathMeasure; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.PorterDuff.Mode; +import android.graphics.PorterDuffColorFilter; +import android.graphics.Rect; +import android.graphics.Region; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.DrawableRes; +import android.support.v4.util.ArrayMap; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Xml; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Stack; + +/** + * This lets you create a drawable based on an XML vector graphic. It can be defined in an XML file + * with the <code><vector></code> element. + * <p/> + * The vector drawable has the following elements: + * <p/> + * <dt><code><vector></code></dt> + * <dl> + * <dd>Used to define a vector drawable + * <dl> + * <dt><code>android:name</code></dt> + * <dd>Defines the name of this vector drawable.</dd> + * <dt><code>android:width</code></dt> + * <dd>Used to define the intrinsic width of the drawable. This support all the dimension units, + * normally specified with dp.</dd> + * <dt><code>android:height</code></dt> + * <dd>Used to define the intrinsic height the drawable. This support all the dimension units, + * normally specified with dp.</dd> + * <dt><code>android:viewportWidth</code></dt> + * <dd>Used to define the width of the viewport space. Viewport is basically the virtual canvas + * where the paths are drawn on.</dd> + * <dt><code>android:viewportHeight</code></dt> + * <dd>Used to define the height of the viewport space. Viewport is basically the virtual canvas + * where the paths are drawn on.</dd> + * <dt><code>android:tint</code></dt> + * <dd>The color to apply to the drawable as a tint. By default, no tint is applied.</dd> + * <dt><code>android:tintMode</code></dt> + * <dd>The Porter-Duff blending mode for the tint color. The default value is src_in.</dd> + * <dt><code>android:autoMirrored</code></dt> + * <dd>Indicates if the drawable needs to be mirrored when its layout direction is RTL + * (right-to-left).</dd> + * <dt><code>android:alpha</code></dt> + * <dd>The opacity of this drawable.</dd> + * </dl> + * </dd> + * </dl> + * <dl> + * <dt><code><group></code></dt> + * <dd>Defines a group of paths or subgroups, plus transformation information. The transformations + * are defined in the same coordinates as the viewport. And the transformations are applied in the + * order of scale, rotate then translate. + * <dl> + * <dt><code>android:name</code></dt> + * <dd>Defines the name of the group.</dd> + * <dt><code>android:rotation</code></dt> + * <dd>The degrees of rotation of the group.</dd> + * <dt><code>android:pivotX</code></dt> + * <dd>The X coordinate of the pivot for the scale and rotation of the group. This is defined in the + * viewport space.</dd> + * <dt><code>android:pivotY</code></dt> + * <dd>The Y coordinate of the pivot for the scale and rotation of the group. This is defined in the + * viewport space.</dd> + * <dt><code>android:scaleX</code></dt> + * <dd>The amount of scale on the X Coordinate.</dd> + * <dt><code>android:scaleY</code></dt> + * <dd>The amount of scale on the Y coordinate.</dd> + * <dt><code>android:translateX</code></dt> + * <dd>The amount of translation on the X coordinate. This is defined in the viewport space.</dd> + * <dt><code>android:translateY</code></dt> + * <dd>The amount of translation on the Y coordinate. This is defined in the viewport space.</dd> + * </dl> + * </dd> + * </dl> + * <dl> + * <dt><code><path></code></dt> + * <dd>Defines paths to be drawn. + * <dl> + * <dt><code>android:name</code></dt> + * <dd>Defines the name of the path.</dd> + * <dt><code>android:pathData</code></dt> + * <dd>Defines path data using exactly same format as "d" attribute in the SVG's path + * data. This is defined in the viewport space.</dd> + * <dt><code>android:fillColor</code></dt> + * <dd>Defines the color to fill the path (none if not present).</dd> + * <dt><code>android:strokeColor</code></dt> + * <dd>Defines the color to draw the path outline (none if not present).</dd> + * <dt><code>android:strokeWidth</code></dt> + * <dd>The width a path stroke.</dd> + * <dt><code>android:strokeAlpha</code></dt> + * <dd>The opacity of a path stroke.</dd> + * <dt><code>android:fillAlpha</code></dt> + * <dd>The opacity to fill the path with.</dd> + * <dt><code>android:trimPathStart</code></dt> + * <dd>The fraction of the path to trim from the start, in the range from 0 to 1.</dd> + * <dt><code>android:trimPathEnd</code></dt> + * <dd>The fraction of the path to trim from the end, in the range from 0 to 1.</dd> + * <dt><code>android:trimPathOffset</code></dt> + * <dd>Shift trim region (allows showed region to include the start and end), in the range from 0 to + * 1.</dd> + * <dt><code>android:strokeLineCap</code></dt> + * <dd>Sets the linecap for a stroked path: butt, round, square.</dd> + * <dt><code>android:strokeLineJoin</code></dt> + * <dd>Sets the lineJoin for a stroked path: miter,round,bevel.</dd> + * <dt><code>android:strokeMiterLimit</code></dt> + * <dd>Sets the Miter limit for a stroked path.</dd> + * </dl> + * </dd> + * </dl> + * <dl> + * <dt><code><clip-path></code></dt> + * <dd>Defines path to be the current clip. + * <dl> + * <dt><code>android:name</code></dt> + * <dd>Defines the name of the clip path.</dd> + * <dt><code>android:pathData</code></dt> + * <dd>Defines clip path data using the same format as "d" attribute in the SVG's + * path data.</dd> + * </dl> + * </dd> + * </dl> + * <li>Here is a simple VectorDrawable in this vectordrawable.xml file. + * <pre> + * <vector xmlns:android="http://schemas.android.com/apk/res/android" + * android:height="64dp" + * android:width="64dp" + * android:viewportHeight="600" + * android:viewportWidth="600" > + * <group + * android:name="rotationGroup" + * android:pivotX="300.0" + * android:pivotY="300.0" + * android:rotation="45.0" > + * <path + * android:name="v" + * android:fillColor="#000000" + * android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /> + * </group> + * </vector> + * </pre></li> + */ +public class VectorDrawableCompat extends Drawable { + static final String LOGTAG = "VectorDrawableCompat"; + + static final PorterDuff.Mode DEFAULT_TINT_MODE = PorterDuff.Mode.SRC_IN; + + private static final String SHAPE_CLIP_PATH = "clip-path"; + private static final String SHAPE_GROUP = "group"; + private static final String SHAPE_PATH = "path"; + private static final String SHAPE_VECTOR = "vector"; + + private static final int LINECAP_BUTT = 0; + private static final int LINECAP_ROUND = 1; + private static final int LINECAP_SQUARE = 2; + + private static final int LINEJOIN_MITER = 0; + private static final int LINEJOIN_ROUND = 1; + private static final int LINEJOIN_BEVEL = 2; + + private static final boolean DBG_VECTOR_DRAWABLE = true; + + private VectorDrawableState mVectorState; + + private PorterDuffColorFilter mTintFilter; + private ColorFilter mColorFilter; + + private boolean mMutated; + + // AnimatedVectorDrawable needs to turn off the cache all the time, otherwise, + // caching the bitmap by default is allowed. + private boolean mAllowCaching = true; + + private VectorDrawableCompat() { + mVectorState = new VectorDrawableState(); + } + + private VectorDrawableCompat(VectorDrawableState state) { + mVectorState = state; + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); + } + + @Override + public Drawable mutate() { + if (!mMutated && super.mutate() == this) { + mVectorState = new VectorDrawableState(mVectorState); + mMutated = true; + } + return this; + } + + Object getTargetByName(String name) { + return mVectorState.mVPathRenderer.mVGTargetsMap.get(name); + } + + @Override + public ConstantState getConstantState() { + mVectorState.mChangingConfigurations = getChangingConfigurations(); + return mVectorState; + } + + @Override + public void draw(Canvas canvas) { + final Rect bounds = getBounds(); + if (bounds.width() == 0 || bounds.height() == 0) { + // too small to draw + return; + } + + final int saveCount = canvas.save(); + final boolean needMirroring = needMirroring(); + + canvas.translate(bounds.left, bounds.top); + if (needMirroring) { + canvas.translate(bounds.width(), 0); + canvas.scale(-1.0f, 1.0f); + } + + // Color filters always override tint filters. + final ColorFilter colorFilter = mColorFilter == null ? mTintFilter : mColorFilter; + + if (!mAllowCaching) { + // AnimatedVectorDrawable + if (!mVectorState.hasTranslucentRoot()) { + mVectorState.mVPathRenderer.draw( + canvas, bounds.width(), bounds.height(), colorFilter); + } else { + mVectorState.createCachedBitmapIfNeeded(bounds); + mVectorState.updateCachedBitmap(bounds); + mVectorState.drawCachedBitmapWithRootAlpha(canvas, colorFilter); + } + } else { + // Static Vector Drawable case. + mVectorState.createCachedBitmapIfNeeded(bounds); + if (!mVectorState.canReuseCache()) { + mVectorState.updateCachedBitmap(bounds); + mVectorState.updateCacheStates(); + } + mVectorState.drawCachedBitmapWithRootAlpha(canvas, colorFilter); + } + + canvas.restoreToCount(saveCount); + } + + public int getAlpha() { + return mVectorState.mVPathRenderer.getRootAlpha(); + } + + @Override + public void setAlpha(int alpha) { + if (mVectorState.mVPathRenderer.getRootAlpha() != alpha) { + mVectorState.mVPathRenderer.setRootAlpha(alpha); + invalidateSelf(); + } + } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + mColorFilter = colorFilter; + invalidateSelf(); + } + + /** + * Ensures the tint filter is consistent with the current tint color and + * mode. + */ + PorterDuffColorFilter updateTintFilter(PorterDuffColorFilter tintFilter, ColorStateList tint, + PorterDuff.Mode tintMode) { + if (tint == null || tintMode == null) { + return null; + } + // setMode, setColor of PorterDuffColorFilter are not public method in SDK v7. + // Therefore we create a new one all the time here. Don't expect this is called often. + final int color = tint.getColorForState(getState(), Color.TRANSPARENT); + return new PorterDuffColorFilter(color, tintMode); + } + + public void setTint(int tint) { + setTintList(ColorStateList.valueOf(tint)); + } + + public void setTintList(ColorStateList tint) { + final VectorDrawableState state = mVectorState; + if (state.mTint != tint) { + state.mTint = tint; + mTintFilter = updateTintFilter(mTintFilter, tint, state.mTintMode); + invalidateSelf(); + } + } + + public void setTintMode(Mode tintMode) { + final VectorDrawableState state = mVectorState; + if (state.mTintMode != tintMode) { + state.mTintMode = tintMode; + mTintFilter = updateTintFilter(mTintFilter, state.mTint, tintMode); + invalidateSelf(); + } + } + + @Override + public boolean isStateful() { + return super.isStateful() || (mVectorState != null && mVectorState.mTint != null + && mVectorState.mTint.isStateful()); + } + + @Override + protected boolean onStateChange(int[] stateSet) { + final VectorDrawableState state = mVectorState; + if (state.mTint != null && state.mTintMode != null) { + // mTintFilter = updateTintFilter(this, mTintFilter, state.mTint, state.mTintMode); + invalidateSelf(); + return true; + } + return false; + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + @Override + public int getIntrinsicWidth() { + return (int) mVectorState.mVPathRenderer.mBaseWidth; + } + + @Override + public int getIntrinsicHeight() { + return (int) mVectorState.mVPathRenderer.mBaseHeight; + } + + // Don't support re-applying themes. The initial theme loading is working. + public boolean canApplyTheme() { + return false; + } + + /** + * The size of a pixel when scaled from the intrinsic dimension to the viewport dimension. This + * is used to calculate the path animation accuracy. + * + * @hide + */ + public float getPixelSize() { + if (mVectorState == null && mVectorState.mVPathRenderer == null || + mVectorState.mVPathRenderer.mBaseWidth == 0 || + mVectorState.mVPathRenderer.mBaseHeight == 0 || + mVectorState.mVPathRenderer.mViewportHeight == 0 || + mVectorState.mVPathRenderer.mViewportWidth == 0) { + return 1; // fall back to 1:1 pixel mapping. + } + float intrinsicWidth = mVectorState.mVPathRenderer.mBaseWidth; + float intrinsicHeight = mVectorState.mVPathRenderer.mBaseHeight; + float viewportWidth = mVectorState.mVPathRenderer.mViewportWidth; + float viewportHeight = mVectorState.mVPathRenderer.mViewportHeight; + float scaleX = viewportWidth / intrinsicWidth; + float scaleY = viewportHeight / intrinsicHeight; + return Math.min(scaleX, scaleY); + } + + /** + * Create a VectorDrawableCompat object. + * + * @param res the resources. + * @param resId the resource ID for VectorDrawableCompat object. + * @param theme the theme of this vector drawable, it can be null. + * @return a new VectorDrawableCompat or null if parsing error is found. + */ + @Nullable + public static VectorDrawableCompat create(@NonNull Resources res, @DrawableRes int resId, + @Nullable Theme theme) { + try { + final XmlPullParser parser = res.getXml(resId); + final AttributeSet attrs = Xml.asAttributeSet(parser); + int type; + while ((type = parser.next()) != XmlPullParser.START_TAG && + type != XmlPullParser.END_DOCUMENT) { + // Empty loop + } + if (type != XmlPullParser.START_TAG) { + throw new XmlPullParserException("No start tag found"); + } + + final VectorDrawableCompat drawable = new VectorDrawableCompat(); + drawable.inflate(res, parser, attrs, theme); + + return drawable; + } catch (XmlPullParserException e) { + Log.e(LOGTAG, "parser error", e); + } catch (IOException e) { + Log.e(LOGTAG, "parser error", e); + } + return null; + } + + private static int applyAlpha(int color, float alpha) { + int alphaBytes = Color.alpha(color); + color &= 0x00FFFFFF; + color |= ((int) (alphaBytes * alpha)) << 24; + return color; + } + + /** + * Obtains styled attributes from the theme, if available, or unstyled + * resources if the theme is null. + */ + static TypedArray obtainAttributes( + Resources res, Theme theme, AttributeSet set, int[] attrs) { + if (theme == null) { + return res.obtainAttributes(set, attrs); + } + return theme.obtainStyledAttributes(set, attrs, 0, 0); + } + + + @Override + public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs) + throws XmlPullParserException, IOException { + inflate(res, parser, attrs, null); + } + + public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme) + throws XmlPullParserException, IOException { + final VectorDrawableState state = mVectorState; + final VPathRenderer pathRenderer = new VPathRenderer(); + state.mVPathRenderer = pathRenderer; + + final TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawable); + updateStateFromTypedArray(a); + a.recycle(); + state.mChangingConfigurations = getChangingConfigurations(); + state.mCacheDirty = true; + inflateInternal(res, parser, attrs, theme); + + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); + } + + private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException { + final VectorDrawableState state = mVectorState; + final VPathRenderer pathRenderer = state.mVPathRenderer; + + // Account for any configuration changes. + // state.mChangingConfigurations |= Utils.getChangingConfigurations(a); + + final int tintMode = a.getInt(R.styleable.VectorDrawable_tintMode, -1); + // if (tintMode != -1) { + // state.mTintMode = Utils.parseTintMode(tintMode, DEFAULT_TINT_MODE); + // } + + final ColorStateList tint = a.getColorStateList(R.styleable.VectorDrawable_tint); + if (tint != null) { + state.mTint = tint; + } + + state.mAutoMirrored = a.getBoolean( + R.styleable.VectorDrawable_autoMirrored, state.mAutoMirrored); + + pathRenderer.mViewportWidth = a.getFloat( + R.styleable.VectorDrawable_viewportWidth, pathRenderer.mViewportWidth); + pathRenderer.mViewportHeight = a.getFloat( + R.styleable.VectorDrawable_viewportHeight, pathRenderer.mViewportHeight); + + if (pathRenderer.mViewportWidth <= 0) { + throw new XmlPullParserException(a.getPositionDescription() + + "<vector> tag requires viewportWidth > 0"); + } else if (pathRenderer.mViewportHeight <= 0) { + throw new XmlPullParserException(a.getPositionDescription() + + "<vector> tag requires viewportHeight > 0"); + } + + pathRenderer.mBaseWidth = a.getDimension( + R.styleable.VectorDrawable_width, pathRenderer.mBaseWidth); + pathRenderer.mBaseHeight = a.getDimension( + R.styleable.VectorDrawable_height, pathRenderer.mBaseHeight); + + if (pathRenderer.mBaseWidth <= 0) { + throw new XmlPullParserException(a.getPositionDescription() + + "<vector> tag requires width > 0"); + } else if (pathRenderer.mBaseHeight <= 0) { + throw new XmlPullParserException(a.getPositionDescription() + + "<vector> tag requires height > 0"); + } + + final float alphaInFloat = a.getFloat(R.styleable.VectorDrawable_alpha, + pathRenderer.getAlpha()); + pathRenderer.setAlpha(alphaInFloat); + + final String name = a.getString(R.styleable.VectorDrawable_name); + if (name != null) { + pathRenderer.mRootName = name; + pathRenderer.mVGTargetsMap.put(name, pathRenderer); + } + } + + private void inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs, + Theme theme) throws XmlPullParserException, IOException { + final VectorDrawableState state = mVectorState; + final VPathRenderer pathRenderer = state.mVPathRenderer; + boolean noPathTag = true; + + // Use a stack to help to build the group tree. + // The top of the stack is always the current group. + final Stack<VGroup> groupStack = new Stack<VGroup>(); + groupStack.push(pathRenderer.mRootGroup); + + int eventType = parser.getEventType(); + while (eventType != XmlPullParser.END_DOCUMENT) { + if (eventType == XmlPullParser.START_TAG) { + final String tagName = parser.getName(); + final VGroup currentGroup = groupStack.peek(); + Log.v(LOGTAG, tagName); + if (SHAPE_PATH.equals(tagName)) { + final VFullPath path = new VFullPath(); + path.inflate(res, attrs, theme); + currentGroup.mChildren.add(path); + if (path.getPathName() != null) { + pathRenderer.mVGTargetsMap.put(path.getPathName(), path); + } + noPathTag = false; + state.mChangingConfigurations |= path.mChangingConfigurations; + } else if (SHAPE_CLIP_PATH.equals(tagName)) { + final VClipPath path = new VClipPath(); + path.inflate(res, attrs, theme); + currentGroup.mChildren.add(path); + if (path.getPathName() != null) { + pathRenderer.mVGTargetsMap.put(path.getPathName(), path); + } + state.mChangingConfigurations |= path.mChangingConfigurations; + } else if (SHAPE_GROUP.equals(tagName)) { + VGroup newChildGroup = new VGroup(); + newChildGroup.inflate(res, attrs, theme); + currentGroup.mChildren.add(newChildGroup); + groupStack.push(newChildGroup); + if (newChildGroup.getGroupName() != null) { + pathRenderer.mVGTargetsMap.put(newChildGroup.getGroupName(), + newChildGroup); + } + state.mChangingConfigurations |= newChildGroup.mChangingConfigurations; + } + } else if (eventType == XmlPullParser.END_TAG) { + final String tagName = parser.getName(); + if (SHAPE_GROUP.equals(tagName)) { + groupStack.pop(); + } + } + eventType = parser.next(); + } + + // Print the tree out for debug. + if (DBG_VECTOR_DRAWABLE) { + printGroupTree(pathRenderer.mRootGroup, 0); + } + + if (noPathTag) { + final StringBuffer tag = new StringBuffer(); + + if (tag.length() > 0) { + tag.append(" or "); + } + tag.append(SHAPE_PATH); + + throw new XmlPullParserException("no " + tag + " defined"); + } + } + + private void printGroupTree(VGroup currentGroup, int level) { + String indent = ""; + for (int i = 0; i < level; i++) { + indent += " "; + } + // Print the current node + Log.v(LOGTAG, indent + "current group is :" + currentGroup.getGroupName() + + " rotation is " + currentGroup.mRotate); + Log.v(LOGTAG, indent + "matrix is :" + currentGroup.getLocalMatrix().toString()); + // Then print all the children groups + for (int i = 0; i < currentGroup.mChildren.size(); i++) { + Object child = currentGroup.mChildren.get(i); + if (child instanceof VGroup) { + printGroupTree((VGroup) child, level + 1); + } + } + } + + void setAllowCaching(boolean allowCaching) { + mAllowCaching = allowCaching; + } + + // We don't support RTL auto mirroring since the getLayoutDirection() is for API 17+. + private boolean needMirroring() { + return false; + } + + private static class VectorDrawableState extends ConstantState { + int mChangingConfigurations; + VPathRenderer mVPathRenderer; + ColorStateList mTint = null; + Mode mTintMode = DEFAULT_TINT_MODE; + boolean mAutoMirrored; + + Bitmap mCachedBitmap; + int[] mCachedThemeAttrs; + ColorStateList mCachedTint; + Mode mCachedTintMode; + int mCachedRootAlpha; + boolean mCachedAutoMirrored; + boolean mCacheDirty; + + /** Temporary paint object used to draw cached bitmaps. */ + Paint mTempPaint; + + // Deep copy for mutate() or implicitly mutate. + public VectorDrawableState(VectorDrawableState copy) { + if (copy != null) { + mChangingConfigurations = copy.mChangingConfigurations; + mVPathRenderer = new VPathRenderer(copy.mVPathRenderer); + if (copy.mVPathRenderer.mFillPaint != null) { + mVPathRenderer.mFillPaint = new Paint(copy.mVPathRenderer.mFillPaint); + } + if (copy.mVPathRenderer.mStrokePaint != null) { + mVPathRenderer.mStrokePaint = new Paint(copy.mVPathRenderer.mStrokePaint); + } + mTint = copy.mTint; + mTintMode = copy.mTintMode; + mAutoMirrored = copy.mAutoMirrored; + } + } + + public void drawCachedBitmapWithRootAlpha(Canvas canvas, ColorFilter filter) { + // The bitmap's size is the same as the bounds. + final Paint p = getPaint(filter); + canvas.drawBitmap(mCachedBitmap, 0, 0, p); + } + + public boolean hasTranslucentRoot() { + return mVPathRenderer.getRootAlpha() < 255; + } + + /** + * @return null when there is no need for alpha paint. + */ + public Paint getPaint(ColorFilter filter) { + if (!hasTranslucentRoot() && filter == null) { + return null; + } + + if (mTempPaint == null) { + mTempPaint = new Paint(); + mTempPaint.setFilterBitmap(true); + } + mTempPaint.setAlpha(mVPathRenderer.getRootAlpha()); + mTempPaint.setColorFilter(filter); + return mTempPaint; + } + + public void updateCachedBitmap(Rect bounds) { + mCachedBitmap.eraseColor(Color.TRANSPARENT); + Canvas tmpCanvas = new Canvas(mCachedBitmap); + mVPathRenderer.draw(tmpCanvas, bounds.width(), bounds.height(), null); + } + + public void createCachedBitmapIfNeeded(Rect bounds) { + if (mCachedBitmap == null || !canReuseBitmap(bounds.width(), + bounds.height())) { + mCachedBitmap = Bitmap.createBitmap(bounds.width(), bounds.height(), + Bitmap.Config.ARGB_8888); + mCacheDirty = true; + } + + } + + public boolean canReuseBitmap(int width, int height) { + if (width == mCachedBitmap.getWidth() + && height == mCachedBitmap.getHeight()) { + return true; + } + return false; + } + + public boolean canReuseCache() { + if (!mCacheDirty + && mCachedTint == mTint + && mCachedTintMode == mTintMode + && mCachedAutoMirrored == mAutoMirrored + && mCachedRootAlpha == mVPathRenderer.getRootAlpha()) { + return true; + } + return false; + } + + public void updateCacheStates() { + // Use shallow copy here and shallow comparison in canReuseCache(), + // likely hit cache miss more, but practically not much difference. + mCachedTint = mTint; + mCachedTintMode = mTintMode; + mCachedRootAlpha = mVPathRenderer.getRootAlpha(); + mCachedAutoMirrored = mAutoMirrored; + mCacheDirty = false; + } + + public VectorDrawableState() { + mVPathRenderer = new VPathRenderer(); + } + + @Override + public Drawable newDrawable() { + return new VectorDrawableCompat(this); + } + + @Override + public Drawable newDrawable(Resources res) { + return new VectorDrawableCompat(this); + } + + @Override + public int getChangingConfigurations() { + return mChangingConfigurations; + } + } + + private static class VPathRenderer { + /* Right now the internal data structure is organized as a tree. + * Each node can be a group node, or a path. + * A group node can have groups or paths as children, but a path node has + * no children. + * One example can be: + * Root Group + * / | \ + * Group Path Group + * / \ | + * Path Path Path + * + */ + // Variables that only used temporarily inside the draw() call, so there + // is no need for deep copying. + private final Path mPath; + private final Path mRenderPath; + private static final Matrix IDENTITY_MATRIX = new Matrix(); + private final Matrix mFinalPathMatrix = new Matrix(); + + private Paint mStrokePaint; + private Paint mFillPaint; + private PathMeasure mPathMeasure; + + ///////////////////////////////////////////////////// + // Variables below need to be copied (deep copy if applicable) for mutation. + private int mChangingConfigurations; + private final VGroup mRootGroup; + float mBaseWidth = 0; + float mBaseHeight = 0; + float mViewportWidth = 0; + float mViewportHeight = 0; + int mRootAlpha = 0xFF; + String mRootName = null; + + final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>(); + + public VPathRenderer() { + mRootGroup = new VGroup(); + mPath = new Path(); + mRenderPath = new Path(); + } + + public void setRootAlpha(int alpha) { + mRootAlpha = alpha; + } + + public int getRootAlpha() { + return mRootAlpha; + } + + // setAlpha() and getAlpha() are used mostly for animation purpose, since + // Animator like to use alpha from 0 to 1. + public void setAlpha(float alpha) { + setRootAlpha((int) (alpha * 255)); + } + + @SuppressWarnings("unused") + public float getAlpha() { + return getRootAlpha() / 255.0f; + } + + public VPathRenderer(VPathRenderer copy) { + mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap); + mPath = new Path(copy.mPath); + mRenderPath = new Path(copy.mRenderPath); + mBaseWidth = copy.mBaseWidth; + mBaseHeight = copy.mBaseHeight; + mViewportWidth = copy.mViewportWidth; + mViewportHeight = copy.mViewportHeight; + mChangingConfigurations = copy.mChangingConfigurations; + mRootAlpha = copy.mRootAlpha; + mRootName = copy.mRootName; + if (copy.mRootName != null) { + mVGTargetsMap.put(copy.mRootName, this); + } + } + + private void drawGroupTree(VGroup currentGroup, Matrix currentMatrix, + Canvas canvas, int w, int h, ColorFilter filter) { + // Calculate current group's matrix by preConcat the parent's and + // and the current one on the top of the stack. + // Basically the Mfinal = Mviewport * M0 * M1 * M2; + // Mi the local matrix at level i of the group tree. + currentGroup.mStackedMatrix.set(currentMatrix); + + currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix); + + // Draw the group tree in the same order as the XML file. + for (int i = 0; i < currentGroup.mChildren.size(); i++) { + Object child = currentGroup.mChildren.get(i); + if (child instanceof VGroup) { + VGroup childGroup = (VGroup) child; + drawGroupTree(childGroup, currentGroup.mStackedMatrix, + canvas, w, h, filter); + } else if (child instanceof VPath) { + VPath childPath = (VPath) child; + drawPath(currentGroup, childPath, canvas, w, h, filter); + } + } + } + + public void draw(Canvas canvas, int w, int h, ColorFilter filter) { + // Travese the tree in pre-order to draw. + drawGroupTree(mRootGroup, IDENTITY_MATRIX, canvas, w, h, filter); + } + + private void drawPath(VGroup vGroup, VPath vPath, Canvas canvas, int w, int h, + ColorFilter filter) { + final float scaleX = w / mViewportWidth; + final float scaleY = h / mViewportHeight; + final float minScale = Math.min(scaleX, scaleY); + + mFinalPathMatrix.set(vGroup.mStackedMatrix); + mFinalPathMatrix.postScale(scaleX, scaleY); + + vPath.toPath(mPath); + final Path path = mPath; + + mRenderPath.reset(); + + if (vPath.isClipPath()) { + mRenderPath.addPath(path, mFinalPathMatrix); + canvas.clipPath(mRenderPath, Region.Op.REPLACE); + } else { + VFullPath fullPath = (VFullPath) vPath; + if (fullPath.mTrimPathStart != 0.0f || fullPath.mTrimPathEnd != 1.0f) { + float start = (fullPath.mTrimPathStart + fullPath.mTrimPathOffset) % 1.0f; + float end = (fullPath.mTrimPathEnd + fullPath.mTrimPathOffset) % 1.0f; + + if (mPathMeasure == null) { + mPathMeasure = new PathMeasure(); + } + mPathMeasure.setPath(mPath, false); + + float len = mPathMeasure.getLength(); + start = start * len; + end = end * len; + path.reset(); + if (start > end) { + mPathMeasure.getSegment(start, len, path, true); + mPathMeasure.getSegment(0f, end, path, true); + } else { + mPathMeasure.getSegment(start, end, path, true); + } + path.rLineTo(0, 0); // fix bug in measure + } + mRenderPath.addPath(path, mFinalPathMatrix); + + if (fullPath.mFillColor != Color.TRANSPARENT) { + if (mFillPaint == null) { + mFillPaint = new Paint(); + mFillPaint.setStyle(Paint.Style.FILL); + mFillPaint.setAntiAlias(true); + } + + final Paint fillPaint = mFillPaint; + fillPaint.setColor(applyAlpha(fullPath.mFillColor, fullPath.mFillAlpha)); + fillPaint.setColorFilter(filter); + canvas.drawPath(mRenderPath, fillPaint); + } + + if (fullPath.mStrokeColor != Color.TRANSPARENT) { + if (mStrokePaint == null) { + mStrokePaint = new Paint(); + mStrokePaint.setStyle(Paint.Style.STROKE); + mStrokePaint.setAntiAlias(true); + } + + final Paint strokePaint = mStrokePaint; + if (fullPath.mStrokeLineJoin != null) { + strokePaint.setStrokeJoin(fullPath.mStrokeLineJoin); + } + + if (fullPath.mStrokeLineCap != null) { + strokePaint.setStrokeCap(fullPath.mStrokeLineCap); + } + + strokePaint.setStrokeMiter(fullPath.mStrokeMiterlimit); + strokePaint.setColor(applyAlpha(fullPath.mStrokeColor, fullPath.mStrokeAlpha)); + strokePaint.setColorFilter(filter); + strokePaint.setStrokeWidth(fullPath.mStrokeWidth * minScale); + canvas.drawPath(mRenderPath, strokePaint); + } + } + } + } + + private static class VGroup { + // mStackedMatrix is only used temporarily when drawing, it combines all + // the parents' local matrices with the current one. + private final Matrix mStackedMatrix = new Matrix(); + + ///////////////////////////////////////////////////// + // Variables below need to be copied (deep copy if applicable) for mutation. + final ArrayList<Object> mChildren = new ArrayList<Object>(); + + private float mRotate = 0; + private float mPivotX = 0; + private float mPivotY = 0; + private float mScaleX = 1; + private float mScaleY = 1; + private float mTranslateX = 0; + private float mTranslateY = 0; + + // mLocalMatrix is updated based on the update of transformation information, + // either parsed from the XML or by animation. + private final Matrix mLocalMatrix = new Matrix(); + private int mChangingConfigurations; + private int[] mThemeAttrs; + private String mGroupName = null; + + public VGroup(VGroup copy, ArrayMap<String, Object> targetsMap) { + mRotate = copy.mRotate; + mPivotX = copy.mPivotX; + mPivotY = copy.mPivotY; + mScaleX = copy.mScaleX; + mScaleY = copy.mScaleY; + mTranslateX = copy.mTranslateX; + mTranslateY = copy.mTranslateY; + mThemeAttrs = copy.mThemeAttrs; + mGroupName = copy.mGroupName; + mChangingConfigurations = copy.mChangingConfigurations; + if (mGroupName != null) { + targetsMap.put(mGroupName, this); + } + + mLocalMatrix.set(copy.mLocalMatrix); + + final ArrayList<Object> children = copy.mChildren; + for (int i = 0; i < children.size(); i++) { + Object copyChild = children.get(i); + if (copyChild instanceof VGroup) { + VGroup copyGroup = (VGroup) copyChild; + mChildren.add(new VGroup(copyGroup, targetsMap)); + } else { + VPath newPath = null; + if (copyChild instanceof VFullPath) { + newPath = new VFullPath((VFullPath) copyChild); + } else if (copyChild instanceof VClipPath) { + newPath = new VClipPath((VClipPath) copyChild); + } else { + throw new IllegalStateException("Unknown object in the tree!"); + } + mChildren.add(newPath); + if (newPath.mPathName != null) { + targetsMap.put(newPath.mPathName, newPath); + } + } + } + } + + public VGroup() { + } + + public String getGroupName() { + return mGroupName; + } + + public Matrix getLocalMatrix() { + return mLocalMatrix; + } + + public void inflate(Resources res, AttributeSet attrs, Theme theme) { + final TypedArray a = obtainAttributes(res, theme, attrs, + R.styleable.VectorDrawableGroup); + updateStateFromTypedArray(a); + a.recycle(); + } + + private void updateStateFromTypedArray(TypedArray a) { + // Account for any configuration changes. + // mChangingConfigurations |= Utils.getChangingConfigurations(a); + + // Extract the theme attributes, if any. + mThemeAttrs = null; // TODO TINT THEME Not supported yet a.extractThemeAttrs(); + + mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate); + mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX); + mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY); + mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX); + mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY); + mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX); + mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY); + + final String groupName = a.getString(R.styleable.VectorDrawableGroup_name); + if (groupName != null) { + mGroupName = groupName; + } + + updateLocalMatrix(); + } + + private void updateLocalMatrix() { + // The order we apply is the same as the + // RenderNode.cpp::applyViewPropertyTransforms(). + mLocalMatrix.reset(); + mLocalMatrix.postTranslate(-mPivotX, -mPivotY); + mLocalMatrix.postScale(mScaleX, mScaleY); + mLocalMatrix.postRotate(mRotate, 0, 0); + mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY); + } + + /* Setters and Getters, used by animator from AnimatedVectorDrawable. */ + @SuppressWarnings("unused") + public float getRotation() { + return mRotate; + } + + @SuppressWarnings("unused") + public void setRotation(float rotation) { + if (rotation != mRotate) { + mRotate = rotation; + updateLocalMatrix(); + } + } + + @SuppressWarnings("unused") + public float getPivotX() { + return mPivotX; + } + + @SuppressWarnings("unused") + public void setPivotX(float pivotX) { + if (pivotX != mPivotX) { + mPivotX = pivotX; + updateLocalMatrix(); + } + } + + @SuppressWarnings("unused") + public float getPivotY() { + return mPivotY; + } + + @SuppressWarnings("unused") + public void setPivotY(float pivotY) { + if (pivotY != mPivotY) { + mPivotY = pivotY; + updateLocalMatrix(); + } + } + + @SuppressWarnings("unused") + public float getScaleX() { + return mScaleX; + } + + @SuppressWarnings("unused") + public void setScaleX(float scaleX) { + if (scaleX != mScaleX) { + mScaleX = scaleX; + updateLocalMatrix(); + } + } + + @SuppressWarnings("unused") + public float getScaleY() { + return mScaleY; + } + + @SuppressWarnings("unused") + public void setScaleY(float scaleY) { + if (scaleY != mScaleY) { + mScaleY = scaleY; + updateLocalMatrix(); + } + } + + @SuppressWarnings("unused") + public float getTranslateX() { + return mTranslateX; + } + + @SuppressWarnings("unused") + public void setTranslateX(float translateX) { + if (translateX != mTranslateX) { + mTranslateX = translateX; + updateLocalMatrix(); + } + } + + @SuppressWarnings("unused") + public float getTranslateY() { + return mTranslateY; + } + + @SuppressWarnings("unused") + public void setTranslateY(float translateY) { + if (translateY != mTranslateY) { + mTranslateY = translateY; + updateLocalMatrix(); + } + } + } + + /** + * Common Path information for clip path and normal path. + */ + private static class VPath { + protected PathParser.PathDataNode[] mNodes = null; + String mPathName; + int mChangingConfigurations; + + public VPath() { + // Empty constructor. + } + + public VPath(VPath copy) { + mPathName = copy.mPathName; + mChangingConfigurations = copy.mChangingConfigurations; + mNodes = PathParser.deepCopyNodes(copy.mNodes); + } + + public void toPath(Path path) { + path.reset(); + if (mNodes != null) { + PathParser.PathDataNode.nodesToPath(mNodes, path); + } + } + + public String getPathName() { + return mPathName; + } + + public boolean canApplyTheme() { + return false; + } + + public void applyTheme(Theme t) { + } + + public boolean isClipPath() { + return false; + } + + /* Setters and Getters, used by animator from AnimatedVectorDrawable. */ + @SuppressWarnings("unused") + public PathParser.PathDataNode[] getPathData() { + return mNodes; + } + + @SuppressWarnings("unused") + public void setPathData(PathParser.PathDataNode[] nodes) { + if (!PathParser.canMorph(mNodes, nodes)) { + // This should not happen in the middle of animation. + mNodes = PathParser.deepCopyNodes(nodes); + } else { + PathParser.updateNodes(mNodes, nodes); + } + } + } + + /** + * Clip path, which only has name and pathData. + */ + private static class VClipPath extends VPath { + public VClipPath() { + // Empty constructor. + } + + public VClipPath(VClipPath copy) { + super(copy); + } + + public void inflate(Resources r, AttributeSet attrs, Theme theme) { + // TODO TINT THEME Not supported yet + final TypedArray a = obtainAttributes(r, theme, attrs, + R.styleable.VectorDrawableClipPath); + updateStateFromTypedArray(a); + a.recycle(); + } + + private void updateStateFromTypedArray(TypedArray a) { + // Account for any configuration changes. + // mChangingConfigurations |= Utils.getChangingConfigurations(a);; + + final String pathName = a.getString(R.styleable.VectorDrawableClipPath_name); + if (pathName != null) { + mPathName = pathName; + } + + final String pathData = a.getString(R.styleable.VectorDrawableClipPath_pathData); + if (pathData != null) { + mNodes = PathParser.createNodesFromPathData(pathData); + } + } + + @Override + public boolean isClipPath() { + return true; + } + } + + /** + * Normal path, which contains all the fill / paint information. + */ + private static class VFullPath extends VPath { + ///////////////////////////////////////////////////// + // Variables below need to be copied (deep copy if applicable) for mutation. + private int[] mThemeAttrs; + + int mStrokeColor = Color.TRANSPARENT; + float mStrokeWidth = 0; + + int mFillColor = Color.TRANSPARENT; + float mStrokeAlpha = 1.0f; + int mFillRule; + float mFillAlpha = 1.0f; + float mTrimPathStart = 0; + float mTrimPathEnd = 1; + float mTrimPathOffset = 0; + + Paint.Cap mStrokeLineCap = Paint.Cap.BUTT; + Paint.Join mStrokeLineJoin = Paint.Join.MITER; + float mStrokeMiterlimit = 4; + + public VFullPath() { + // Empty constructor. + } + + public VFullPath(VFullPath copy) { + super(copy); + mThemeAttrs = copy.mThemeAttrs; + + mStrokeColor = copy.mStrokeColor; + mStrokeWidth = copy.mStrokeWidth; + mStrokeAlpha = copy.mStrokeAlpha; + mFillColor = copy.mFillColor; + mFillRule = copy.mFillRule; + mFillAlpha = copy.mFillAlpha; + mTrimPathStart = copy.mTrimPathStart; + mTrimPathEnd = copy.mTrimPathEnd; + mTrimPathOffset = copy.mTrimPathOffset; + + mStrokeLineCap = copy.mStrokeLineCap; + mStrokeLineJoin = copy.mStrokeLineJoin; + mStrokeMiterlimit = copy.mStrokeMiterlimit; + } + + private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) { + switch (id) { + case LINECAP_BUTT: + return Paint.Cap.BUTT; + case LINECAP_ROUND: + return Paint.Cap.ROUND; + case LINECAP_SQUARE: + return Paint.Cap.SQUARE; + default: + return defValue; + } + } + + private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) { + switch (id) { + case LINEJOIN_MITER: + return Paint.Join.MITER; + case LINEJOIN_ROUND: + return Paint.Join.ROUND; + case LINEJOIN_BEVEL: + return Paint.Join.BEVEL; + default: + return defValue; + } + } + + @Override + public boolean canApplyTheme() { + return mThemeAttrs != null; + } + + public void inflate(Resources r, AttributeSet attrs, Theme theme) { + final TypedArray a = obtainAttributes(r, theme, attrs, + R.styleable.VectorDrawablePath); + updateStateFromTypedArray(a); + a.recycle(); + } + + private void updateStateFromTypedArray(TypedArray a) { + // Account for any configuration changes. + // mChangingConfigurations |= Utils.getChangingConfigurations(a); + + // Extract the theme attributes, if any. + mThemeAttrs = null; // TODO TINT THEME Not supported yet a.extractThemeAttrs(); + + final String pathName = a.getString(R.styleable.VectorDrawablePath_name); + if (pathName != null) { + mPathName = pathName; + } + + final String pathData = a.getString(R.styleable.VectorDrawablePath_pathData); + if (pathData != null) { + mNodes = PathParser.createNodesFromPathData(pathData); + } + + mFillColor = a.getColor(R.styleable.VectorDrawablePath_fillColor, + mFillColor); + mFillAlpha = a.getFloat(R.styleable.VectorDrawablePath_fillAlpha, + mFillAlpha); + mStrokeLineCap = getStrokeLineCap(a.getInt( + R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap); + mStrokeLineJoin = getStrokeLineJoin(a.getInt( + R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin); + mStrokeMiterlimit = a.getFloat( + R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit); + mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_strokeColor, + mStrokeColor); + mStrokeAlpha = a.getFloat(R.styleable.VectorDrawablePath_strokeAlpha, + mStrokeAlpha); + mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, + mStrokeWidth); + mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, + mTrimPathEnd); + mTrimPathOffset = a.getFloat( + R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset); + mTrimPathStart = a.getFloat( + R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart); + } + + @Override + public void applyTheme(Theme t) { + if (mThemeAttrs == null) { + return; + } + + /* + * TODO TINT THEME Not supported yet final TypedArray a = + * t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath); + * updateStateFromTypedArray(a); a.recycle(); + */ + } + + /* Setters and Getters, used by animator from AnimatedVectorDrawable. */ + @SuppressWarnings("unused") + int getStrokeColor() { + return mStrokeColor; + } + + @SuppressWarnings("unused") + void setStrokeColor(int strokeColor) { + mStrokeColor = strokeColor; + } + + @SuppressWarnings("unused") + float getStrokeWidth() { + return mStrokeWidth; + } + + @SuppressWarnings("unused") + void setStrokeWidth(float strokeWidth) { + mStrokeWidth = strokeWidth; + } + + @SuppressWarnings("unused") + float getStrokeAlpha() { + return mStrokeAlpha; + } + + @SuppressWarnings("unused") + void setStrokeAlpha(float strokeAlpha) { + mStrokeAlpha = strokeAlpha; + } + + @SuppressWarnings("unused") + int getFillColor() { + return mFillColor; + } + + @SuppressWarnings("unused") + void setFillColor(int fillColor) { + mFillColor = fillColor; + } + + @SuppressWarnings("unused") + float getFillAlpha() { + return mFillAlpha; + } + + @SuppressWarnings("unused") + void setFillAlpha(float fillAlpha) { + mFillAlpha = fillAlpha; + } + + @SuppressWarnings("unused") + float getTrimPathStart() { + return mTrimPathStart; + } + + @SuppressWarnings("unused") + void setTrimPathStart(float trimPathStart) { + mTrimPathStart = trimPathStart; + } + + @SuppressWarnings("unused") + float getTrimPathEnd() { + return mTrimPathEnd; + } + + @SuppressWarnings("unused") + void setTrimPathEnd(float trimPathEnd) { + mTrimPathEnd = trimPathEnd; + } + + @SuppressWarnings("unused") + float getTrimPathOffset() { + return mTrimPathOffset; + } + + @SuppressWarnings("unused") + void setTrimPathOffset(float trimPathOffset) { + mTrimPathOffset = trimPathOffset; + } + } +} diff --git a/graphics/drawable/testanimated/Android.mk b/graphics/drawable/testanimated/Android.mk new file mode 100644 index 0000000000..c888d9e220 --- /dev/null +++ b/graphics/drawable/testanimated/Android.mk @@ -0,0 +1,35 @@ +# Copyright (C) 2015 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SDK_VERSION := 11 + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_RESOURCE_DIR = \ + $(LOCAL_PATH)/res \ + frameworks/support/graphics/drawable/res \ + +LOCAL_PACKAGE_NAME := AndroidAnimatedVectorDrawableTests + +LOCAL_STATIC_JAVA_LIBRARIES := android-support-v11-animatedvectordrawable android-support-v4 + +LOCAL_AAPT_FLAGS += --auto-add-overlay --extra-packages android.support.graphics.drawable + +include $(BUILD_PACKAGE) diff --git a/graphics/drawable/testanimated/AndroidManifest.xml b/graphics/drawable/testanimated/AndroidManifest.xml new file mode 100644 index 0000000000..16171f27eb --- /dev/null +++ b/graphics/drawable/testanimated/AndroidManifest.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2015 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. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.support.test.vectordrawable" > + + <uses-sdk android:minSdkVersion="11" /> + + <application android:icon="@drawable/app_sample_code" android:label="AnimatedVectorDrawableCompatTest" > + <activity android:name="android.support.test.vectordrawable.TestAVDActivity" /> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </application> + +</manifest>
\ No newline at end of file diff --git a/graphics/drawable/testanimated/res/anim/alpha_animation_progress_bar.xml b/graphics/drawable/testanimated/res/anim/alpha_animation_progress_bar.xml new file mode 100644 index 0000000000..2463a8940d --- /dev/null +++ b/graphics/drawable/testanimated/res/anim/alpha_animation_progress_bar.xml @@ -0,0 +1,24 @@ +<!-- Copyright (C) 2015 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. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + + <objectAnimator + android:duration="3350" + android:propertyName="alpha" + android:valueFrom="1" + android:valueTo="0.2" /> + +</set>
\ No newline at end of file diff --git a/graphics/drawable/testanimated/res/anim/animation_grouping_1_01.xml b/graphics/drawable/testanimated/res/anim/animation_grouping_1_01.xml new file mode 100644 index 0000000000..36c297fbe9 --- /dev/null +++ b/graphics/drawable/testanimated/res/anim/animation_grouping_1_01.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2015 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. +--> + +<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" + android:duration="3300" + android:propertyName="rotation" + android:valueFrom="0" + android:valueTo="450" /> diff --git a/graphics/drawable/testanimated/res/anim/trim_path_animation_progress_bar.xml b/graphics/drawable/testanimated/res/anim/trim_path_animation_progress_bar.xml new file mode 100644 index 0000000000..388c759a77 --- /dev/null +++ b/graphics/drawable/testanimated/res/anim/trim_path_animation_progress_bar.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2015 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. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + + <objectAnimator + android:duration="1300" + android:interpolator="@android:anim/linear_interpolator" + android:propertyName="trimPathStart" + android:repeatCount="-1" + android:valueFrom="0" + android:valueTo="0.75" + android:valueType="floatType" /> + <objectAnimator + android:duration="1300" + android:interpolator="@android:anim/linear_interpolator" + android:propertyName="trimPathEnd" + android:repeatCount="-1" + android:valueFrom="0.25" + android:valueTo="1.0" + android:valueType="floatType" /> + <objectAnimator + android:duration="1300" + android:interpolator="@android:anim/linear_interpolator" + android:propertyName="trimPathOffset" + android:repeatCount="-1" + android:valueFrom="0" + android:valueTo="0.25" + android:valueType="floatType" /> + +</set>
\ No newline at end of file diff --git a/graphics/drawable/testanimated/res/drawable/animation_vector_drawable_grouping_1.xml b/graphics/drawable/testanimated/res/drawable/animation_vector_drawable_grouping_1.xml new file mode 100644 index 0000000000..7c3b1de076 --- /dev/null +++ b/graphics/drawable/testanimated/res/drawable/animation_vector_drawable_grouping_1.xml @@ -0,0 +1,27 @@ +<!-- + Copyright (C) 2015 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. +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:drawable="@drawable/vector_drawable_grouping_1" > + + <target + auto:name="sun" + auto:animation="@anim/animation_grouping_1_01" /> + <target + auto:name="earth" + auto:animation="@anim/animation_grouping_1_01" /> + +</animated-vector>
\ No newline at end of file diff --git a/graphics/drawable/testanimated/res/drawable/animation_vector_progress_bar.xml b/graphics/drawable/testanimated/res/drawable/animation_vector_progress_bar.xml new file mode 100644 index 0000000000..e37d2a1afe --- /dev/null +++ b/graphics/drawable/testanimated/res/drawable/animation_vector_progress_bar.xml @@ -0,0 +1,26 @@ +<!-- + Copyright (C) 2015 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. +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:drawable="@drawable/vector_drawable_progress_bar" > + + <target + auto:name="pie1" + auto:animation="@anim/trim_path_animation_progress_bar" /> + <target + auto:name="root_bar" + auto:animation="@anim/alpha_animation_progress_bar" /> +</animated-vector>
\ No newline at end of file diff --git a/graphics/drawable/testanimated/res/drawable/app_sample_code.png b/graphics/drawable/testanimated/res/drawable/app_sample_code.png Binary files differnew file mode 100755 index 0000000000..66a198496c --- /dev/null +++ b/graphics/drawable/testanimated/res/drawable/app_sample_code.png diff --git a/graphics/drawable/testanimated/res/drawable/vector_drawable_grouping_1.xml b/graphics/drawable/testanimated/res/drawable/vector_drawable_grouping_1.xml new file mode 100644 index 0000000000..eceda711fa --- /dev/null +++ b/graphics/drawable/testanimated/res/drawable/vector_drawable_grouping_1.xml @@ -0,0 +1,53 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:width="64dp" + auto:viewportHeight="256" + auto:viewportWidth="256" > + + <group + auto:name="shape_layer_1" + auto:translateX="128" + auto:translateY="128" > + <group auto:name="sun" > + <path + auto:name="ellipse_path_1" + auto:fillColor="#ffff8000" + auto:pathData="m -25 0 a 25,25 0 1,0 50,0 a 25,25 0 1,0 -50,0" /> + + <group + auto:name="earth" + auto:translateX="75" > + <path + auto:name="ellipse_path_1_1" + auto:fillColor="#ff5656ea" + auto:pathData="m -10 0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0" /> + + <group + auto:name="moon" + auto:translateX="25" > + <path + auto:name="ellipse_path_1_2" + auto:fillColor="#ffadadad" + auto:pathData="m -5 0 a 5,5 0 1,0 10,0 a 5,5 0 1,0 -10,0" /> + </group> + </group> + </group> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/testanimated/res/drawable/vector_drawable_progress_bar.xml b/graphics/drawable/testanimated/res/drawable/vector_drawable_progress_bar.xml new file mode 100644 index 0000000000..0b8884b487 --- /dev/null +++ b/graphics/drawable/testanimated/res/drawable/vector_drawable_progress_bar.xml @@ -0,0 +1,50 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:width="64dp" + auto:viewportHeight="64" + auto:viewportWidth="64" + auto:name="root_bar" > + + <group + auto:name="root" + auto:pivotX="0.0" + auto:pivotY="0.0" + auto:rotation="0" + auto:translateX="32.0" + auto:translateY="32.0" > + <group + auto:name="rotationGroup" + auto:pivotX="0.0" + auto:pivotY="0.0" + auto:rotation="0" > + <path + auto:name="pie1" + auto:fillColor="#00000000" + auto:pathData="M0, 0 m 0, -9.5 a 9.5,9.5 0 1,1 0,19 a 9.5,9.5 0 1,1 0,-19" + auto:strokeColor="#FF00FFFF" + auto:strokeLineCap="round" + auto:strokeLineJoin="miter" + auto:strokeWidth="2" + auto:trimPathEnd="0.1" + auto:trimPathOffset="0" + auto:trimPathStart="0" /> + </group> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/testanimated/res/values/strings.xml b/graphics/drawable/testanimated/res/values/strings.xml new file mode 100644 index 0000000000..c5451c8845 --- /dev/null +++ b/graphics/drawable/testanimated/res/values/strings.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2015 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. +--> + +<resources> + + <string name="twoLinePathData">"M 0,0 v 100 M 0,0 h 100"</string> + <string name="triangle"> "M300,70 l 0,-70 70,70 0,0 -70,70z"</string> + <string name="rectangle">"M300,70 l 0,-70 70,0 0,140 -70,0 z"</string> + <string name="rectangle2">"M300,70 l 0,-70 70,0 0,70z M300,70 l 70,0 0,70 -70,0z"</string> + <string name="equal2"> "M300,35 l 0,-35 70,0 0,35z M300,105 l 70,0 0,35 -70,0z"</string> + <string name="round_box">"m2.10001,-6c-1.9551,0 -0.5,0.02499 -2.10001,0.02499c-1.575,0 0.0031,-0.02499 -1.95,-0.02499c-2.543,0 -4,2.2816 -4,4.85001c0,3.52929 0.25,6.25 5.95,6.25c5.7,0 6,-2.72071 6,-6.25c0,-2.56841 -1.35699,-4.85001 -3.89999,-4.85001"</string> + <string name="heart"> "m4.5,-7c-1.95509,0 -3.83009,1.26759 -4.5,3c-0.66991,-1.73241 -2.54691,-3 -4.5,-3c-2.543,0 -4.5,1.93159 -4.5,4.5c0,3.5293 3.793,6.2578 9,11.5c5.207,-5.2422 9,-7.9707 9,-11.5c0,-2.56841 -1.957,-4.5 -4.5,-4.5"</string> + <string name="rectangle200">"M 0,0 l 200,0 l 0, 200 l -200, 0 z"</string> +</resources>
\ No newline at end of file diff --git a/graphics/drawable/testanimated/src/android/support/test/vectordrawable/TestAVDActivity.java b/graphics/drawable/testanimated/src/android/support/test/vectordrawable/TestAVDActivity.java new file mode 100644 index 0000000000..c63c69f947 --- /dev/null +++ b/graphics/drawable/testanimated/src/android/support/test/vectordrawable/TestAVDActivity.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2015 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.support.test.vectordrawable; + +import android.animation.ObjectAnimator; +import android.app.Activity; +import android.content.res.Resources; +import android.os.Bundle; +import android.support.graphics.drawable.AnimatedVectorDrawableCompat; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TextView; + +import java.text.DecimalFormat; + +public class TestAVDActivity extends Activity implements View.OnClickListener{ + private static final String LOG_TAG = "TestActivity"; + + private static final String LOGCAT = "VectorDrawable1"; + protected int[] icon = { + R.drawable.animation_vector_drawable_grouping_1, + R.drawable.animation_vector_progress_bar, + }; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + ObjectAnimator oa = new ObjectAnimator(); + super.onCreate(savedInstanceState); + ScrollView scrollView = new ScrollView(this); + LinearLayout container = new LinearLayout(this); + scrollView.addView(container); + container.setOrientation(LinearLayout.VERTICAL); + Resources res = this.getResources(); + container.setBackgroundColor(0xFF888888); + AnimatedVectorDrawableCompat []d = new AnimatedVectorDrawableCompat[icon.length]; + long time = android.os.SystemClock.currentThreadTimeMillis(); + for (int i = 0; i < icon.length; i++) { + d[i] = AnimatedVectorDrawableCompat.create(this, icon[i]); + } + time = android.os.SystemClock.currentThreadTimeMillis()-time; + TextView t = new TextView(this); + DecimalFormat df = new DecimalFormat("#.##"); + t.setText("avgL=" + df.format(time / (icon.length)) + " ms"); + container.addView(t); + + addDrawableButtons(container, d); + + // Now test constant state and mutate a bit. + AnimatedVectorDrawableCompat []copies = new AnimatedVectorDrawableCompat[3]; + copies[0] = (AnimatedVectorDrawableCompat) d[0].getConstantState().newDrawable(); + copies[1] = (AnimatedVectorDrawableCompat) d[0].getConstantState().newDrawable(); + copies[2] = (AnimatedVectorDrawableCompat) d[0].getConstantState().newDrawable(); + copies[0].setAlpha(128); + + // Expect to see the copies[0, 1] are showing alpha 128, and [2] are showing 255. + copies[2].mutate(); + copies[2].setAlpha(255); + + addDrawableButtons(container, copies); + + setContentView(scrollView); + } + + private void addDrawableButtons(LinearLayout container, AnimatedVectorDrawableCompat[] d) { + for (int i = 0; i < d.length; i++) { + Button button = new Button(this); + button.setWidth(200); + button.setHeight(200); + button.setBackgroundDrawable(d[i]); + container.addView(button); + button.setOnClickListener(this); + } + } + + @Override + public void onClick(View v) { + AnimatedVectorDrawableCompat d = (AnimatedVectorDrawableCompat) v.getBackground(); + d.start(); + } +} diff --git a/graphics/drawable/teststatic/Android.mk b/graphics/drawable/teststatic/Android.mk new file mode 100644 index 0000000000..d8a0fd743f --- /dev/null +++ b/graphics/drawable/teststatic/Android.mk @@ -0,0 +1,38 @@ +# Copyright (C) 2015 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SDK_VERSION := 7 + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_RESOURCE_DIR = \ + $(LOCAL_PATH)/res \ + frameworks/support/graphics/drawable/res \ + +LOCAL_PACKAGE_NAME := AndroidVectorDrawableTests + +LOCAL_STATIC_JAVA_LIBRARIES := android-support-v7-vectordrawable android-support-v4 + +LOCAL_AAPT_FLAGS := \ + --auto-add-overlay \ + --extra-packages android.support.graphics.drawable + +include $(BUILD_PACKAGE) + diff --git a/graphics/drawable/teststatic/AndroidManifest.xml b/graphics/drawable/teststatic/AndroidManifest.xml new file mode 100644 index 0000000000..19586fb5d0 --- /dev/null +++ b/graphics/drawable/teststatic/AndroidManifest.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2015 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. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.support.test.vectordrawable" > + + <uses-sdk android:minSdkVersion="7" /> + + <application android:icon="@drawable/app_sample_code" android:label="VectorDrawableCompatTest" > + <activity android:name="android.support.test.vectordrawable.TestActivity" /> + + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </application> + +</manifest>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/app_sample_code.png b/graphics/drawable/teststatic/res/drawable/app_sample_code.png Binary files differnew file mode 100755 index 0000000000..66a198496c --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/app_sample_code.png diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable01.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable01.xml new file mode 100644 index 0000000000..12357ef442 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable01.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="48dp" + auto:viewportHeight="480" + auto:viewportWidth="480" + auto:width="48dp" > + + <group> + <path + auto:name="box1" + auto:fillColor="?android:attr/textColorPrimary" + auto:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z" + auto:strokeColor="?android:attr/colorBackground" + auto:strokeLineCap="round" + auto:strokeLineJoin="round" /> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable02.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable02.xml new file mode 100644 index 0000000000..cb6b9dffbd --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable02.xml @@ -0,0 +1,37 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:viewportHeight="320" + auto:viewportWidth="320" + auto:width="64dp" > + + <group + auto:pivotX="70" + auto:pivotY="120" + auto:rotation="180" > + <path + auto:name="house" + auto:fillColor="#ff440000" + auto:pathData="M 130,225 L 130,115 L 130,115 L 70,15 L 10,115 L 10,115 L 10,225 z" + auto:strokeColor="#FF00FF00" + auto:strokeWidth="10" + auto:trimPathEnd=".9" + auto:trimPathStart=".1" /> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable03.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable03.xml new file mode 100644 index 0000000000..37d00863c4 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable03.xml @@ -0,0 +1,72 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:viewportHeight="12.25" + auto:viewportWidth="7.30625" + auto:width="64dp" > + + <group + auto:pivotX="3.65" + auto:pivotY="6.125" + auto:rotation="-30" > + <clip-path + auto:name="clip1" + auto:pathData=" + M 0, 6.125 + l 7.3, 0 + l 0, 12.25 + l-7.3, 0 + z" /> + </group> + <group> + <path + auto:name="one" + auto:fillColor="#ff88ff" + auto:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125 + l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0 + l-5.046875,0.0 0.0-1.0Z" /> + </group> + <group + auto:pivotX="3.65" + auto:pivotY="6.125" + auto:rotation="-30" > + <clip-path + auto:name="clip2" + auto:pathData=" + M 0, 0 + l 7.3, 0 + l 0, 6.125 + l-7.3, 0 + z" /> + </group> + <group> + <path + auto:name="two" + auto:fillColor="#ff88ff" + auto:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375 + q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625 + q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625 + q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875 + q-0.609375,0.1875-1.3125,0.59375l 0.0-1.203125q 0.71875-0.28125 1.328125-0.421875 + q 0.625-0.15625 1.140625-0.15625 1.3593752,0.0 2.1718752,0.6875 + q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625 + q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375 + q-0.78125024,0.8125-2.2187502,2.265625Z" /> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable04.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable04.xml new file mode 100644 index 0000000000..4e2086f858 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable04.xml @@ -0,0 +1,58 @@ +<!-- Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:width="64dp" + auto:height="64dp" + auto:viewportWidth="7.30625" + auto:viewportHeight="12.25" + auto:autoMirrored="true"> + + <group> + <clip-path + auto:name="clip1" + auto:pathData=" + M 3.65, 6.125 + m-.001, 0 + a .001,.001 0 1,0 .002,0 + a .001,.001 0 1,0-.002,0z"/> + <path + auto:name="one" + auto:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125 + l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0 + l-5.046875,0.0 0.0-1.0Z" + auto:fillColor="#ff88ff"/> + + <clip-path + auto:name="clip2" + auto:pathData=" + M 3.65, 6.125 + m-6, 0 + a 6,6 0 1,0 12,0 + a 6,6 0 1,0-12,0z"/> + <path + auto:name="two" + auto:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375 + q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625 + q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625 + q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875 + q-0.609375,0.1875-1.3125,0.59375l 0.0-1.203125q 0.71875-0.28125 1.328125-0.421875 + q 0.625-0.15625 1.140625-0.15625 1.3593752,0.0 2.1718752,0.6875 + q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625 + q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375 + q-0.78125024,0.8125-2.2187502,2.265625Z" + auto:fillColor="#ff88ff"/> + </group> +</vector> diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable05.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable05.xml new file mode 100644 index 0000000000..48801e3232 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable05.xml @@ -0,0 +1,44 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:width="64dp" + auto:viewportHeight="12.25" + auto:viewportWidth="7.30625" > + + <group> + <path + auto:name="one" + auto:fillColor="#ffff00" + auto:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125 + l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0 + l-5.046875,0.0 0.0-1.0Z" /> + <path + auto:name="two" + auto:fillColor="#ffff00" + auto:fillAlpha="0" + auto:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375 + q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625 + q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625 + q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875 + q-0.609375,0.1875-1.3125,0.59375l 0.0-1.203125q 0.71875-0.28125 1.328125-0.421875 + q 0.625-0.15625 1.140625-0.15625 1.3593752,0.0 2.1718752,0.6875 + q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625 + q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375 + q-0.78125024,0.8125-2.2187502,2.265625Z" /> + </group> +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable06.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable06.xml new file mode 100644 index 0000000000..24173e2fc3 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable06.xml @@ -0,0 +1,49 @@ +<!-- Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:width="64dp" + auto:height="64dp" + auto:viewportWidth="700" + auto:viewportHeight="700"> + + <group> + <path auto:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z" + auto:name="path2451" + auto:fillColor="#00000000" + auto:strokeColor="#FF000000" + auto:strokeWidth="30.65500000000000"/> + <path auto:pathData="M 365.015 311.066" + auto:name="path2453" + auto:fillColor="#00000000" + auto:strokeColor="#FF000000" + auto:strokeWidth="30.655000000000001"/> + <path auto:pathData="M 164.46 164.49L 340.78 343.158C 353.849 356.328 377.63 356.172 390.423 343.278L 566.622 165.928" + auto:name="path2455" + auto:strokeColor="#FF000000" + auto:fillColor="#FFFFFFFF" + auto:strokeWidth="30.655000000000001"/> + <path auto:pathData="M 170.515 451.566L 305.61 313.46" + auto:name="path2457" + auto:fillColor="#00000000" + auto:strokeColor="#000000" + auto:strokeWidth="30.655000000000001"/> + <path auto:pathData="M 557.968 449.974L 426.515 315.375" + auto:name="path2459" + auto:fillColor="#00000000" + auto:strokeColor="#000000" + auto:strokeWidth="30.655000000000001"/> + </group> +</vector> diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable07.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable07.xml new file mode 100644 index 0000000000..90435d3bf9 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable07.xml @@ -0,0 +1,30 @@ +<!-- Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:width="64dp" + auto:height="64dp" auto:viewportWidth="140" + auto:viewportHeight="110"> + + <group> + <path + auto:name="back" + auto:pathData="M 20,55 l 35.3-35.3 7.07,7.07-35.3,35.3 z + M 27,50 l 97,0 0,10-97,0 z + M 20,55 l 7.07-7.07 35.3,35.3-7.07,7.07 z" + auto:fillColor="#ffffffff" + /> + </group> +</vector> diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable08.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable08.xml new file mode 100644 index 0000000000..251d694d72 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable08.xml @@ -0,0 +1,30 @@ +<!-- Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:width="64dp" + auto:height="64dp" auto:viewportWidth="600" + auto:viewportHeight="600"> + + <group> + <path + auto:name="pie1" + auto:pathData="M535.441,412.339A280.868,280.868 0 1,1 536.186,161.733L284.493,286.29Z" + auto:fillColor="#ffffcc00" + auto:strokeColor="#FF00FF00" + auto:strokeWidth="1"/> + </group> + +</vector> diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable09.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable09.xml new file mode 100644 index 0000000000..eccb0d092c --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable09.xml @@ -0,0 +1,33 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:width="64dp" + auto:viewportHeight="200" + auto:viewportWidth="200" > + + <group + auto:pivotX="100" + auto:pivotY="100" + auto:rotation="90"> + <path + auto:name="house" + auto:fillColor="#ffffffff" + auto:pathData="M 100,20 l 0,0 0,140-80,0 z M 100,20 l 0,0 80,140-80,0 z"/> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable10.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable10.xml new file mode 100644 index 0000000000..b26d30d087 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable10.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:width="64dp" + auto:viewportWidth="200" + auto:viewportHeight="200"> + + <group> + <path + auto:name="bar3" + auto:fillColor="#FFFFFFFF" + auto:pathData="M49.001,60c-5.466,0-9.899,4.478-9.899,10s4.434,10,9.899,10c5.468,0,9.899-4.478,9.899-10S54.469,60,49.001,60z" /> + <path + auto:name="bar2" + auto:fillColor="#FFFFFFFF" + auto:pathData="M28.001,48.787l7,7.07c7.731-7.811,20.269-7.81,28.001,0l6.999-7.07C58.403,37.071,39.599,37.071,28.001,48.787z" /> + <path + auto:name="bar1" + auto:fillColor="#FF555555" + auto:pathData="M14.001,34.645 L21,41.716c15.464-15.621,40.536-15.621,56,0l7.001-7.071C64.672,15.119,33.33,15.119,14.001,34.645z" /> + <path + auto:name="bar0" + auto:fillColor="#FF555555" + auto:pathData="M0,20.502l6.999,7.071 c23.196-23.431,60.806-23.431,84.002,0L98,20.503C70.938-6.834,27.063-6.834,0,20.502z" /> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable11.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable11.xml new file mode 100644 index 0000000000..eb440f5d31 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable11.xml @@ -0,0 +1,36 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:width="64dp" + auto:viewportHeight="80" + auto:viewportWidth="40" > + + <group> + <path + auto:name="battery" + auto:fillColor="#3388ff" + auto:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z" + auto:strokeColor="#ff8833" + auto:strokeWidth="1" /> + <path + auto:name="spark" + auto:fillColor="#FFFF0000" + auto:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" /> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable12.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable12.xml new file mode 100644 index 0000000000..94a23e8b23 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable12.xml @@ -0,0 +1,98 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:name="rootGroup" + auto:height="64dp" + auto:width="64dp" + auto:viewportHeight="600" + auto:viewportWidth="600" + auto:alpha="0.5" > + + <group + auto:name="rotationGroup" + auto:pivotX="300.0" + auto:pivotY="300.0" + auto:rotation="45.0" > + <path + auto:name="pie1" + auto:fillColor="#00000000" + auto:pathData="M300,70 a230,230 0 1,0 1,0 z" + auto:strokeColor="#FF777777" + auto:strokeWidth="70" + auto:trimPathEnd=".75" + auto:trimPathOffset="0" + auto:trimPathStart="0" /> + <path + auto:name="v" + auto:fillColor="#000000" + auto:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /> + + <group + auto:name="translateToCenterGroup" + auto:rotation="0.0" + auto:translateX="200.0" + auto:translateY="200.0" > + <group + auto:name="rotationGroup2" + auto:pivotX="0.0" + auto:pivotY="0.0" + auto:rotation="-45.0" > + <path + auto:name="twoLines1" + auto:pathData="@string/twoLinePathData" + auto:strokeColor="#FFFF0000" + auto:strokeWidth="20" /> + + <group + auto:name="translateGroupHalf" + auto:translateX="65.0" + auto:translateY="80.0" > + <group + auto:name="rotationGroup3" + auto:pivotX="-65.0" + auto:pivotY="-80.0" + auto:rotation="-45.0" > + <path + auto:name="twoLines2" + auto:fillColor="#FF00FF00" + auto:pathData="@string/twoLinePathData" + auto:strokeColor="#FF00FF00" + auto:strokeWidth="20" /> + + <group + auto:name="translateGroup" + auto:translateX="65.0" + auto:translateY="80.0" > + <group + auto:name="rotationGroupBlue" + auto:pivotX="-65.0" + auto:pivotY="-80.0" + auto:rotation="-45.0" > + <path + auto:name="twoLines3" + auto:pathData="@string/twoLinePathData" + auto:strokeColor="#FF0000FF" + auto:strokeWidth="20" /> + </group> + </group> + </group> + </group> + </group> + </group> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable13.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable13.xml new file mode 100644 index 0000000000..43fc7eadd2 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable13.xml @@ -0,0 +1,38 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:width="64dp" + auto:viewportHeight="400" + auto:viewportWidth="600" > + + <group> + <path + auto:name="pie1" + auto:fillColor="#ffffffff" + auto:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z" + auto:strokeColor="#FF00FF00" + auto:strokeWidth="1" /> + <path + auto:name="half" + auto:fillColor="#FFFF0000" + auto:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z" + auto:strokeColor="#FF0000FF" + auto:strokeWidth="5" /> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable14.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable14.xml new file mode 100644 index 0000000000..5b4fdd1851 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable14.xml @@ -0,0 +1,39 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:width="64dp" + auto:viewportHeight="500" + auto:viewportWidth="800" > + + <group + auto:pivotX="90" + auto:pivotY="100" + auto:rotation="20"> + <path + auto:name="pie2" + auto:pathData="M200,350 l 50,-25 + a25,12 -30 0,1 100,-50 l 50,-25 + a25,25 -30 0,1 100,-50 l 50,-25 + a25,37 -30 0,1 100,-50 l 50,-25 + a25,50 -30 0,1 100,-50 l 50,-25" + auto:fillColor="#00000000" + auto:strokeColor="#FF00FF00" + auto:strokeWidth="10" /> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable15.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable15.xml new file mode 100644 index 0000000000..f4ef87fc3f --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable15.xml @@ -0,0 +1,35 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:width="64dp" + auto:viewportHeight="400" + auto:viewportWidth="500" > + + <group + auto:pivotX="250" + auto:pivotY="200" + auto:rotation="180"> + <path + auto:name="house" + auto:fillColor="#ff440000" + auto:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200" + auto:strokeColor="#FFFF0000" + auto:strokeWidth="10" /> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable16.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable16.xml new file mode 100644 index 0000000000..0c64bca831 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable16.xml @@ -0,0 +1,48 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:width="64dp" + auto:viewportHeight="200" + auto:viewportWidth="200" > + + <group> + <path + auto:name="background1" + auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" + auto:fillColor="#FF000000"/> + <path + auto:name="background2" + auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" + auto:fillColor="#FF000000"/> + </group> + <group + auto:pivotX="100" + auto:pivotY="100" + auto:rotation="90" + auto:scaleX="0.75" + auto:scaleY="0.5" + auto:translateX="0.0" + auto:translateY="100.0"> + <path + auto:name="twoLines" + auto:pathData="M 100,10 v 90 M 10,100 h 90" + auto:strokeColor="#FF00FF00" + auto:strokeWidth="10" /> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable17.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable17.xml new file mode 100644 index 0000000000..28cf09a1ee --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable17.xml @@ -0,0 +1,30 @@ +<!-- Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:width="64dp" + auto:height="64dp" auto:viewportWidth="1200" + auto:viewportHeight="600"> + + <group> + <path + auto:name="house" + auto:pathData="M200,300 Q400,50 600,300 T1000,300" + auto:fillColor="#00000000" + auto:strokeColor="#FFFF0000" + auto:strokeWidth="10"/> + </group> + +</vector> diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable18.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable18.xml new file mode 100644 index 0000000000..d66d4ff4c1 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable18.xml @@ -0,0 +1,32 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:width="64dp" + auto:viewportHeight="400" + auto:viewportWidth="500" > + + <group> + <path + auto:name="house" + auto:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200" + auto:fillColor="#00000000" + auto:strokeColor="#FFFFFF00" + auto:strokeWidth="10" /> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable19.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable19.xml new file mode 100644 index 0000000000..3a6559d818 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable19.xml @@ -0,0 +1,34 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:width="64dp" + auto:viewportHeight="800" + auto:viewportWidth="1000" > + + <group> + <path + auto:name="house" + auto:pathData="M10,300 Q400,550 600,300 T1000,300" + auto:pivotX="90" + auto:pivotY="100" + auto:fillColor="#00000000" + auto:strokeColor="#FFFF0000" + auto:strokeWidth="60" /> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable20.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable20.xml new file mode 100644 index 0000000000..d6fd7043eb --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable20.xml @@ -0,0 +1,35 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:width="64dp" + auto:viewportHeight="480" + auto:viewportWidth="480" > + + <group> + <path + auto:name="edit" + auto:fillColor="#FF00FFFF" + auto:pathData="M406.667,180c0,0 -100 -100 -113.334 -113.333 + c-13.333 -13.334 -33.333,0 -33.333,0l-160,160c0,0 -40,153.333 -40,173.333c0,13.333,13.333,13.333,13.333,13.333l173.334 -40 + c0,0,146.666 -146.666,160 -160C420,200,406.667,180,406.667,180z M226.399,356.823L131.95,378.62l-38.516 -38.522 + c7.848 -34.675,20.152 -82.52,23.538 -95.593l3.027,2.162l106.667,106.666L226.399,356.823z" + auto:strokeColor="#FF000000" + auto:strokeWidth="10" /> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable21.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable21.xml new file mode 100644 index 0000000000..9136b73417 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable21.xml @@ -0,0 +1,48 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:width="64dp" + auto:viewportHeight="200" + auto:viewportWidth="200" > + + <group> + <path + auto:name="background1" + auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" + auto:fillColor="#FF000000"/> + <path + auto:name="background2" + auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" + auto:fillColor="#FF000000"/> + </group> + <group + auto:pivotX="0" + auto:pivotY="0" + auto:rotation="90" + auto:scaleX="0.75" + auto:scaleY="0.5" + auto:translateX="100.0" + auto:translateY="100.0"> + <path + auto:name="twoLines" + auto:pathData="M 100,10 v 90 M 10,100 h 90" + auto:strokeColor="#FF00FF00" + auto:strokeWidth="10" /> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable22.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable22.xml new file mode 100644 index 0000000000..2b33a8903a --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable22.xml @@ -0,0 +1,69 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:width="64dp" + auto:viewportHeight="400" + auto:viewportWidth="400" > + + <group auto:name="backgroundGroup" > + <path + auto:name="background1" + auto:fillColor="#80000000" + auto:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" /> + <path + auto:name="background2" + auto:fillColor="#80000000" + auto:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" /> + </group> + <group + auto:name="translateToCenterGroup" + auto:translateX="50.0" + auto:translateY="90.0" > + <path + auto:name="twoLines" + auto:pathData="M 0,0 v 100 M 0,0 h 100" + auto:strokeColor="#FFFF0000" + auto:strokeWidth="20" /> + + <group + auto:name="rotationGroup" + auto:pivotX="0.0" + auto:pivotY="0.0" + auto:rotation="-45.0" > + <path + auto:name="twoLines1" + auto:pathData="M 0,0 v 100 M 0,0 h 100" + auto:strokeColor="#FF00FF00" + auto:strokeWidth="20" /> + + <group + auto:name="translateGroup" + auto:translateX="130.0" + auto:translateY="160.0" > + <group auto:name="scaleGroup" > + <path + auto:name="twoLines2" + auto:pathData="M 0,0 v 100 M 0,0 h 100" + auto:strokeColor="#FF0000FF" + auto:strokeWidth="20" /> + </group> + </group> + </group> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable23.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable23.xml new file mode 100644 index 0000000000..d5759f99f9 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable23.xml @@ -0,0 +1,83 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:width="64dp" + auto:viewportHeight="400" + auto:viewportWidth="400" > + + <group auto:name="backgroundGroup" > + <path + auto:name="background1" + auto:fillColor="#80000000" + auto:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" /> + <path + auto:name="background2" + auto:fillColor="#80000000" + auto:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" /> + </group> + <group + auto:name="translateToCenterGroup" + auto:translateX="50.0" + auto:translateY="90.0" > + <path + auto:name="twoLines" + auto:pathData="@string/twoLinePathData" + auto:strokeColor="#FFFF0000" + auto:strokeWidth="20" /> + + <group + auto:name="rotationGroup" + auto:pivotX="0.0" + auto:pivotY="0.0" + auto:rotation="-45.0" > + <path + auto:name="twoLines1" + auto:pathData="@string/twoLinePathData" + auto:strokeColor="#FF00FF00" + auto:strokeWidth="20" /> + + <group + auto:name="translateGroup" + auto:translateX="130.0" + auto:translateY="160.0" > + <group auto:name="scaleGroup" > + <path + auto:name="twoLines3" + auto:pathData="@string/twoLinePathData" + auto:strokeColor="#FF0000FF" + auto:strokeWidth="20" /> + </group> + </group> + + <group + auto:name="translateGroupHalf" + auto:translateX="65.0" + auto:translateY="80.0" > + <group auto:name="scaleGroup" > + <path + auto:name="twoLines2" + auto:pathData="@string/twoLinePathData" + auto:fillColor="#FFFFFFFF" + auto:strokeColor="#FFFFFFFF" + auto:strokeWidth="20" /> + </group> + </group> + </group> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable24.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable24.xml new file mode 100644 index 0000000000..b05469281c --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable24.xml @@ -0,0 +1,83 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:width="64dp" + auto:viewportHeight="400" + auto:viewportWidth="400" > + + <group auto:name="backgroundGroup"> + <path + auto:name="background1" + auto:fillColor="#FF000000" + auto:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" /> + <path + auto:name="background2" + auto:fillColor="#FF000000" + auto:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" /> + </group> + <group + auto:name="translateToCenterGroup" + auto:translateX="50.0" + auto:translateY="90.0" > + <path + auto:name="twoLines" + auto:pathData="@string/twoLinePathData" + auto:strokeColor="#FFFF0000" + auto:strokeWidth="20" /> + + <group + auto:name="rotationGroup" + auto:pivotX="0.0" + auto:pivotY="0.0" + auto:rotation="-45.0"> + <path + auto:name="twoLines1" + auto:pathData="@string/twoLinePathData" + auto:strokeColor="#FF00FF00" + auto:strokeWidth="20" /> + + <group + auto:name="translateGroup" + auto:translateX="130.0" + auto:translateY="160.0"> + <group auto:name="scaleGroup" > + <path + auto:name="twoLines3" + auto:pathData="@string/twoLinePathData" + auto:strokeColor="#FF0000FF" + auto:strokeWidth="20" /> + </group> + </group> + + <group + auto:name="translateGroupHalf" + auto:translateX="65.0" + auto:translateY="80.0"> + <group auto:name="scaleGroup" > + <path + auto:name="twoLines2" + auto:pathData="@string/twoLinePathData" + auto:fillColor="#FFFFFFFF" + auto:strokeColor="#FFFFFFFF" + auto:strokeWidth="20" /> + </group> + </group> + </group> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable25.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable25.xml new file mode 100644 index 0000000000..7a94ed6ca3 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable25.xml @@ -0,0 +1,83 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:width="64dp" + auto:viewportHeight="400" + auto:viewportWidth="400" > + + <group + auto:name="FirstLevelGroup" + auto:translateX="100.0" + auto:translateY="0.0" > + <group + auto:name="SecondLevelGroup1" + auto:translateX="-100.0" + auto:translateY="50.0" > + <path + auto:fillColor="#FF00FF00" + auto:pathData="@string/rectangle200" /> + + <group + auto:name="ThridLevelGroup1" + auto:translateX="-100.0" + auto:translateY="50.0" > + <path + auto:fillColor="#FF0000FF" + auto:pathData="@string/rectangle200" /> + </group> + <group + auto:name="ThridLevelGroup2" + auto:translateX="100.0" + auto:translateY="50.0" > + <path + auto:fillColor="#FF000000" + auto:pathData="@string/rectangle200" /> + </group> + </group> + <group + auto:name="SecondLevelGroup2" + auto:translateX="100.0" + auto:translateY="50.0" > + <path + auto:fillColor="#FF0000FF" + auto:pathData="@string/rectangle200" /> + + <group + auto:name="ThridLevelGroup3" + auto:translateX="-100.0" + auto:translateY="50.0" > + <path + auto:fillColor="#FFFF0000" + auto:pathData="@string/rectangle200" /> + </group> + <group + auto:name="ThridLevelGroup4" + auto:translateX="100.0" + auto:translateY="50.0" > + <path + auto:fillColor="#FF00FF00" + auto:pathData="@string/rectangle200" /> + </group> + </group> + + <path + auto:fillColor="#FFFF0000" + auto:pathData="@string/rectangle200" /> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable26.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable26.xml new file mode 100644 index 0000000000..b2dd4a3947 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable26.xml @@ -0,0 +1,46 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:viewportHeight="200" + auto:viewportWidth="200" + auto:width="64dp" > + + <group> + <path + auto:name="background1" + auto:fillColor="#FF000000" + auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" /> + <path + auto:name="background2" + auto:fillColor="#FF000000" + auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" /> + </group> + <group + auto:translateX="50" + auto:translateY="50" > + <path + auto:name="twoLines" + auto:pathData="M 100,20 l 0 80 l -30 -80" + auto:strokeColor="#FF00FF00" + auto:strokeLineCap="butt" + auto:strokeLineJoin="miter" + auto:strokeMiterLimit="5" + auto:strokeWidth="20" /> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable27.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable27.xml new file mode 100644 index 0000000000..b8f88cee1c --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable27.xml @@ -0,0 +1,46 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:viewportHeight="200" + auto:viewportWidth="200" + auto:width="64dp" > + + <group> + <path + auto:name="background1" + auto:fillColor="#FF000000" + auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" /> + <path + auto:name="background2" + auto:fillColor="#FF000000" + auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" /> + </group> + <group + auto:translateX="50" + auto:translateY="50" > + <path + auto:name="twoLines" + auto:pathData="M 100,20 l 0 80 l -30 -80" + auto:strokeColor="#FF00FF00" + auto:strokeLineCap="round" + auto:strokeLineJoin="round" + auto:strokeMiterLimit="10" + auto:strokeWidth="20" /> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable28.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable28.xml new file mode 100644 index 0000000000..30c7fce346 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable28.xml @@ -0,0 +1,47 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="64dp" + auto:viewportHeight="200" + auto:viewportWidth="200" + auto:width="64dp" + auto:autoMirrored="true" > + + <group> + <path + auto:name="background1" + auto:fillColor="#FF000000" + auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" /> + <path + auto:name="background2" + auto:fillColor="#FF000000" + auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" /> + </group> + <group + auto:translateX="50" + auto:translateY="50" > + <path + auto:name="twoLines" + auto:pathData="M 100,20 l 0 80 l -30 -80" + auto:strokeColor="#FF00FF00" + auto:strokeLineCap="square" + auto:strokeLineJoin="bevel" + auto:strokeMiterLimit="10" + auto:strokeWidth="20" /> + </group> + +</vector>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable29.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable29.xml new file mode 100644 index 0000000000..2ac1d428f4 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable29.xml @@ -0,0 +1,29 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="48dp" + auto:width="48dp" + auto:viewportHeight="1" + auto:viewportWidth="1" > + + <group> + <path + auto:name="box1" + auto:pathData="l0.0.0.5.0.0.5-0.5.0.0-.5z" + auto:fillColor="#ff00ff00"/> + </group> +</vector> diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable30.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable30.xml new file mode 100644 index 0000000000..6abb4552c8 --- /dev/null +++ b/graphics/drawable/teststatic/res/drawable/vector_drawable30.xml @@ -0,0 +1,29 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + auto:height="48dp" + auto:width="48dp" + auto:viewportHeight="48" + auto:viewportWidth="48" > + + <group> + <path + auto:name="plus1" + auto:pathData="M20 16h-4v8h-8v4h8v8h4v-8h8v-4h-8zm9-3.84v3.64l5-1v21.2h4v-26z" + auto:fillColor="#ff00ff00"/> + </group> +</vector> diff --git a/graphics/drawable/teststatic/res/raw/vector_drawable01.xml b/graphics/drawable/teststatic/res/raw/vector_drawable01.xml new file mode 100644 index 0000000000..baa3fc7162 --- /dev/null +++ b/graphics/drawable/teststatic/res/raw/vector_drawable01.xml @@ -0,0 +1,32 @@ +<!-- + Copyright (C) 2015 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" + xmlns:auto="http://schemas.android.com/apk/res-auto" + android:height="48dp" + android:width="48dp" + android:viewportHeight="480" + android:viewportWidth="480" > + + <group> + <path + android:name="box1" + android:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z" + android:fillColor="?android:attr/colorControlActivated" + android:strokeColor="?android:attr/colorControlActivated" + android:strokeLineCap="round" + android:strokeLineJoin="round" /> + </group> +</vector> diff --git a/graphics/drawable/teststatic/res/values/strings.xml b/graphics/drawable/teststatic/res/values/strings.xml new file mode 100644 index 0000000000..c5451c8845 --- /dev/null +++ b/graphics/drawable/teststatic/res/values/strings.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2015 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. +--> + +<resources> + + <string name="twoLinePathData">"M 0,0 v 100 M 0,0 h 100"</string> + <string name="triangle"> "M300,70 l 0,-70 70,70 0,0 -70,70z"</string> + <string name="rectangle">"M300,70 l 0,-70 70,0 0,140 -70,0 z"</string> + <string name="rectangle2">"M300,70 l 0,-70 70,0 0,70z M300,70 l 70,0 0,70 -70,0z"</string> + <string name="equal2"> "M300,35 l 0,-35 70,0 0,35z M300,105 l 70,0 0,35 -70,0z"</string> + <string name="round_box">"m2.10001,-6c-1.9551,0 -0.5,0.02499 -2.10001,0.02499c-1.575,0 0.0031,-0.02499 -1.95,-0.02499c-2.543,0 -4,2.2816 -4,4.85001c0,3.52929 0.25,6.25 5.95,6.25c5.7,0 6,-2.72071 6,-6.25c0,-2.56841 -1.35699,-4.85001 -3.89999,-4.85001"</string> + <string name="heart"> "m4.5,-7c-1.95509,0 -3.83009,1.26759 -4.5,3c-0.66991,-1.73241 -2.54691,-3 -4.5,-3c-2.543,0 -4.5,1.93159 -4.5,4.5c0,3.5293 3.793,6.2578 9,11.5c5.207,-5.2422 9,-7.9707 9,-11.5c0,-2.56841 -1.957,-4.5 -4.5,-4.5"</string> + <string name="rectangle200">"M 0,0 l 200,0 l 0, 200 l -200, 0 z"</string> +</resources>
\ No newline at end of file diff --git a/graphics/drawable/teststatic/src/android/support/test/vectordrawable/TestActivity.java b/graphics/drawable/teststatic/src/android/support/test/vectordrawable/TestActivity.java new file mode 100644 index 0000000000..8bb766e511 --- /dev/null +++ b/graphics/drawable/teststatic/src/android/support/test/vectordrawable/TestActivity.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2015 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.support.test.vectordrawable; + +import android.app.Activity; +import android.content.res.Resources; +import android.graphics.PorterDuff.Mode; +import android.graphics.drawable.Drawable.ConstantState; +import android.os.Bundle; +import android.support.graphics.drawable.VectorDrawableCompat; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TextView; + +import java.text.DecimalFormat; + +public class TestActivity extends Activity { + private static final String LOG_TAG = "TestActivity"; + + private static final String LOGCAT = "VectorDrawable1"; + protected int[] icon = { + R.drawable.vector_drawable01, + R.drawable.vector_drawable02, + R.drawable.vector_drawable03, + R.drawable.vector_drawable04, + R.drawable.vector_drawable05, + R.drawable.vector_drawable06, + R.drawable.vector_drawable07, + R.drawable.vector_drawable08, + R.drawable.vector_drawable09, + R.drawable.vector_drawable10, + R.drawable.vector_drawable11, + R.drawable.vector_drawable12, + R.drawable.vector_drawable13, + R.drawable.vector_drawable14, + R.drawable.vector_drawable15, + R.drawable.vector_drawable16, + R.drawable.vector_drawable17, + R.drawable.vector_drawable18, + R.drawable.vector_drawable19, + R.drawable.vector_drawable20, + R.drawable.vector_drawable21, + R.drawable.vector_drawable22, + R.drawable.vector_drawable23, + R.drawable.vector_drawable24, + R.drawable.vector_drawable25, + R.drawable.vector_drawable26, + R.drawable.vector_drawable27, + R.drawable.vector_drawable28, + R.drawable.vector_drawable29, + R.drawable.vector_drawable30, + }; + + private static final int EXTRA_TESTS = 2; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ScrollView scrollView = new ScrollView(this); + LinearLayout container = new LinearLayout(this); + scrollView.addView(container); + container.setOrientation(LinearLayout.VERTICAL); + Resources res = this.getResources(); + container.setBackgroundColor(0xFF888888); + VectorDrawableCompat []d = new VectorDrawableCompat[icon.length]; + long time = android.os.SystemClock.currentThreadTimeMillis(); + for (int i = 0; i < icon.length; i++) { + d[i] = VectorDrawableCompat.create(res, icon[i], getTheme()); + } + time = android.os.SystemClock.currentThreadTimeMillis()-time; + + // Testing Tint on one particular case. + d[3].setTint(0x8000FF00); + d[3].setTintMode(Mode.MULTIPLY); + + // Testing Constant State like operation by creating the first 2 icons + // from the 3rd one's constant state. + VectorDrawableCompat []extras = new VectorDrawableCompat[EXTRA_TESTS]; + ConstantState state = d[0].getConstantState(); + extras[0] = (VectorDrawableCompat) state.newDrawable(); + extras[1] = (VectorDrawableCompat) state.newDrawable(); + + // This alpha change is expected to affect both extra 0, 1, and d0. + extras[0].setAlpha(128); + + d[0].mutate(); + d[0].setAlpha(255); + + // Just show the average create time as the first view. + TextView t = new TextView(this); + DecimalFormat df = new DecimalFormat("#.##"); + t.setText("avgL=" + df.format(time / (icon.length)) + " ms"); + container.addView(t); + + addDrawableButtons(container, extras); + + addDrawableButtons(container, d); + + setContentView(scrollView); + } + + private void addDrawableButtons(LinearLayout container, VectorDrawableCompat[] d) { + // Add the VD into consequent views. + for (int i = 0; i < d.length; i++) { + Button button = new Button(this); + button.setWidth(200); + // Note that setBackgroundResource() will fail b/c createFromXmlInner() failed + // to recognize <vector> pre-L. + button.setBackgroundDrawable(d[i]); + container.addView(button); + } + } +} |
