Loading core/java/android/app/Activity.java +1 −1 Original line number Diff line number Diff line Loading @@ -2590,7 +2590,7 @@ public class Activity extends ContextThemeWrapper protected void onStop() { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this); if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false); mActivityTransitionState.onStop(); mActivityTransitionState.onStop(this); dispatchActivityStopped(); mTranslucentCallback = null; mCalled = true; Loading core/java/android/app/ActivityOptions.java +26 −92 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.TestApi; import android.app.ExitTransitionCoordinator.ActivityExitTransitionCallbacks; import android.app.ExitTransitionCoordinator.ExitTransitionCallbacks; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; Loading @@ -44,8 +46,6 @@ import android.os.Parcelable; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.UserHandle; import android.transition.Transition; import android.transition.TransitionListenerAdapter; import android.transition.TransitionManager; import android.util.Pair; import android.util.Slog; Loading Loading @@ -806,8 +806,11 @@ public class ActivityOptions { public static ActivityOptions makeSceneTransitionAnimation(Activity activity, Pair<View, String>... sharedElements) { ActivityOptions opts = new ActivityOptions(); makeSceneTransitionAnimation(activity, activity.getWindow(), opts, activity.mExitTransitionListener, sharedElements); ExitTransitionCoordinator exit = makeSceneTransitionAnimation( new ActivityExitTransitionCallbacks(activity), activity.mExitTransitionListener, activity.getWindow(), opts, sharedElements); opts.mExitCoordinatorIndex = activity.mActivityTransitionState.addExitTransitionCoordinator(exit); return opts; } Loading @@ -823,25 +826,19 @@ public class ActivityOptions { * @hide */ @SafeVarargs public static ActivityOptions startSharedElementAnimation(Window window, public static Pair<ActivityOptions, ExitTransitionCoordinator> startSharedElementAnimation( Window window, ExitTransitionCallbacks exitCallbacks, SharedElementCallback callback, Pair<View, String>... sharedElements) { ActivityOptions opts = new ActivityOptions(); final View decorView = window.getDecorView(); if (decorView == null) { return opts; } final ExitTransitionCoordinator exit = makeSceneTransitionAnimation(null, window, opts, null, sharedElements); if (exit != null) { HideWindowListener listener = new HideWindowListener(window, exit); exit.setHideSharedElementsCallback(listener); exit.startExit(); } return opts; ExitTransitionCoordinator exit = makeSceneTransitionAnimation( exitCallbacks, callback, window, opts, sharedElements); opts.mExitCoordinatorIndex = -1; return Pair.create(opts, exit); } /** * This method should be called when the {@link #startSharedElementAnimation(Window, Pair[])} * This method should be called when the * {@link #startSharedElementAnimation(Window, ExitTransitionCallbacks, Pair[])} * animation must be stopped and the Views reset. This can happen if there was an error * from startActivity or a springboard activity and the animation should stop and reset. * Loading @@ -864,9 +861,9 @@ public class ActivityOptions { } } static ExitTransitionCoordinator makeSceneTransitionAnimation(Activity activity, Window window, ActivityOptions opts, SharedElementCallback callback, Pair<View, String>[] sharedElements) { static ExitTransitionCoordinator makeSceneTransitionAnimation( ExitTransitionCallbacks exitCallbacks, SharedElementCallback callback, Window window, ActivityOptions opts, Pair<View, String>[] sharedElements) { if (!window.hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)) { opts.mAnimationType = ANIM_DEFAULT; return null; Loading @@ -892,17 +889,11 @@ public class ActivityOptions { } } ExitTransitionCoordinator exit = new ExitTransitionCoordinator(activity, window, ExitTransitionCoordinator exit = new ExitTransitionCoordinator(exitCallbacks, window, callback, names, names, views, false); opts.mTransitionReceiver = exit; opts.mSharedElementNames = names; opts.mIsReturning = (activity == null); if (activity == null) { opts.mExitCoordinatorIndex = -1; } else { opts.mExitCoordinatorIndex = activity.mActivityTransitionState.addExitTransitionCoordinator(exit); } opts.mIsReturning = false; return exit; } Loading @@ -928,8 +919,12 @@ public class ActivityOptions { opts.mIsReturning = true; opts.mResultCode = resultCode; opts.mResultData = resultData; if (activity == null) { opts.mExitCoordinatorIndex = -1; } else { opts.mExitCoordinatorIndex = activity.mActivityTransitionState.addExitTransitionCoordinator(exitCoordinator); } return opts; } Loading Loading @@ -1868,67 +1863,6 @@ public class ActivityOptions { + mStartY + ", mWidth=" + mWidth + ", mHeight=" + mHeight; } private static class HideWindowListener extends TransitionListenerAdapter implements ExitTransitionCoordinator.HideSharedElementsCallback { private final Window mWindow; private final ExitTransitionCoordinator mExit; private final boolean mWaitingForTransition; private boolean mTransitionEnded; private boolean mSharedElementHidden; private ArrayList<View> mSharedElements; public HideWindowListener(Window window, ExitTransitionCoordinator exit) { mWindow = window; mExit = exit; mSharedElements = new ArrayList<>(exit.mSharedElements); Transition transition = mWindow.getExitTransition(); if (transition != null) { transition.addListener(this); mWaitingForTransition = true; } else { mWaitingForTransition = false; } View decorView = mWindow.getDecorView(); if (decorView != null) { if (decorView.getTag(com.android.internal.R.id.cross_task_transition) != null) { throw new IllegalStateException( "Cannot start a transition while one is running"); } decorView.setTagInternal(com.android.internal.R.id.cross_task_transition, exit); } } @Override public void onTransitionEnd(Transition transition) { mTransitionEnded = true; hideWhenDone(); transition.removeListener(this); } @Override public void hideSharedElements() { mSharedElementHidden = true; hideWhenDone(); } private void hideWhenDone() { if (mSharedElementHidden && (!mWaitingForTransition || mTransitionEnded)) { mExit.resetViews(); int numSharedElements = mSharedElements.size(); for (int i = 0; i < numSharedElements; i++) { View view = mSharedElements.get(i); view.requestLayout(); } View decorView = mWindow.getDecorView(); if (decorView != null) { decorView.setTagInternal( com.android.internal.R.id.cross_task_transition, null); decorView.setVisibility(View.GONE); } } } } /** * The information about the source of activity launch. E.g. describe an activity is launched * from launcher by receiving a motion event with a timestamp. Loading core/java/android/app/ActivityTransitionState.java +6 −6 Original line number Diff line number Diff line Loading @@ -247,14 +247,14 @@ class ActivityTransitionState { mEnterActivityOptions = null; } public void onStop() { public void onStop(Activity activity) { restoreExitedViews(); if (mEnterTransitionCoordinator != null) { mEnterTransitionCoordinator.stop(); mEnterTransitionCoordinator = null; } if (mReturnExitCoordinator != null) { mReturnExitCoordinator.stop(); mReturnExitCoordinator.stop(activity); mReturnExitCoordinator = null; } } Loading Loading @@ -331,7 +331,8 @@ class ActivityTransitionState { } } mReturnExitCoordinator = new ExitTransitionCoordinator(activity, mReturnExitCoordinator = new ExitTransitionCoordinator( new ExitTransitionCoordinator.ActivityExitTransitionCallbacks(activity), activity.getWindow(), activity.mEnterTransitionListener, pendingExitNames, null, null, true); if (enterViewsTransition != null && decor != null) { Loading @@ -341,12 +342,11 @@ class ActivityTransitionState { final ViewGroup finalDecor = decor; OneShotPreDrawListener.add(decor, () -> { if (mReturnExitCoordinator != null) { mReturnExitCoordinator.startExit(activity.mResultCode, activity.mResultData); mReturnExitCoordinator.startExit(activity); } }); } else { mReturnExitCoordinator.startExit(activity.mResultCode, activity.mResultData); mReturnExitCoordinator.startExit(activity); } } return true; Loading core/java/android/app/ExitTransitionCoordinator.java +77 −45 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.app; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.annotation.NonNull; import android.app.SharedElementCallback.OnSharedElementsReadyListener; import android.content.Intent; import android.graphics.Color; Loading Loading @@ -45,15 +46,17 @@ import java.util.ArrayList; * This ActivityTransitionCoordinator is created in ActivityOptions#makeSceneTransitionAnimation * to govern the exit of the Scene and the shared elements when calling an Activity as well as * the reentry of the Scene when coming back from the called Activity. * * @hide */ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { public class ExitTransitionCoordinator extends ActivityTransitionCoordinator { private static final String TAG = "ExitTransitionCoordinator"; static long sMaxWaitMillis = 1000; private Bundle mSharedElementBundle; private boolean mExitNotified; private boolean mSharedElementNotified; private Activity mActivity; private ExitTransitionCallbacks mExitCallbacks; private boolean mIsBackgroundReady; private boolean mIsCanceled; private Handler mHandler; Loading @@ -62,20 +65,15 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { private Bundle mExitSharedElementBundle; private boolean mIsExitStarted; private boolean mSharedElementsHidden; private HideSharedElementsCallback mHideSharedElementsCallback; public ExitTransitionCoordinator(Activity activity, Window window, SharedElementCallback listener, ArrayList<String> names, public ExitTransitionCoordinator(ExitTransitionCallbacks exitCallbacks, Window window, SharedElementCallback listener, ArrayList<String> names, ArrayList<String> accepted, ArrayList<View> mapped, boolean isReturning) { super(window, names, listener, isReturning); viewsReady(mapSharedElements(accepted, mapped)); stripOffscreenViews(); mIsBackgroundReady = !isReturning; mActivity = activity; } void setHideSharedElementsCallback(HideSharedElementsCallback callback) { mHideSharedElementsCallback = callback; mExitCallbacks = exitCallbacks; } @Override Loading Loading @@ -190,8 +188,8 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { private void hideSharedElements() { moveSharedElementsFromOverlay(); if (mHideSharedElementsCallback != null) { mHideSharedElementsCallback.hideSharedElements(); if (mExitCallbacks != null) { mExitCallbacks.hideSharedElements(); } if (!mIsHidden) { hideViews(mSharedElements); Loading @@ -210,20 +208,16 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { decorView.suppressLayout(true); } moveSharedElementsToOverlay(); startTransition(new Runnable() { @Override public void run() { if (mActivity != null) { beginTransitions(); } else { startExitTransition(); } } }); startTransition(this::beginTransitions); } } public void startExit(int resultCode, Intent data) { /** * Starts the exit animation and sends back the activity result */ public void startExit(Activity activity) { int resultCode = activity.mResultCode; Intent data = activity.mResultData; if (!mIsExitStarted) { mIsExitStarted = true; pauseInput(); Loading @@ -247,9 +241,9 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { .getApplicationInfo().targetSdkVersion >= VERSION_CODES.M; ArrayList<String> sharedElementNames = targetsM ? mSharedElementNames : mAllSharedElementNames; ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this, ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(activity, this, sharedElementNames, resultCode, data); mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() { activity.convertToTranslucent(new Activity.TranslucentConversionListener() { @Override public void onTranslucentConversionComplete(boolean drawComplete) { if (!mIsCanceled) { Loading @@ -257,21 +251,19 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { } } }, options); startTransition(new Runnable() { @Override public void run() { startExitTransition(); } }); startTransition(this::startExitTransition); } } public void stop() { if (mIsReturning && mActivity != null) { /** * Called from {@link Activity#onStop()} */ public void stop(Activity activity) { if (mIsReturning && mExitCallbacks != null) { // Override the previous ActivityOptions. We don't want the // activity to have options since we're essentially canceling the // transition and finishing right now. mActivity.convertToTranslucent(null, null); activity.convertToTranslucent(null, null); finish(); } } Loading Loading @@ -434,7 +426,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { mSharedElementNotified = true; delayCancel(); if (!mActivity.isTopOfTask()) { if (mExitCallbacks.isReturnTransitionAllowed()) { mResultReceiver.send(MSG_ALLOW_RETURN_TRANSITION, null); } Loading Loading @@ -474,22 +466,20 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { } private void finishIfNecessary() { if (mIsReturning && mExitNotified && mActivity != null && (mSharedElements.isEmpty() || mSharedElementsHidden)) { if (mIsReturning && mExitNotified && mExitCallbacks != null && (mSharedElements.isEmpty() || mSharedElementsHidden)) { finish(); } if (!mIsReturning && mExitNotified) { mActivity = null; // don't need it anymore mExitCallbacks = null; // don't need it anymore } } private void finish() { stopCancel(); if (mActivity != null) { mActivity.mActivityTransitionState.clear(); mActivity.finish(); mActivity.overridePendingTransition(0, 0); mActivity = null; if (mExitCallbacks != null) { mExitCallbacks.onFinish(); mExitCallbacks = null; } // Clear the state so that we can't hold any references accidentally and leak memory. clearState(); Loading Loading @@ -529,7 +519,49 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { } } interface HideSharedElementsCallback { void hideSharedElements(); /** * @hide */ public interface ExitTransitionCallbacks { /** * Returns true if reverse exit animation is supported */ boolean isReturnTransitionAllowed(); /** * Called then the transition finishes */ void onFinish(); /** * Optional callback when the transition is hiding elements in the source surface */ default void hideSharedElements() { }; } /** * @hide */ public static class ActivityExitTransitionCallbacks implements ExitTransitionCallbacks { @NonNull final Activity mActivity; ActivityExitTransitionCallbacks(@NonNull Activity activity) { mActivity = activity; } @Override public boolean isReturnTransitionAllowed() { return !mActivity.isTopOfTask(); } @Override public void onFinish() { mActivity.mActivityTransitionState.clear(); mActivity.finish(); mActivity.overridePendingTransition(0, 0); } } } Loading
core/java/android/app/Activity.java +1 −1 Original line number Diff line number Diff line Loading @@ -2590,7 +2590,7 @@ public class Activity extends ContextThemeWrapper protected void onStop() { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this); if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false); mActivityTransitionState.onStop(); mActivityTransitionState.onStop(this); dispatchActivityStopped(); mTranslucentCallback = null; mCalled = true; Loading
core/java/android/app/ActivityOptions.java +26 −92 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.TestApi; import android.app.ExitTransitionCoordinator.ActivityExitTransitionCallbacks; import android.app.ExitTransitionCoordinator.ExitTransitionCallbacks; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; Loading @@ -44,8 +46,6 @@ import android.os.Parcelable; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.UserHandle; import android.transition.Transition; import android.transition.TransitionListenerAdapter; import android.transition.TransitionManager; import android.util.Pair; import android.util.Slog; Loading Loading @@ -806,8 +806,11 @@ public class ActivityOptions { public static ActivityOptions makeSceneTransitionAnimation(Activity activity, Pair<View, String>... sharedElements) { ActivityOptions opts = new ActivityOptions(); makeSceneTransitionAnimation(activity, activity.getWindow(), opts, activity.mExitTransitionListener, sharedElements); ExitTransitionCoordinator exit = makeSceneTransitionAnimation( new ActivityExitTransitionCallbacks(activity), activity.mExitTransitionListener, activity.getWindow(), opts, sharedElements); opts.mExitCoordinatorIndex = activity.mActivityTransitionState.addExitTransitionCoordinator(exit); return opts; } Loading @@ -823,25 +826,19 @@ public class ActivityOptions { * @hide */ @SafeVarargs public static ActivityOptions startSharedElementAnimation(Window window, public static Pair<ActivityOptions, ExitTransitionCoordinator> startSharedElementAnimation( Window window, ExitTransitionCallbacks exitCallbacks, SharedElementCallback callback, Pair<View, String>... sharedElements) { ActivityOptions opts = new ActivityOptions(); final View decorView = window.getDecorView(); if (decorView == null) { return opts; } final ExitTransitionCoordinator exit = makeSceneTransitionAnimation(null, window, opts, null, sharedElements); if (exit != null) { HideWindowListener listener = new HideWindowListener(window, exit); exit.setHideSharedElementsCallback(listener); exit.startExit(); } return opts; ExitTransitionCoordinator exit = makeSceneTransitionAnimation( exitCallbacks, callback, window, opts, sharedElements); opts.mExitCoordinatorIndex = -1; return Pair.create(opts, exit); } /** * This method should be called when the {@link #startSharedElementAnimation(Window, Pair[])} * This method should be called when the * {@link #startSharedElementAnimation(Window, ExitTransitionCallbacks, Pair[])} * animation must be stopped and the Views reset. This can happen if there was an error * from startActivity or a springboard activity and the animation should stop and reset. * Loading @@ -864,9 +861,9 @@ public class ActivityOptions { } } static ExitTransitionCoordinator makeSceneTransitionAnimation(Activity activity, Window window, ActivityOptions opts, SharedElementCallback callback, Pair<View, String>[] sharedElements) { static ExitTransitionCoordinator makeSceneTransitionAnimation( ExitTransitionCallbacks exitCallbacks, SharedElementCallback callback, Window window, ActivityOptions opts, Pair<View, String>[] sharedElements) { if (!window.hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)) { opts.mAnimationType = ANIM_DEFAULT; return null; Loading @@ -892,17 +889,11 @@ public class ActivityOptions { } } ExitTransitionCoordinator exit = new ExitTransitionCoordinator(activity, window, ExitTransitionCoordinator exit = new ExitTransitionCoordinator(exitCallbacks, window, callback, names, names, views, false); opts.mTransitionReceiver = exit; opts.mSharedElementNames = names; opts.mIsReturning = (activity == null); if (activity == null) { opts.mExitCoordinatorIndex = -1; } else { opts.mExitCoordinatorIndex = activity.mActivityTransitionState.addExitTransitionCoordinator(exit); } opts.mIsReturning = false; return exit; } Loading @@ -928,8 +919,12 @@ public class ActivityOptions { opts.mIsReturning = true; opts.mResultCode = resultCode; opts.mResultData = resultData; if (activity == null) { opts.mExitCoordinatorIndex = -1; } else { opts.mExitCoordinatorIndex = activity.mActivityTransitionState.addExitTransitionCoordinator(exitCoordinator); } return opts; } Loading Loading @@ -1868,67 +1863,6 @@ public class ActivityOptions { + mStartY + ", mWidth=" + mWidth + ", mHeight=" + mHeight; } private static class HideWindowListener extends TransitionListenerAdapter implements ExitTransitionCoordinator.HideSharedElementsCallback { private final Window mWindow; private final ExitTransitionCoordinator mExit; private final boolean mWaitingForTransition; private boolean mTransitionEnded; private boolean mSharedElementHidden; private ArrayList<View> mSharedElements; public HideWindowListener(Window window, ExitTransitionCoordinator exit) { mWindow = window; mExit = exit; mSharedElements = new ArrayList<>(exit.mSharedElements); Transition transition = mWindow.getExitTransition(); if (transition != null) { transition.addListener(this); mWaitingForTransition = true; } else { mWaitingForTransition = false; } View decorView = mWindow.getDecorView(); if (decorView != null) { if (decorView.getTag(com.android.internal.R.id.cross_task_transition) != null) { throw new IllegalStateException( "Cannot start a transition while one is running"); } decorView.setTagInternal(com.android.internal.R.id.cross_task_transition, exit); } } @Override public void onTransitionEnd(Transition transition) { mTransitionEnded = true; hideWhenDone(); transition.removeListener(this); } @Override public void hideSharedElements() { mSharedElementHidden = true; hideWhenDone(); } private void hideWhenDone() { if (mSharedElementHidden && (!mWaitingForTransition || mTransitionEnded)) { mExit.resetViews(); int numSharedElements = mSharedElements.size(); for (int i = 0; i < numSharedElements; i++) { View view = mSharedElements.get(i); view.requestLayout(); } View decorView = mWindow.getDecorView(); if (decorView != null) { decorView.setTagInternal( com.android.internal.R.id.cross_task_transition, null); decorView.setVisibility(View.GONE); } } } } /** * The information about the source of activity launch. E.g. describe an activity is launched * from launcher by receiving a motion event with a timestamp. Loading
core/java/android/app/ActivityTransitionState.java +6 −6 Original line number Diff line number Diff line Loading @@ -247,14 +247,14 @@ class ActivityTransitionState { mEnterActivityOptions = null; } public void onStop() { public void onStop(Activity activity) { restoreExitedViews(); if (mEnterTransitionCoordinator != null) { mEnterTransitionCoordinator.stop(); mEnterTransitionCoordinator = null; } if (mReturnExitCoordinator != null) { mReturnExitCoordinator.stop(); mReturnExitCoordinator.stop(activity); mReturnExitCoordinator = null; } } Loading Loading @@ -331,7 +331,8 @@ class ActivityTransitionState { } } mReturnExitCoordinator = new ExitTransitionCoordinator(activity, mReturnExitCoordinator = new ExitTransitionCoordinator( new ExitTransitionCoordinator.ActivityExitTransitionCallbacks(activity), activity.getWindow(), activity.mEnterTransitionListener, pendingExitNames, null, null, true); if (enterViewsTransition != null && decor != null) { Loading @@ -341,12 +342,11 @@ class ActivityTransitionState { final ViewGroup finalDecor = decor; OneShotPreDrawListener.add(decor, () -> { if (mReturnExitCoordinator != null) { mReturnExitCoordinator.startExit(activity.mResultCode, activity.mResultData); mReturnExitCoordinator.startExit(activity); } }); } else { mReturnExitCoordinator.startExit(activity.mResultCode, activity.mResultData); mReturnExitCoordinator.startExit(activity); } } return true; Loading
core/java/android/app/ExitTransitionCoordinator.java +77 −45 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.app; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.annotation.NonNull; import android.app.SharedElementCallback.OnSharedElementsReadyListener; import android.content.Intent; import android.graphics.Color; Loading Loading @@ -45,15 +46,17 @@ import java.util.ArrayList; * This ActivityTransitionCoordinator is created in ActivityOptions#makeSceneTransitionAnimation * to govern the exit of the Scene and the shared elements when calling an Activity as well as * the reentry of the Scene when coming back from the called Activity. * * @hide */ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { public class ExitTransitionCoordinator extends ActivityTransitionCoordinator { private static final String TAG = "ExitTransitionCoordinator"; static long sMaxWaitMillis = 1000; private Bundle mSharedElementBundle; private boolean mExitNotified; private boolean mSharedElementNotified; private Activity mActivity; private ExitTransitionCallbacks mExitCallbacks; private boolean mIsBackgroundReady; private boolean mIsCanceled; private Handler mHandler; Loading @@ -62,20 +65,15 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { private Bundle mExitSharedElementBundle; private boolean mIsExitStarted; private boolean mSharedElementsHidden; private HideSharedElementsCallback mHideSharedElementsCallback; public ExitTransitionCoordinator(Activity activity, Window window, SharedElementCallback listener, ArrayList<String> names, public ExitTransitionCoordinator(ExitTransitionCallbacks exitCallbacks, Window window, SharedElementCallback listener, ArrayList<String> names, ArrayList<String> accepted, ArrayList<View> mapped, boolean isReturning) { super(window, names, listener, isReturning); viewsReady(mapSharedElements(accepted, mapped)); stripOffscreenViews(); mIsBackgroundReady = !isReturning; mActivity = activity; } void setHideSharedElementsCallback(HideSharedElementsCallback callback) { mHideSharedElementsCallback = callback; mExitCallbacks = exitCallbacks; } @Override Loading Loading @@ -190,8 +188,8 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { private void hideSharedElements() { moveSharedElementsFromOverlay(); if (mHideSharedElementsCallback != null) { mHideSharedElementsCallback.hideSharedElements(); if (mExitCallbacks != null) { mExitCallbacks.hideSharedElements(); } if (!mIsHidden) { hideViews(mSharedElements); Loading @@ -210,20 +208,16 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { decorView.suppressLayout(true); } moveSharedElementsToOverlay(); startTransition(new Runnable() { @Override public void run() { if (mActivity != null) { beginTransitions(); } else { startExitTransition(); } } }); startTransition(this::beginTransitions); } } public void startExit(int resultCode, Intent data) { /** * Starts the exit animation and sends back the activity result */ public void startExit(Activity activity) { int resultCode = activity.mResultCode; Intent data = activity.mResultData; if (!mIsExitStarted) { mIsExitStarted = true; pauseInput(); Loading @@ -247,9 +241,9 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { .getApplicationInfo().targetSdkVersion >= VERSION_CODES.M; ArrayList<String> sharedElementNames = targetsM ? mSharedElementNames : mAllSharedElementNames; ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this, ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(activity, this, sharedElementNames, resultCode, data); mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() { activity.convertToTranslucent(new Activity.TranslucentConversionListener() { @Override public void onTranslucentConversionComplete(boolean drawComplete) { if (!mIsCanceled) { Loading @@ -257,21 +251,19 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { } } }, options); startTransition(new Runnable() { @Override public void run() { startExitTransition(); } }); startTransition(this::startExitTransition); } } public void stop() { if (mIsReturning && mActivity != null) { /** * Called from {@link Activity#onStop()} */ public void stop(Activity activity) { if (mIsReturning && mExitCallbacks != null) { // Override the previous ActivityOptions. We don't want the // activity to have options since we're essentially canceling the // transition and finishing right now. mActivity.convertToTranslucent(null, null); activity.convertToTranslucent(null, null); finish(); } } Loading Loading @@ -434,7 +426,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { mSharedElementNotified = true; delayCancel(); if (!mActivity.isTopOfTask()) { if (mExitCallbacks.isReturnTransitionAllowed()) { mResultReceiver.send(MSG_ALLOW_RETURN_TRANSITION, null); } Loading Loading @@ -474,22 +466,20 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { } private void finishIfNecessary() { if (mIsReturning && mExitNotified && mActivity != null && (mSharedElements.isEmpty() || mSharedElementsHidden)) { if (mIsReturning && mExitNotified && mExitCallbacks != null && (mSharedElements.isEmpty() || mSharedElementsHidden)) { finish(); } if (!mIsReturning && mExitNotified) { mActivity = null; // don't need it anymore mExitCallbacks = null; // don't need it anymore } } private void finish() { stopCancel(); if (mActivity != null) { mActivity.mActivityTransitionState.clear(); mActivity.finish(); mActivity.overridePendingTransition(0, 0); mActivity = null; if (mExitCallbacks != null) { mExitCallbacks.onFinish(); mExitCallbacks = null; } // Clear the state so that we can't hold any references accidentally and leak memory. clearState(); Loading Loading @@ -529,7 +519,49 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { } } interface HideSharedElementsCallback { void hideSharedElements(); /** * @hide */ public interface ExitTransitionCallbacks { /** * Returns true if reverse exit animation is supported */ boolean isReturnTransitionAllowed(); /** * Called then the transition finishes */ void onFinish(); /** * Optional callback when the transition is hiding elements in the source surface */ default void hideSharedElements() { }; } /** * @hide */ public static class ActivityExitTransitionCallbacks implements ExitTransitionCallbacks { @NonNull final Activity mActivity; ActivityExitTransitionCallbacks(@NonNull Activity activity) { mActivity = activity; } @Override public boolean isReturnTransitionAllowed() { return !mActivity.isTopOfTask(); } @Override public void onFinish() { mActivity.mActivityTransitionState.clear(); mActivity.finish(); mActivity.overridePendingTransition(0, 0); } } }