131a217290cf376d0573fc36e21c8940987485019George Mount/*
231a217290cf376d0573fc36e21c8940987485019George Mount * Copyright (C) 2014 The Android Open Source Project
331a217290cf376d0573fc36e21c8940987485019George Mount *
431a217290cf376d0573fc36e21c8940987485019George Mount * Licensed under the Apache License, Version 2.0 (the "License");
531a217290cf376d0573fc36e21c8940987485019George Mount * you may not use this file except in compliance with the License.
631a217290cf376d0573fc36e21c8940987485019George Mount * You may obtain a copy of the License at
731a217290cf376d0573fc36e21c8940987485019George Mount *
831a217290cf376d0573fc36e21c8940987485019George Mount *      http://www.apache.org/licenses/LICENSE-2.0
931a217290cf376d0573fc36e21c8940987485019George Mount *
1031a217290cf376d0573fc36e21c8940987485019George Mount * Unless required by applicable law or agreed to in writing, software
1131a217290cf376d0573fc36e21c8940987485019George Mount * distributed under the License is distributed on an "AS IS" BASIS,
1231a217290cf376d0573fc36e21c8940987485019George Mount * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1331a217290cf376d0573fc36e21c8940987485019George Mount * See the License for the specific language governing permissions and
1431a217290cf376d0573fc36e21c8940987485019George Mount * limitations under the License.
1531a217290cf376d0573fc36e21c8940987485019George Mount */
1631a217290cf376d0573fc36e21c8940987485019George Mountpackage android.app;
1731a217290cf376d0573fc36e21c8940987485019George Mount
1862ab9b78b77b7dd851c47115f4d8d7611d657585George Mountimport android.animation.Animator;
1962ab9b78b77b7dd851c47115f4d8d7611d657585George Mountimport android.animation.AnimatorListenerAdapter;
2062ab9b78b77b7dd851c47115f4d8d7611d657585George Mountimport android.animation.ObjectAnimator;
2162ab9b78b77b7dd851c47115f4d8d7611d657585George Mountimport android.content.Intent;
2285b764e22babfe5508286fbad5d7fee12345704fCraig Mautnerimport android.graphics.Color;
237bf379c8af399626d5b8b568fe1d4f96f56badccDake Guimport android.graphics.Matrix;
247bf379c8af399626d5b8b568fe1d4f96f56badccDake Guimport android.graphics.RectF;
2562ab9b78b77b7dd851c47115f4d8d7611d657585George Mountimport android.graphics.drawable.ColorDrawable;
268cab50afda0d8485436f72a93d668697f549d3b3George Mountimport android.graphics.drawable.Drawable;
2731a217290cf376d0573fc36e21c8940987485019George Mountimport android.os.Bundle;
2862ab9b78b77b7dd851c47115f4d8d7611d657585George Mountimport android.os.Handler;
2962ab9b78b77b7dd851c47115f4d8d7611d657585George Mountimport android.os.Message;
3031a217290cf376d0573fc36e21c8940987485019George Mountimport android.transition.Transition;
3162ab9b78b77b7dd851c47115f4d8d7611d657585George Mountimport android.transition.TransitionManager;
3231a217290cf376d0573fc36e21c8940987485019George Mountimport android.view.View;
33e678ab686643127b4b297ae7a1e4869b4cfc6e53George Mountimport android.view.ViewGroup;
34c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mountimport android.view.ViewTreeObserver;
3531a217290cf376d0573fc36e21c8940987485019George Mount
3631a217290cf376d0573fc36e21c8940987485019George Mountimport java.util.ArrayList;
3731a217290cf376d0573fc36e21c8940987485019George Mount
3831a217290cf376d0573fc36e21c8940987485019George Mount/**
3931a217290cf376d0573fc36e21c8940987485019George Mount * This ActivityTransitionCoordinator is created in ActivityOptions#makeSceneTransitionAnimation
4031a217290cf376d0573fc36e21c8940987485019George Mount * to govern the exit of the Scene and the shared elements when calling an Activity as well as
4131a217290cf376d0573fc36e21c8940987485019George Mount * the reentry of the Scene when coming back from the called Activity.
4231a217290cf376d0573fc36e21c8940987485019George Mount */
4331a217290cf376d0573fc36e21c8940987485019George Mountclass ExitTransitionCoordinator extends ActivityTransitionCoordinator {
4431a217290cf376d0573fc36e21c8940987485019George Mount    private static final String TAG = "ExitTransitionCoordinator";
458cab50afda0d8485436f72a93d668697f549d3b3George Mount    private static final long MAX_WAIT_MS = 1000;
4631a217290cf376d0573fc36e21c8940987485019George Mount
4762ab9b78b77b7dd851c47115f4d8d7611d657585George Mount    private boolean mExitComplete;
4831a217290cf376d0573fc36e21c8940987485019George Mount
4962ab9b78b77b7dd851c47115f4d8d7611d657585George Mount    private Bundle mSharedElementBundle;
5031a217290cf376d0573fc36e21c8940987485019George Mount
5162ab9b78b77b7dd851c47115f4d8d7611d657585George Mount    private boolean mExitNotified;
5231a217290cf376d0573fc36e21c8940987485019George Mount
5362ab9b78b77b7dd851c47115f4d8d7611d657585George Mount    private boolean mSharedElementNotified;
5431a217290cf376d0573fc36e21c8940987485019George Mount
5562ab9b78b77b7dd851c47115f4d8d7611d657585George Mount    private Activity mActivity;
5631a217290cf376d0573fc36e21c8940987485019George Mount
5762ab9b78b77b7dd851c47115f4d8d7611d657585George Mount    private boolean mIsBackgroundReady;
5862ab9b78b77b7dd851c47115f4d8d7611d657585George Mount
5962ab9b78b77b7dd851c47115f4d8d7611d657585George Mount    private boolean mIsCanceled;
6062ab9b78b77b7dd851c47115f4d8d7611d657585George Mount
6162ab9b78b77b7dd851c47115f4d8d7611d657585George Mount    private Handler mHandler;
6262ab9b78b77b7dd851c47115f4d8d7611d657585George Mount
638cab50afda0d8485436f72a93d668697f549d3b3George Mount    private ObjectAnimator mBackgroundAnimator;
648cab50afda0d8485436f72a93d668697f549d3b3George Mount
658cab50afda0d8485436f72a93d668697f549d3b3George Mount    private boolean mIsHidden;
668cab50afda0d8485436f72a93d668697f549d3b3George Mount
67c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount    private Bundle mExitSharedElementBundle;
68c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount
69700db2a325bced35cebc403f272f988fad522892George Mount    private boolean mIsExitStarted;
70700db2a325bced35cebc403f272f988fad522892George Mount
71b5ef7f8c6d4629b2998de6c0b27bc1a4779b3e49George Mount    private boolean mSharedElementsHidden;
72b5ef7f8c6d4629b2998de6c0b27bc1a4779b3e49George Mount
7362ab9b78b77b7dd851c47115f4d8d7611d657585George Mount    public ExitTransitionCoordinator(Activity activity, ArrayList<String> names,
741fecfb2ddcdf4335ff543bdd549b8e4d36139da8George Mount            ArrayList<String> accepted, ArrayList<View> mapped, boolean isReturning) {
75fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        super(activity.getWindow(), names, getListener(activity, isReturning), isReturning);
761fecfb2ddcdf4335ff543bdd549b8e4d36139da8George Mount        viewsReady(mapSharedElements(accepted, mapped));
7760625b02ac099bacc96a387ec270751745dafae0George Mount        stripOffscreenViews();
78a712e8cc2f16ac32ee5f1bbf5b962969f2f3451eGeorge Mount        mIsBackgroundReady = !isReturning;
7962ab9b78b77b7dd851c47115f4d8d7611d657585George Mount        mActivity = activity;
8031a217290cf376d0573fc36e21c8940987485019George Mount    }
8131a217290cf376d0573fc36e21c8940987485019George Mount
826558056e8fccc32f9e1dc59e46d09f8d916b7538George Mount    private static SharedElementCallback getListener(Activity activity, boolean isReturning) {
83d80154fba1c23834b5139aa764f9426bbf38a721George Mount        return isReturning ? activity.mEnterTransitionListener : activity.mExitTransitionListener;
84800d72b0e05049e4a8f90ea96ec165fc975264ceGeorge Mount    }
85800d72b0e05049e4a8f90ea96ec165fc975264ceGeorge Mount
8631a217290cf376d0573fc36e21c8940987485019George Mount    @Override
8762ab9b78b77b7dd851c47115f4d8d7611d657585George Mount    protected void onReceiveResult(int resultCode, Bundle resultData) {
8862ab9b78b77b7dd851c47115f4d8d7611d657585George Mount        switch (resultCode) {
8962ab9b78b77b7dd851c47115f4d8d7611d657585George Mount            case MSG_SET_REMOTE_RECEIVER:
90fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount                stopCancel();
9162ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                mResultReceiver = resultData.getParcelable(KEY_REMOTE_RECEIVER);
9262ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                if (mIsCanceled) {
9362ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                    mResultReceiver.send(MSG_CANCEL, null);
9462ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                    mResultReceiver = null;
9562ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                } else {
9662ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                    notifyComplete();
9762ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                }
9862ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                break;
9962ab9b78b77b7dd851c47115f4d8d7611d657585George Mount            case MSG_HIDE_SHARED_ELEMENTS:
100fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount                stopCancel();
10162ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                if (!mIsCanceled) {
10262ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                    hideSharedElements();
10362ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                }
10462ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                break;
10562ab9b78b77b7dd851c47115f4d8d7611d657585George Mount            case MSG_START_EXIT_TRANSITION:
106fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount                mHandler.removeMessages(MSG_CANCEL);
10762ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                startExit();
10862ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                break;
109c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount            case MSG_SHARED_ELEMENT_DESTINATION:
110c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount                mExitSharedElementBundle = resultData;
11167d924341a1d0994ac68b3b7898d5576edd987b4George Mount                sharedElementExitBack();
11267d924341a1d0994ac68b3b7898d5576edd987b4George Mount                break;
11367d924341a1d0994ac68b3b7898d5576edd987b4George Mount        }
11467d924341a1d0994ac68b3b7898d5576edd987b4George Mount    }
11567d924341a1d0994ac68b3b7898d5576edd987b4George Mount
116fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount    private void stopCancel() {
117fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        if (mHandler != null) {
118fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount            mHandler.removeMessages(MSG_CANCEL);
119fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        }
120fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount    }
121fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount
122fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount    private void delayCancel() {
123fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        if (mHandler != null) {
124fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount            mHandler.sendEmptyMessageDelayed(MSG_CANCEL, MAX_WAIT_MS);
125fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        }
126fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount    }
127fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount
1281fecfb2ddcdf4335ff543bdd549b8e4d36139da8George Mount    public void resetViews() {
129b694e080546316a27d22eba759027f6cb0a24705George Mount        if (mTransitioningViews != null) {
130b694e080546316a27d22eba759027f6cb0a24705George Mount            showViews(mTransitioningViews, true);
131b694e080546316a27d22eba759027f6cb0a24705George Mount        }
132ce2ee3d6de670e52abed7f432778701113ba9c07George Mount        showViews(mSharedElements, true);
1331fecfb2ddcdf4335ff543bdd549b8e4d36139da8George Mount        mIsHidden = true;
13448bd13c9cb2627847cf1f7707a084eb354e9c303George Mount        ViewGroup decorView = getDecor();
13548bd13c9cb2627847cf1f7707a084eb354e9c303George Mount        if (!mIsReturning && decorView != null) {
13648bd13c9cb2627847cf1f7707a084eb354e9c303George Mount            decorView.suppressLayout(false);
137f7ff2205d96e468950e9011de60d2ff4bd84c66dDake Gu        }
138fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        moveSharedElementsFromOverlay();
1398d3cd2c8cf8ec355265941a8457ffd8e2e348648George Mount        clearState();
1401fecfb2ddcdf4335ff543bdd549b8e4d36139da8George Mount    }
1411fecfb2ddcdf4335ff543bdd549b8e4d36139da8George Mount
14267d924341a1d0994ac68b3b7898d5576edd987b4George Mount    private void sharedElementExitBack() {
14348bd13c9cb2627847cf1f7707a084eb354e9c303George Mount        final ViewGroup decorView = getDecor();
14448bd13c9cb2627847cf1f7707a084eb354e9c303George Mount        if (decorView != null) {
14548bd13c9cb2627847cf1f7707a084eb354e9c303George Mount            decorView.suppressLayout(true);
146f7ff2205d96e468950e9011de60d2ff4bd84c66dDake Gu        }
14748bd13c9cb2627847cf1f7707a084eb354e9c303George Mount        if (decorView != null && mExitSharedElementBundle != null &&
14848bd13c9cb2627847cf1f7707a084eb354e9c303George Mount                !mExitSharedElementBundle.isEmpty() &&
149872efe45d5b3a4d6376cd15e118d5bb68ef334daDake Gu                !mSharedElements.isEmpty() && getSharedElementTransition() != null) {
15067d924341a1d0994ac68b3b7898d5576edd987b4George Mount            startTransition(new Runnable() {
15167d924341a1d0994ac68b3b7898d5576edd987b4George Mount                public void run() {
15248bd13c9cb2627847cf1f7707a084eb354e9c303George Mount                    startSharedElementExit(decorView);
153c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount                }
15467d924341a1d0994ac68b3b7898d5576edd987b4George Mount            });
15500dde0bd469ba7a34369dcaaa701bd06fdf6c3adGeorge Mount        } else {
15600dde0bd469ba7a34369dcaaa701bd06fdf6c3adGeorge Mount            sharedElementTransitionComplete();
157c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount        }
158c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount    }
159c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount
16048bd13c9cb2627847cf1f7707a084eb354e9c303George Mount    private void startSharedElementExit(final ViewGroup decorView) {
16167d924341a1d0994ac68b3b7898d5576edd987b4George Mount        Transition transition = getSharedElementExitTransition();
162fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        transition.addListener(new Transition.TransitionListenerAdapter() {
163fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount            @Override
164fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount            public void onTransitionEnd(Transition transition) {
165fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount                transition.removeListener(this);
166fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount                if (mExitComplete) {
167fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount                    delayCancel();
168fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount                }
169fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount            }
170fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        });
17167d924341a1d0994ac68b3b7898d5576edd987b4George Mount        final ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle,
17267d924341a1d0994ac68b3b7898d5576edd987b4George Mount                mSharedElementNames);
1736e7fb60b93d3449d256282a9cc34ba3356add90eGeorge Mount        decorView.getViewTreeObserver()
17467d924341a1d0994ac68b3b7898d5576edd987b4George Mount                .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
17567d924341a1d0994ac68b3b7898d5576edd987b4George Mount                    @Override
17667d924341a1d0994ac68b3b7898d5576edd987b4George Mount                    public boolean onPreDraw() {
1776e7fb60b93d3449d256282a9cc34ba3356add90eGeorge Mount                        decorView.getViewTreeObserver().removeOnPreDrawListener(this);
17867d924341a1d0994ac68b3b7898d5576edd987b4George Mount                        setSharedElementState(mExitSharedElementBundle, sharedElementSnapshots);
17967d924341a1d0994ac68b3b7898d5576edd987b4George Mount                        return true;
18067d924341a1d0994ac68b3b7898d5576edd987b4George Mount                    }
18167d924341a1d0994ac68b3b7898d5576edd987b4George Mount                });
182fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        setGhostVisibility(View.INVISIBLE);
183fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        scheduleGhostVisibilityChange(View.INVISIBLE);
1841732f528952ea2df0bfd503fabb958af03dbfc81George Mount        if (mListener != null) {
1851732f528952ea2df0bfd503fabb958af03dbfc81George Mount            mListener.onSharedElementEnd(mSharedElementNames, mSharedElements,
1861732f528952ea2df0bfd503fabb958af03dbfc81George Mount                    sharedElementSnapshots);
1871732f528952ea2df0bfd503fabb958af03dbfc81George Mount        }
18848bd13c9cb2627847cf1f7707a084eb354e9c303George Mount        TransitionManager.beginDelayedTransition(decorView, transition);
189fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        scheduleGhostVisibilityChange(View.VISIBLE);
190fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        setGhostVisibility(View.VISIBLE);
19148bd13c9cb2627847cf1f7707a084eb354e9c303George Mount        decorView.invalidate();
19267d924341a1d0994ac68b3b7898d5576edd987b4George Mount    }
19367d924341a1d0994ac68b3b7898d5576edd987b4George Mount
19462ab9b78b77b7dd851c47115f4d8d7611d657585George Mount    private void hideSharedElements() {
195fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        moveSharedElementsFromOverlay();
19667d924341a1d0994ac68b3b7898d5576edd987b4George Mount        if (!mIsHidden) {
1970f0c473488f8e8becc8883d3cdd9610324610dc4George Mount            hideViews(mSharedElements);
19867d924341a1d0994ac68b3b7898d5576edd987b4George Mount        }
199b5ef7f8c6d4629b2998de6c0b27bc1a4779b3e49George Mount        mSharedElementsHidden = true;
200c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount        finishIfNecessary();
20131a217290cf376d0573fc36e21c8940987485019George Mount    }
20231a217290cf376d0573fc36e21c8940987485019George Mount
20362ab9b78b77b7dd851c47115f4d8d7611d657585George Mount    public void startExit() {
204700db2a325bced35cebc403f272f988fad522892George Mount        if (!mIsExitStarted) {
205700db2a325bced35cebc403f272f988fad522892George Mount            mIsExitStarted = true;
20648bd13c9cb2627847cf1f7707a084eb354e9c303George Mount            ViewGroup decorView = getDecor();
20748bd13c9cb2627847cf1f7707a084eb354e9c303George Mount            if (decorView != null) {
20848bd13c9cb2627847cf1f7707a084eb354e9c303George Mount                decorView.suppressLayout(true);
209f7ff2205d96e468950e9011de60d2ff4bd84c66dDake Gu            }
210fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount            moveSharedElementsToOverlay();
211700db2a325bced35cebc403f272f988fad522892George Mount            startTransition(new Runnable() {
212700db2a325bced35cebc403f272f988fad522892George Mount                @Override
213700db2a325bced35cebc403f272f988fad522892George Mount                public void run() {
214700db2a325bced35cebc403f272f988fad522892George Mount                    beginTransitions();
215700db2a325bced35cebc403f272f988fad522892George Mount                }
216700db2a325bced35cebc403f272f988fad522892George Mount            });
217700db2a325bced35cebc403f272f988fad522892George Mount        }
21831a217290cf376d0573fc36e21c8940987485019George Mount    }
21931a217290cf376d0573fc36e21c8940987485019George Mount
22062ab9b78b77b7dd851c47115f4d8d7611d657585George Mount    public void startExit(int resultCode, Intent data) {
221700db2a325bced35cebc403f272f988fad522892George Mount        if (!mIsExitStarted) {
222700db2a325bced35cebc403f272f988fad522892George Mount            mIsExitStarted = true;
22348bd13c9cb2627847cf1f7707a084eb354e9c303George Mount            ViewGroup decorView = getDecor();
22448bd13c9cb2627847cf1f7707a084eb354e9c303George Mount            if (decorView != null) {
22548bd13c9cb2627847cf1f7707a084eb354e9c303George Mount                decorView.suppressLayout(true);
226f7ff2205d96e468950e9011de60d2ff4bd84c66dDake Gu            }
227700db2a325bced35cebc403f272f988fad522892George Mount            mHandler = new Handler() {
228700db2a325bced35cebc403f272f988fad522892George Mount                @Override
229700db2a325bced35cebc403f272f988fad522892George Mount                public void handleMessage(Message msg) {
230700db2a325bced35cebc403f272f988fad522892George Mount                    mIsCanceled = true;
231700db2a325bced35cebc403f272f988fad522892George Mount                    finish();
23262ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                }
233700db2a325bced35cebc403f272f988fad522892George Mount            };
234fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount            delayCancel();
235fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount            moveSharedElementsToOverlay();
23648bd13c9cb2627847cf1f7707a084eb354e9c303George Mount            if (decorView != null && decorView.getBackground() == null) {
23785b764e22babfe5508286fbad5d7fee12345704fCraig Mautner                getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
23862ab9b78b77b7dd851c47115f4d8d7611d657585George Mount            }
239700db2a325bced35cebc403f272f988fad522892George Mount            ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this,
240700db2a325bced35cebc403f272f988fad522892George Mount                    mAllSharedElementNames, resultCode, data);
241700db2a325bced35cebc403f272f988fad522892George Mount            mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
242700db2a325bced35cebc403f272f988fad522892George Mount                @Override
243700db2a325bced35cebc403f272f988fad522892George Mount                public void onTranslucentConversionComplete(boolean drawComplete) {
244700db2a325bced35cebc403f272f988fad522892George Mount                    if (!mIsCanceled) {
245700db2a325bced35cebc403f272f988fad522892George Mount                        fadeOutBackground();
246700db2a325bced35cebc403f272f988fad522892George Mount                    }
247700db2a325bced35cebc403f272f988fad522892George Mount                }
248700db2a325bced35cebc403f272f988fad522892George Mount            }, options);
249700db2a325bced35cebc403f272f988fad522892George Mount            startTransition(new Runnable() {
250700db2a325bced35cebc403f272f988fad522892George Mount                @Override
251700db2a325bced35cebc403f272f988fad522892George Mount                public void run() {
252700db2a325bced35cebc403f272f988fad522892George Mount                    startExitTransition();
253700db2a325bced35cebc403f272f988fad522892George Mount                }
254700db2a325bced35cebc403f272f988fad522892George Mount            });
255700db2a325bced35cebc403f272f988fad522892George Mount        }
25667d924341a1d0994ac68b3b7898d5576edd987b4George Mount    }
25767d924341a1d0994ac68b3b7898d5576edd987b4George Mount
258f1abef6fc2194e72af521202ee4b17c10e03c935George Mount    public void stop() {
259f1abef6fc2194e72af521202ee4b17c10e03c935George Mount        if (mIsReturning && mActivity != null) {
260f1abef6fc2194e72af521202ee4b17c10e03c935George Mount            // Override the previous ActivityOptions. We don't want the
261f1abef6fc2194e72af521202ee4b17c10e03c935George Mount            // activity to have options since we're essentially canceling the
262f1abef6fc2194e72af521202ee4b17c10e03c935George Mount            // transition and finishing right now.
263f1abef6fc2194e72af521202ee4b17c10e03c935George Mount            mActivity.convertToTranslucent(null, null);
264f1abef6fc2194e72af521202ee4b17c10e03c935George Mount            finish();
265f1abef6fc2194e72af521202ee4b17c10e03c935George Mount        }
266f1abef6fc2194e72af521202ee4b17c10e03c935George Mount    }
267f1abef6fc2194e72af521202ee4b17c10e03c935George Mount
26867d924341a1d0994ac68b3b7898d5576edd987b4George Mount    private void startExitTransition() {
269f451d8a6d1a454f338e37f99c0867e17ce9e06f1George Mount        Transition transition = getExitTransition();
27048bd13c9cb2627847cf1f7707a084eb354e9c303George Mount        ViewGroup decorView = getDecor();
271b694e080546316a27d22eba759027f6cb0a24705George Mount        if (transition != null && decorView != null && mTransitioningViews != null) {
27248bd13c9cb2627847cf1f7707a084eb354e9c303George Mount            TransitionManager.beginDelayedTransition(decorView, transition);
273b5ef7f8c6d4629b2998de6c0b27bc1a4779b3e49George Mount            mTransitioningViews.get(0).invalidate();
274b4c5d7bf218865d28f030c852fd303e127d676dbGeorge Mount        } else {
275b4c5d7bf218865d28f030c852fd303e127d676dbGeorge Mount            transitionStarted();
276c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount        }
27731a217290cf376d0573fc36e21c8940987485019George Mount    }
27831a217290cf376d0573fc36e21c8940987485019George Mount
27962ab9b78b77b7dd851c47115f4d8d7611d657585George Mount    private void fadeOutBackground() {
2808cab50afda0d8485436f72a93d668697f549d3b3George Mount        if (mBackgroundAnimator == null) {
281700db2a325bced35cebc403f272f988fad522892George Mount            ViewGroup decor = getDecor();
282700db2a325bced35cebc403f272f988fad522892George Mount            Drawable background;
283700db2a325bced35cebc403f272f988fad522892George Mount            if (decor != null && (background = decor.getBackground()) != null) {
28499c82fd1de23deeb8cf640bb574c76af76429df6George Mount                background = background.mutate();
28599c82fd1de23deeb8cf640bb574c76af76429df6George Mount                getWindow().setBackgroundDrawable(background);
286700db2a325bced35cebc403f272f988fad522892George Mount                mBackgroundAnimator = ObjectAnimator.ofInt(background, "alpha", 0);
287700db2a325bced35cebc403f272f988fad522892George Mount                mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
288700db2a325bced35cebc403f272f988fad522892George Mount                    @Override
289700db2a325bced35cebc403f272f988fad522892George Mount                    public void onAnimationEnd(Animator animation) {
290700db2a325bced35cebc403f272f988fad522892George Mount                        mBackgroundAnimator = null;
291700db2a325bced35cebc403f272f988fad522892George Mount                        if (!mIsCanceled) {
292700db2a325bced35cebc403f272f988fad522892George Mount                            mIsBackgroundReady = true;
293700db2a325bced35cebc403f272f988fad522892George Mount                            notifyComplete();
294700db2a325bced35cebc403f272f988fad522892George Mount                        }
2958cab50afda0d8485436f72a93d668697f549d3b3George Mount                    }
296700db2a325bced35cebc403f272f988fad522892George Mount                });
297700db2a325bced35cebc403f272f988fad522892George Mount                mBackgroundAnimator.setDuration(getFadeDuration());
298700db2a325bced35cebc403f272f988fad522892George Mount                mBackgroundAnimator.start();
299b5ef7f8c6d4629b2998de6c0b27bc1a4779b3e49George Mount            } else {
300b5ef7f8c6d4629b2998de6c0b27bc1a4779b3e49George Mount                mIsBackgroundReady = true;
301700db2a325bced35cebc403f272f988fad522892George Mount            }
3028cab50afda0d8485436f72a93d668697f549d3b3George Mount        }
30331a217290cf376d0573fc36e21c8940987485019George Mount    }
30431a217290cf376d0573fc36e21c8940987485019George Mount
305c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount    private Transition getExitTransition() {
306c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount        Transition viewsTransition = null;
307b694e080546316a27d22eba759027f6cb0a24705George Mount        if (mTransitioningViews != null && !mTransitioningViews.isEmpty()) {
3088881502da5b319e139ab85c1825d2d2d239356a1George Mount            viewsTransition = configureTransition(getViewsTransition(), true);
309c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount        }
310c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount        if (viewsTransition == null) {
311c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount            exitTransitionComplete();
31262ab9b78b77b7dd851c47115f4d8d7611d657585George Mount        } else {
313b694e080546316a27d22eba759027f6cb0a24705George Mount            final ArrayList<View> transitioningViews = mTransitioningViews;
31467d924341a1d0994ac68b3b7898d5576edd987b4George Mount            viewsTransition.addListener(new ContinueTransitionListener() {
31562ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                @Override
31662ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                public void onTransitionEnd(Transition transition) {
317a0a0260e48e1ee4e9b5d98b49571e8d2a6fd6c3aGeorge Mount                    transition.removeListener(this);
318c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount                    exitTransitionComplete();
319b694e080546316a27d22eba759027f6cb0a24705George Mount                    if (mIsHidden && transitioningViews != null) {
320b694e080546316a27d22eba759027f6cb0a24705George Mount                        showViews(transitioningViews, true);
321c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount                    }
322fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount                    if (mSharedElementBundle != null) {
323fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount                        delayCancel();
324fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount                    }
325fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount                    super.onTransitionEnd(transition);
32662ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                }
32762ab9b78b77b7dd851c47115f4d8d7611d657585George Mount            });
328b5ef7f8c6d4629b2998de6c0b27bc1a4779b3e49George Mount            viewsTransition.forceVisibility(View.INVISIBLE, false);
32962ab9b78b77b7dd851c47115f4d8d7611d657585George Mount        }
330c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount        return viewsTransition;
331c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount    }
332c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount
333c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount    private Transition getSharedElementExitTransition() {
334c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount        Transition sharedElementTransition = null;
335c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount        if (!mSharedElements.isEmpty()) {
3368881502da5b319e139ab85c1825d2d2d239356a1George Mount            sharedElementTransition = configureTransition(getSharedElementTransition(), false);
337c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount        }
338c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount        if (sharedElementTransition == null) {
339c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount            sharedElementTransitionComplete();
34062ab9b78b77b7dd851c47115f4d8d7611d657585George Mount        } else {
34167d924341a1d0994ac68b3b7898d5576edd987b4George Mount            sharedElementTransition.addListener(new ContinueTransitionListener() {
34262ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                @Override
34362ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                public void onTransitionEnd(Transition transition) {
344a0a0260e48e1ee4e9b5d98b49571e8d2a6fd6c3aGeorge Mount                    transition.removeListener(this);
345c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount                    sharedElementTransitionComplete();
3468cab50afda0d8485436f72a93d668697f549d3b3George Mount                    if (mIsHidden) {
347ce2ee3d6de670e52abed7f432778701113ba9c07George Mount                        showViews(mSharedElements, true);
3488cab50afda0d8485436f72a93d668697f549d3b3George Mount                    }
34962ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                }
35062ab9b78b77b7dd851c47115f4d8d7611d657585George Mount            });
351c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount            mSharedElements.get(0).invalidate();
35262ab9b78b77b7dd851c47115f4d8d7611d657585George Mount        }
353c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount        return sharedElementTransition;
354c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount    }
355c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount
356c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount    private void beginTransitions() {
357c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount        Transition sharedElementTransition = getSharedElementExitTransition();
358c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount        Transition viewsTransition = getExitTransition();
35962ab9b78b77b7dd851c47115f4d8d7611d657585George Mount
36062ab9b78b77b7dd851c47115f4d8d7611d657585George Mount        Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
36148bd13c9cb2627847cf1f7707a084eb354e9c303George Mount        ViewGroup decorView = getDecor();
36248bd13c9cb2627847cf1f7707a084eb354e9c303George Mount        if (transition != null && decorView != null) {
363fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount            setGhostVisibility(View.INVISIBLE);
364fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount            scheduleGhostVisibilityChange(View.INVISIBLE);
36548bd13c9cb2627847cf1f7707a084eb354e9c303George Mount            TransitionManager.beginDelayedTransition(decorView, transition);
366fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount            scheduleGhostVisibilityChange(View.VISIBLE);
367fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount            setGhostVisibility(View.VISIBLE);
36848bd13c9cb2627847cf1f7707a084eb354e9c303George Mount            decorView.invalidate();
369b4c5d7bf218865d28f030c852fd303e127d676dbGeorge Mount        } else {
370b4c5d7bf218865d28f030c852fd303e127d676dbGeorge Mount            transitionStarted();
371a712e8cc2f16ac32ee5f1bbf5b962969f2f3451eGeorge Mount        }
37262ab9b78b77b7dd851c47115f4d8d7611d657585George Mount    }
37362ab9b78b77b7dd851c47115f4d8d7611d657585George Mount
37462ab9b78b77b7dd851c47115f4d8d7611d657585George Mount    private void exitTransitionComplete() {
37531a217290cf376d0573fc36e21c8940987485019George Mount        mExitComplete = true;
37662ab9b78b77b7dd851c47115f4d8d7611d657585George Mount        notifyComplete();
37731a217290cf376d0573fc36e21c8940987485019George Mount    }
37831a217290cf376d0573fc36e21c8940987485019George Mount
37962ab9b78b77b7dd851c47115f4d8d7611d657585George Mount    protected boolean isReadyToNotify() {
38067d924341a1d0994ac68b3b7898d5576edd987b4George Mount        return mSharedElementBundle != null && mResultReceiver != null && mIsBackgroundReady;
38131a217290cf376d0573fc36e21c8940987485019George Mount    }
38231a217290cf376d0573fc36e21c8940987485019George Mount
38362ab9b78b77b7dd851c47115f4d8d7611d657585George Mount    private void sharedElementTransitionComplete() {
38467d924341a1d0994ac68b3b7898d5576edd987b4George Mount        mSharedElementBundle = mExitSharedElementBundle == null
38567d924341a1d0994ac68b3b7898d5576edd987b4George Mount                ? captureSharedElementState() : captureExitSharedElementsState();
38662ab9b78b77b7dd851c47115f4d8d7611d657585George Mount        notifyComplete();
38731a217290cf376d0573fc36e21c8940987485019George Mount    }
38831a217290cf376d0573fc36e21c8940987485019George Mount
38967d924341a1d0994ac68b3b7898d5576edd987b4George Mount    private Bundle captureExitSharedElementsState() {
39067d924341a1d0994ac68b3b7898d5576edd987b4George Mount        Bundle bundle = new Bundle();
3917bf379c8af399626d5b8b568fe1d4f96f56badccDake Gu        RectF bounds = new RectF();
3927bf379c8af399626d5b8b568fe1d4f96f56badccDake Gu        Matrix matrix = new Matrix();
39301e9a97fe68dbba42a0edd0ad965ccfe2b8efe7dGeorge Mount        for (int i = 0; i < mSharedElements.size(); i++) {
39467d924341a1d0994ac68b3b7898d5576edd987b4George Mount            String name = mSharedElementNames.get(i);
39567d924341a1d0994ac68b3b7898d5576edd987b4George Mount            Bundle sharedElementState = mExitSharedElementBundle.getBundle(name);
39667d924341a1d0994ac68b3b7898d5576edd987b4George Mount            if (sharedElementState != null) {
39767d924341a1d0994ac68b3b7898d5576edd987b4George Mount                bundle.putBundle(name, sharedElementState);
39867d924341a1d0994ac68b3b7898d5576edd987b4George Mount            } else {
39967d924341a1d0994ac68b3b7898d5576edd987b4George Mount                View view = mSharedElements.get(i);
4007bf379c8af399626d5b8b568fe1d4f96f56badccDake Gu                captureSharedElementState(view, name, bundle, matrix, bounds);
40167d924341a1d0994ac68b3b7898d5576edd987b4George Mount            }
40267d924341a1d0994ac68b3b7898d5576edd987b4George Mount        }
40367d924341a1d0994ac68b3b7898d5576edd987b4George Mount        return bundle;
40467d924341a1d0994ac68b3b7898d5576edd987b4George Mount    }
40567d924341a1d0994ac68b3b7898d5576edd987b4George Mount
40662ab9b78b77b7dd851c47115f4d8d7611d657585George Mount    protected void notifyComplete() {
40762ab9b78b77b7dd851c47115f4d8d7611d657585George Mount        if (isReadyToNotify()) {
40862ab9b78b77b7dd851c47115f4d8d7611d657585George Mount            if (!mSharedElementNotified) {
40962ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                mSharedElementNotified = true;
410fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount                delayCancel();
41162ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                mResultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, mSharedElementBundle);
41262ab9b78b77b7dd851c47115f4d8d7611d657585George Mount            }
41362ab9b78b77b7dd851c47115f4d8d7611d657585George Mount            if (!mExitNotified && mExitComplete) {
41462ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                mExitNotified = true;
41562ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                mResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null);
41662ab9b78b77b7dd851c47115f4d8d7611d657585George Mount                mResultReceiver = null; // done talking
41748bd13c9cb2627847cf1f7707a084eb354e9c303George Mount                ViewGroup decorView = getDecor();
41848bd13c9cb2627847cf1f7707a084eb354e9c303George Mount                if (!mIsReturning && decorView != null) {
41948bd13c9cb2627847cf1f7707a084eb354e9c303George Mount                    decorView.suppressLayout(false);
420f7ff2205d96e468950e9011de60d2ff4bd84c66dDake Gu                }
421c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount                finishIfNecessary();
42262ab9b78b77b7dd851c47115f4d8d7611d657585George Mount            }
42331a217290cf376d0573fc36e21c8940987485019George Mount        }
42431a217290cf376d0573fc36e21c8940987485019George Mount    }
42531a217290cf376d0573fc36e21c8940987485019George Mount
426c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount    private void finishIfNecessary() {
427e678ab686643127b4b297ae7a1e4869b4cfc6e53George Mount        if (mIsReturning && mExitNotified && mActivity != null && (mSharedElements.isEmpty() ||
428b5ef7f8c6d4629b2998de6c0b27bc1a4779b3e49George Mount                mSharedElementsHidden)) {
429a0a0260e48e1ee4e9b5d98b49571e8d2a6fd6c3aGeorge Mount            finish();
430c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount        }
431c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount        if (!mIsReturning && mExitNotified) {
432c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount            mActivity = null; // don't need it anymore
433c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount        }
434c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount    }
435c93ca1617397aace8449f88d1a1e94ec704a2ef4George Mount
436a0a0260e48e1ee4e9b5d98b49571e8d2a6fd6c3aGeorge Mount    private void finish() {
437fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        stopCancel();
438f1abef6fc2194e72af521202ee4b17c10e03c935George Mount        if (mActivity != null) {
439f1abef6fc2194e72af521202ee4b17c10e03c935George Mount            mActivity.mActivityTransitionState.clear();
440f1abef6fc2194e72af521202ee4b17c10e03c935George Mount            mActivity.finish();
441f1abef6fc2194e72af521202ee4b17c10e03c935George Mount            mActivity.overridePendingTransition(0, 0);
442f1abef6fc2194e72af521202ee4b17c10e03c935George Mount            mActivity = null;
443f1abef6fc2194e72af521202ee4b17c10e03c935George Mount        }
444a0a0260e48e1ee4e9b5d98b49571e8d2a6fd6c3aGeorge Mount        // Clear the state so that we can't hold any references accidentally and leak memory.
445a0a0260e48e1ee4e9b5d98b49571e8d2a6fd6c3aGeorge Mount        mHandler = null;
446a0a0260e48e1ee4e9b5d98b49571e8d2a6fd6c3aGeorge Mount        mSharedElementBundle = null;
447a0a0260e48e1ee4e9b5d98b49571e8d2a6fd6c3aGeorge Mount        if (mBackgroundAnimator != null) {
448a0a0260e48e1ee4e9b5d98b49571e8d2a6fd6c3aGeorge Mount            mBackgroundAnimator.cancel();
449a0a0260e48e1ee4e9b5d98b49571e8d2a6fd6c3aGeorge Mount            mBackgroundAnimator = null;
450a0a0260e48e1ee4e9b5d98b49571e8d2a6fd6c3aGeorge Mount        }
451a0a0260e48e1ee4e9b5d98b49571e8d2a6fd6c3aGeorge Mount        mExitSharedElementBundle = null;
452a0a0260e48e1ee4e9b5d98b49571e8d2a6fd6c3aGeorge Mount        clearState();
453a0a0260e48e1ee4e9b5d98b49571e8d2a6fd6c3aGeorge Mount    }
454a0a0260e48e1ee4e9b5d98b49571e8d2a6fd6c3aGeorge Mount
455a712e8cc2f16ac32ee5f1bbf5b962969f2f3451eGeorge Mount    @Override
456fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount    protected boolean moveSharedElementWithParent() {
457fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        return !mIsReturning;
458fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount    }
459fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount
460fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount    @Override
461a712e8cc2f16ac32ee5f1bbf5b962969f2f3451eGeorge Mount    protected Transition getViewsTransition() {
462a712e8cc2f16ac32ee5f1bbf5b962969f2f3451eGeorge Mount        if (mIsReturning) {
46368f96d8db5e5e701b6a12b5cddecc985e56a26c6George Mount            return getWindow().getReturnTransition();
464a712e8cc2f16ac32ee5f1bbf5b962969f2f3451eGeorge Mount        } else {
465a712e8cc2f16ac32ee5f1bbf5b962969f2f3451eGeorge Mount            return getWindow().getExitTransition();
466a712e8cc2f16ac32ee5f1bbf5b962969f2f3451eGeorge Mount        }
467a712e8cc2f16ac32ee5f1bbf5b962969f2f3451eGeorge Mount    }
468a712e8cc2f16ac32ee5f1bbf5b962969f2f3451eGeorge Mount
469a712e8cc2f16ac32ee5f1bbf5b962969f2f3451eGeorge Mount    protected Transition getSharedElementTransition() {
470a712e8cc2f16ac32ee5f1bbf5b962969f2f3451eGeorge Mount        if (mIsReturning) {
47168f96d8db5e5e701b6a12b5cddecc985e56a26c6George Mount            return getWindow().getSharedElementReturnTransition();
472a712e8cc2f16ac32ee5f1bbf5b962969f2f3451eGeorge Mount        } else {
473a712e8cc2f16ac32ee5f1bbf5b962969f2f3451eGeorge Mount            return getWindow().getSharedElementExitTransition();
474a712e8cc2f16ac32ee5f1bbf5b962969f2f3451eGeorge Mount        }
475a712e8cc2f16ac32ee5f1bbf5b962969f2f3451eGeorge Mount    }
47631a217290cf376d0573fc36e21c8940987485019George Mount}
477