blob: b5b6e4aa1892005a8ab03c35adbefd60a8745303 [file] [log] [blame]
George Mount31a21722014-03-24 17:44:36 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package android.app;
17
George Mount62ab9b72014-05-02 13:51:17 -070018import android.animation.Animator;
19import android.animation.AnimatorListenerAdapter;
20import android.animation.ObjectAnimator;
George Mount4dc668c2015-04-09 20:55:59 +000021import android.app.SharedElementCallback.OnSharedElementsReadyListener;
George Mount62ab9b72014-05-02 13:51:17 -070022import android.content.Intent;
Craig Mautner85b764e2014-08-27 13:45:10 -070023import android.graphics.Color;
Dake Gu7bf379c2014-07-15 16:29:38 -070024import android.graphics.Matrix;
25import android.graphics.RectF;
George Mount62ab9b72014-05-02 13:51:17 -070026import android.graphics.drawable.ColorDrawable;
George Mount8cab50a2014-05-15 09:57:17 -070027import android.graphics.drawable.Drawable;
George Mount2c256a02015-07-15 16:30:20 -070028import android.os.Build.VERSION_CODES;
George Mount31a21722014-03-24 17:44:36 -070029import android.os.Bundle;
George Mount62ab9b72014-05-02 13:51:17 -070030import android.os.Handler;
31import android.os.Message;
George Mount4dc668c2015-04-09 20:55:59 +000032import android.os.ResultReceiver;
George Mount31a21722014-03-24 17:44:36 -070033import android.transition.Transition;
George Mount62ab9b72014-05-02 13:51:17 -070034import android.transition.TransitionManager;
George Mount31a21722014-03-24 17:44:36 -070035import android.view.View;
George Mounte678ab62014-06-30 15:28:28 -070036import android.view.ViewGroup;
George Mountc93ca162014-05-23 19:21:36 -070037import android.view.ViewTreeObserver;
George Mount413739e2016-06-08 07:13:37 -070038import android.view.Window;
George Mount31a21722014-03-24 17:44:36 -070039
40import java.util.ArrayList;
41
42/**
43 * This ActivityTransitionCoordinator is created in ActivityOptions#makeSceneTransitionAnimation
44 * to govern the exit of the Scene and the shared elements when calling an Activity as well as
45 * the reentry of the Scene when coming back from the called Activity.
46 */
47class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
48 private static final String TAG = "ExitTransitionCoordinator";
George Mount8cab50a2014-05-15 09:57:17 -070049 private static final long MAX_WAIT_MS = 1000;
George Mount31a21722014-03-24 17:44:36 -070050
George Mount62ab9b72014-05-02 13:51:17 -070051 private Bundle mSharedElementBundle;
George Mount62ab9b72014-05-02 13:51:17 -070052 private boolean mExitNotified;
George Mount62ab9b72014-05-02 13:51:17 -070053 private boolean mSharedElementNotified;
George Mount62ab9b72014-05-02 13:51:17 -070054 private Activity mActivity;
George Mount62ab9b72014-05-02 13:51:17 -070055 private boolean mIsBackgroundReady;
George Mount62ab9b72014-05-02 13:51:17 -070056 private boolean mIsCanceled;
George Mount62ab9b72014-05-02 13:51:17 -070057 private Handler mHandler;
George Mount8cab50a2014-05-15 09:57:17 -070058 private ObjectAnimator mBackgroundAnimator;
George Mount8cab50a2014-05-15 09:57:17 -070059 private boolean mIsHidden;
George Mountc93ca162014-05-23 19:21:36 -070060 private Bundle mExitSharedElementBundle;
George Mount700db2a2014-07-07 17:17:49 -070061 private boolean mIsExitStarted;
George Mountb5ef7f82014-07-09 14:55:03 -070062 private boolean mSharedElementsHidden;
George Mount413739e2016-06-08 07:13:37 -070063 private HideSharedElementsCallback mHideSharedElementsCallback;
George Mountb5ef7f82014-07-09 14:55:03 -070064
George Mount413739e2016-06-08 07:13:37 -070065 public ExitTransitionCoordinator(Activity activity, Window window,
66 SharedElementCallback listener, ArrayList<String> names,
George Mount1fecfb22014-06-18 14:55:55 -070067 ArrayList<String> accepted, ArrayList<View> mapped, boolean isReturning) {
George Mount413739e2016-06-08 07:13:37 -070068 super(window, names, listener, isReturning);
George Mount1fecfb22014-06-18 14:55:55 -070069 viewsReady(mapSharedElements(accepted, mapped));
George Mount60625b02014-06-24 07:46:23 -070070 stripOffscreenViews();
George Mounta712e8c2014-05-20 15:10:20 -070071 mIsBackgroundReady = !isReturning;
George Mount62ab9b72014-05-02 13:51:17 -070072 mActivity = activity;
George Mount31a21722014-03-24 17:44:36 -070073 }
74
George Mount413739e2016-06-08 07:13:37 -070075 void setHideSharedElementsCallback(HideSharedElementsCallback callback) {
76 mHideSharedElementsCallback = callback;
George Mount800d72b2014-05-19 07:09:00 -070077 }
78
George Mount31a21722014-03-24 17:44:36 -070079 @Override
George Mount62ab9b72014-05-02 13:51:17 -070080 protected void onReceiveResult(int resultCode, Bundle resultData) {
81 switch (resultCode) {
82 case MSG_SET_REMOTE_RECEIVER:
George Mountfe361d22014-07-08 17:25:25 -070083 stopCancel();
George Mount62ab9b72014-05-02 13:51:17 -070084 mResultReceiver = resultData.getParcelable(KEY_REMOTE_RECEIVER);
85 if (mIsCanceled) {
86 mResultReceiver.send(MSG_CANCEL, null);
87 mResultReceiver = null;
88 } else {
George Mount62ab9b72014-05-02 13:51:17 -070089 notifyComplete();
90 }
91 break;
92 case MSG_HIDE_SHARED_ELEMENTS:
George Mountfe361d22014-07-08 17:25:25 -070093 stopCancel();
George Mount62ab9b72014-05-02 13:51:17 -070094 if (!mIsCanceled) {
95 hideSharedElements();
96 }
97 break;
98 case MSG_START_EXIT_TRANSITION:
George Mountfe361d22014-07-08 17:25:25 -070099 mHandler.removeMessages(MSG_CANCEL);
George Mount62ab9b72014-05-02 13:51:17 -0700100 startExit();
101 break;
George Mountc93ca162014-05-23 19:21:36 -0700102 case MSG_SHARED_ELEMENT_DESTINATION:
103 mExitSharedElementBundle = resultData;
George Mount67d92432014-06-06 13:34:20 -0700104 sharedElementExitBack();
George Mountc93ca162014-05-23 19:21:36 -0700105 break;
George Mountbdc4d8d2016-03-23 13:10:13 -0700106 case MSG_CANCEL:
107 mIsCanceled = true;
108 finish();
109 break;
George Mountc93ca162014-05-23 19:21:36 -0700110 }
111 }
112
George Mountfe361d22014-07-08 17:25:25 -0700113 private void stopCancel() {
114 if (mHandler != null) {
115 mHandler.removeMessages(MSG_CANCEL);
116 }
117 }
118
119 private void delayCancel() {
120 if (mHandler != null) {
121 mHandler.sendEmptyMessageDelayed(MSG_CANCEL, MAX_WAIT_MS);
122 }
123 }
124
George Mount1fecfb22014-06-18 14:55:55 -0700125 public void resetViews() {
George Mountb694e082014-09-12 07:34:52 -0700126 if (mTransitioningViews != null) {
127 showViews(mTransitioningViews, true);
George Mount62976722016-02-04 16:45:53 -0800128 setTransitioningViewsVisiblity(View.VISIBLE, true);
George Mountb694e082014-09-12 07:34:52 -0700129 }
George Mountce2ee3d2014-09-09 15:04:31 -0700130 showViews(mSharedElements, true);
George Mount1fecfb22014-06-18 14:55:55 -0700131 mIsHidden = true;
George Mount48bd13c2014-09-12 10:54:54 -0700132 ViewGroup decorView = getDecor();
133 if (!mIsReturning && decorView != null) {
134 decorView.suppressLayout(false);
Dake Guf7ff2202014-07-25 14:00:17 -0700135 }
George Mountfe361d22014-07-08 17:25:25 -0700136 moveSharedElementsFromOverlay();
George Mount8d3cd2c2014-07-08 11:07:33 -0700137 clearState();
George Mount1fecfb22014-06-18 14:55:55 -0700138 }
139
George Mount67d92432014-06-06 13:34:20 -0700140 private void sharedElementExitBack() {
George Mount48bd13c2014-09-12 10:54:54 -0700141 final ViewGroup decorView = getDecor();
142 if (decorView != null) {
143 decorView.suppressLayout(true);
Dake Guf7ff2202014-07-25 14:00:17 -0700144 }
George Mount48bd13c2014-09-12 10:54:54 -0700145 if (decorView != null && mExitSharedElementBundle != null &&
146 !mExitSharedElementBundle.isEmpty() &&
Dake Gu872efe42014-08-29 15:24:58 -0700147 !mSharedElements.isEmpty() && getSharedElementTransition() != null) {
George Mount67d92432014-06-06 13:34:20 -0700148 startTransition(new Runnable() {
149 public void run() {
George Mount48bd13c2014-09-12 10:54:54 -0700150 startSharedElementExit(decorView);
George Mount67d92432014-06-06 13:34:20 -0700151 }
152 });
George Mount00dde0b2014-07-01 15:27:07 -0700153 } else {
154 sharedElementTransitionComplete();
George Mount31a21722014-03-24 17:44:36 -0700155 }
156 }
157
George Mount48bd13c2014-09-12 10:54:54 -0700158 private void startSharedElementExit(final ViewGroup decorView) {
George Mount67d92432014-06-06 13:34:20 -0700159 Transition transition = getSharedElementExitTransition();
George Mountfe361d22014-07-08 17:25:25 -0700160 transition.addListener(new Transition.TransitionListenerAdapter() {
161 @Override
162 public void onTransitionEnd(Transition transition) {
163 transition.removeListener(this);
George Mount41725de2015-04-09 08:23:05 -0700164 if (isViewsTransitionComplete()) {
George Mountfe361d22014-07-08 17:25:25 -0700165 delayCancel();
166 }
167 }
168 });
George Mount67d92432014-06-06 13:34:20 -0700169 final ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle,
170 mSharedElementNames);
George Mount6e7fb602014-09-04 16:20:20 -0700171 decorView.getViewTreeObserver()
George Mount67d92432014-06-06 13:34:20 -0700172 .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
173 @Override
174 public boolean onPreDraw() {
George Mount6e7fb602014-09-04 16:20:20 -0700175 decorView.getViewTreeObserver().removeOnPreDrawListener(this);
George Mount67d92432014-06-06 13:34:20 -0700176 setSharedElementState(mExitSharedElementBundle, sharedElementSnapshots);
177 return true;
178 }
179 });
George Mountfe361d22014-07-08 17:25:25 -0700180 setGhostVisibility(View.INVISIBLE);
181 scheduleGhostVisibilityChange(View.INVISIBLE);
George Mount1732f522014-09-17 16:59:36 -0700182 if (mListener != null) {
183 mListener.onSharedElementEnd(mSharedElementNames, mSharedElements,
184 sharedElementSnapshots);
185 }
George Mount48bd13c2014-09-12 10:54:54 -0700186 TransitionManager.beginDelayedTransition(decorView, transition);
George Mountfe361d22014-07-08 17:25:25 -0700187 scheduleGhostVisibilityChange(View.VISIBLE);
188 setGhostVisibility(View.VISIBLE);
George Mount48bd13c2014-09-12 10:54:54 -0700189 decorView.invalidate();
George Mount67d92432014-06-06 13:34:20 -0700190 }
191
George Mount62ab9b72014-05-02 13:51:17 -0700192 private void hideSharedElements() {
George Mountfe361d22014-07-08 17:25:25 -0700193 moveSharedElementsFromOverlay();
George Mount413739e2016-06-08 07:13:37 -0700194 if (mHideSharedElementsCallback != null) {
195 mHideSharedElementsCallback.hideSharedElements();
196 }
George Mount67d92432014-06-06 13:34:20 -0700197 if (!mIsHidden) {
George Mount0f0c4732014-09-05 13:47:47 -0700198 hideViews(mSharedElements);
George Mount67d92432014-06-06 13:34:20 -0700199 }
George Mountb5ef7f82014-07-09 14:55:03 -0700200 mSharedElementsHidden = true;
George Mountc93ca162014-05-23 19:21:36 -0700201 finishIfNecessary();
George Mount62ab9b72014-05-02 13:51:17 -0700202 }
203
George Mount31a21722014-03-24 17:44:36 -0700204 public void startExit() {
George Mount700db2a2014-07-07 17:17:49 -0700205 if (!mIsExitStarted) {
206 mIsExitStarted = true;
George Mount80141d12015-07-14 10:03:06 -0700207 pauseInput();
George Mount48bd13c2014-09-12 10:54:54 -0700208 ViewGroup decorView = getDecor();
209 if (decorView != null) {
210 decorView.suppressLayout(true);
Dake Guf7ff2202014-07-25 14:00:17 -0700211 }
George Mountfe361d22014-07-08 17:25:25 -0700212 moveSharedElementsToOverlay();
George Mount700db2a2014-07-07 17:17:49 -0700213 startTransition(new Runnable() {
214 @Override
215 public void run() {
George Mount413739e2016-06-08 07:13:37 -0700216 if (mActivity != null) {
217 beginTransitions();
218 } else {
219 startExitTransition();
220 }
George Mount700db2a2014-07-07 17:17:49 -0700221 }
222 });
George Mount700db2a2014-07-07 17:17:49 -0700223 }
George Mount62ab9b72014-05-02 13:51:17 -0700224 }
225
226 public void startExit(int resultCode, Intent data) {
George Mount700db2a2014-07-07 17:17:49 -0700227 if (!mIsExitStarted) {
228 mIsExitStarted = true;
George Mount80141d12015-07-14 10:03:06 -0700229 pauseInput();
George Mount48bd13c2014-09-12 10:54:54 -0700230 ViewGroup decorView = getDecor();
231 if (decorView != null) {
232 decorView.suppressLayout(true);
Dake Guf7ff2202014-07-25 14:00:17 -0700233 }
George Mount700db2a2014-07-07 17:17:49 -0700234 mHandler = new Handler() {
235 @Override
236 public void handleMessage(Message msg) {
237 mIsCanceled = true;
238 finish();
George Mount62ab9b72014-05-02 13:51:17 -0700239 }
George Mount700db2a2014-07-07 17:17:49 -0700240 };
George Mountfe361d22014-07-08 17:25:25 -0700241 delayCancel();
242 moveSharedElementsToOverlay();
George Mount48bd13c2014-09-12 10:54:54 -0700243 if (decorView != null && decorView.getBackground() == null) {
Craig Mautner85b764e2014-08-27 13:45:10 -0700244 getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
George Mount62ab9b72014-05-02 13:51:17 -0700245 }
George Mount2c256a02015-07-15 16:30:20 -0700246 final boolean targetsM = decorView == null || decorView.getContext()
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -0700247 .getApplicationInfo().targetSdkVersion >= VERSION_CODES.M;
George Mount2c256a02015-07-15 16:30:20 -0700248 ArrayList<String> sharedElementNames = targetsM ? mSharedElementNames :
249 mAllSharedElementNames;
George Mount700db2a2014-07-07 17:17:49 -0700250 ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this,
George Mount2c256a02015-07-15 16:30:20 -0700251 sharedElementNames, resultCode, data);
George Mount700db2a2014-07-07 17:17:49 -0700252 mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
253 @Override
254 public void onTranslucentConversionComplete(boolean drawComplete) {
255 if (!mIsCanceled) {
256 fadeOutBackground();
257 }
258 }
259 }, options);
260 startTransition(new Runnable() {
261 @Override
262 public void run() {
263 startExitTransition();
264 }
265 });
266 }
George Mount67d92432014-06-06 13:34:20 -0700267 }
268
George Mountf1abef62014-09-22 13:58:21 -0700269 public void stop() {
270 if (mIsReturning && mActivity != null) {
271 // Override the previous ActivityOptions. We don't want the
272 // activity to have options since we're essentially canceling the
273 // transition and finishing right now.
274 mActivity.convertToTranslucent(null, null);
275 finish();
276 }
277 }
278
George Mount67d92432014-06-06 13:34:20 -0700279 private void startExitTransition() {
George Mountf451d8a2014-06-23 11:09:32 -0700280 Transition transition = getExitTransition();
George Mount48bd13c2014-09-12 10:54:54 -0700281 ViewGroup decorView = getDecor();
George Mountb694e082014-09-12 07:34:52 -0700282 if (transition != null && decorView != null && mTransitioningViews != null) {
George Mount62976722016-02-04 16:45:53 -0800283 setTransitioningViewsVisiblity(View.VISIBLE, false);
George Mount48bd13c2014-09-12 10:54:54 -0700284 TransitionManager.beginDelayedTransition(decorView, transition);
George Mount52ff2b72016-03-23 11:08:39 -0700285 setTransitioningViewsVisiblity(View.INVISIBLE, false);
286 decorView.invalidate();
George Mountb4c5d7b2014-07-24 13:19:51 -0700287 } else {
288 transitionStarted();
George Mountc93ca162014-05-23 19:21:36 -0700289 }
George Mount62ab9b72014-05-02 13:51:17 -0700290 }
291
292 private void fadeOutBackground() {
George Mount8cab50a2014-05-15 09:57:17 -0700293 if (mBackgroundAnimator == null) {
George Mount700db2a2014-07-07 17:17:49 -0700294 ViewGroup decor = getDecor();
295 Drawable background;
296 if (decor != null && (background = decor.getBackground()) != null) {
George Mount99c82fd2014-09-03 07:27:47 -0700297 background = background.mutate();
298 getWindow().setBackgroundDrawable(background);
George Mount700db2a2014-07-07 17:17:49 -0700299 mBackgroundAnimator = ObjectAnimator.ofInt(background, "alpha", 0);
300 mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
301 @Override
302 public void onAnimationEnd(Animator animation) {
303 mBackgroundAnimator = null;
304 if (!mIsCanceled) {
305 mIsBackgroundReady = true;
306 notifyComplete();
307 }
George Mount8cab50a2014-05-15 09:57:17 -0700308 }
George Mount700db2a2014-07-07 17:17:49 -0700309 });
310 mBackgroundAnimator.setDuration(getFadeDuration());
311 mBackgroundAnimator.start();
George Mountb5ef7f82014-07-09 14:55:03 -0700312 } else {
313 mIsBackgroundReady = true;
George Mount700db2a2014-07-07 17:17:49 -0700314 }
George Mount8cab50a2014-05-15 09:57:17 -0700315 }
George Mount62ab9b72014-05-02 13:51:17 -0700316 }
317
George Mountc93ca162014-05-23 19:21:36 -0700318 private Transition getExitTransition() {
319 Transition viewsTransition = null;
George Mountb694e082014-09-12 07:34:52 -0700320 if (mTransitioningViews != null && !mTransitioningViews.isEmpty()) {
George Mount88815022014-06-25 14:33:54 -0700321 viewsTransition = configureTransition(getViewsTransition(), true);
George Mount62ab9b72014-05-02 13:51:17 -0700322 }
George Mountc93ca162014-05-23 19:21:36 -0700323 if (viewsTransition == null) {
George Mount41725de2015-04-09 08:23:05 -0700324 viewsTransitionComplete();
George Mount62ab9b72014-05-02 13:51:17 -0700325 } else {
George Mountb694e082014-09-12 07:34:52 -0700326 final ArrayList<View> transitioningViews = mTransitioningViews;
George Mount67d92432014-06-06 13:34:20 -0700327 viewsTransition.addListener(new ContinueTransitionListener() {
George Mount62ab9b72014-05-02 13:51:17 -0700328 @Override
329 public void onTransitionEnd(Transition transition) {
George Mount41725de2015-04-09 08:23:05 -0700330 viewsTransitionComplete();
George Mountb694e082014-09-12 07:34:52 -0700331 if (mIsHidden && transitioningViews != null) {
332 showViews(transitioningViews, true);
George Mount62976722016-02-04 16:45:53 -0800333 setTransitioningViewsVisiblity(View.VISIBLE, true);
George Mount8cab50a2014-05-15 09:57:17 -0700334 }
George Mountfe361d22014-07-08 17:25:25 -0700335 if (mSharedElementBundle != null) {
336 delayCancel();
337 }
338 super.onTransitionEnd(transition);
George Mountc93ca162014-05-23 19:21:36 -0700339 }
George Mount62ab9b72014-05-02 13:51:17 -0700340 });
341 }
George Mountc93ca162014-05-23 19:21:36 -0700342 return viewsTransition;
343 }
344
345 private Transition getSharedElementExitTransition() {
346 Transition sharedElementTransition = null;
347 if (!mSharedElements.isEmpty()) {
George Mount88815022014-06-25 14:33:54 -0700348 sharedElementTransition = configureTransition(getSharedElementTransition(), false);
George Mountc93ca162014-05-23 19:21:36 -0700349 }
350 if (sharedElementTransition == null) {
351 sharedElementTransitionComplete();
352 } else {
George Mount67d92432014-06-06 13:34:20 -0700353 sharedElementTransition.addListener(new ContinueTransitionListener() {
George Mountc93ca162014-05-23 19:21:36 -0700354 @Override
355 public void onTransitionEnd(Transition transition) {
356 sharedElementTransitionComplete();
357 if (mIsHidden) {
George Mountce2ee3d2014-09-09 15:04:31 -0700358 showViews(mSharedElements, true);
George Mountc93ca162014-05-23 19:21:36 -0700359 }
George Mount25f98a42016-06-14 14:06:39 -0700360 super.onTransitionEnd(transition);
George Mountc93ca162014-05-23 19:21:36 -0700361 }
362 });
363 mSharedElements.get(0).invalidate();
364 }
365 return sharedElementTransition;
366 }
367
368 private void beginTransitions() {
369 Transition sharedElementTransition = getSharedElementExitTransition();
370 Transition viewsTransition = getExitTransition();
George Mount62ab9b72014-05-02 13:51:17 -0700371
372 Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
George Mount48bd13c2014-09-12 10:54:54 -0700373 ViewGroup decorView = getDecor();
374 if (transition != null && decorView != null) {
George Mountfe361d22014-07-08 17:25:25 -0700375 setGhostVisibility(View.INVISIBLE);
376 scheduleGhostVisibilityChange(View.INVISIBLE);
George Mount62976722016-02-04 16:45:53 -0800377 if (viewsTransition != null) {
378 setTransitioningViewsVisiblity(View.VISIBLE, false);
379 }
George Mount48bd13c2014-09-12 10:54:54 -0700380 TransitionManager.beginDelayedTransition(decorView, transition);
George Mountfe361d22014-07-08 17:25:25 -0700381 scheduleGhostVisibilityChange(View.VISIBLE);
382 setGhostVisibility(View.VISIBLE);
George Mount62976722016-02-04 16:45:53 -0800383 if (viewsTransition != null) {
George Mount52ff2b72016-03-23 11:08:39 -0700384 setTransitioningViewsVisiblity(View.INVISIBLE, false);
George Mount62976722016-02-04 16:45:53 -0800385 }
George Mount48bd13c2014-09-12 10:54:54 -0700386 decorView.invalidate();
George Mountb4c5d7b2014-07-24 13:19:51 -0700387 } else {
388 transitionStarted();
George Mounta712e8c2014-05-20 15:10:20 -0700389 }
George Mount62ab9b72014-05-02 13:51:17 -0700390 }
391
George Mount62ab9b72014-05-02 13:51:17 -0700392 protected boolean isReadyToNotify() {
George Mount67d92432014-06-06 13:34:20 -0700393 return mSharedElementBundle != null && mResultReceiver != null && mIsBackgroundReady;
George Mount62ab9b72014-05-02 13:51:17 -0700394 }
395
George Mount41725de2015-04-09 08:23:05 -0700396 @Override
397 protected void sharedElementTransitionComplete() {
George Mount67d92432014-06-06 13:34:20 -0700398 mSharedElementBundle = mExitSharedElementBundle == null
399 ? captureSharedElementState() : captureExitSharedElementsState();
George Mount41725de2015-04-09 08:23:05 -0700400 super.sharedElementTransitionComplete();
George Mount62ab9b72014-05-02 13:51:17 -0700401 }
402
George Mount67d92432014-06-06 13:34:20 -0700403 private Bundle captureExitSharedElementsState() {
404 Bundle bundle = new Bundle();
Dake Gu7bf379c2014-07-15 16:29:38 -0700405 RectF bounds = new RectF();
406 Matrix matrix = new Matrix();
George Mount01e9a972014-07-09 15:39:23 -0700407 for (int i = 0; i < mSharedElements.size(); i++) {
George Mount67d92432014-06-06 13:34:20 -0700408 String name = mSharedElementNames.get(i);
409 Bundle sharedElementState = mExitSharedElementBundle.getBundle(name);
410 if (sharedElementState != null) {
411 bundle.putBundle(name, sharedElementState);
412 } else {
413 View view = mSharedElements.get(i);
Dake Gu7bf379c2014-07-15 16:29:38 -0700414 captureSharedElementState(view, name, bundle, matrix, bounds);
George Mount67d92432014-06-06 13:34:20 -0700415 }
416 }
417 return bundle;
418 }
419
George Mount41725de2015-04-09 08:23:05 -0700420 @Override
421 protected void onTransitionsComplete() {
422 notifyComplete();
423 }
424
George Mount62ab9b72014-05-02 13:51:17 -0700425 protected void notifyComplete() {
426 if (isReadyToNotify()) {
427 if (!mSharedElementNotified) {
428 mSharedElementNotified = true;
George Mountfe361d22014-07-08 17:25:25 -0700429 delayCancel();
George Mount4dc668c2015-04-09 20:55:59 +0000430 if (mListener == null) {
431 mResultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, mSharedElementBundle);
432 notifyExitComplete();
433 } else {
434 final ResultReceiver resultReceiver = mResultReceiver;
435 final Bundle sharedElementBundle = mSharedElementBundle;
436 mListener.onSharedElementsArrived(mSharedElementNames, mSharedElements,
437 new OnSharedElementsReadyListener() {
438 @Override
439 public void onSharedElementsReady() {
440 resultReceiver.send(MSG_TAKE_SHARED_ELEMENTS,
441 sharedElementBundle);
442 notifyExitComplete();
443 }
444 });
Dake Guf7ff2202014-07-25 14:00:17 -0700445 }
George Mount4dc668c2015-04-09 20:55:59 +0000446 } else {
447 notifyExitComplete();
George Mount62ab9b72014-05-02 13:51:17 -0700448 }
449 }
450 }
451
George Mount4dc668c2015-04-09 20:55:59 +0000452 private void notifyExitComplete() {
George Mount41725de2015-04-09 08:23:05 -0700453 if (!mExitNotified && isViewsTransitionComplete()) {
George Mount4dc668c2015-04-09 20:55:59 +0000454 mExitNotified = true;
455 mResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null);
456 mResultReceiver = null; // done talking
457 ViewGroup decorView = getDecor();
458 if (!mIsReturning && decorView != null) {
459 decorView.suppressLayout(false);
460 }
461 finishIfNecessary();
462 }
463 }
464
George Mountc93ca162014-05-23 19:21:36 -0700465 private void finishIfNecessary() {
George Mounte678ab62014-06-30 15:28:28 -0700466 if (mIsReturning && mExitNotified && mActivity != null && (mSharedElements.isEmpty() ||
George Mountb5ef7f82014-07-09 14:55:03 -0700467 mSharedElementsHidden)) {
George Mounta0a02602014-06-20 18:22:26 -0700468 finish();
George Mountc93ca162014-05-23 19:21:36 -0700469 }
470 if (!mIsReturning && mExitNotified) {
471 mActivity = null; // don't need it anymore
472 }
473 }
474
George Mounta0a02602014-06-20 18:22:26 -0700475 private void finish() {
George Mountfe361d22014-07-08 17:25:25 -0700476 stopCancel();
George Mountf1abef62014-09-22 13:58:21 -0700477 if (mActivity != null) {
478 mActivity.mActivityTransitionState.clear();
479 mActivity.finish();
480 mActivity.overridePendingTransition(0, 0);
481 mActivity = null;
482 }
George Mounta0a02602014-06-20 18:22:26 -0700483 // Clear the state so that we can't hold any references accidentally and leak memory.
George Mount3bbc2ed2015-11-18 11:10:55 -0800484 clearState();
485 }
486
487 @Override
488 protected void clearState() {
George Mounta0a02602014-06-20 18:22:26 -0700489 mHandler = null;
George Mounta0a02602014-06-20 18:22:26 -0700490 mSharedElementBundle = null;
491 if (mBackgroundAnimator != null) {
492 mBackgroundAnimator.cancel();
493 mBackgroundAnimator = null;
494 }
495 mExitSharedElementBundle = null;
George Mount3bbc2ed2015-11-18 11:10:55 -0800496 super.clearState();
George Mounta0a02602014-06-20 18:22:26 -0700497 }
498
George Mounta712e8c2014-05-20 15:10:20 -0700499 @Override
George Mountfe361d22014-07-08 17:25:25 -0700500 protected boolean moveSharedElementWithParent() {
501 return !mIsReturning;
502 }
503
504 @Override
George Mounta712e8c2014-05-20 15:10:20 -0700505 protected Transition getViewsTransition() {
506 if (mIsReturning) {
George Mount68f96d82014-07-31 13:13:10 -0700507 return getWindow().getReturnTransition();
George Mounta712e8c2014-05-20 15:10:20 -0700508 } else {
509 return getWindow().getExitTransition();
510 }
511 }
512
513 protected Transition getSharedElementTransition() {
514 if (mIsReturning) {
George Mount68f96d82014-07-31 13:13:10 -0700515 return getWindow().getSharedElementReturnTransition();
George Mounta712e8c2014-05-20 15:10:20 -0700516 } else {
517 return getWindow().getSharedElementExitTransition();
518 }
519 }
George Mount413739e2016-06-08 07:13:37 -0700520
521 interface HideSharedElementsCallback {
522 void hideSharedElements();
523 }
George Mount31a21722014-03-24 17:44:36 -0700524}