From fbd459642fe732115f135e456eafdec2dc8e9bb6 Mon Sep 17 00:00:00 2001 From: George Mount Date: Mon, 26 Jan 2015 14:38:19 -0800 Subject: [PATCH] Activity Transition: fix quick back after enter. Bug 19105460 When an Activity Transition was receiving an exit call immediately after the enter, the transition for the enter was still in progress. TransitionManager does not allow multiple transitions to work at once, so the enter transition would run, but the exit did not. This CL detects when the enter transition is still pending and tells the ActivityTransitionState to delay one frame so that the enter can finish its required work prior to starting the exit transition. Change-Id: I1b40f1e41d61a67da3fd672419ea321e7d0496da --- .../app/ActivityTransitionCoordinator.java | 9 +++++++ .../android/app/ActivityTransitionState.java | 24 ++++++++++++++++--- .../app/EnterTransitionCoordinator.java | 9 +++++-- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java index d0d9d7153eaf4..e3b27b51f69a8 100644 --- a/core/java/android/app/ActivityTransitionCoordinator.java +++ b/core/java/android/app/ActivityTransitionCoordinator.java @@ -799,6 +799,15 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { mIsStartingTransition = false; } + /** + * Cancels any pending transitions and returns true if there is a transition is in + * the middle of starting. + */ + protected boolean cancelPendingTransitions() { + mPendingTransition = null; + return mIsStartingTransition; + } + protected void moveSharedElementsToOverlay() { if (mWindow == null || !mWindow.getSharedElementsUseOverlay()) { return; diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java index 555d20bba99a3..a2bfa4e4fba99 100644 --- a/core/java/android/app/ActivityTransitionState.java +++ b/core/java/android/app/ActivityTransitionState.java @@ -22,6 +22,7 @@ import android.util.ArrayMap; import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; +import android.view.ViewTreeObserver; import android.view.Window; import java.lang.ref.WeakReference; @@ -252,7 +253,7 @@ class ActivityTransitionState { } } - public boolean startExitBackTransition(Activity activity) { + public boolean startExitBackTransition(final Activity activity) { if (mEnteringNames == null) { return false; } else { @@ -260,10 +261,11 @@ class ActivityTransitionState { mHasExited = true; Transition enterViewsTransition = null; ViewGroup decor = null; + boolean delayExitBack = false; if (mEnterTransitionCoordinator != null) { enterViewsTransition = mEnterTransitionCoordinator.getEnterViewsTransition(); decor = mEnterTransitionCoordinator.getDecor(); - mEnterTransitionCoordinator.cancelEnter(); + delayExitBack = mEnterTransitionCoordinator.cancelEnter(); mEnterTransitionCoordinator = null; if (enterViewsTransition != null && decor != null) { enterViewsTransition.pause(decor); @@ -275,7 +277,23 @@ class ActivityTransitionState { if (enterViewsTransition != null && decor != null) { enterViewsTransition.resume(decor); } - mReturnExitCoordinator.startExit(activity.mResultCode, activity.mResultData); + if (delayExitBack && decor != null) { + final ViewGroup finalDecor = decor; + decor.getViewTreeObserver().addOnPreDrawListener( + new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + finalDecor.getViewTreeObserver().removeOnPreDrawListener(this); + if (mReturnExitCoordinator != null) { + mReturnExitCoordinator.startExit(activity.mResultCode, + activity.mResultData); + } + return true; + } + }); + } else { + mReturnExitCoordinator.startExit(activity.mResultCode, activity.mResultData); + } } return true; } diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java index ecf19c783e839..c053c830adfc7 100644 --- a/core/java/android/app/EnterTransitionCoordinator.java +++ b/core/java/android/app/EnterTransitionCoordinator.java @@ -18,7 +18,6 @@ package android.app; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; -import android.graphics.Matrix; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.ResultReceiver; @@ -565,7 +564,12 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { clearState(); } - public void cancelEnter() { + /** + * Cancels the enter transition. + * @return True if the enter transition is still pending capturing the target state. If so, + * any transition started on the decor will do nothing. + */ + public boolean cancelEnter() { setGhostVisibility(View.INVISIBLE); mHasStopped = true; mIsCanceled = true; @@ -576,6 +580,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { } mActivity = null; clearState(); + return super.cancelPendingTransitions(); } private void makeOpaque() {