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
This commit is contained in:
George Mount
2015-01-26 14:38:19 -08:00
parent d57adbbc4f
commit fbd459642f
3 changed files with 37 additions and 5 deletions

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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() {