diff options
| author | 2010-11-01 13:53:31 -0700 | |
|---|---|---|
| committer | 2010-11-01 13:53:31 -0700 | |
| commit | e58a5ad04b4e181e86ae573fa3a06d141bddf63a (patch) | |
| tree | b45ffee77df388e0e88d522c37c564e30acc91db | |
| parent | 63f366978e10ed243e7d63d24fddcc1b0017eb68 (diff) | |
| parent | 70d4ba15b1f0c1133c5aabc86de828b41e482fff (diff) | |
Merge "Performance optimizations for animations and toolkit"
| -rw-r--r-- | api/current.xml | 24 | ||||
| -rw-r--r-- | core/java/android/animation/KeyframeSet.java | 49 | ||||
| -rw-r--r-- | core/java/android/animation/ObjectAnimator.java | 11 | ||||
| -rwxr-xr-x | core/java/android/animation/ValueAnimator.java | 2 | ||||
| -rw-r--r-- | core/java/android/view/View.java | 17 | ||||
| -rw-r--r-- | core/java/android/view/ViewGroup.java | 176 | ||||
| -rw-r--r-- | core/java/android/view/ViewRoot.java | 5 | ||||
| -rw-r--r-- | graphics/java/android/graphics/drawable/ColorDrawable.java | 23 |
8 files changed, 213 insertions, 94 deletions
diff --git a/api/current.xml b/api/current.xml index 35fb3ef05a11..2a89d043e631 100644 --- a/api/current.xml +++ b/api/current.xml @@ -83600,6 +83600,17 @@ visibility="public" > </method> +<method name="getColor" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getOpacity" return="int" abstract="false" @@ -83624,6 +83635,19 @@ <parameter name="alpha" type="int"> </parameter> </method> +<method name="setColor" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="color" type="int"> +</parameter> +</method> <method name="setColorFilter" return="void" abstract="false" diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java index 1741e60a62be..22424628c47f 100644 --- a/core/java/android/animation/KeyframeSet.java +++ b/core/java/android/animation/KeyframeSet.java @@ -28,12 +28,18 @@ class KeyframeSet { private int mNumKeyframes; - ArrayList<Keyframe> mKeyframes; + Keyframe mFirstKeyframe; + Keyframe mLastKeyframe; + TimeInterpolator mInterpolator; // only used in the 2-keyframe case + ArrayList<Keyframe> mKeyframes; // only used when there are not 2 keyframes public KeyframeSet(Keyframe... keyframes) { + mNumKeyframes = keyframes.length; mKeyframes = new ArrayList<Keyframe>(); mKeyframes.addAll(Arrays.asList(keyframes)); - mNumKeyframes = mKeyframes.size(); + mFirstKeyframe = mKeyframes.get(0); + mLastKeyframe = mKeyframes.get(mNumKeyframes - 1); + mInterpolator = mLastKeyframe.getInterpolator(); } public static KeyframeSet ofInt(int... values) { @@ -125,32 +131,40 @@ class KeyframeSet { * @return The animated value. */ public Object getValue(float fraction, TypeEvaluator evaluator) { - // TODO: special-case 2-keyframe common case + + // Special-case optimization for the common case of only two keyframes + if (mNumKeyframes == 2) { + if (mInterpolator != null) { + fraction = mInterpolator.getInterpolation(fraction); + } + return evaluator.evaluate(fraction, mFirstKeyframe.getValue(), + mLastKeyframe.getValue()); + } if (fraction <= 0f) { - final Keyframe prevKeyframe = mKeyframes.get(0); final Keyframe nextKeyframe = mKeyframes.get(1); final TimeInterpolator interpolator = nextKeyframe.getInterpolator(); if (interpolator != null) { fraction = interpolator.getInterpolation(fraction); } - float intervalFraction = (fraction - prevKeyframe.getFraction()) / - (nextKeyframe.getFraction() - prevKeyframe.getFraction()); - return evaluator.evaluate(intervalFraction, prevKeyframe.getValue(), + final float prevFraction = mFirstKeyframe.getFraction(); + float intervalFraction = (fraction - prevFraction) / + (nextKeyframe.getFraction() - prevFraction); + return evaluator.evaluate(intervalFraction, mFirstKeyframe.getValue(), nextKeyframe.getValue()); } else if (fraction >= 1f) { final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2); - final Keyframe nextKeyframe = mKeyframes.get(mNumKeyframes - 1); - final TimeInterpolator interpolator = nextKeyframe.getInterpolator(); + final TimeInterpolator interpolator = mLastKeyframe.getInterpolator(); if (interpolator != null) { fraction = interpolator.getInterpolation(fraction); } - float intervalFraction = (fraction - prevKeyframe.getFraction()) / - (nextKeyframe.getFraction() - prevKeyframe.getFraction()); + final float prevFraction = prevKeyframe.getFraction(); + float intervalFraction = (fraction - prevFraction) / + (mLastKeyframe.getFraction() - prevFraction); return evaluator.evaluate(intervalFraction, prevKeyframe.getValue(), - nextKeyframe.getValue()); + mLastKeyframe.getValue()); } - Keyframe prevKeyframe = mKeyframes.get(0); + Keyframe prevKeyframe = mFirstKeyframe; for (int i = 1; i < mNumKeyframes; ++i) { Keyframe nextKeyframe = mKeyframes.get(i); if (fraction < nextKeyframe.getFraction()) { @@ -158,14 +172,15 @@ class KeyframeSet { if (interpolator != null) { fraction = interpolator.getInterpolation(fraction); } - float intervalFraction = (fraction - prevKeyframe.getFraction()) / - (nextKeyframe.getFraction() - prevKeyframe.getFraction()); + final float prevFraction = prevKeyframe.getFraction(); + float intervalFraction = (fraction - prevFraction) / + (nextKeyframe.getFraction() - prevFraction); return evaluator.evaluate(intervalFraction, prevKeyframe.getValue(), nextKeyframe.getValue()); } prevKeyframe = nextKeyframe; } - // shouldn't get here - return mKeyframes.get(mNumKeyframes - 1).getValue(); + // shouldn't reach here + return mLastKeyframe.getValue(); } } diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java index 7427651b0923..5b8c91d39e50 100644 --- a/core/java/android/animation/ObjectAnimator.java +++ b/core/java/android/animation/ObjectAnimator.java @@ -376,9 +376,14 @@ public final class ObjectAnimator extends ValueAnimator { */ @Override public void setTarget(Object target) { - mTarget = target; - // New property/values/target should cause re-initialization prior to starting - mInitialized = false; + if (mTarget != target) { + mTarget = target; + if (mTarget != null && target != null && mTarget.getClass() == target.getClass()) { + return; + } + // New target type should cause re-initialization prior to starting + mInitialized = false; + } } @Override diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index ad8c971359f3..a0b70b585adc 100755 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -1142,7 +1142,7 @@ public class ValueAnimator extends Animator { switch (mPlayingState) { case RUNNING: case SEEKED: - float fraction = (float)(currentTime - mStartTime) / mDuration; + float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f; if (fraction >= 1f) { if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) { // Time to repeat diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 87e03cf0c8f6..ab975697bd6f 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -6296,8 +6296,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility if (invalidateCache) { mPrivateFlags &= ~DRAWING_CACHE_VALID; } - final ViewParent p = mParent; final AttachInfo ai = mAttachInfo; + final ViewParent p = mParent; + if (ai != null && ai.mHardwareAccelerated) { + // fast-track for GL-enabled applications; just invalidate the whole hierarchy + // with a null dirty rect, which tells the ViewRoot to redraw everything + p.invalidateChild(this, null); + return; + } if (p != null && ai != null) { final Rect r = ai.mTmpInvalRect; r.set(0, 0, mRight - mLeft, mBottom - mTop); @@ -6321,7 +6327,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility */ @ViewDebug.ExportedProperty(category = "drawing") public boolean isOpaque() { - return (mPrivateFlags & OPAQUE_MASK) == OPAQUE_MASK; + return (mPrivateFlags & OPAQUE_MASK) == OPAQUE_MASK && + (mAlpha >= 1.0f - ViewConfiguration.ALPHA_THRESHOLD); } private void computeOpaqueFlags() { @@ -8618,7 +8625,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility */ @RemotableViewMethod public void setBackgroundColor(int color) { - setBackgroundDrawable(new ColorDrawable(color)); + if (mBGDrawable instanceof ColorDrawable) { + ((ColorDrawable) mBGDrawable).setColor(color); + } else { + setBackgroundDrawable(new ColorDrawable(color)); + } } /** diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index b881bdda73a2..aef13add5197 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -2101,6 +2101,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final int cr = child.mRight; final int cb = child.mBottom; + final boolean childHasIdentityMatrix = child.hasIdentityMatrix(); + final int flags = mGroupFlags; if ((flags & FLAG_CLEAR_TRANSFORMATION) == FLAG_CLEAR_TRANSFORMATION) { @@ -2182,7 +2184,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } - concatMatrix |= !child.hasIdentityMatrix(); + concatMatrix |= !childHasIdentityMatrix; // Sets the flag as early as possible to allow draw() implementations // to call invalidate() successfully when doing animations @@ -2231,40 +2233,41 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } if (transformToApply != null || alpha < 1.0f || !child.hasIdentityMatrix()) { - int transX = 0; - int transY = 0; - - if (hasNoCache) { - transX = -sx; - transY = -sy; - } + if (transformToApply != null || !childHasIdentityMatrix) { + int transX = 0; + int transY = 0; - if (transformToApply != null) { - if (concatMatrix) { - // Undo the scroll translation, apply the transformation matrix, - // then redo the scroll translate to get the correct result. - canvas.translate(-transX, -transY); - canvas.concat(transformToApply.getMatrix()); - canvas.translate(transX, transY); - mGroupFlags |= FLAG_CLEAR_TRANSFORMATION; + if (hasNoCache) { + transX = -sx; + transY = -sy; } - float transformAlpha = transformToApply.getAlpha(); - if (transformAlpha < 1.0f) { - alpha *= transformToApply.getAlpha(); - mGroupFlags |= FLAG_CLEAR_TRANSFORMATION; + if (transformToApply != null) { + if (concatMatrix) { + // Undo the scroll translation, apply the transformation matrix, + // then redo the scroll translate to get the correct result. + canvas.translate(-transX, -transY); + canvas.concat(transformToApply.getMatrix()); + canvas.translate(transX, transY); + mGroupFlags |= FLAG_CLEAR_TRANSFORMATION; + } + + float transformAlpha = transformToApply.getAlpha(); + if (transformAlpha < 1.0f) { + alpha *= transformToApply.getAlpha(); + mGroupFlags |= FLAG_CLEAR_TRANSFORMATION; + } } - } - if (!child.hasIdentityMatrix()) { - canvas.translate(-transX, -transY); - canvas.concat(child.getMatrix()); - canvas.translate(transX, transY); + if (!childHasIdentityMatrix) { + canvas.translate(-transX, -transY); + canvas.concat(child.getMatrix()); + canvas.translate(transX, transY); + } } if (alpha < 1.0f) { mGroupFlags |= FLAG_CLEAR_TRANSFORMATION; - if (hasNoCache) { final int multipliedAlpha = (int) (255 * alpha); if (!child.onSetAlpha(multipliedAlpha)) { @@ -3209,19 +3212,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { - final int[] location = attachInfo.mInvalidateChildLocation; - location[CHILD_LEFT_INDEX] = child.mLeft; - location[CHILD_TOP_INDEX] = child.mTop; - Matrix childMatrix = child.getMatrix(); - if (!childMatrix.isIdentity()) { - RectF boundingRect = attachInfo.mTmpTransformRect; - boundingRect.set(dirty); - childMatrix.mapRect(boundingRect); - dirty.set((int) boundingRect.left, (int) boundingRect.top, - (int) (boundingRect.right + 0.5f), - (int) (boundingRect.bottom + 0.5f)); - } - // If the child is drawing an animation, we want to copy this flag onto // ourselves and the parent to make sure the invalidate request goes // through @@ -3229,45 +3219,95 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // Check whether the child that requests the invalidate is fully opaque final boolean isOpaque = child.isOpaque() && !drawAnimation && - child.getAnimation() != null; + child.getAnimation() == null; // Mark the child as dirty, using the appropriate flag // Make sure we do not set both flags at the same time final int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY; - do { - View view = null; - if (parent instanceof View) { - view = (View) parent; - } + if (dirty == null) { + do { + View view = null; + if (parent instanceof View) { + view = (View) parent; + if ((view.mPrivateFlags & DIRTY_MASK) != 0) { + // already marked dirty - we're done + break; + } + } - if (drawAnimation) { - if (view != null) { - view.mPrivateFlags |= DRAW_ANIMATION; - } else if (parent instanceof ViewRoot) { - ((ViewRoot) parent).mIsAnimating = true; + if (drawAnimation) { + if (view != null) { + view.mPrivateFlags |= DRAW_ANIMATION; + } else if (parent instanceof ViewRoot) { + ((ViewRoot) parent).mIsAnimating = true; + } } - } - // If the parent is dirty opaque or not dirty, mark it dirty with the opaque - // flag coming from the child that initiated the invalidate - if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) { - view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag; + if (parent instanceof ViewRoot) { + ((ViewRoot) parent).invalidate(); + parent = null; + } else if (view != null) { + if ((mPrivateFlags & DRAWN) == DRAWN) { + view.mPrivateFlags &= ~DRAWING_CACHE_VALID; + if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) { + view.mPrivateFlags = + (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag; + } + parent = view.mParent; + } else { + parent = null; + } + } + } while (parent != null); + } else { + final int[] location = attachInfo.mInvalidateChildLocation; + location[CHILD_LEFT_INDEX] = child.mLeft; + location[CHILD_TOP_INDEX] = child.mTop; + Matrix childMatrix = child.getMatrix(); + if (!childMatrix.isIdentity()) { + RectF boundingRect = attachInfo.mTmpTransformRect; + boundingRect.set(dirty); + childMatrix.mapRect(boundingRect); + dirty.set((int) boundingRect.left, (int) boundingRect.top, + (int) (boundingRect.right + 0.5f), + (int) (boundingRect.bottom + 0.5f)); } - parent = parent.invalidateChildInParent(location, dirty); - if (view != null) { - // Account for transform on current parent - Matrix m = view.getMatrix(); - if (!m.isIdentity()) { - RectF boundingRect = attachInfo.mTmpTransformRect; - boundingRect.set(dirty); - m.mapRect(boundingRect); - dirty.set((int) boundingRect.left, (int) boundingRect.top, - (int) (boundingRect.right + 0.5f), - (int) (boundingRect.bottom + 0.5f)); + do { + View view = null; + if (parent instanceof View) { + view = (View) parent; } - } - } while (parent != null); + + if (drawAnimation) { + if (view != null) { + view.mPrivateFlags |= DRAW_ANIMATION; + } else if (parent instanceof ViewRoot) { + ((ViewRoot) parent).mIsAnimating = true; + } + } + + // If the parent is dirty opaque or not dirty, mark it dirty with the opaque + // flag coming from the child that initiated the invalidate + if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) { + view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag; + } + + parent = parent.invalidateChildInParent(location, dirty); + if (view != null) { + // Account for transform on current parent + Matrix m = view.getMatrix(); + if (!m.isIdentity()) { + RectF boundingRect = attachInfo.mTmpTransformRect; + boundingRect.set(dirty); + m.mapRect(boundingRect); + dirty.set((int) boundingRect.left, (int) boundingRect.top, + (int) (boundingRect.right + 0.5f), + (int) (boundingRect.bottom + 0.5f)); + } + } + } while (parent != null); + } } } diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 06261bb03aaf..22a7773fd1e1 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -543,6 +543,11 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn public void invalidateChild(View child, Rect dirty) { checkThread(); if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty); + if (dirty == null) { + // Fast invalidation for GL-enabled applications; GL must redraw everything + invalidate(); + return; + } if (mCurScrollY != 0 || mTranslator != null) { mTempRect.set(dirty); dirty = mTempRect; diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java index a25fad4d349d..289348a29222 100644 --- a/graphics/java/android/graphics/drawable/ColorDrawable.java +++ b/graphics/java/android/graphics/drawable/ColorDrawable.java @@ -51,7 +51,7 @@ public class ColorDrawable extends Drawable { */ public ColorDrawable(int color) { this(null); - mState.mBaseColor = mState.mUseColor = color; + setColor(color); } private ColorDrawable(ColorState state) { @@ -72,6 +72,25 @@ public class ColorDrawable extends Drawable { } /** + * Gets the drawable's color value. + * + * @return int The color to draw. + */ + public int getColor() { + return mState.mUseColor; + } + + /** + * Sets the drawable's color value. This action will clobber the results of prior calls to + * {@link #setAlpha(int)} on this object, which side-affected the underlying color. + * + * @param color The color to draw. + */ + public void setColor(int color) { + mState.mBaseColor = mState.mUseColor = color; + } + + /** * Returns the alpha value of this drawable's color. * * @return A value between 0 and 255. @@ -131,7 +150,7 @@ public class ColorDrawable extends Drawable { } final static class ColorState extends ConstantState { - int mBaseColor; // initial color. never changes + int mBaseColor; // base color, independent of setAlpha() int mUseColor; // basecolor modulated by setAlpha() int mChangingConfigurations; |