diff options
| -rw-r--r-- | api/current.txt | 8 | ||||
| -rw-r--r-- | core/java/android/transition/ChangeBounds.java | 2 | ||||
| -rw-r--r-- | core/java/android/transition/ChangeImageTransform.java | 25 | ||||
| -rw-r--r-- | core/java/android/transition/ChangeTransform.java | 437 | ||||
| -rw-r--r-- | core/java/android/transition/Transition.java | 42 | ||||
| -rw-r--r-- | core/java/android/transition/TransitionUtils.java | 23 | ||||
| -rw-r--r-- | core/java/android/transition/Visibility.java | 2 | ||||
| -rw-r--r-- | core/java/android/view/View.java | 9 | ||||
| -rw-r--r-- | core/res/res/values/attrs.xml | 13 | ||||
| -rw-r--r-- | core/res/res/values/ids.xml | 2 | ||||
| -rw-r--r-- | core/res/res/values/public.xml | 2 | ||||
| -rw-r--r-- | core/res/res/values/symbols.xml | 2 |
12 files changed, 442 insertions, 125 deletions
diff --git a/api/current.txt b/api/current.txt index aac7fcd393be..dbd64a1c2b94 100644 --- a/api/current.txt +++ b/api/current.txt @@ -1028,6 +1028,8 @@ package android { field public static final int readPermission = 16842759; // 0x1010007 field public static final int recognitionService = 16843932; // 0x101049c field public static final int relinquishTaskIdentity = 16843894; // 0x1010476 + field public static final int reparent = 16843965; // 0x10104bd + field public static final int reparentWithOverlay = 16843966; // 0x10104be field public static final int repeatCount = 16843199; // 0x10101bf field public static final int repeatMode = 16843200; // 0x10101c0 field public static final int reqFiveWayNav = 16843314; // 0x1010232 @@ -31804,7 +31806,7 @@ package android.transition { ctor public ChangeBounds(android.content.Context, android.util.AttributeSet); method public void captureEndValues(android.transition.TransitionValues); method public void captureStartValues(android.transition.TransitionValues); - method public void setReparent(boolean); + method public deprecated void setReparent(boolean); method public void setResizeClip(boolean); } @@ -31827,6 +31829,10 @@ package android.transition { ctor public ChangeTransform(android.content.Context, android.util.AttributeSet); method public void captureEndValues(android.transition.TransitionValues); method public void captureStartValues(android.transition.TransitionValues); + method public boolean getReparent(); + method public boolean getReparentWithOverlay(); + method public void setReparent(boolean); + method public void setReparentWithOverlay(boolean); } public class CircularPropagation extends android.transition.VisibilityPropagation { diff --git a/core/java/android/transition/ChangeBounds.java b/core/java/android/transition/ChangeBounds.java index 6246cbe003cd..ebb1a5cf5e78 100644 --- a/core/java/android/transition/ChangeBounds.java +++ b/core/java/android/transition/ChangeBounds.java @@ -107,6 +107,8 @@ public class ChangeBounds extends Transition { * * @param reparent true if the transition should track the parent * container of target views and animate parent changes. + * @deprecated Use {@link android.transition.ChangeTransform} to handle + * transitions between different parents. */ public void setReparent(boolean reparent) { mReparent = reparent; diff --git a/core/java/android/transition/ChangeImageTransform.java b/core/java/android/transition/ChangeImageTransform.java index 4b230eb0bae8..d7a912057858 100644 --- a/core/java/android/transition/ChangeImageTransform.java +++ b/core/java/android/transition/ChangeImageTransform.java @@ -16,7 +16,6 @@ package android.transition; import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.TypeEvaluator; import android.content.Context; @@ -196,28 +195,6 @@ public class ChangeImageTransform extends Transition { private ObjectAnimator createMatrixAnimator(final ImageView imageView, Matrix startMatrix, final Matrix endMatrix) { return ObjectAnimator.ofObject(imageView, ANIMATED_TRANSFORM_PROPERTY, - new MatrixEvaluator(), startMatrix, endMatrix); + new TransitionUtils.MatrixEvaluator(), startMatrix, endMatrix); } - - private static class MatrixEvaluator implements TypeEvaluator<Matrix> { - - float[] mTempStartValues = new float[9]; - - float[] mTempEndValues = new float[9]; - - Matrix mTempMatrix = new Matrix(); - - @Override - public Matrix evaluate(float fraction, Matrix startValue, Matrix endValue) { - startValue.getValues(mTempStartValues); - endValue.getValues(mTempEndValues); - for (int i = 0; i < 9; i++) { - float diff = mTempEndValues[i] - mTempStartValues[i]; - mTempEndValues[i] = mTempStartValues[i] + (fraction * diff); - } - mTempMatrix.setValues(mTempEndValues); - return mTempMatrix; - } - } - } diff --git a/core/java/android/transition/ChangeTransform.java b/core/java/android/transition/ChangeTransform.java index e9be3b90872c..d579f54d3ca3 100644 --- a/core/java/android/transition/ChangeTransform.java +++ b/core/java/android/transition/ChangeTransform.java @@ -16,72 +16,134 @@ package android.transition; import android.animation.Animator; -import android.animation.FloatArrayEvaluator; +import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Matrix; import android.util.AttributeSet; -import android.util.FloatProperty; import android.util.Property; +import android.view.GhostView; import android.view.View; import android.view.ViewGroup; +import com.android.internal.R; /** * This Transition captures scale and rotation for Views before and after the * scene change and animates those changes during the transition. * - * <p>ChangeTransform does not work when the pivot changes between scenes, so either the - * pivot must be set to prevent automatic pivot adjustment or the View's size must be unchanged.</p> + * A change in parent is handled as well by capturing the transforms from + * the parent before and after the scene change and animating those during the + * transition. */ public class ChangeTransform extends Transition { private static final String TAG = "ChangeTransform"; - private static final String PROPNAME_SCALE_X = "android:changeTransform:scaleX"; - private static final String PROPNAME_SCALE_Y = "android:changeTransform:scaleY"; - private static final String PROPNAME_ROTATION_X = "android:changeTransform:rotationX"; - private static final String PROPNAME_ROTATION_Y = "android:changeTransform:rotationY"; - private static final String PROPNAME_ROTATION_Z = "android:changeTransform:rotationZ"; - private static final String PROPNAME_PIVOT_X = "android:changeTransform:pivotX"; - private static final String PROPNAME_PIVOT_Y = "android:changeTransform:pivotY"; + private static final String PROPNAME_MATRIX = "android:changeTransform:matrix"; + private static final String PROPNAME_TRANSFORMS = "android:changeTransform:transforms"; + private static final String PROPNAME_PARENT = "android:changeTransform:parent"; + private static final String PROPNAME_PARENT_MATRIX = "android:changeTransform:parentMatrix"; private static final String[] sTransitionProperties = { - PROPNAME_SCALE_X, - PROPNAME_SCALE_Y, - PROPNAME_ROTATION_X, - PROPNAME_ROTATION_Y, - PROPNAME_ROTATION_Z, + PROPNAME_MATRIX, + PROPNAME_TRANSFORMS, + PROPNAME_PARENT_MATRIX, }; - private static final FloatProperty<View>[] sChangedProperties = new FloatProperty[] { - (FloatProperty) View.SCALE_X, - (FloatProperty) View.SCALE_Y, - (FloatProperty) View.ROTATION_X, - (FloatProperty) View.ROTATION_Y, - (FloatProperty) View.ROTATION, - }; - - private static Property<View, float[]> TRANSFORMS = new Property<View, float[]>(float[].class, - "transforms") { - @Override - public float[] get(View object) { - return null; - } + private static final Property<View, Matrix> ANIMATION_MATRIX_PROPERTY = + new Property<View, Matrix>(Matrix.class, "animationMatrix") { + @Override + public Matrix get(View object) { + return null; + } - @Override - public void set(View view, float[] values) { - for (int i = 0; i < values.length; i++) { - float value = values[i]; - if (!Float.isNaN(value)) { - sChangedProperties[i].setValue(view, value); + @Override + public void set(View object, Matrix value) { + object.setAnimationMatrix(value); } - } - } - }; + }; + + private boolean mUseOverlay = true; + private boolean mReparent = true; + private Matrix mTempMatrix = new Matrix(); public ChangeTransform() {} public ChangeTransform(Context context, AttributeSet attrs) { super(context, attrs); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ChangeTransform); + mUseOverlay = a.getBoolean(R.styleable.ChangeTransform_reparentWithOverlay, true); + mReparent = a.getBoolean(R.styleable.ChangeTransform_reparent, true); + a.recycle(); + } + + /** + * Returns whether changes to parent should use an overlay or not. When the parent + * change doesn't use an overlay, it affects the transforms of the child. The + * default value is <code>true</code>. + * + * <p>Note: when Overlays are not used when a parent changes, a view can be clipped when + * it moves outside the bounds of its parent. Setting + * {@link android.view.ViewGroup#setClipChildren(boolean)} and + * {@link android.view.ViewGroup#setClipToPadding(boolean)} can help. Also, when + * Overlays are not used and the parent is animating its location, the position of the + * child view will be relative to its parent's final position, so it may appear to "jump" + * at the beginning.</p> + * + * @return <code>true</code> when a changed parent should execute the transition + * inside the scene root's overlay or <code>false</code> if a parent change only + * affects the transform of the transitioning view. + */ + public boolean getReparentWithOverlay() { + return mUseOverlay; + } + + /** + * Sets whether changes to parent should use an overlay or not. When the parent + * change doesn't use an overlay, it affects the transforms of the child. The + * default value is <code>true</code>. + * + * <p>Note: when Overlays are not used when a parent changes, a view can be clipped when + * it moves outside the bounds of its parent. Setting + * {@link android.view.ViewGroup#setClipChildren(boolean)} and + * {@link android.view.ViewGroup#setClipToPadding(boolean)} can help. Also, when + * Overlays are not used and the parent is animating its location, the position of the + * child view will be relative to its parent's final position, so it may appear to "jump" + * at the beginning.</p> + * + * @return <code>true</code> when a changed parent should execute the transition + * inside the scene root's overlay or <code>false</code> if a parent change only + * affects the transform of the transitioning view. + */ + public void setReparentWithOverlay(boolean reparentWithOverlay) { + mUseOverlay = reparentWithOverlay; + } + + /** + * Returns whether parent changes will be tracked by the ChangeTransform. If parent + * changes are tracked, then the transform will adjust to the transforms of the + * different parents. If they aren't tracked, only the transforms of the transitioning + * view will be tracked. Default is true. + * + * @return whether parent changes will be tracked by the ChangeTransform. + */ + public boolean getReparent() { + return mReparent; + } + + /** + * Sets whether parent changes will be tracked by the ChangeTransform. If parent + * changes are tracked, then the transform will adjust to the transforms of the + * different parents. If they aren't tracked, only the transforms of the transitioning + * view will be tracked. Default is true. + * + * @param reparent Set to true to track parent changes or false to only track changes + * of the transitioning view without considering the parent change. + */ + public void setReparent(boolean reparent) { + mReparent = reparent; } @Override @@ -89,19 +151,29 @@ public class ChangeTransform extends Transition { return sTransitionProperties; } - private void captureValues(TransitionValues values) { - View view = values.view; + private void captureValues(TransitionValues transitionValues) { + View view = transitionValues.view; if (view.getVisibility() == View.GONE) { return; } - - values.values.put(PROPNAME_SCALE_X, view.getScaleX()); - values.values.put(PROPNAME_SCALE_Y, view.getScaleY()); - values.values.put(PROPNAME_PIVOT_X, view.getPivotX()); - values.values.put(PROPNAME_PIVOT_Y, view.getPivotY()); - values.values.put(PROPNAME_ROTATION_X, view.getRotationX()); - values.values.put(PROPNAME_ROTATION_Y, view.getRotationY()); - values.values.put(PROPNAME_ROTATION_Z, view.getRotation()); + transitionValues.values.put(PROPNAME_PARENT, view.getParent()); + Transforms transforms = new Transforms(view); + transitionValues.values.put(PROPNAME_TRANSFORMS, transforms); + Matrix matrix = view.getMatrix(); + if (matrix == null || matrix.isIdentity()) { + matrix = null; + } else { + matrix = new Matrix(matrix); + } + transitionValues.values.put(PROPNAME_MATRIX, matrix); + if (mReparent) { + Matrix parentMatrix = new Matrix(); + ViewGroup parent = (ViewGroup) view.getParent(); + parent.transformMatrixToGlobal(parentMatrix); + parentMatrix.preTranslate(-parent.getScrollX(), -parent.getScrollY()); + transitionValues.values.put(PROPNAME_PARENT_MATRIX, parentMatrix); + } + return; } @Override @@ -115,57 +187,252 @@ public class ChangeTransform extends Transition { } @Override - public Animator createAnimator(final ViewGroup sceneRoot, TransitionValues startValues, + public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, + TransitionValues endValues) { + if (startValues == null || endValues == null || + !startValues.values.containsKey(PROPNAME_PARENT) || + !endValues.values.containsKey(PROPNAME_PARENT)) { + return null; + } + + ViewGroup startParent = (ViewGroup) startValues.values.get(PROPNAME_PARENT); + ViewGroup endParent = (ViewGroup) endValues.values.get(PROPNAME_PARENT); + boolean handleParentChange = mReparent && !parentsMatch(startParent, endParent); + + Matrix startMatrix = (Matrix) startValues.view.getTag(R.id.transitionTransform); + if (startMatrix != null) { + startValues.values.put(PROPNAME_MATRIX, startMatrix); + } + + Matrix startParentMatrix = (Matrix) startValues.view.getTag(R.id.parentMatrix); + if (startParentMatrix != null) { + startValues.values.put(PROPNAME_PARENT_MATRIX, startParentMatrix); + } + + // First handle the parent change: + if (handleParentChange) { + setMatricesForParent(startValues, endValues); + } + + // Next handle the normal matrix transform: + ObjectAnimator transformAnimator = createTransformAnimator(startValues, endValues); + + if (handleParentChange && transformAnimator != null && mUseOverlay) { + createGhostView(sceneRoot, startValues, endValues); + } + + return transformAnimator; + } + + private ObjectAnimator createTransformAnimator(TransitionValues startValues, TransitionValues endValues) { - if (startValues == null || endValues == null - || !startValues.values.containsKey(PROPNAME_SCALE_X) - || !endValues.values.containsKey(PROPNAME_SCALE_X) - || !isPivotSame(startValues, endValues) - || !isChanged(startValues, endValues)) { + Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_MATRIX); + Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_MATRIX); + + if (startMatrix == null) { + startMatrix = Matrix.IDENTITY_MATRIX; + } + + if (endMatrix == null) { + endMatrix = Matrix.IDENTITY_MATRIX; + } + + if (startMatrix.equals(endMatrix)) { return null; } - float[] start = createValues(startValues); - float[] end = createValues(endValues); - for (int i = 0; i < start.length; i++) { - if (start[i] == end[i]) { - start[i] = Float.NaN; - end[i] = Float.NaN; - } else { - sChangedProperties[i].setValue(endValues.view, start[i]); + final Transforms transforms = (Transforms) endValues.values.get(PROPNAME_TRANSFORMS); + + // clear the transform properties so that we can use the animation matrix instead + final View view = endValues.view; + setIdentityTransforms(view); + + ObjectAnimator animator = ObjectAnimator.ofObject(view, ANIMATION_MATRIX_PROPERTY, + new TransitionUtils.MatrixEvaluator(), startMatrix, endMatrix); + + AnimatorListenerAdapter listener = new AnimatorListenerAdapter() { + private boolean mIsCanceled; + private Matrix mTempMatrix; + + @Override + public void onAnimationCancel(Animator animation) { + mIsCanceled = true; + } + + @Override + public void onAnimationEnd(Animator animation) { + if (!mIsCanceled) { + view.setTagInternal(R.id.transitionTransform, null); + view.setTagInternal(R.id.parentMatrix, null); + } + ANIMATION_MATRIX_PROPERTY.set(view, null); + transforms.restore(view); + } + + @Override + public void onAnimationPause(Animator animation) { + ValueAnimator animator = (ValueAnimator) animation; + Matrix currentMatrix = (Matrix) animator.getAnimatedValue(); + if (mTempMatrix == null) { + mTempMatrix = new Matrix(currentMatrix); + } else { + mTempMatrix.set(currentMatrix); + } + view.setTagInternal(R.id.transitionTransform, mTempMatrix); + transforms.restore(view); + } + + @Override + public void onAnimationResume(Animator animation) { + setIdentityTransforms(view); + } + }; + + animator.addListener(listener); + animator.addPauseListener(listener); + return animator; + } + + private boolean parentsMatch(ViewGroup startParent, ViewGroup endParent) { + boolean parentsMatch = false; + if (!isValidTarget(startParent) || !isValidTarget(endParent)) { + parentsMatch = startParent == endParent; + } else { + TransitionValues endValues = getMatchedTransitionValues(startParent, true); + if (endValues != null) { + parentsMatch = endParent == endValues.view; } } - FloatArrayEvaluator evaluator = new FloatArrayEvaluator(new float[start.length]); - return ObjectAnimator.ofObject(endValues.view, TRANSFORMS, evaluator, start, end); + return parentsMatch; } - private static float[] createValues(TransitionValues transitionValues) { - float[] values = new float[sChangedProperties.length]; - for (int i = 0; i < values.length; i++) { - values[i] = (Float) transitionValues.values.get(sTransitionProperties[i]); + private void createGhostView(final ViewGroup sceneRoot, TransitionValues startValues, + TransitionValues endValues) { + View view = endValues.view; + + Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_PARENT_MATRIX); + Matrix localEndMatrix = new Matrix(endMatrix); + sceneRoot.transformMatrixToLocal(localEndMatrix); + + GhostView ghostView = GhostView.addGhost(view, sceneRoot, localEndMatrix); + + Transition outerTransition = this; + while (outerTransition.mParent != null) { + outerTransition = outerTransition.mParent; } - return values; + GhostListener listener = new GhostListener(view, ghostView, endMatrix); + outerTransition.addListener(listener); + + if (startValues.view != endValues.view) { + startValues.view.setTransitionAlpha(0); + } + view.setTransitionAlpha(1); } - private static boolean isPivotSame(TransitionValues startValues, TransitionValues endValues) { - float startPivotX = (Float) startValues.values.get(PROPNAME_PIVOT_X); - float startPivotY = (Float) startValues.values.get(PROPNAME_PIVOT_Y); - float endPivotX = (Float) endValues.values.get(PROPNAME_PIVOT_X); - float endPivotY = (Float) endValues.values.get(PROPNAME_PIVOT_Y); + private void setMatricesForParent(TransitionValues startValues, TransitionValues endValues) { + Matrix endParentMatrix = (Matrix) endValues.values.get(PROPNAME_PARENT_MATRIX); + endValues.view.setTagInternal(R.id.parentMatrix, endParentMatrix); + + Matrix toLocal = mTempMatrix; + toLocal.reset(); + endParentMatrix.invert(toLocal); - // We don't support pivot changes, because they could be automatically set - // and we can't end the state in an automatic state. - return startPivotX == endPivotX && startPivotY == endPivotY; + Matrix startLocal = (Matrix) startValues.values.get(PROPNAME_MATRIX); + if (startLocal == null) { + startLocal = new Matrix(); + startValues.values.put(PROPNAME_MATRIX, startLocal); + } + + Matrix startParentMatrix = (Matrix) startValues.values.get(PROPNAME_PARENT_MATRIX); + startLocal.postConcat(startParentMatrix); + startLocal.postConcat(toLocal); } - private static boolean isChanged(TransitionValues startValues, TransitionValues endValues) { - for (int i = 0; i < sChangedProperties.length; i++) { - Object start = startValues.values.get(sTransitionProperties[i]); - Object end = endValues.values.get(sTransitionProperties[i]); - if (!start.equals(end)) { - return true; + private static void setIdentityTransforms(View view) { + setTransforms(view, 0, 0, 0, 1, 1, 0, 0, 0); + } + + private static void setTransforms(View view, float translationX, float translationY, + float translationZ, float scaleX, float scaleY, float rotationX, + float rotationY, float rotationZ) { + view.setTranslationX(translationX); + view.setTranslationY(translationY); + view.setTranslationZ(translationZ); + view.setScaleX(scaleX); + view.setScaleY(scaleY); + view.setRotationX(rotationX); + view.setRotationY(rotationY); + view.setRotation(rotationZ); + } + + private static class Transforms { + public final float translationX; + public final float translationY; + public final float translationZ; + public final float scaleX; + public final float scaleY; + public final float rotationX; + public final float rotationY; + public final float rotationZ; + + public Transforms(View view) { + translationX = view.getTranslationX(); + translationY = view.getTranslationY(); + translationZ = view.getTranslationZ(); + scaleX = view.getScaleX(); + scaleY = view.getScaleY(); + rotationX = view.getRotationX(); + rotationY = view.getRotationY(); + rotationZ = view.getRotation(); + } + + public void restore(View view) { + setTransforms(view, translationX, translationY, translationZ, scaleX, scaleY, + rotationX, rotationY, rotationZ); + } + + @Override + public boolean equals(Object that) { + if (!(that instanceof Transforms)) { + return false; } + Transforms thatTransform = (Transforms) that; + return thatTransform.translationX == translationX && + thatTransform.translationY == translationY && + thatTransform.translationZ == translationZ && + thatTransform.scaleX == scaleX && + thatTransform.scaleY == scaleY && + thatTransform.rotationX == rotationX && + thatTransform.rotationY == rotationY && + thatTransform.rotationZ == rotationZ; + } + } + + private static class GhostListener extends Transition.TransitionListenerAdapter { + private View mView; + private GhostView mGhostView; + private Matrix mEndMatrix; + + public GhostListener(View view, GhostView ghostView, Matrix endMatrix) { + mView = view; + mGhostView = ghostView; + mEndMatrix = endMatrix; + } + + @Override + public void onTransitionEnd(Transition transition) { + transition.removeListener(this); + GhostView.removeGhost(mView); + } + + @Override + public void onTransitionPause(Transition transition) { + mGhostView.setVisibility(View.INVISIBLE); + } + + @Override + public void onTransitionResume(Transition transition) { + mGhostView.setVisibility(View.VISIBLE); } - return false; } } diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java index 0d32d4038e29..59ba71fa8208 100644 --- a/core/java/android/transition/Transition.java +++ b/core/java/android/transition/Transition.java @@ -112,8 +112,8 @@ import com.android.internal.R; * * Further information on XML resource descriptions for transitions can be found for * {@link android.R.styleable#Transition}, {@link android.R.styleable#TransitionSet}, - * {@link android.R.styleable#TransitionTarget}, {@link android.R.styleable#Fade}, and - * {@link android.R.styleable#Slide}. + * {@link android.R.styleable#TransitionTarget}, {@link android.R.styleable#Fade}, + * {@link android.R.styleable#Slide}, and {@link android.R.styleable#ChangeTransform}. * */ public abstract class Transition implements Cloneable { @@ -1755,24 +1755,40 @@ public abstract class Transition implements Cloneable { // if oldValues null, then transition didn't care to stash values, // and won't get canceled if (oldValues != null && newValues != null) { - for (String key : oldValues.values.keySet()) { - Object oldValue = oldValues.values.get(key); - Object newValue = newValues.values.get(key); - if (oldValue != null && newValue != null && - !oldValue.equals(newValue)) { - valuesChanged = true; - if (DBG) { - Log.d(LOG_TAG, "Transition.playTransition: " + - "oldValue != newValue for " + key + - ": old, new = " + oldValue + ", " + newValue); + String[] properties = getTransitionProperties(); + if (properties != null) { + int count = properties.length; + for (int i = 0; i < count; i++) { + if (isValueChanged(oldValues, newValues, properties[i])) { + valuesChanged = true; + break; + } + } + } else { + for (String key : oldValues.values.keySet()) { + if (isValueChanged(oldValues, newValues, key)) { + valuesChanged = true; + break; } - break; } } } return valuesChanged; } + private static boolean isValueChanged(TransitionValues oldValues, TransitionValues newValues, + String key) { + Object oldValue = oldValues.values.get(key); + Object newValue = newValues.values.get(key); + boolean changed = (oldValue != null && newValue != null && !oldValue.equals(newValue)); + if (DBG && changed) { + Log.d(LOG_TAG, "Transition.playTransition: " + + "oldValue != newValue for " + key + + ": old, new = " + oldValue + ", " + newValue); + } + return changed; + } + /** * This is a utility method used by subclasses to handle standard parts of * setting up and running an Animator: it sets the {@link #getDuration() diff --git a/core/java/android/transition/TransitionUtils.java b/core/java/android/transition/TransitionUtils.java index 931d46a53187..b0c9e9adec22 100644 --- a/core/java/android/transition/TransitionUtils.java +++ b/core/java/android/transition/TransitionUtils.java @@ -18,6 +18,8 @@ package android.transition; import android.animation.Animator; import android.animation.AnimatorSet; +import android.animation.TypeEvaluator; +import android.graphics.Matrix; /** * Static utility methods for Transitions. @@ -37,4 +39,25 @@ public class TransitionUtils { return animatorSet; } } + + public static class MatrixEvaluator implements TypeEvaluator<Matrix> { + + float[] mTempStartValues = new float[9]; + + float[] mTempEndValues = new float[9]; + + Matrix mTempMatrix = new Matrix(); + + @Override + public Matrix evaluate(float fraction, Matrix startValue, Matrix endValue) { + startValue.getValues(mTempStartValues); + endValue.getValues(mTempEndValues); + for (int i = 0; i < 9; i++) { + float diff = mTempEndValues[i] - mTempStartValues[i]; + mTempEndValues[i] = mTempStartValues[i] + (fraction * diff); + } + mTempMatrix.setValues(mTempEndValues); + return mTempMatrix; + } + } } diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java index 79dbb49f5245..81c69d18e82d 100644 --- a/core/java/android/transition/Visibility.java +++ b/core/java/android/transition/Visibility.java @@ -63,8 +63,6 @@ public abstract class Visibility extends Transition { private static final String[] sTransitionProperties = { PROPNAME_VISIBILITY, - PROPNAME_PARENT, - PROPNAME_SCREEN_LOCATION, }; private static class VisibilityInfo { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 243d7d797062..64d008347e1e 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -10793,6 +10793,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } + /** @hide */ + public void setAnimationMatrix(Matrix matrix) { + invalidateViewProperty(true, false); + mRenderNode.setAnimationMatrix(matrix); + invalidateViewProperty(false, true); + + invalidateParentIfNeededAndWasQuickRejected(); + } + /** * Returns the current StateListAnimator if exists. * diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 27b770141da9..23edc48b34d8 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -5597,6 +5597,19 @@ </attr> </declare-styleable> + <!-- Use <code>changeTransform</code> as the root tag of the XML resource that + describes a {@link android.transition.ChangeTransform} transition. --> + <declare-styleable name="ChangeTransform"> + <!-- A parent change should use an overlay or affect the transform of the + transitionining View. Default is true. Corresponds to + {@link android.transition.ChangeTransform#setReparentWithOverlay(boolean)}. --> + <attr name="reparentWithOverlay" format="boolean"/> + + <!-- Tells ChangeTransform to track parent changes. Default is true. Corresponds to + {@link android.transition.ChangeTransform#setReparent(boolean)}. --> + <attr name="reparent" format="boolean"/> + </declare-styleable> + <!-- Use <code>transitionManager</code> as the root tag of the XML resource that describes a {@link android.transition.TransitionManager TransitionManager}. --> diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index c64e910e955d..4c59f73ff53e 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -85,4 +85,6 @@ <item type="id" name="scene_layoutid_cache" /> <item type="id" name="mask" /> <item type="id" name="transitionPosition" /> + <item type="id" name="transitionTransform" /> + <item type="id" name="parentMatrix" /> </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index b3b5ca955136..f2466f78c326 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2276,6 +2276,8 @@ <public type="attr" name="ageHint" /> <public type="attr" name="country" /> <public type="attr" name="windowSharedElementsUseOverlay" /> + <public type="attr" name="reparent" /> + <public type="attr" name="reparentWithOverlay" /> <public-padding type="dimen" name="l_resource_pad" end="0x01050010" /> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 9b3c05efe373..9e18a46d0f8c 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1986,4 +1986,6 @@ <java-symbol type="color" name="battery_saver_mode_color" /> <java-symbol type="color" name="system_notification_accent_color" /> <java-symbol type="dimen" name="text_handle_min_size" /> + <java-symbol type="id" name="transitionTransform" /> + <java-symbol type="id" name="parentMatrix" /> </resources> |