Loading core/res/res/values/attrs.xml +7 −2 Original line number Diff line number Diff line Loading @@ -5271,11 +5271,16 @@ <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 --> <!-- The name of this group --> <attr name="name" /> <!-- The amount to rotate the group --> <attr name="rotation" /> Loading @@ -5295,7 +5300,7 @@ <!-- Defines the path used in VectorDrawables. --> <declare-styleable name="VectorDrawablePath"> <!-- The Name of this path --> <!-- The name of this path --> <attr name="name" /> <!-- The width a path stroke --> <attr name="strokeWidth" format="float" /> Loading graphics/java/android/graphics/drawable/VectorDrawable.java +90 −19 Original line number Diff line number Diff line Loading @@ -256,21 +256,22 @@ public class VectorDrawable extends Drawable { } if (!mAllowCaching) { // AnimatedVectorDrawable if (!mVectorState.hasTranslucentRoot()) { mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height()); } else { Bitmap bitmap = mVectorState.mCachedBitmap; if (bitmap == null || !mVectorState.canReuseCache(bounds.width(), bounds.height())) { bitmap = Bitmap.createBitmap(bounds.width(), bounds.height(), Bitmap.Config.ARGB_8888); Canvas tmpCanvas = new Canvas(bitmap); mVectorState.mVPathRenderer.draw(tmpCanvas, bounds.width(), bounds.height()); mVectorState.mCachedBitmap = bitmap; mVectorState.createCachedBitmapIfNeeded(bounds); mVectorState.updateCachedBitmap(bounds); mVectorState.drawCachedBitmapWithRootAlpha(canvas); } } else { // Static Vector Drawable case. mVectorState.createCachedBitmapIfNeeded(bounds); if (!mVectorState.canReuseCache()) { mVectorState.updateCachedBitmap(bounds); mVectorState.updateCacheStates(); } // The bitmap's size is the same as the bounds. canvas.drawBitmap(bitmap, 0, 0, null); mVectorState.drawCachedBitmapWithRootAlpha(canvas); } canvas.restoreToCount(saveCount); Loading Loading @@ -492,6 +493,15 @@ public class VectorDrawable extends Drawable { throw new XmlPullParserException(a.getPositionDescription() + "<vector> tag requires height > 0"); } final float alphaInFloat = a.getFloat(R.styleable.VectorDrawable_alpha, pathRenderer.getAlpha()); pathRenderer.setAlpha(alphaInFloat); pathRenderer.mRootName = a.getString(R.styleable.VectorDrawable_name); if (pathRenderer.mRootName != null) { pathRenderer.mVGTargetsMap.put(pathRenderer.mRootName, pathRenderer); } } private void inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs, Loading Loading @@ -646,14 +656,59 @@ public class VectorDrawable extends Drawable { } } public boolean canReuseCache(int width, int height) { // TODO: Support colorFilter here. public void drawCachedBitmapWithRootAlpha(Canvas canvas) { Paint alphaPaint = getRootAlphaPaint(); // The bitmap's size is the same as the bounds. canvas.drawBitmap(mCachedBitmap, 0, 0, alphaPaint); } public boolean hasTranslucentRoot() { return mVPathRenderer.getRootAlpha() < 255; } /** * @return null when there is no need for alpha paint. */ public Paint getRootAlphaPaint() { Paint paint = null; boolean needsAlphaPaint = hasTranslucentRoot(); if (needsAlphaPaint) { paint = new Paint(); paint.setAlpha(mVPathRenderer.getRootAlpha()); } return paint; } public void updateCachedBitmap(Rect bounds) { mCachedBitmap.eraseColor(Color.TRANSPARENT); Canvas tmpCanvas = new Canvas(mCachedBitmap); mVPathRenderer.draw(tmpCanvas, bounds.width(), bounds.height()); } public void createCachedBitmapIfNeeded(Rect bounds) { if (mCachedBitmap == null || !canReuseBitmap(bounds.width(), bounds.height())) { mCachedBitmap = Bitmap.createBitmap(bounds.width(), bounds.height(), Bitmap.Config.ARGB_8888); } } public boolean canReuseBitmap(int width, int height) { if (width == mCachedBitmap.getWidth() && height == mCachedBitmap.getHeight()) { return true; } return false; } public boolean canReuseCache() { if (!mCacheDirty && mCachedThemeAttrs == mThemeAttrs && mCachedTint == mTint && mCachedTintMode == mTintMode && mCachedAutoMirrored == mAutoMirrored && width == mCachedBitmap.getWidth() && height == mCachedBitmap.getHeight() && mCachedRootAlpha == mVPathRenderer.getRootAlpha()) { return true; } Loading Loading @@ -729,7 +784,8 @@ public class VectorDrawable extends Drawable { float mBaseHeight = 0; float mViewportWidth = 0; float mViewportHeight = 0; private int mRootAlpha = 0xFF; int mRootAlpha = 0xFF; String mRootName = null; final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>(); Loading @@ -747,6 +803,17 @@ public class VectorDrawable extends Drawable { 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); Loading @@ -757,6 +824,10 @@ public class VectorDrawable extends Drawable { mViewportHeight = copy.mViewportHeight; mChangingConfigurations = copy.mChangingConfigurations; mRootAlpha = copy.mRootAlpha; mRootName = copy.mRootName; if (copy.mRootName != null) { mVGTargetsMap.put(copy.mRootName, this); } } public boolean canApplyTheme() { Loading tests/VectorDrawableTest/res/anim/trim_path_animation06.xml 0 → 100644 +25 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2014 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="9000" android:propertyName="alpha" android:valueFrom="1.0" android:valueTo="0.0"/> </set> No newline at end of file tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml +3 −0 Original line number Diff line number Diff line Loading @@ -37,5 +37,8 @@ <target android:name="rotationGroup" android:animation="@anim/trim_path_animation04" /> <target android:name="rootGroup" android:animation="@anim/trim_path_animation06" /> </animated-vector> No newline at end of file tests/VectorDrawableTest/res/drawable/vector_drawable12.xml +3 −1 Original line number Diff line number Diff line Loading @@ -14,10 +14,12 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:name="rootGroup" android:height="64dp" android:width="64dp" android:viewportHeight="600" android:viewportWidth="600" > android:viewportWidth="600" android:alpha="0.5" > <group android:name="rotationGroup" Loading Loading
core/res/res/values/attrs.xml +7 −2 Original line number Diff line number Diff line Loading @@ -5271,11 +5271,16 @@ <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 --> <!-- The name of this group --> <attr name="name" /> <!-- The amount to rotate the group --> <attr name="rotation" /> Loading @@ -5295,7 +5300,7 @@ <!-- Defines the path used in VectorDrawables. --> <declare-styleable name="VectorDrawablePath"> <!-- The Name of this path --> <!-- The name of this path --> <attr name="name" /> <!-- The width a path stroke --> <attr name="strokeWidth" format="float" /> Loading
graphics/java/android/graphics/drawable/VectorDrawable.java +90 −19 Original line number Diff line number Diff line Loading @@ -256,21 +256,22 @@ public class VectorDrawable extends Drawable { } if (!mAllowCaching) { // AnimatedVectorDrawable if (!mVectorState.hasTranslucentRoot()) { mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height()); } else { Bitmap bitmap = mVectorState.mCachedBitmap; if (bitmap == null || !mVectorState.canReuseCache(bounds.width(), bounds.height())) { bitmap = Bitmap.createBitmap(bounds.width(), bounds.height(), Bitmap.Config.ARGB_8888); Canvas tmpCanvas = new Canvas(bitmap); mVectorState.mVPathRenderer.draw(tmpCanvas, bounds.width(), bounds.height()); mVectorState.mCachedBitmap = bitmap; mVectorState.createCachedBitmapIfNeeded(bounds); mVectorState.updateCachedBitmap(bounds); mVectorState.drawCachedBitmapWithRootAlpha(canvas); } } else { // Static Vector Drawable case. mVectorState.createCachedBitmapIfNeeded(bounds); if (!mVectorState.canReuseCache()) { mVectorState.updateCachedBitmap(bounds); mVectorState.updateCacheStates(); } // The bitmap's size is the same as the bounds. canvas.drawBitmap(bitmap, 0, 0, null); mVectorState.drawCachedBitmapWithRootAlpha(canvas); } canvas.restoreToCount(saveCount); Loading Loading @@ -492,6 +493,15 @@ public class VectorDrawable extends Drawable { throw new XmlPullParserException(a.getPositionDescription() + "<vector> tag requires height > 0"); } final float alphaInFloat = a.getFloat(R.styleable.VectorDrawable_alpha, pathRenderer.getAlpha()); pathRenderer.setAlpha(alphaInFloat); pathRenderer.mRootName = a.getString(R.styleable.VectorDrawable_name); if (pathRenderer.mRootName != null) { pathRenderer.mVGTargetsMap.put(pathRenderer.mRootName, pathRenderer); } } private void inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs, Loading Loading @@ -646,14 +656,59 @@ public class VectorDrawable extends Drawable { } } public boolean canReuseCache(int width, int height) { // TODO: Support colorFilter here. public void drawCachedBitmapWithRootAlpha(Canvas canvas) { Paint alphaPaint = getRootAlphaPaint(); // The bitmap's size is the same as the bounds. canvas.drawBitmap(mCachedBitmap, 0, 0, alphaPaint); } public boolean hasTranslucentRoot() { return mVPathRenderer.getRootAlpha() < 255; } /** * @return null when there is no need for alpha paint. */ public Paint getRootAlphaPaint() { Paint paint = null; boolean needsAlphaPaint = hasTranslucentRoot(); if (needsAlphaPaint) { paint = new Paint(); paint.setAlpha(mVPathRenderer.getRootAlpha()); } return paint; } public void updateCachedBitmap(Rect bounds) { mCachedBitmap.eraseColor(Color.TRANSPARENT); Canvas tmpCanvas = new Canvas(mCachedBitmap); mVPathRenderer.draw(tmpCanvas, bounds.width(), bounds.height()); } public void createCachedBitmapIfNeeded(Rect bounds) { if (mCachedBitmap == null || !canReuseBitmap(bounds.width(), bounds.height())) { mCachedBitmap = Bitmap.createBitmap(bounds.width(), bounds.height(), Bitmap.Config.ARGB_8888); } } public boolean canReuseBitmap(int width, int height) { if (width == mCachedBitmap.getWidth() && height == mCachedBitmap.getHeight()) { return true; } return false; } public boolean canReuseCache() { if (!mCacheDirty && mCachedThemeAttrs == mThemeAttrs && mCachedTint == mTint && mCachedTintMode == mTintMode && mCachedAutoMirrored == mAutoMirrored && width == mCachedBitmap.getWidth() && height == mCachedBitmap.getHeight() && mCachedRootAlpha == mVPathRenderer.getRootAlpha()) { return true; } Loading Loading @@ -729,7 +784,8 @@ public class VectorDrawable extends Drawable { float mBaseHeight = 0; float mViewportWidth = 0; float mViewportHeight = 0; private int mRootAlpha = 0xFF; int mRootAlpha = 0xFF; String mRootName = null; final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>(); Loading @@ -747,6 +803,17 @@ public class VectorDrawable extends Drawable { 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); Loading @@ -757,6 +824,10 @@ public class VectorDrawable extends Drawable { mViewportHeight = copy.mViewportHeight; mChangingConfigurations = copy.mChangingConfigurations; mRootAlpha = copy.mRootAlpha; mRootName = copy.mRootName; if (copy.mRootName != null) { mVGTargetsMap.put(copy.mRootName, this); } } public boolean canApplyTheme() { Loading
tests/VectorDrawableTest/res/anim/trim_path_animation06.xml 0 → 100644 +25 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2014 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="9000" android:propertyName="alpha" android:valueFrom="1.0" android:valueTo="0.0"/> </set> No newline at end of file
tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml +3 −0 Original line number Diff line number Diff line Loading @@ -37,5 +37,8 @@ <target android:name="rotationGroup" android:animation="@anim/trim_path_animation04" /> <target android:name="rootGroup" android:animation="@anim/trim_path_animation06" /> </animated-vector> No newline at end of file
tests/VectorDrawableTest/res/drawable/vector_drawable12.xml +3 −1 Original line number Diff line number Diff line Loading @@ -14,10 +14,12 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:name="rootGroup" android:height="64dp" android:width="64dp" android:viewportHeight="600" android:viewportWidth="600" > android:viewportWidth="600" android:alpha="0.5" > <group android:name="rotationGroup" Loading