FileDocCategorySizeDatePackage
ExitTransitionCoordinator.javaAPI DocAndroid 5.1 API17104Thu Mar 12 22:22:10 GMT 2015android.app

ExitTransitionCoordinator

public class ExitTransitionCoordinator extends ActivityTransitionCoordinator
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.

Fields Summary
private static final String
TAG
private static final long
MAX_WAIT_MS
private boolean
mExitComplete
private android.os.Bundle
mSharedElementBundle
private boolean
mExitNotified
private boolean
mSharedElementNotified
private Activity
mActivity
private boolean
mIsBackgroundReady
private boolean
mIsCanceled
private android.os.Handler
mHandler
private android.animation.ObjectAnimator
mBackgroundAnimator
private boolean
mIsHidden
private android.os.Bundle
mExitSharedElementBundle
private boolean
mIsExitStarted
private boolean
mSharedElementsHidden
Constructors Summary
public ExitTransitionCoordinator(Activity activity, ArrayList names, ArrayList accepted, ArrayList mapped, boolean isReturning)


        
                  
        super(activity.getWindow(), names, getListener(activity, isReturning), isReturning);
        viewsReady(mapSharedElements(accepted, mapped));
        stripOffscreenViews();
        mIsBackgroundReady = !isReturning;
        mActivity = activity;
    
Methods Summary
private voidbeginTransitions()

        Transition sharedElementTransition = getSharedElementExitTransition();
        Transition viewsTransition = getExitTransition();

        Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
        ViewGroup decorView = getDecor();
        if (transition != null && decorView != null) {
            setGhostVisibility(View.INVISIBLE);
            scheduleGhostVisibilityChange(View.INVISIBLE);
            TransitionManager.beginDelayedTransition(decorView, transition);
            scheduleGhostVisibilityChange(View.VISIBLE);
            setGhostVisibility(View.VISIBLE);
            decorView.invalidate();
        } else {
            transitionStarted();
        }
    
private android.os.BundlecaptureExitSharedElementsState()

        Bundle bundle = new Bundle();
        RectF bounds = new RectF();
        Matrix matrix = new Matrix();
        for (int i = 0; i < mSharedElements.size(); i++) {
            String name = mSharedElementNames.get(i);
            Bundle sharedElementState = mExitSharedElementBundle.getBundle(name);
            if (sharedElementState != null) {
                bundle.putBundle(name, sharedElementState);
            } else {
                View view = mSharedElements.get(i);
                captureSharedElementState(view, name, bundle, matrix, bounds);
            }
        }
        return bundle;
    
private voiddelayCancel()

        if (mHandler != null) {
            mHandler.sendEmptyMessageDelayed(MSG_CANCEL, MAX_WAIT_MS);
        }
    
private voidexitTransitionComplete()

        mExitComplete = true;
        notifyComplete();
    
private voidfadeOutBackground()

        if (mBackgroundAnimator == null) {
            ViewGroup decor = getDecor();
            Drawable background;
            if (decor != null && (background = decor.getBackground()) != null) {
                background = background.mutate();
                getWindow().setBackgroundDrawable(background);
                mBackgroundAnimator = ObjectAnimator.ofInt(background, "alpha", 0);
                mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        mBackgroundAnimator = null;
                        if (!mIsCanceled) {
                            mIsBackgroundReady = true;
                            notifyComplete();
                        }
                    }
                });
                mBackgroundAnimator.setDuration(getFadeDuration());
                mBackgroundAnimator.start();
            } else {
                mIsBackgroundReady = true;
            }
        }
    
private voidfinish()

        stopCancel();
        if (mActivity != null) {
            mActivity.mActivityTransitionState.clear();
            mActivity.finish();
            mActivity.overridePendingTransition(0, 0);
            mActivity = null;
        }
        // Clear the state so that we can't hold any references accidentally and leak memory.
        mHandler = null;
        mSharedElementBundle = null;
        if (mBackgroundAnimator != null) {
            mBackgroundAnimator.cancel();
            mBackgroundAnimator = null;
        }
        mExitSharedElementBundle = null;
        clearState();
    
private voidfinishIfNecessary()

        if (mIsReturning && mExitNotified && mActivity != null && (mSharedElements.isEmpty() ||
                mSharedElementsHidden)) {
            finish();
        }
        if (!mIsReturning && mExitNotified) {
            mActivity = null; // don't need it anymore
        }
    
private android.transition.TransitiongetExitTransition()

        Transition viewsTransition = null;
        if (mTransitioningViews != null && !mTransitioningViews.isEmpty()) {
            viewsTransition = configureTransition(getViewsTransition(), true);
        }
        if (viewsTransition == null) {
            exitTransitionComplete();
        } else {
            final ArrayList<View> transitioningViews = mTransitioningViews;
            viewsTransition.addListener(new ContinueTransitionListener() {
                @Override
                public void onTransitionEnd(Transition transition) {
                    transition.removeListener(this);
                    exitTransitionComplete();
                    if (mIsHidden && transitioningViews != null) {
                        showViews(transitioningViews, true);
                    }
                    if (mSharedElementBundle != null) {
                        delayCancel();
                    }
                    super.onTransitionEnd(transition);
                }
            });
            viewsTransition.forceVisibility(View.INVISIBLE, false);
        }
        return viewsTransition;
    
private static SharedElementCallbackgetListener(Activity activity, boolean isReturning)

        return isReturning ? activity.mEnterTransitionListener : activity.mExitTransitionListener;
    
private android.transition.TransitiongetSharedElementExitTransition()

        Transition sharedElementTransition = null;
        if (!mSharedElements.isEmpty()) {
            sharedElementTransition = configureTransition(getSharedElementTransition(), false);
        }
        if (sharedElementTransition == null) {
            sharedElementTransitionComplete();
        } else {
            sharedElementTransition.addListener(new ContinueTransitionListener() {
                @Override
                public void onTransitionEnd(Transition transition) {
                    transition.removeListener(this);
                    sharedElementTransitionComplete();
                    if (mIsHidden) {
                        showViews(mSharedElements, true);
                    }
                }
            });
            mSharedElements.get(0).invalidate();
        }
        return sharedElementTransition;
    
protected android.transition.TransitiongetSharedElementTransition()

        if (mIsReturning) {
            return getWindow().getSharedElementReturnTransition();
        } else {
            return getWindow().getSharedElementExitTransition();
        }
    
protected android.transition.TransitiongetViewsTransition()

        if (mIsReturning) {
            return getWindow().getReturnTransition();
        } else {
            return getWindow().getExitTransition();
        }
    
private voidhideSharedElements()

        moveSharedElementsFromOverlay();
        if (!mIsHidden) {
            hideViews(mSharedElements);
        }
        mSharedElementsHidden = true;
        finishIfNecessary();
    
protected booleanisReadyToNotify()

        return mSharedElementBundle != null && mResultReceiver != null && mIsBackgroundReady;
    
protected booleanmoveSharedElementWithParent()

        return !mIsReturning;
    
protected voidnotifyComplete()

        if (isReadyToNotify()) {
            if (!mSharedElementNotified) {
                mSharedElementNotified = true;
                delayCancel();
                mResultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, mSharedElementBundle);
            }
            if (!mExitNotified && mExitComplete) {
                mExitNotified = true;
                mResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null);
                mResultReceiver = null; // done talking
                ViewGroup decorView = getDecor();
                if (!mIsReturning && decorView != null) {
                    decorView.suppressLayout(false);
                }
                finishIfNecessary();
            }
        }
    
protected voidonReceiveResult(int resultCode, android.os.Bundle resultData)

        switch (resultCode) {
            case MSG_SET_REMOTE_RECEIVER:
                stopCancel();
                mResultReceiver = resultData.getParcelable(KEY_REMOTE_RECEIVER);
                if (mIsCanceled) {
                    mResultReceiver.send(MSG_CANCEL, null);
                    mResultReceiver = null;
                } else {
                    notifyComplete();
                }
                break;
            case MSG_HIDE_SHARED_ELEMENTS:
                stopCancel();
                if (!mIsCanceled) {
                    hideSharedElements();
                }
                break;
            case MSG_START_EXIT_TRANSITION:
                mHandler.removeMessages(MSG_CANCEL);
                startExit();
                break;
            case MSG_SHARED_ELEMENT_DESTINATION:
                mExitSharedElementBundle = resultData;
                sharedElementExitBack();
                break;
        }
    
public voidresetViews()

        if (mTransitioningViews != null) {
            showViews(mTransitioningViews, true);
        }
        showViews(mSharedElements, true);
        mIsHidden = true;
        ViewGroup decorView = getDecor();
        if (!mIsReturning && decorView != null) {
            decorView.suppressLayout(false);
        }
        moveSharedElementsFromOverlay();
        clearState();
    
private voidsharedElementExitBack()

        final ViewGroup decorView = getDecor();
        if (decorView != null) {
            decorView.suppressLayout(true);
        }
        if (decorView != null && mExitSharedElementBundle != null &&
                !mExitSharedElementBundle.isEmpty() &&
                !mSharedElements.isEmpty() && getSharedElementTransition() != null) {
            startTransition(new Runnable() {
                public void run() {
                    startSharedElementExit(decorView);
                }
            });
        } else {
            sharedElementTransitionComplete();
        }
    
private voidsharedElementTransitionComplete()

        mSharedElementBundle = mExitSharedElementBundle == null
                ? captureSharedElementState() : captureExitSharedElementsState();
        notifyComplete();
    
public voidstartExit()

        if (!mIsExitStarted) {
            mIsExitStarted = true;
            ViewGroup decorView = getDecor();
            if (decorView != null) {
                decorView.suppressLayout(true);
            }
            moveSharedElementsToOverlay();
            startTransition(new Runnable() {
                @Override
                public void run() {
                    beginTransitions();
                }
            });
        }
    
public voidstartExit(int resultCode, android.content.Intent data)

        if (!mIsExitStarted) {
            mIsExitStarted = true;
            ViewGroup decorView = getDecor();
            if (decorView != null) {
                decorView.suppressLayout(true);
            }
            mHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    mIsCanceled = true;
                    finish();
                }
            };
            delayCancel();
            moveSharedElementsToOverlay();
            if (decorView != null && decorView.getBackground() == null) {
                getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
            }
            ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this,
                    mAllSharedElementNames, resultCode, data);
            mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
                @Override
                public void onTranslucentConversionComplete(boolean drawComplete) {
                    if (!mIsCanceled) {
                        fadeOutBackground();
                    }
                }
            }, options);
            startTransition(new Runnable() {
                @Override
                public void run() {
                    startExitTransition();
                }
            });
        }
    
private voidstartExitTransition()

        Transition transition = getExitTransition();
        ViewGroup decorView = getDecor();
        if (transition != null && decorView != null && mTransitioningViews != null) {
            TransitionManager.beginDelayedTransition(decorView, transition);
            mTransitioningViews.get(0).invalidate();
        } else {
            transitionStarted();
        }
    
private voidstartSharedElementExit(android.view.ViewGroup decorView)

        Transition transition = getSharedElementExitTransition();
        transition.addListener(new Transition.TransitionListenerAdapter() {
            @Override
            public void onTransitionEnd(Transition transition) {
                transition.removeListener(this);
                if (mExitComplete) {
                    delayCancel();
                }
            }
        });
        final ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle,
                mSharedElementNames);
        decorView.getViewTreeObserver()
                .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                    @Override
                    public boolean onPreDraw() {
                        decorView.getViewTreeObserver().removeOnPreDrawListener(this);
                        setSharedElementState(mExitSharedElementBundle, sharedElementSnapshots);
                        return true;
                    }
                });
        setGhostVisibility(View.INVISIBLE);
        scheduleGhostVisibilityChange(View.INVISIBLE);
        if (mListener != null) {
            mListener.onSharedElementEnd(mSharedElementNames, mSharedElements,
                    sharedElementSnapshots);
        }
        TransitionManager.beginDelayedTransition(decorView, transition);
        scheduleGhostVisibilityChange(View.VISIBLE);
        setGhostVisibility(View.VISIBLE);
        decorView.invalidate();
    
public voidstop()

        if (mIsReturning && mActivity != 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);
            finish();
        }
    
private voidstopCancel()

        if (mHandler != null) {
            mHandler.removeMessages(MSG_CANCEL);
        }