blob: f2af2b4eb789b2885229c0badf63d25533cb1241 [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
18import android.animation.Animator;
19import android.animation.AnimatorListenerAdapter;
20import android.animation.ObjectAnimator;
George Mount62ab9b72014-05-02 13:51:17 -070021import android.graphics.Matrix;
George Mount31a21722014-03-24 17:44:36 -070022import android.graphics.drawable.Drawable;
23import android.os.Bundle;
George Mount62ab9b72014-05-02 13:51:17 -070024import android.os.Handler;
25import android.os.Message;
George Mount31a21722014-03-24 17:44:36 -070026import android.os.ResultReceiver;
Dake Gub04b36e2014-08-08 11:22:30 -070027import android.text.TextUtils;
George Mount31a21722014-03-24 17:44:36 -070028import android.transition.Transition;
George Mount62ab9b72014-05-02 13:51:17 -070029import android.transition.TransitionManager;
30import android.util.ArrayMap;
George Mount31a21722014-03-24 17:44:36 -070031import android.view.View;
George Mountd265bd72014-06-02 07:22:59 -070032import android.view.ViewGroup;
George Mount62ab9b72014-05-02 13:51:17 -070033import android.view.ViewGroupOverlay;
George Mount31a21722014-03-24 17:44:36 -070034import android.view.ViewTreeObserver;
George Mount31a21722014-03-24 17:44:36 -070035
36import java.util.ArrayList;
37
38/**
39 * This ActivityTransitionCoordinator is created by the Activity to manage
George Mount62ab9b72014-05-02 13:51:17 -070040 * the enter scene and shared element transfer into the Scene, either during
41 * launch of an Activity or returning from a launched Activity.
George Mount31a21722014-03-24 17:44:36 -070042 */
George Mount62ab9b72014-05-02 13:51:17 -070043class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
George Mount31a21722014-03-24 17:44:36 -070044 private static final String TAG = "EnterTransitionCoordinator";
45
George Mounte678ab62014-06-30 15:28:28 -070046 private static final int MIN_ANIMATION_FRAMES = 2;
George Mount31a21722014-03-24 17:44:36 -070047
George Mount62ab9b72014-05-02 13:51:17 -070048 private boolean mSharedElementTransitionStarted;
George Mount31a21722014-03-24 17:44:36 -070049 private Activity mActivity;
George Mount62ab9b72014-05-02 13:51:17 -070050 private boolean mHasStopped;
George Mount62ab9b72014-05-02 13:51:17 -070051 private boolean mIsCanceled;
George Mount8cab50a2014-05-15 09:57:17 -070052 private ObjectAnimator mBackgroundAnimator;
George Mountc93ca162014-05-23 19:21:36 -070053 private boolean mIsExitTransitionComplete;
George Mount8c2614c2014-06-10 11:12:01 -070054 private boolean mIsReadyForTransition;
55 private Bundle mSharedElementsBundle;
George Mount3cc716c2014-06-12 16:35:35 -070056 private boolean mWasOpaque;
George Mount82ffc142014-06-30 16:47:34 -070057 private boolean mAreViewsReady;
George Mount8d3cd2c2014-07-08 11:07:33 -070058 private boolean mIsViewsTransitionStarted;
George Mountfe361d22014-07-08 17:25:25 -070059 private boolean mIsViewsTransitionComplete;
60 private boolean mIsSharedElementTransitionComplete;
61 private ArrayList<Matrix> mSharedElementParentMatrices;
George Mounta2bbbb32014-08-12 10:16:20 -070062 private Transition mEnterViewsTransition;
George Mount31a21722014-03-24 17:44:36 -070063
George Mount62ab9b72014-05-02 13:51:17 -070064 public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver,
George Mount8c2614c2014-06-10 11:12:01 -070065 ArrayList<String> sharedElementNames, boolean isReturning) {
66 super(activity.getWindow(), sharedElementNames,
67 getListener(activity, isReturning), isReturning);
George Mount31a21722014-03-24 17:44:36 -070068 mActivity = activity;
George Mount62ab9b72014-05-02 13:51:17 -070069 setResultReceiver(resultReceiver);
70 prepareEnter();
71 Bundle resultReceiverBundle = new Bundle();
72 resultReceiverBundle.putParcelable(KEY_REMOTE_RECEIVER, this);
73 mResultReceiver.send(MSG_SET_REMOTE_RECEIVER, resultReceiverBundle);
George Mounted1e01d2014-06-05 13:49:12 -070074 getDecor().getViewTreeObserver().addOnPreDrawListener(
75 new ViewTreeObserver.OnPreDrawListener() {
76 @Override
77 public boolean onPreDraw() {
78 if (mIsReadyForTransition) {
79 getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
80 }
81 return mIsReadyForTransition;
82 }
83 });
George Mount8c2614c2014-06-10 11:12:01 -070084 }
85
Dake Gub04b36e2014-08-08 11:22:30 -070086 public void viewInstancesReady(ArrayList<String> accepted, ArrayList<String> localNames,
87 ArrayList<View> localViews) {
88 boolean remap = false;
89 for (int i = 0; i < localViews.size(); i++) {
90 View view = localViews.get(i);
91 if (!TextUtils.equals(view.getTransitionName(), localNames.get(i))
92 || !view.isAttachedToWindow()) {
93 remap = true;
94 break;
95 }
96 }
97 if (remap) {
98 triggerViewsReady(mapNamedElements(accepted, localNames));
99 } else {
100 triggerViewsReady(mapSharedElements(accepted, localViews));
101 }
George Mount1fecfb22014-06-18 14:55:55 -0700102 }
George Mount8c2614c2014-06-10 11:12:01 -0700103
George Mount1fecfb22014-06-18 14:55:55 -0700104 public void namedViewsReady(ArrayList<String> accepted, ArrayList<String> localNames) {
George Mount82ffc142014-06-30 16:47:34 -0700105 triggerViewsReady(mapNamedElements(accepted, localNames));
George Mount1fecfb22014-06-18 14:55:55 -0700106 }
107
George Mounta2bbbb32014-08-12 10:16:20 -0700108 public Transition getEnterViewsTransition() {
109 return mEnterViewsTransition;
110 }
111
George Mount1fecfb22014-06-18 14:55:55 -0700112 @Override
113 protected void viewsReady(ArrayMap<String, View> sharedElements) {
114 super.viewsReady(sharedElements);
George Mount8c2614c2014-06-10 11:12:01 -0700115 mIsReadyForTransition = true;
George Mountb5ef7f82014-07-09 14:55:03 -0700116 setTransitionAlpha(mSharedElements, 0);
George Mount8c2614c2014-06-10 11:12:01 -0700117 if (getViewsTransition() != null) {
George Mountb5ef7f82014-07-09 14:55:03 -0700118 setTransitionAlpha(mTransitioningViews, 0);
George Mount8c2614c2014-06-10 11:12:01 -0700119 }
George Mountfe361d22014-07-08 17:25:25 -0700120 if (mIsReturning) {
121 sendSharedElementDestination();
122 } else {
123 setSharedElementMatrices();
124 moveSharedElementsToOverlay();
125 }
George Mount8c2614c2014-06-10 11:12:01 -0700126 if (mSharedElementsBundle != null) {
127 onTakeSharedElements();
128 }
George Mountd265bd72014-06-02 07:22:59 -0700129 }
130
George Mount82ffc142014-06-30 16:47:34 -0700131 private void triggerViewsReady(final ArrayMap<String, View> sharedElements) {
132 if (mAreViewsReady) {
133 return;
134 }
135 mAreViewsReady = true;
136 // Ensure the views have been laid out before capturing the views -- we need the epicenter.
137 if (sharedElements.isEmpty() || !sharedElements.valueAt(0).isLayoutRequested()) {
138 viewsReady(sharedElements);
139 } else {
140 sharedElements.valueAt(0).getViewTreeObserver()
141 .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
142 @Override
143 public boolean onPreDraw() {
144 sharedElements.valueAt(0).getViewTreeObserver().removeOnPreDrawListener(this);
145 viewsReady(sharedElements);
146 return true;
147 }
148 });
149 }
150 }
151
George Mount1fecfb22014-06-18 14:55:55 -0700152 private ArrayMap<String, View> mapNamedElements(ArrayList<String> accepted,
153 ArrayList<String> localNames) {
154 ArrayMap<String, View> sharedElements = new ArrayMap<String, View>();
155 getDecor().findNamedViews(sharedElements);
156 if (accepted != null) {
157 for (int i = 0; i < localNames.size(); i++) {
158 String localName = localNames.get(i);
159 String acceptedName = accepted.get(i);
160 if (localName != null && !localName.equals(acceptedName)) {
161 View view = sharedElements.remove(localName);
162 if (view != null) {
163 sharedElements.put(acceptedName, view);
164 }
165 }
166 }
167 }
168 return sharedElements;
169 }
170
George Mountd265bd72014-06-02 07:22:59 -0700171 private void sendSharedElementDestination() {
George Mountfe361d22014-07-08 17:25:25 -0700172 boolean allReady;
Dake Gu872efe42014-08-29 15:24:58 -0700173 if (allowOverlappingTransitions() && getEnterViewsTransition() != null) {
George Mountfe361d22014-07-08 17:25:25 -0700174 allReady = false;
175 } else {
176 allReady = !getDecor().isLayoutRequested();
177 if (allReady) {
178 for (int i = 0; i < mSharedElements.size(); i++) {
179 if (mSharedElements.get(i).isLayoutRequested()) {
180 allReady = false;
181 break;
182 }
George Mount67d92432014-06-06 13:34:20 -0700183 }
184 }
185 }
186 if (allReady) {
George Mountc93ca162014-05-23 19:21:36 -0700187 Bundle state = captureSharedElementState();
George Mountfe361d22014-07-08 17:25:25 -0700188 setSharedElementMatrices();
189 moveSharedElementsToOverlay();
George Mountc93ca162014-05-23 19:21:36 -0700190 mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state);
George Mountd265bd72014-06-02 07:22:59 -0700191 } else {
192 getDecor().getViewTreeObserver()
193 .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
194 @Override
195 public boolean onPreDraw() {
196 getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
George Mount67d92432014-06-06 13:34:20 -0700197 Bundle state = captureSharedElementState();
George Mountfe361d22014-07-08 17:25:25 -0700198 setSharedElementMatrices();
199 moveSharedElementsToOverlay();
George Mount67d92432014-06-06 13:34:20 -0700200 mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state);
George Mountd265bd72014-06-02 07:22:59 -0700201 return true;
202 }
203 });
George Mount31a21722014-03-24 17:44:36 -0700204 }
George Mount13ccb792014-06-06 17:02:20 -0700205 if (allowOverlappingTransitions()) {
206 startEnterTransitionOnly();
207 }
George Mount31a21722014-03-24 17:44:36 -0700208 }
209
George Mount8c2614c2014-06-10 11:12:01 -0700210 private static SharedElementListener getListener(Activity activity, boolean isReturning) {
George Mount800d72b2014-05-19 07:09:00 -0700211 return isReturning ? activity.mExitTransitionListener : activity.mEnterTransitionListener;
212 }
213
George Mount31a21722014-03-24 17:44:36 -0700214 @Override
George Mount62ab9b72014-05-02 13:51:17 -0700215 protected void onReceiveResult(int resultCode, Bundle resultData) {
216 switch (resultCode) {
217 case MSG_TAKE_SHARED_ELEMENTS:
218 if (!mIsCanceled) {
George Mount8c2614c2014-06-10 11:12:01 -0700219 mSharedElementsBundle = resultData;
220 onTakeSharedElements();
George Mount62ab9b72014-05-02 13:51:17 -0700221 }
222 break;
223 case MSG_EXIT_TRANSITION_COMPLETE:
224 if (!mIsCanceled) {
George Mountc93ca162014-05-23 19:21:36 -0700225 mIsExitTransitionComplete = true;
226 if (mSharedElementTransitionStarted) {
George Mount62ab9b72014-05-02 13:51:17 -0700227 onRemoteExitTransitionComplete();
228 }
229 }
230 break;
231 case MSG_CANCEL:
232 cancel();
233 break;
234 }
George Mount31a21722014-03-24 17:44:36 -0700235 }
236
George Mount62ab9b72014-05-02 13:51:17 -0700237 private void cancel() {
238 if (!mIsCanceled) {
239 mIsCanceled = true;
George Mount8d3cd2c2014-07-08 11:07:33 -0700240 if (getViewsTransition() == null || mIsViewsTransitionStarted) {
George Mountb5ef7f82014-07-09 14:55:03 -0700241 setTransitionAlpha(mSharedElements, 1);
George Mount62ab9b72014-05-02 13:51:17 -0700242 } else {
243 mTransitioningViews.addAll(mSharedElements);
244 }
245 mSharedElementNames.clear();
246 mSharedElements.clear();
247 mAllSharedElementNames.clear();
George Mount8c2614c2014-06-10 11:12:01 -0700248 startSharedElementTransition(null);
George Mount62ab9b72014-05-02 13:51:17 -0700249 onRemoteExitTransitionComplete();
250 }
George Mount31a21722014-03-24 17:44:36 -0700251 }
252
George Mount62ab9b72014-05-02 13:51:17 -0700253 public boolean isReturning() {
254 return mIsReturning;
George Mount31a21722014-03-24 17:44:36 -0700255 }
256
George Mount62ab9b72014-05-02 13:51:17 -0700257 protected void prepareEnter() {
George Mount62ab9b72014-05-02 13:51:17 -0700258 mActivity.overridePendingTransition(0, 0);
259 if (!mIsReturning) {
George Mount3cc716c2014-06-12 16:35:35 -0700260 mWasOpaque = mActivity.convertToTranslucent(null, null);
George Mount62ab9b72014-05-02 13:51:17 -0700261 Drawable background = getDecor().getBackground();
262 if (background != null) {
263 getWindow().setBackgroundDrawable(null);
264 background = background.mutate();
265 background.setAlpha(0);
266 getWindow().setBackgroundDrawable(background);
267 }
268 } else {
269 mActivity = null; // all done with it now.
270 }
271 }
272
George Mounta712e8c2014-05-20 15:10:20 -0700273 @Override
274 protected Transition getViewsTransition() {
275 if (mIsReturning) {
George Mount68f96d82014-07-31 13:13:10 -0700276 return getWindow().getReenterTransition();
George Mounta712e8c2014-05-20 15:10:20 -0700277 } else {
278 return getWindow().getEnterTransition();
279 }
280 }
281
282 protected Transition getSharedElementTransition() {
283 if (mIsReturning) {
George Mount68f96d82014-07-31 13:13:10 -0700284 return getWindow().getSharedElementReenterTransition();
George Mounta712e8c2014-05-20 15:10:20 -0700285 } else {
286 return getWindow().getSharedElementEnterTransition();
287 }
288 }
289
George Mount8c2614c2014-06-10 11:12:01 -0700290 private void startSharedElementTransition(Bundle sharedElementState) {
George Mount62ab9b72014-05-02 13:51:17 -0700291 // Remove rejected shared elements
292 ArrayList<String> rejectedNames = new ArrayList<String>(mAllSharedElementNames);
293 rejectedNames.removeAll(mSharedElementNames);
294 ArrayList<View> rejectedSnapshots = createSnapshots(sharedElementState, rejectedNames);
295 mListener.handleRejectedSharedElements(rejectedSnapshots);
296 startRejectedAnimations(rejectedSnapshots);
297
298 // Now start shared element transition
299 ArrayList<View> sharedElementSnapshots = createSnapshots(sharedElementState,
300 mSharedElementNames);
George Mountb5ef7f82014-07-09 14:55:03 -0700301 setTransitionAlpha(mSharedElements, 1);
George Mountfe361d22014-07-08 17:25:25 -0700302 scheduleSetSharedElementEnd(sharedElementSnapshots);
Dake Guc18f4cc2014-07-11 17:48:37 -0700303 ArrayList<SharedElementOriginalState> originalImageViewState =
George Mount62ab9b72014-05-02 13:51:17 -0700304 setSharedElementState(sharedElementState, sharedElementSnapshots);
George Mountc93ca162014-05-23 19:21:36 -0700305 requestLayoutForSharedElements();
George Mount62ab9b72014-05-02 13:51:17 -0700306
George Mount13ccb792014-06-06 17:02:20 -0700307 boolean startEnterTransition = allowOverlappingTransitions() && !mIsReturning;
George Mount62ab9b72014-05-02 13:51:17 -0700308 boolean startSharedElementTransition = true;
George Mountfe361d22014-07-08 17:25:25 -0700309 setGhostVisibility(View.INVISIBLE);
310 scheduleGhostVisibilityChange(View.INVISIBLE);
George Mount62ab9b72014-05-02 13:51:17 -0700311 Transition transition = beginTransition(startEnterTransition, startSharedElementTransition);
George Mountfe361d22014-07-08 17:25:25 -0700312 scheduleGhostVisibilityChange(View.VISIBLE);
313 setGhostVisibility(View.VISIBLE);
George Mount62ab9b72014-05-02 13:51:17 -0700314
315 if (startEnterTransition) {
316 startEnterTransition(transition);
317 }
318
Dake Guc18f4cc2014-07-11 17:48:37 -0700319 setOriginalSharedElementState(mSharedElements, originalImageViewState);
George Mount62ab9b72014-05-02 13:51:17 -0700320
321 if (mResultReceiver != null) {
George Mounte678ab62014-06-30 15:28:28 -0700322 // We can't trust that the view will disappear on the same frame that the shared
323 // element appears here. Assure that we get at least 2 frames for double-buffering.
324 getDecor().postOnAnimation(new Runnable() {
325 int mAnimations;
326 @Override
327 public void run() {
328 if (mAnimations++ < MIN_ANIMATION_FRAMES) {
329 getDecor().postOnAnimation(this);
George Mount407d1fa2014-08-28 16:11:49 -0700330 } else if (mResultReceiver != null) {
George Mounte678ab62014-06-30 15:28:28 -0700331 mResultReceiver.send(MSG_HIDE_SHARED_ELEMENTS, null);
332 mResultReceiver = null; // all done sending messages.
333 }
334 }
335 });
George Mount62ab9b72014-05-02 13:51:17 -0700336 }
George Mount62ab9b72014-05-02 13:51:17 -0700337 }
338
George Mount13ccb792014-06-06 17:02:20 -0700339 private void onTakeSharedElements() {
340 if (!mIsReadyForTransition || mSharedElementsBundle == null) {
341 return;
342 }
343 final Bundle sharedElementState = mSharedElementsBundle;
344 mSharedElementsBundle = null;
345 getDecor().getViewTreeObserver()
346 .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
347 @Override
348 public boolean onPreDraw() {
349 getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
350 startTransition(new Runnable() {
351 @Override
352 public void run() {
353 startSharedElementTransition(sharedElementState);
354 }
355 });
356 return false;
357 }
358 });
359 getDecor().invalidate();
360 }
361
George Mountc93ca162014-05-23 19:21:36 -0700362 private void requestLayoutForSharedElements() {
363 int numSharedElements = mSharedElements.size();
364 for (int i = 0; i < numSharedElements; i++) {
365 mSharedElements.get(i).requestLayout();
366 }
367 }
368
George Mount62ab9b72014-05-02 13:51:17 -0700369 private Transition beginTransition(boolean startEnterTransition,
370 boolean startSharedElementTransition) {
371 Transition sharedElementTransition = null;
George Mountc93ca162014-05-23 19:21:36 -0700372 if (startSharedElementTransition) {
George Mountfe361d22014-07-08 17:25:25 -0700373 if (!mSharedElementNames.isEmpty()) {
374 sharedElementTransition = configureTransition(getSharedElementTransition(), false);
375 }
376 if (sharedElementTransition == null) {
George Mountc93ca162014-05-23 19:21:36 -0700377 sharedElementTransitionStarted();
George Mountfe361d22014-07-08 17:25:25 -0700378 sharedElementTransitionComplete();
George Mountc93ca162014-05-23 19:21:36 -0700379 } else {
George Mountfe361d22014-07-08 17:25:25 -0700380 sharedElementTransition.addListener(new Transition.TransitionListenerAdapter() {
George Mountc93ca162014-05-23 19:21:36 -0700381 @Override
382 public void onTransitionStart(Transition transition) {
George Mountc93ca162014-05-23 19:21:36 -0700383 sharedElementTransitionStarted();
384 }
George Mountfe361d22014-07-08 17:25:25 -0700385
386 @Override
387 public void onTransitionEnd(Transition transition) {
388 transition.removeListener(this);
389 sharedElementTransitionComplete();
390 }
George Mountc93ca162014-05-23 19:21:36 -0700391 });
392 }
393 }
George Mountfe361d22014-07-08 17:25:25 -0700394 Transition viewsTransition = null;
395 if (startEnterTransition) {
396 mIsViewsTransitionStarted = true;
397 if (!mTransitioningViews.isEmpty()) {
398 viewsTransition = configureTransition(getViewsTransition(), true);
399 if (viewsTransition != null && !mIsReturning) {
400 stripOffscreenViews();
401 }
George Mount13ccb792014-06-06 17:02:20 -0700402 }
George Mountfe361d22014-07-08 17:25:25 -0700403 if (viewsTransition == null) {
404 viewTransitionComplete();
405 } else {
406 viewsTransition.forceVisibility(View.INVISIBLE, true);
George Mountfe361d22014-07-08 17:25:25 -0700407 viewsTransition.addListener(new ContinueTransitionListener() {
408 @Override
George Mounta2bbbb32014-08-12 10:16:20 -0700409 public void onTransitionStart(Transition transition) {
410 mEnterViewsTransition = transition;
411 setTransitionAlpha(mTransitioningViews, 1);
412 super.onTransitionStart(transition);
413 }
414
415 @Override
George Mountfe361d22014-07-08 17:25:25 -0700416 public void onTransitionEnd(Transition transition) {
George Mounta2bbbb32014-08-12 10:16:20 -0700417 mEnterViewsTransition = null;
George Mountfe361d22014-07-08 17:25:25 -0700418 transition.removeListener(this);
419 viewTransitionComplete();
420 super.onTransitionEnd(transition);
421 }
422 });
423 }
424 }
425
426 Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
427 if (transition != null) {
428 transition.addListener(new ContinueTransitionListener());
George Mount62ab9b72014-05-02 13:51:17 -0700429 TransitionManager.beginDelayedTransition(getDecor(), transition);
430 if (startSharedElementTransition && !mSharedElementNames.isEmpty()) {
431 mSharedElements.get(0).invalidate();
432 } else if (startEnterTransition && !mTransitioningViews.isEmpty()) {
433 mTransitioningViews.get(0).invalidate();
434 }
George Mount13ccb792014-06-06 17:02:20 -0700435 } else {
436 transitionStarted();
George Mount62ab9b72014-05-02 13:51:17 -0700437 }
438 return transition;
439 }
440
George Mountfe361d22014-07-08 17:25:25 -0700441 private void viewTransitionComplete() {
442 mIsViewsTransitionComplete = true;
443 if (mIsSharedElementTransitionComplete) {
444 moveSharedElementsFromOverlay();
445 }
446 }
447
448 private void sharedElementTransitionComplete() {
449 mIsSharedElementTransitionComplete = true;
450 if (mIsViewsTransitionComplete) {
451 moveSharedElementsFromOverlay();
452 }
453 }
454
George Mountc93ca162014-05-23 19:21:36 -0700455 private void sharedElementTransitionStarted() {
456 mSharedElementTransitionStarted = true;
457 if (mIsExitTransitionComplete) {
458 send(MSG_EXIT_TRANSITION_COMPLETE, null);
459 }
460 }
461
George Mount62ab9b72014-05-02 13:51:17 -0700462 private void startEnterTransition(Transition transition) {
George Mount62ab9b72014-05-02 13:51:17 -0700463 if (!mIsReturning) {
464 Drawable background = getDecor().getBackground();
465 if (background != null) {
466 background = background.mutate();
George Mount8cab50a2014-05-15 09:57:17 -0700467 mBackgroundAnimator = ObjectAnimator.ofInt(background, "alpha", 255);
George Mounted1e01d2014-06-05 13:49:12 -0700468 mBackgroundAnimator.setDuration(getFadeDuration());
George Mount8cab50a2014-05-15 09:57:17 -0700469 mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
George Mount62ab9b72014-05-02 13:51:17 -0700470 @Override
471 public void onAnimationEnd(Animator animation) {
472 makeOpaque();
473 }
474 });
George Mount8cab50a2014-05-15 09:57:17 -0700475 mBackgroundAnimator.start();
George Mount62ab9b72014-05-02 13:51:17 -0700476 } else if (transition != null) {
477 transition.addListener(new Transition.TransitionListenerAdapter() {
478 @Override
479 public void onTransitionEnd(Transition transition) {
480 transition.removeListener(this);
481 makeOpaque();
482 }
483 });
484 } else {
485 makeOpaque();
486 }
487 }
488 }
489
490 public void stop() {
George Mount8c2614c2014-06-10 11:12:01 -0700491 makeOpaque();
George Mount700db2a2014-07-07 17:17:49 -0700492 mIsCanceled = true;
493 mResultReceiver = null;
494 if (mBackgroundAnimator != null) {
495 mBackgroundAnimator.end();
496 mBackgroundAnimator = null;
497 }
498 mActivity = null;
George Mountfe361d22014-07-08 17:25:25 -0700499 moveSharedElementsFromOverlay();
George Mount700db2a2014-07-07 17:17:49 -0700500 clearState();
501 }
502
503 public void cancelEnter() {
George Mountfe361d22014-07-08 17:25:25 -0700504 setGhostVisibility(View.INVISIBLE);
George Mount62ab9b72014-05-02 13:51:17 -0700505 mHasStopped = true;
George Mount62ab9b72014-05-02 13:51:17 -0700506 mIsCanceled = true;
507 mResultReceiver = null;
George Mount8cab50a2014-05-15 09:57:17 -0700508 if (mBackgroundAnimator != null) {
509 mBackgroundAnimator.cancel();
510 mBackgroundAnimator = null;
511 }
George Mount700db2a2014-07-07 17:17:49 -0700512 mActivity = null;
513 clearState();
George Mount62ab9b72014-05-02 13:51:17 -0700514 }
515
516 private void makeOpaque() {
George Mount8c2614c2014-06-10 11:12:01 -0700517 if (!mHasStopped && mActivity != null) {
George Mount3cc716c2014-06-12 16:35:35 -0700518 if (mWasOpaque) {
519 mActivity.convertFromTranslucent();
520 }
George Mount62ab9b72014-05-02 13:51:17 -0700521 mActivity = null;
522 }
523 }
524
525 private boolean allowOverlappingTransitions() {
526 return mIsReturning ? getWindow().getAllowExitTransitionOverlap()
527 : getWindow().getAllowEnterTransitionOverlap();
528 }
529
530 private void startRejectedAnimations(final ArrayList<View> rejectedSnapshots) {
531 if (rejectedSnapshots == null || rejectedSnapshots.isEmpty()) {
532 return;
533 }
534 ViewGroupOverlay overlay = getDecor().getOverlay();
535 ObjectAnimator animator = null;
536 int numRejected = rejectedSnapshots.size();
537 for (int i = 0; i < numRejected; i++) {
538 View snapshot = rejectedSnapshots.get(i);
539 overlay.add(snapshot);
540 animator = ObjectAnimator.ofFloat(snapshot, View.ALPHA, 1, 0);
541 animator.start();
542 }
543 animator.addListener(new AnimatorListenerAdapter() {
544 @Override
545 public void onAnimationEnd(Animator animation) {
546 ViewGroupOverlay overlay = getDecor().getOverlay();
547 int numRejected = rejectedSnapshots.size();
548 for (int i = 0; i < numRejected; i++) {
549 overlay.remove(rejectedSnapshots.get(i));
550 }
551 }
552 });
553 }
554
555 protected void onRemoteExitTransitionComplete() {
556 if (!allowOverlappingTransitions()) {
George Mount13ccb792014-06-06 17:02:20 -0700557 startEnterTransitionOnly();
George Mount62ab9b72014-05-02 13:51:17 -0700558 }
559 }
George Mount13ccb792014-06-06 17:02:20 -0700560
561 private void startEnterTransitionOnly() {
562 startTransition(new Runnable() {
563 @Override
564 public void run() {
George Mount13ccb792014-06-06 17:02:20 -0700565 boolean startEnterTransition = true;
566 boolean startSharedElementTransition = false;
567 Transition transition = beginTransition(startEnterTransition,
568 startSharedElementTransition);
569 startEnterTransition(transition);
570 }
571 });
572 }
George Mountfe361d22014-07-08 17:25:25 -0700573
574 private void setSharedElementMatrices() {
575 int numSharedElements = mSharedElements.size();
576 if (numSharedElements > 0) {
577 mSharedElementParentMatrices = new ArrayList<Matrix>(numSharedElements);
578 }
579 for (int i = 0; i < numSharedElements; i++) {
580 View view = mSharedElements.get(i);
581
582 // Find the location in the view's parent
583 ViewGroup parent = (ViewGroup) view.getParent();
584 Matrix matrix = new Matrix();
585 parent.transformMatrixToLocal(matrix);
586
587 mSharedElementParentMatrices.add(matrix);
588 }
589 }
590
591 @Override
592 protected void getSharedElementParentMatrix(View view, Matrix matrix) {
593 int index = mSharedElementParentMatrices == null ? -1 : mSharedElements.indexOf(view);
594 if (index < 0) {
595 super.getSharedElementParentMatrix(view, matrix);
596 } else {
597 matrix.set(mSharedElementParentMatrices.get(index));
598 }
599 }
George Mount31a21722014-03-24 17:44:36 -0700600}