From af78bdd615ecd5ce9d41a6160ce9f53fa269b119 Mon Sep 17 00:00:00 2001 From: Chet Haase Date: Tue, 27 Aug 2013 16:06:26 -0700 Subject: [PATCH] Better transition interruption and TextChange fixes Previously, the TextChange transition didn't handle interruption/ cancellation at all, which made it problematic to use in any real situation where a transition might get interrupted mid-animation. Also, the way that it side-effected the text of TextView objects caused errors in the UI when the transition was interrupted, because it would not clean up after itself properly as new transitions queried the current state of the UI. Also, the prior cancellation logic for all transitions was not quite correct; we were pausing transitions but resuming the animations, making it tricky to write transitions that would restore state correctly. Change-Id: I5a9f3c915e9834ec59ce1e1c3c96a88d11e4aa1b --- core/java/android/view/transition/Move.java | 2 +- .../android/view/transition/TextChange.java | 35 +++++++++++++++++-- .../android/view/transition/Transition.java | 32 +++++++++-------- .../view/transition/TransitionManager.java | 8 +++++ .../android/view/transition/Visibility.java | 2 +- 5 files changed, 59 insertions(+), 20 deletions(-) diff --git a/core/java/android/view/transition/Move.java b/core/java/android/view/transition/Move.java index ae7d75938c1d1..fda0cd248f9cd 100644 --- a/core/java/android/view/transition/Move.java +++ b/core/java/android/view/transition/Move.java @@ -40,7 +40,7 @@ public class Move extends Transition { private static final String PROPNAME_PARENT = "android:move:parent"; private static final String PROPNAME_WINDOW_X = "android:move:windowX"; private static final String PROPNAME_WINDOW_Y = "android:move:windowY"; - private static String[] sTransitionProperties = { + private static final String[] sTransitionProperties = { PROPNAME_BOUNDS, PROPNAME_PARENT, PROPNAME_WINDOW_X, diff --git a/core/java/android/view/transition/TextChange.java b/core/java/android/view/transition/TextChange.java index 04ff707003403..7973c97eda259 100644 --- a/core/java/android/view/transition/TextChange.java +++ b/core/java/android/view/transition/TextChange.java @@ -78,6 +78,10 @@ public class TextChange extends Transition { */ public static final int CHANGE_BEHAVIOR_OUT_IN = 3; + private static final String[] sTransitionProperties = { + PROPNAME_TEXT + }; + /** * Sets the type of changing animation that will be run, one of * {@link #CHANGE_BEHAVIOR_KEEP} and {@link #CHANGE_BEHAVIOR_OUT_IN}. @@ -91,6 +95,11 @@ public class TextChange extends Transition { } } + @Override + public String[] getTransitionProperties() { + return sTransitionProperties; + } + @Override protected void captureValues(TransitionValues values, boolean start) { if (values.view instanceof TextView) { @@ -111,7 +120,7 @@ public class TextChange extends Transition { final TextView view = (TextView) endValues.view; Map startVals = startValues.values; Map endVals = endValues.values; - String startText = (String) startVals.get(PROPNAME_TEXT); + final String startText = (String) startVals.get(PROPNAME_TEXT); final String endText = (String) endVals.get(PROPNAME_TEXT); if (!startText.equals(endText)) { view.setText(startText); @@ -121,7 +130,10 @@ public class TextChange extends Transition { anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - view.setText(endText); + if (startText.equals(view.getText())) { + // Only set if it hasn't been changed since anim started + view.setText(endText); + } } }); } else { @@ -143,7 +155,10 @@ public class TextChange extends Transition { outAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - view.setText(endText); + if (startText.equals(view.getText())) { + // Only set if it hasn't been changed since anim started + view.setText(endText); + } } }); } @@ -169,6 +184,20 @@ public class TextChange extends Transition { anim = inAnim; } } + TransitionListener transitionListener = new TransitionListenerAdapter() { + boolean mCanceled = false; + + @Override + public void onTransitionPause(Transition transition) { + view.setText(endText); + } + + @Override + public void onTransitionResume(Transition transition) { + view.setText(startText); + } + }; + addListener(transitionListener); return anim; } return null; diff --git a/core/java/android/view/transition/Transition.java b/core/java/android/view/transition/Transition.java index 0444843ef2221..a66fa52cd33ec 100644 --- a/core/java/android/view/transition/Transition.java +++ b/core/java/android/view/transition/Transition.java @@ -843,7 +843,6 @@ public abstract class Transition implements Cloneable { for (int i = numOldAnims - 1; i >= 0; i--) { Animator anim = runningAnimators.keyAt(i); if (anim != null) { - anim.resume(); AnimationInfo oldInfo = runningAnimators.get(anim); if (oldInfo != null) { boolean cancel = false; @@ -851,22 +850,25 @@ public abstract class Transition implements Cloneable { View oldView = oldInfo.view; TransitionValues newValues = mEndValues.viewValues != null ? mEndValues.viewValues.get(oldView) : null; - if (oldValues == null || newValues == null) { - if (oldValues != null || newValues != null) { + if (oldValues != null) { + // if oldValues null, then transition didn't care to stash values, + // and won't get canceled + if (newValues == null) { cancel = true; - } - } else { - for (String key : oldValues.values.keySet()) { - Object oldValue = oldValues.values.get(key); - Object newValue = newValues.values.get(key); - if ((oldValue == null && newValue != null) || - (oldValue != null && !oldValue.equals(newValue))) { - cancel = true; - if (DBG) { - Log.d(LOG_TAG, "Transition.play: oldValue != newValue for " + - key + ": old, new = " + oldValue + ", " + newValue); + } else { + 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)) { + cancel = true; + if (DBG) { + Log.d(LOG_TAG, "Transition.playTransition: " + + "oldValue != newValue for " + key + + ": old, new = " + oldValue + ", " + newValue); + } + break; } - break; } } } diff --git a/core/java/android/view/transition/TransitionManager.java b/core/java/android/view/transition/TransitionManager.java index 3cb6f68177831..bde891dc5489f 100644 --- a/core/java/android/view/transition/TransitionManager.java +++ b/core/java/android/view/transition/TransitionManager.java @@ -183,9 +183,12 @@ public class TransitionManager { final ArrayMap> runningTransitions = getRunningTransitions(); ArrayList currentTransitions = runningTransitions.get(sceneRoot); + ArrayList previousRunningTransitions = null; if (currentTransitions == null) { currentTransitions = new ArrayList(); runningTransitions.put(sceneRoot, currentTransitions); + } else if (currentTransitions.size() > 0) { + previousRunningTransitions = new ArrayList(currentTransitions); } currentTransitions.add(transition); transition.addListener(new Transition.TransitionListenerAdapter() { @@ -197,6 +200,11 @@ public class TransitionManager { } }); transition.captureValues(sceneRoot, false); + if (previousRunningTransitions != null) { + for (Transition runningTransition : previousRunningTransitions) { + runningTransition.resume(); + } + } transition.playTransition(sceneRoot); // Returning false from onPreDraw() skips the current frame. This is diff --git a/core/java/android/view/transition/Visibility.java b/core/java/android/view/transition/Visibility.java index 4df53daf5e81f..348dcfb163019 100644 --- a/core/java/android/view/transition/Visibility.java +++ b/core/java/android/view/transition/Visibility.java @@ -53,7 +53,7 @@ public abstract class Visibility extends Transition { private static final String PROPNAME_VISIBILITY = "android:visibility:visibility"; private static final String PROPNAME_PARENT = "android:visibility:parent"; - private static String[] sTransitionProperties = { + private static final String[] sTransitionProperties = { PROPNAME_VISIBILITY, PROPNAME_PARENT, };