diff options
Diffstat (limited to 'graphics')
8 files changed, 195 insertions, 96 deletions
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index 499608e..b0580d5 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -250,15 +250,6 @@ public class Canvas { public void insertInorderBarrier() {} /** - * Set a transfer mode that overrides any transfer modes - * in paints used for drawing. Pass null to disable this - * override. Only implemented in GLES20Canvas. - * - * @hide - */ - public void setOverrideXfermode(@Nullable PorterDuff.Mode xfermode) {} - - /** * Return true if the device that the current layer draws into is opaque * (i.e. does not support per-pixel alpha). * diff --git a/graphics/java/android/graphics/ColorMatrix.java b/graphics/java/android/graphics/ColorMatrix.java index 1242eb5..64f0c05 100644 --- a/graphics/java/android/graphics/ColorMatrix.java +++ b/graphics/java/android/graphics/ColorMatrix.java @@ -21,23 +21,43 @@ import android.util.FloatMath; import java.util.Arrays; /** - * 4x5 matrix for transforming the color+alpha components of a Bitmap. - * The matrix is stored in a single array, and its treated as follows: + * 4x5 matrix for transforming the color and alpha components of a Bitmap. + * The matrix can be passed as single array, and is treated as follows: + * * <pre> * [ a, b, c, d, e, * f, g, h, i, j, * k, l, m, n, o, - * p, q, r, s, t ] - * </pre> + * p, q, r, s, t ]</pre> + * + * <p> + * When applied to a color <code>[R, G, B, A]</code>, the resulting color + * is computed as: + * </p> + * + * <pre> + * R’ = a*R + b*G + c*B + d*A + e; + * G’ = f*R + g*G + h*B + i*A + j; + * B’ = k*R + l*G + m*B + n*A + o; + * A’ = p*R + q*G + r*B + s*A + t;</pre> + * + * <p> + * That resulting color <code>[R’, G’, B’, A’]</code> + * then has each channel clamped to the <code>0</code> to <code>255</code> + * range. + * </p> + * + * <p> + * The sample ColorMatrix below inverts incoming colors by scaling each + * channel by <code>-1</code>, and then shifting the result up by + * <code>255</code> to remain in the standard color space. + * </p> * - * When applied to a color <code>[r, g, b, a]</code>, the resulting color - * is computed as (after clamping): * <pre> - * R' = a*R + b*G + c*B + d*A + e; - * G' = f*R + g*G + h*B + i*A + j; - * B' = k*R + l*G + m*B + n*A + o; - * A' = p*R + q*G + r*B + s*A + t; - * </pre> + * [ -1, 0, 0, 0, 255, + * 0, -1, 0, 0, 255, + * 0, 0, -1, 0, 255, + * 0, 0, 0, 1, 0 ]</pre> */ @SuppressWarnings({ "MismatchedReadAndWriteOfArray", "PointlessArithmeticExpression" }) public class ColorMatrix { @@ -52,24 +72,24 @@ public class ColorMatrix { } /** - * Create a new colormatrix initialized with the specified array of values. + * Create a new colormatrix initialized with the specified array of values. */ public ColorMatrix(float[] src) { System.arraycopy(src, 0, mArray, 0, 20); } - + /** * Create a new colormatrix initialized with the specified colormatrix. */ public ColorMatrix(ColorMatrix src) { System.arraycopy(src.mArray, 0, mArray, 0, 20); } - + /** * Return the array of floats representing this colormatrix. */ public final float[] getArray() { return mArray; } - + /** * Set this colormatrix to identity: * <pre> @@ -84,7 +104,7 @@ public class ColorMatrix { Arrays.fill(a, 0); a[0] = a[6] = a[12] = a[18] = 1; } - + /** * Assign the src colormatrix into this matrix, copying all of its values. */ @@ -98,7 +118,7 @@ public class ColorMatrix { public void set(float[] src) { System.arraycopy(src, 0, mArray, 0, 20); } - + /** * Set this colormatrix to scale by the specified values. */ @@ -114,12 +134,14 @@ public class ColorMatrix { a[12] = bScale; a[18] = aScale; } - + /** * Set the rotation on a color axis by the specified values. + * <p> * <code>axis=0</code> correspond to a rotation around the RED color * <code>axis=1</code> correspond to a rotation around the GREEN color * <code>axis=2</code> correspond to a rotation around the BLUE color + * </p> */ public void setRotate(int axis, float degrees) { reset(); @@ -153,8 +175,10 @@ public class ColorMatrix { /** * Set this colormatrix to the concatenation of the two specified * colormatrices, such that the resulting colormatrix has the same effect - * as applying matB and then applying matA. It is legal for either matA or - * matB to be the same colormatrix as this. + * as applying matB and then applying matA. + * <p> + * It is legal for either matA or matB to be the same colormatrix as this. + * </p> */ public void setConcat(ColorMatrix matA, ColorMatrix matB) { float[] tmp; @@ -163,7 +187,7 @@ public class ColorMatrix { } else { tmp = mArray; } - + final float[] a = matA.mArray; final float[] b = matB.mArray; int index = 0; @@ -176,38 +200,43 @@ public class ColorMatrix { a[j + 2] * b[14] + a[j + 3] * b[19] + a[j + 4]; } - + if (tmp != mArray) { System.arraycopy(tmp, 0, mArray, 0, 20); } } /** - * Concat this colormatrix with the specified prematrix. This is logically - * the same as calling setConcat(this, prematrix); + * Concat this colormatrix with the specified prematrix. + * <p> + * This is logically the same as calling setConcat(this, prematrix); + * </p> */ public void preConcat(ColorMatrix prematrix) { setConcat(this, prematrix); } /** - * Concat this colormatrix with the specified postmatrix. This is logically - * the same as calling setConcat(postmatrix, this); + * Concat this colormatrix with the specified postmatrix. + * <p> + * This is logically the same as calling setConcat(postmatrix, this); + * </p> */ public void postConcat(ColorMatrix postmatrix) { setConcat(postmatrix, this); } /////////////////////////////////////////////////////////////////////////// - + /** - * Set the matrix to affect the saturation of colors. A value of 0 maps the - * color to gray-scale. 1 is identity. + * Set the matrix to affect the saturation of colors. + * + * @param sat A value of 0 maps the color to gray-scale. 1 is identity. */ public void setSaturation(float sat) { reset(); float[] m = mArray; - + final float invSat = 1 - sat; final float R = 0.213f * invSat; final float G = 0.715f * invSat; @@ -217,7 +246,7 @@ public class ColorMatrix { m[5] = R; m[6] = G + sat; m[7] = B; m[10] = R; m[11] = G; m[12] = B + sat; } - + /** * Set the matrix to convert RGB to YUV */ @@ -229,7 +258,7 @@ public class ColorMatrix { m[5] = -0.16874f; m[6] = -0.33126f; m[7] = 0.5f; m[10] = 0.5f; m[11] = -0.41869f; m[12] = -0.08131f; } - + /** * Set the matrix to convert from YUV to RGB */ @@ -242,4 +271,3 @@ public class ColorMatrix { m[10] = 1; m[11] = 1.772f; m[12] = 0; } } - diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java index 6d23634..c58563f 100644 --- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java @@ -199,6 +199,8 @@ public class AnimatedStateListDrawable extends StateListDrawable { return false; } + boolean hasReversibleFlag = state.transitionHasReversibleFlag(fromId, toId); + // This may fail if we're already on the transition, but that's okay! selectDrawable(transitionIndex); @@ -206,10 +208,14 @@ public class AnimatedStateListDrawable extends StateListDrawable { final Drawable d = getCurrent(); if (d instanceof AnimationDrawable) { final boolean reversed = state.isTransitionReversed(fromId, toId); - transition = new AnimationDrawableTransition((AnimationDrawable) d, reversed); + + transition = new AnimationDrawableTransition((AnimationDrawable) d, + reversed, hasReversibleFlag); } else if (d instanceof AnimatedVectorDrawable) { final boolean reversed = state.isTransitionReversed(fromId, toId); - transition = new AnimatedVectorDrawableTransition((AnimatedVectorDrawable) d, reversed); + + transition = new AnimatedVectorDrawableTransition((AnimatedVectorDrawable) d, + reversed, hasReversibleFlag); } else if (d instanceof Animatable) { transition = new AnimatableTransition((Animatable) d); } else { @@ -260,7 +266,12 @@ public class AnimatedStateListDrawable extends StateListDrawable { private static class AnimationDrawableTransition extends Transition { private final ObjectAnimator mAnim; - public AnimationDrawableTransition(AnimationDrawable ad, boolean reversed) { + // Even AnimationDrawable is always reversible technically, but + // we should obey the XML's android:reversible flag. + private final boolean mHasReversibleFlag; + + public AnimationDrawableTransition(AnimationDrawable ad, + boolean reversed, boolean hasReversibleFlag) { final int frameCount = ad.getNumberOfFrames(); final int fromFrame = reversed ? frameCount - 1 : 0; final int toFrame = reversed ? 0 : frameCount - 1; @@ -269,13 +280,13 @@ public class AnimatedStateListDrawable extends StateListDrawable { anim.setAutoCancel(true); anim.setDuration(interp.getTotalDuration()); anim.setInterpolator(interp); - + mHasReversibleFlag = hasReversibleFlag; mAnim = anim; } @Override public boolean canReverse() { - return true; + return mHasReversibleFlag; } @Override @@ -296,16 +307,28 @@ public class AnimatedStateListDrawable extends StateListDrawable { private static class AnimatedVectorDrawableTransition extends Transition { private final AnimatedVectorDrawable mAvd; + + // mReversed is indicating the current transition's direction. private final boolean mReversed; - public AnimatedVectorDrawableTransition(AnimatedVectorDrawable avd, boolean reversed) { + // mHasReversibleFlag is indicating whether the whole transition has + // reversible flag set to true. + // If mHasReversibleFlag is false, then mReversed is always false. + private final boolean mHasReversibleFlag; + + public AnimatedVectorDrawableTransition(AnimatedVectorDrawable avd, + boolean reversed, boolean hasReversibleFlag) { mAvd = avd; mReversed = reversed; + mHasReversibleFlag = hasReversibleFlag; } @Override public boolean canReverse() { - return mAvd.canReverse(); + // When the transition's XML says it is not reversible, then we obey + // it, even if the AVD itself is reversible. + // This will help the single direction transition. + return mAvd.canReverse() && mHasReversibleFlag; } @Override @@ -322,7 +345,8 @@ public class AnimatedStateListDrawable extends StateListDrawable { if (canReverse()) { mAvd.reverse(); } else { - Log.w(LOGTAG, "Reverse() is called on a drawable can't reverse"); + Log.w(LOGTAG, "Can't reverse, either the reversible is set to false," + + " or the AnimatedVectorDrawable can't reverse"); } } @@ -503,14 +527,18 @@ public class AnimatedStateListDrawable extends StateListDrawable { @Override public Drawable mutate() { if (!mMutated && super.mutate() == this) { - final AnimatedStateListState newState = new AnimatedStateListState(mState, this, null); - setConstantState(newState); + mState.mutate(); mMutated = true; } return this; } + @Override + AnimatedStateListState cloneConstantState() { + return new AnimatedStateListState(mState, this, null); + } + /** * @hide */ @@ -520,36 +548,50 @@ public class AnimatedStateListDrawable extends StateListDrawable { } static class AnimatedStateListState extends StateListState { - private static final int REVERSE_SHIFT = 32; - private static final int REVERSE_MASK = 0x1; + // REVERSED_BIT is indicating the current transition's direction. + private static final long REVERSED_BIT = 0x100000000l; + + // REVERSIBLE_FLAG_BIT is indicating whether the whole transition has + // reversible flag set to true. + private static final long REVERSIBLE_FLAG_BIT = 0x200000000l; int[] mAnimThemeAttrs; - final LongSparseLongArray mTransitions; - final SparseIntArray mStateIds; + LongSparseLongArray mTransitions; + SparseIntArray mStateIds; AnimatedStateListState(@Nullable AnimatedStateListState orig, @NonNull AnimatedStateListDrawable owner, @Nullable Resources res) { super(orig, owner, res); if (orig != null) { + // Perform a shallow copy and rely on mutate() to deep-copy. mAnimThemeAttrs = orig.mAnimThemeAttrs; - mTransitions = orig.mTransitions.clone(); - mStateIds = orig.mStateIds.clone(); + mTransitions = orig.mTransitions; + mStateIds = orig.mStateIds; } else { mTransitions = new LongSparseLongArray(); mStateIds = new SparseIntArray(); } } + private void mutate() { + mTransitions = mTransitions.clone(); + mStateIds = mStateIds.clone(); + } + int addTransition(int fromId, int toId, @NonNull Drawable anim, boolean reversible) { final int pos = super.addChild(anim); final long keyFromTo = generateTransitionKey(fromId, toId); - mTransitions.append(keyFromTo, pos); + long reversibleBit = 0; + if (reversible) { + reversibleBit = REVERSIBLE_FLAG_BIT; + } + mTransitions.append(keyFromTo, pos | reversibleBit); if (reversible) { final long keyToFrom = generateTransitionKey(toId, fromId); - mTransitions.append(keyToFrom, pos | (1L << REVERSE_SHIFT)); + mTransitions.append(keyToFrom, pos | REVERSED_BIT | reversibleBit); } return addChild(anim); @@ -581,7 +623,12 @@ public class AnimatedStateListDrawable extends StateListDrawable { boolean isTransitionReversed(int fromId, int toId) { final long keyFromTo = generateTransitionKey(fromId, toId); - return (mTransitions.get(keyFromTo, -1) >> REVERSE_SHIFT & REVERSE_MASK) == 1; + return (mTransitions.get(keyFromTo, -1) & REVERSED_BIT) != 0; + } + + boolean transitionHasReversibleFlag(int fromId, int toId) { + final long keyFromTo = generateTransitionKey(fromId, toId); + return (mTransitions.get(keyFromTo, -1) & REVERSIBLE_FLAG_BIT) != 0; } @Override @@ -604,7 +651,7 @@ public class AnimatedStateListDrawable extends StateListDrawable { } } - void setConstantState(@NonNull AnimatedStateListState state) { + protected void setConstantState(@NonNull AnimatedStateListState state) { super.setConstantState(state); mState = state; @@ -613,6 +660,7 @@ public class AnimatedStateListDrawable extends StateListDrawable { private AnimatedStateListDrawable(@Nullable AnimatedStateListState state, @Nullable Resources res) { super(null); + // Every animated state list drawable has its own constant state. final AnimatedStateListState newState = new AnimatedStateListState(state, this, res); setConstantState(newState); onStateChange(getState()); diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java index d0edeba..e9c8c2a 100644 --- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -462,19 +462,22 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { /** * Reverses ongoing animations or starts pending animations in reverse. * <p> - * NOTE: Only works of all animations are ValueAnimators. + * NOTE: Only works if all animations support reverse. Otherwise, this will + * do nothing. * @hide */ public void reverse() { + // Only reverse when all the animators can be reverse. Otherwise, partially + // reverse is confusing. + if (!canReverse()) { + Log.w(LOGTAG, "AnimatedVectorDrawable can't reverse()"); + return; + } 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.canReverse()) { - animator.reverse(); - } else { - Log.w(LOGTAG, "AnimatedVectorDrawable can't reverse()"); - } + animator.reverse(); } } diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java index 2ddf9df..28ada82 100644 --- a/graphics/java/android/graphics/drawable/AnimationDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java @@ -342,12 +342,17 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An @Override public Drawable mutate() { if (!mMutated && super.mutate() == this) { - mAnimationState.mDurations = mAnimationState.mDurations.clone(); + mAnimationState.mutate(); mMutated = true; } return this; } + @Override + AnimationState cloneConstantState() { + return new AnimationState(mAnimationState, this, null); + } + /** * @hide */ @@ -373,6 +378,10 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An } } + private void mutate() { + mDurations = mDurations.clone(); + } + @Override public Drawable newDrawable() { return new AnimationDrawable(this, null); diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index 326490f..6d43a0c 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -536,7 +536,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } if (schedule && animating) { - scheduleSelf(mAnimationRunnable, now + 1000/60); + scheduleSelf(mAnimationRunnable, now + 1000 / 60); } } @@ -567,6 +567,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { @Override public Drawable mutate() { if (!mMutated && super.mutate() == this) { + mDrawableContainerState = cloneConstantState(); mDrawableContainerState.mutate(); mMutated = true; } @@ -574,6 +575,16 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } /** + * Returns a shallow copy of the container's constant state to be used as + * the base state for {@link #mutate()}. + * + * @return a shallow copy of the constant state + */ + DrawableContainerState cloneConstantState() { + return mDrawableContainerState; + } + + /** * @hide */ public void clearMutated() { @@ -833,7 +844,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return false; } - final void mutate() { + private void mutate() { // No need to call createAllFutures, since future drawables will // mutate when they are prepared. final int N = mNumChildren; diff --git a/graphics/java/android/graphics/drawable/LevelListDrawable.java b/graphics/java/android/graphics/drawable/LevelListDrawable.java index 9e918f6..dc41216 100644 --- a/graphics/java/android/graphics/drawable/LevelListDrawable.java +++ b/graphics/java/android/graphics/drawable/LevelListDrawable.java @@ -146,13 +146,17 @@ public class LevelListDrawable extends DrawableContainer { @Override public Drawable mutate() { if (!mMutated && super.mutate() == this) { - mLevelListState.mLows = mLevelListState.mLows.clone(); - mLevelListState.mHighs = mLevelListState.mHighs.clone(); + mLevelListState.mutate(); mMutated = true; } return this; } + @Override + LevelListState cloneConstantState() { + return new LevelListState(mLevelListState, this, null); + } + /** * @hide */ @@ -169,6 +173,7 @@ public class LevelListDrawable extends DrawableContainer { super(orig, owner, res); if (orig != null) { + // Perform a shallow copy and rely on mutate() to deep-copy. mLows = orig.mLows; mHighs = orig.mHighs; } else { @@ -177,6 +182,11 @@ public class LevelListDrawable extends DrawableContainer { } } + private void mutate() { + mLows = mLows.clone(); + mHighs = mHighs.clone(); + } + public void addLevel(int low, int high, Drawable drawable) { int pos = addChild(drawable); mLows[pos] = low; diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java index e7a8233..eb6f94f 100644 --- a/graphics/java/android/graphics/drawable/StateListDrawable.java +++ b/graphics/java/android/graphics/drawable/StateListDrawable.java @@ -24,6 +24,8 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.Arrays; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.Resources.Theme; @@ -288,20 +290,17 @@ public class StateListDrawable extends DrawableContainer { @Override public Drawable mutate() { if (!mMutated && super.mutate() == this) { - final int[][] sets = mStateListState.mStateSets; - final int count = sets.length; - mStateListState.mStateSets = new int[count][]; - for (int i = 0; i < count; i++) { - final int[] set = sets[i]; - if (set != null) { - mStateListState.mStateSets[i] = set.clone(); - } - } + mStateListState.mutate(); mMutated = true; } return this; } + @Override + StateListState cloneConstantState() { + return new StateListState(mStateListState, this, null); + } + /** * @hide */ @@ -328,25 +327,24 @@ public class StateListDrawable extends DrawableContainer { super(orig, owner, res); if (orig != null) { - // Perform a deep copy. - final int[][] sets = orig.mStateSets; - final int count = sets.length; - mStateSets = new int[count][]; - for (int i = 0; i < count; i++) { - final int[] set = sets[i]; - if (set != null) { - mStateSets[i] = set.clone(); - } - } - + // Perform a shallow copy and rely on mutate() to deep-copy. mThemeAttrs = orig.mThemeAttrs; - mStateSets = Arrays.copyOf(orig.mStateSets, orig.mStateSets.length); + mStateSets = orig.mStateSets; } else { mThemeAttrs = null; mStateSets = new int[getCapacity()][]; } } + private void mutate() { + mThemeAttrs = mThemeAttrs != null ? mThemeAttrs.clone() : null; + + final int[][] stateSets = new int[mStateSets.length][]; + for (int i = mStateSets.length - 1; i >= 0; i--) { + stateSets[i] = mStateSets[i] != null ? mStateSets[i].clone() : null; + } + } + int addStateSet(int[] stateSet, Drawable drawable) { final int pos = addChild(drawable); mStateSets[pos] = stateSet; @@ -395,13 +393,14 @@ public class StateListDrawable extends DrawableContainer { onStateChange(getState()); } - void setConstantState(StateListState state) { + protected void setConstantState(@NonNull StateListState state) { super.setConstantState(state); mStateListState = state; } private StateListDrawable(StateListState state, Resources res) { + // Every state list drawable has its own constant state. final StateListState newState = new StateListState(state, this, res); setConstantState(newState); onStateChange(getState()); @@ -411,7 +410,7 @@ public class StateListDrawable extends DrawableContainer { * This constructor exists so subclasses can avoid calling the default * constructor and setting up a StateListDrawable-specific constant state. */ - StateListDrawable(StateListState state) { + StateListDrawable(@Nullable StateListState state) { if (state != null) { setConstantState(state); } |