diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 438d1fb04cbb1..0e597d0c1a70b 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -5271,11 +5271,16 @@ + + + + - + @@ -5295,7 +5300,7 @@ - + diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index 4407a3cfd98cc..5fd8c793a78e9 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -256,21 +256,22 @@ public class VectorDrawable extends Drawable { } if (!mAllowCaching) { - mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height()); + // AnimatedVectorDrawable + if (!mVectorState.hasTranslucentRoot()) { + mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height()); + } else { + mVectorState.createCachedBitmapIfNeeded(bounds); + mVectorState.updateCachedBitmap(bounds); + mVectorState.drawCachedBitmapWithRootAlpha(canvas); + } } 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; - + // 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); @@ -492,6 +493,15 @@ public class VectorDrawable extends Drawable { throw new XmlPullParserException(a.getPositionDescription() + " 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, @@ -646,15 +656,60 @@ 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()) { + && mCachedRootAlpha == mVPathRenderer.getRootAlpha()) { return true; } return false; @@ -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 mVGTargetsMap = new ArrayMap(); @@ -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); @@ -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() { @@ -856,7 +927,7 @@ public class VectorDrawable extends Drawable { } private void drawPath(VGroup vGroup, VPath vPath, Canvas canvas, int w, int h) { - final float scaleX = w / mViewportWidth; + final float scaleX = w / mViewportWidth; final float scaleY = h / mViewportHeight; final float minScale = Math.min(scaleX, scaleY); @@ -1219,7 +1290,7 @@ public class VectorDrawable extends Drawable { /** * Clip path, which only has name and pathData. */ - private static class VClipPath extends VPath{ + private static class VClipPath extends VPath { public VClipPath() { // Empty constructor. } diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation06.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation06.xml new file mode 100644 index 0000000000000..1a81866669bc8 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/trim_path_animation06.xml @@ -0,0 +1,25 @@ + + + + + + + \ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml index 19b82adcc143d..8b0ceda4939f5 100644 --- a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml +++ b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml @@ -37,5 +37,8 @@ + \ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml index 2c8b75118dfe9..69ae62c19aba7 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml @@ -14,10 +14,12 @@ limitations under the License. --> + android:viewportWidth="600" + android:alpha="0.5" >