diff options
-rw-r--r-- | core/java/android/app/ActivityTransitionCoordinator.java | 145 | ||||
-rw-r--r-- | core/java/android/app/EnterTransitionCoordinator.java | 160 | ||||
-rw-r--r-- | core/java/android/app/ExitTransitionCoordinator.java | 60 | ||||
-rw-r--r-- | core/java/android/transition/Transition.java | 4 | ||||
-rw-r--r-- | core/java/android/view/GhostView.java | 41 | ||||
-rw-r--r-- | core/java/android/view/View.java | 2 | ||||
-rw-r--r-- | core/java/android/view/ViewGroup.java | 2 |
7 files changed, 325 insertions, 89 deletions
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java index 75af2df..a765dd1 100644 --- a/core/java/android/app/ActivityTransitionCoordinator.java +++ b/core/java/android/app/ActivityTransitionCoordinator.java @@ -29,8 +29,11 @@ import android.os.ResultReceiver; import android.transition.Transition; import android.transition.TransitionSet; import android.util.ArrayMap; +import android.view.GhostView; import android.view.View; import android.view.ViewGroup; +import android.view.ViewGroupOverlay; +import android.view.ViewParent; import android.view.ViewTreeObserver; import android.view.Window; import android.widget.ImageView; @@ -202,6 +205,8 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { final protected boolean mIsReturning; private Runnable mPendingTransition; private boolean mIsStartingTransition; + private ArrayList<GhostViewListeners> mGhostViewListeners = + new ArrayList<GhostViewListeners>(); public ActivityTransitionCoordinator(Window window, ArrayList<String> allSharedElementNames, @@ -301,6 +306,12 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { // By adding the transition after addTarget, we prevent addTarget from // affecting transition. set.addTransition(transition); + + if (!add && mTransitioningViews != null && !mTransitioningViews.isEmpty()) { + // Allow children of excluded transitioning views, but not the views themselves + set = new TransitionSet().addTransition(set); + } + return set; } @@ -362,7 +373,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { protected abstract Transition getViewsTransition(); - private static void setSharedElementState(View view, String name, Bundle transitionArgs, + private void setSharedElementState(View view, String name, Bundle transitionArgs, Matrix tempMatrix, RectF tempRect, int[] decorLoc) { Bundle sharedElementBundle = transitionArgs.getBundle(name); if (sharedElementBundle == null) { @@ -396,9 +407,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { top -= decorLoc[1]; } else { // Find the location in the view's parent - ViewGroup parent = (ViewGroup) view.getParent(); - tempMatrix.reset(); - parent.transformMatrixToLocal(tempMatrix); + getSharedElementParentMatrix(view, tempMatrix); tempRect.set(left, top, right, bottom); tempMatrix.mapRect(tempRect); @@ -418,6 +427,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { tempRect.set(0, 0, width, height); view.getMatrix().mapRect(tempRect); + ViewGroup parent = (ViewGroup) view.getParent(); left = leftInParent - tempRect.left + parent.getScrollX(); top = topInParent - tempRect.top + parent.getScrollY(); right = left + width; @@ -435,6 +445,13 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { view.layout(x, y, x + width, y + height); } + protected void getSharedElementParentMatrix(View view, Matrix matrix) { + // Find the location in the view's parent + ViewGroup parent = (ViewGroup) view.getParent(); + matrix.reset(); + parent.transformMatrixToLocal(matrix); + } + protected ArrayList<SharedElementOriginalState> setSharedElementState( Bundle sharedElementState, final ArrayList<View> snapshots) { ArrayList<SharedElementOriginalState> originalImageState = @@ -453,19 +470,24 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { } } mListener.setSharedElementStart(mSharedElementNames, mSharedElements, snapshots); + return originalImageState; + } + + protected void notifySharedElementEnd(ArrayList<View> snapshots) { + mListener.setSharedElementEnd(mSharedElementNames, mSharedElements, snapshots); + } + protected void scheduleSetSharedElementEnd(final ArrayList<View> snapshots) { getDecor().getViewTreeObserver().addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { getDecor().getViewTreeObserver().removeOnPreDrawListener(this); - mListener.setSharedElementEnd(mSharedElementNames, mSharedElements, - snapshots); + notifySharedElementEnd(snapshots); return true; } } ); - return originalImageState; } private static SharedElementOriginalState getOldSharedElementState(View view, String name, @@ -572,8 +594,8 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { } protected static void setTransitionAlpha(ArrayList<View> views, float alpha) { - int numSharedElements = views.size(); - for (int i = 0; i < numSharedElements; i++) { + int count = views.size(); + for (int i = 0; i < count; i++) { views.get(i).setTransitionAlpha(alpha); } } @@ -639,6 +661,82 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { mIsStartingTransition = false; } + protected void moveSharedElementsToOverlay() { + int numSharedElements = mSharedElements.size(); + ViewGroup decor = getDecor(); + if (decor != null) { + boolean moveWithParent = moveSharedElementWithParent(); + for (int i = 0; i < numSharedElements; i++) { + View view = mSharedElements.get(i); + GhostView.addGhost(view, decor); + ViewGroup parent = (ViewGroup) view.getParent(); + if (moveWithParent && !isInTransitionGroup(parent, decor)) { + GhostViewListeners listener = + new GhostViewListeners(view, decor); + parent.getViewTreeObserver().addOnPreDrawListener(listener); + mGhostViewListeners.add(listener); + } + } + } + } + + protected boolean moveSharedElementWithParent() { + return true; + } + + public static boolean isInTransitionGroup(ViewParent viewParent, ViewGroup decor) { + if (viewParent == decor || !(viewParent instanceof ViewGroup)) { + return false; + } + ViewGroup parent = (ViewGroup) viewParent; + if (parent.isTransitionGroup()) { + return true; + } else { + return isInTransitionGroup(parent.getParent(), decor); + } + } + + protected void moveSharedElementsFromOverlay() { + ViewGroup decor = getDecor(); + if (decor != null) { + ViewGroupOverlay overlay = decor.getOverlay(); + int count = mSharedElements.size(); + for (int i = 0; i < count; i++) { + View sharedElement = mSharedElements.get(i); + GhostView.removeGhost(sharedElement); + } + } + int numListeners = mGhostViewListeners.size(); + for (int i = 0; i < numListeners; i++) { + GhostViewListeners listener = mGhostViewListeners.get(i); + ViewGroup parent = (ViewGroup) listener.getView().getParent(); + parent.getViewTreeObserver().removeOnPreDrawListener(listener); + } + mGhostViewListeners.clear(); + } + + protected void setGhostVisibility(int visibility) { + int numSharedElements = mSharedElements.size(); + for (int i = 0; i < numSharedElements; i++) { + GhostView ghostView = GhostView.getGhost(mSharedElements.get(i)); + if (ghostView != null) { + ghostView.setVisibility(visibility); + } + } + } + + protected void scheduleGhostVisibilityChange(final int visibility) { + getDecor().getViewTreeObserver() + .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + getDecor().getViewTreeObserver().removeOnPreDrawListener(this); + setGhostVisibility(visibility); + return true; + } + }); + } + protected class ContinueTransitionListener extends Transition.TransitionListenerAdapter { @Override public void onTransitionStart(Transition transition) { @@ -671,6 +769,34 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { } } + private static class GhostViewListeners implements ViewTreeObserver.OnPreDrawListener { + private View mView; + private ViewGroup mDecor; + private Matrix mMatrix = new Matrix(); + + public GhostViewListeners(View view, ViewGroup decor) { + mView = view; + mDecor = decor; + } + + public View getView() { + return mView; + } + + @Override + public boolean onPreDraw() { + ViewGroup parent = ((ViewGroup) mView.getParent()); + GhostView ghostView = GhostView.getGhost(mView); + if (ghostView == null) { + parent.getViewTreeObserver().removeOnPreDrawListener(this); + } else { + GhostView.calculateMatrix(mView, mDecor, mMatrix); + ghostView.setMatrix(mMatrix); + } + return true; + } + } + static class SharedElementOriginalState { int mLeft; int mTop; @@ -681,5 +807,4 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { ImageView.ScaleType mScaleType; Matrix mMatrix; } - } diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java index b5d362d..87da24a 100644 --- a/core/java/android/app/EnterTransitionCoordinator.java +++ b/core/java/android/app/EnterTransitionCoordinator.java @@ -27,12 +27,10 @@ import android.os.ResultReceiver; import android.transition.Transition; import android.transition.TransitionManager; import android.util.ArrayMap; -import android.util.Pair; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroupOverlay; import android.view.ViewTreeObserver; -import android.widget.ImageView; import java.util.ArrayList; @@ -44,13 +42,11 @@ import java.util.ArrayList; class EnterTransitionCoordinator extends ActivityTransitionCoordinator { private static final String TAG = "EnterTransitionCoordinator"; - private static final long MAX_WAIT_MS = 1000; private static final int MIN_ANIMATION_FRAMES = 2; private boolean mSharedElementTransitionStarted; private Activity mActivity; private boolean mHasStopped; - private Handler mHandler; private boolean mIsCanceled; private ObjectAnimator mBackgroundAnimator; private boolean mIsExitTransitionComplete; @@ -59,6 +55,9 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { private boolean mWasOpaque; private boolean mAreViewsReady; private boolean mIsViewsTransitionStarted; + private boolean mIsViewsTransitionComplete; + private boolean mIsSharedElementTransitionComplete; + private ArrayList<Matrix> mSharedElementParentMatrices; public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver, ArrayList<String> sharedElementNames, boolean isReturning) { @@ -94,20 +93,16 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { protected void viewsReady(ArrayMap<String, View> sharedElements) { super.viewsReady(sharedElements); mIsReadyForTransition = true; - if (mIsReturning) { - mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - cancel(); - } - }; - mHandler.sendEmptyMessageDelayed(MSG_CANCEL, MAX_WAIT_MS); - send(MSG_SEND_SHARED_ELEMENT_DESTINATION, null); - } setTransitionAlpha(mSharedElements, 0); if (getViewsTransition() != null) { setTransitionAlpha(mTransitioningViews, 0); } + if (mIsReturning) { + sendSharedElementDestination(); + } else { + setSharedElementMatrices(); + moveSharedElementsToOverlay(); + } if (mSharedElementsBundle != null) { onTakeSharedElements(); } @@ -154,18 +149,24 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { } private void sendSharedElementDestination() { - ViewGroup decor = getDecor(); - boolean allReady = !decor.isLayoutRequested(); - if (allReady) { - for (int i = 0; i < mSharedElements.size(); i++) { - if (mSharedElements.get(i).isLayoutRequested()) { - allReady = false; - break; + boolean allReady; + if (allowOverlappingTransitions()) { + allReady = false; + } else { + allReady = !getDecor().isLayoutRequested(); + if (allReady) { + for (int i = 0; i < mSharedElements.size(); i++) { + if (mSharedElements.get(i).isLayoutRequested()) { + allReady = false; + break; + } } } } if (allReady) { Bundle state = captureSharedElementState(); + setSharedElementMatrices(); + moveSharedElementsToOverlay(); mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state); } else { getDecor().getViewTreeObserver() @@ -174,6 +175,8 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { public boolean onPreDraw() { getDecor().getViewTreeObserver().removeOnPreDrawListener(this); Bundle state = captureSharedElementState(); + setSharedElementMatrices(); + moveSharedElementsToOverlay(); mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state); return true; } @@ -193,9 +196,6 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { switch (resultCode) { case MSG_TAKE_SHARED_ELEMENTS: if (!mIsCanceled) { - if (mHandler != null) { - mHandler.removeMessages(MSG_CANCEL); - } mSharedElementsBundle = resultData; onTakeSharedElements(); } @@ -211,9 +211,6 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { case MSG_CANCEL: cancel(); break; - case MSG_SEND_SHARED_ELEMENT_DESTINATION: - sendSharedElementDestination(); - break; } } @@ -282,13 +279,18 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { ArrayList<View> sharedElementSnapshots = createSnapshots(sharedElementState, mSharedElementNames); setTransitionAlpha(mSharedElements, 1); + scheduleSetSharedElementEnd(sharedElementSnapshots); ArrayList<SharedElementOriginalState> originalImageViewState = setSharedElementState(sharedElementState, sharedElementSnapshots); requestLayoutForSharedElements(); boolean startEnterTransition = allowOverlappingTransitions() && !mIsReturning; boolean startSharedElementTransition = true; + setGhostVisibility(View.INVISIBLE); + scheduleGhostVisibilityChange(View.INVISIBLE); Transition transition = beginTransition(startEnterTransition, startSharedElementTransition); + scheduleGhostVisibilityChange(View.VISIBLE); + setGhostVisibility(View.VISIBLE); if (startEnterTransition) { startEnterTransition(transition); @@ -347,39 +349,56 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { private Transition beginTransition(boolean startEnterTransition, boolean startSharedElementTransition) { Transition sharedElementTransition = null; - if (startSharedElementTransition && !mSharedElementNames.isEmpty()) { - sharedElementTransition = configureTransition(getSharedElementTransition(), false); - } - Transition viewsTransition = null; - if (startEnterTransition && !mTransitioningViews.isEmpty()) { - viewsTransition = configureTransition(getViewsTransition(), true); - if (viewsTransition != null) { - stripOffscreenViews(); - viewsTransition.forceVisibility(View.INVISIBLE, true); - setTransitionAlpha(mTransitioningViews, 1); - } - } - mIsViewsTransitionStarted = mIsViewsTransitionStarted || startEnterTransition; - - Transition transition = mergeTransitions(sharedElementTransition, viewsTransition); if (startSharedElementTransition) { - if (transition == null) { + if (!mSharedElementNames.isEmpty()) { + sharedElementTransition = configureTransition(getSharedElementTransition(), false); + } + if (sharedElementTransition == null) { sharedElementTransitionStarted(); + sharedElementTransitionComplete(); } else { - transition.addListener(new ContinueTransitionListener() { + sharedElementTransition.addListener(new Transition.TransitionListenerAdapter() { @Override public void onTransitionStart(Transition transition) { - super.onTransitionStart(transition); - transition.removeListener(this); sharedElementTransitionStarted(); } + + @Override + public void onTransitionEnd(Transition transition) { + transition.removeListener(this); + sharedElementTransitionComplete(); + } }); } } - if (transition != null) { - if (sharedElementTransition == null) { - transition.addListener(new ContinueTransitionListener()); + Transition viewsTransition = null; + if (startEnterTransition) { + mIsViewsTransitionStarted = true; + if (!mTransitioningViews.isEmpty()) { + viewsTransition = configureTransition(getViewsTransition(), true); + if (viewsTransition != null && !mIsReturning) { + stripOffscreenViews(); + } } + if (viewsTransition == null) { + viewTransitionComplete(); + } else { + viewsTransition.forceVisibility(View.INVISIBLE, true); + setTransitionAlpha(mTransitioningViews, 1); + viewsTransition.addListener(new ContinueTransitionListener() { + @Override + public void onTransitionEnd(Transition transition) { + transition.removeListener(this); + viewTransitionComplete(); + super.onTransitionEnd(transition); + } + }); + } + } + + Transition transition = mergeTransitions(sharedElementTransition, viewsTransition); + if (transition != null) { + transition.addListener(new ContinueTransitionListener()); TransitionManager.beginDelayedTransition(getDecor(), transition); if (startSharedElementTransition && !mSharedElementNames.isEmpty()) { mSharedElements.get(0).invalidate(); @@ -392,6 +411,20 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { return transition; } + private void viewTransitionComplete() { + mIsViewsTransitionComplete = true; + if (mIsSharedElementTransitionComplete) { + moveSharedElementsFromOverlay(); + } + } + + private void sharedElementTransitionComplete() { + mIsSharedElementTransitionComplete = true; + if (mIsViewsTransitionComplete) { + moveSharedElementsFromOverlay(); + } + } + private void sharedElementTransitionStarted() { mSharedElementTransitionStarted = true; if (mIsExitTransitionComplete) { @@ -436,10 +469,12 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { mBackgroundAnimator = null; } mActivity = null; + moveSharedElementsFromOverlay(); clearState(); } public void cancelEnter() { + setGhostVisibility(View.INVISIBLE); mHasStopped = true; mIsCanceled = true; mResultReceiver = null; @@ -508,4 +543,31 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { } }); } + + private void setSharedElementMatrices() { + int numSharedElements = mSharedElements.size(); + if (numSharedElements > 0) { + mSharedElementParentMatrices = new ArrayList<Matrix>(numSharedElements); + } + for (int i = 0; i < numSharedElements; i++) { + View view = mSharedElements.get(i); + + // Find the location in the view's parent + ViewGroup parent = (ViewGroup) view.getParent(); + Matrix matrix = new Matrix(); + parent.transformMatrixToLocal(matrix); + + mSharedElementParentMatrices.add(matrix); + } + } + + @Override + protected void getSharedElementParentMatrix(View view, Matrix matrix) { + int index = mSharedElementParentMatrices == null ? -1 : mSharedElements.indexOf(view); + if (index < 0) { + super.getSharedElementParentMatrix(view, matrix); + } else { + matrix.set(mSharedElementParentMatrices.get(index)); + } + } } diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java index b3fdcc7..43b9ea8 100644 --- a/core/java/android/app/ExitTransitionCoordinator.java +++ b/core/java/android/app/ExitTransitionCoordinator.java @@ -71,8 +71,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { public ExitTransitionCoordinator(Activity activity, ArrayList<String> names, ArrayList<String> accepted, ArrayList<View> mapped, boolean isReturning) { - super(activity.getWindow(), names, getListener(activity, isReturning), - isReturning); + super(activity.getWindow(), names, getListener(activity, isReturning), isReturning); viewsReady(mapSharedElements(accepted, mapped)); stripOffscreenViews(); mIsBackgroundReady = !isReturning; @@ -87,23 +86,23 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { protected void onReceiveResult(int resultCode, Bundle resultData) { switch (resultCode) { case MSG_SET_REMOTE_RECEIVER: + stopCancel(); mResultReceiver = resultData.getParcelable(KEY_REMOTE_RECEIVER); if (mIsCanceled) { mResultReceiver.send(MSG_CANCEL, null); mResultReceiver = null; } else { - if (mHandler != null) { - mHandler.removeMessages(MSG_CANCEL); - } notifyComplete(); } break; case MSG_HIDE_SHARED_ELEMENTS: + stopCancel(); if (!mIsCanceled) { hideSharedElements(); } break; case MSG_START_EXIT_TRANSITION: + mHandler.removeMessages(MSG_CANCEL); startExit(); break; case MSG_SHARED_ELEMENT_DESTINATION: @@ -113,6 +112,18 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { } } + private void stopCancel() { + if (mHandler != null) { + mHandler.removeMessages(MSG_CANCEL); + } + } + + private void delayCancel() { + if (mHandler != null) { + mHandler.sendEmptyMessageDelayed(MSG_CANCEL, MAX_WAIT_MS); + } + } + public void resetViews() { setTransitionAlpha(mTransitioningViews, 1); setTransitionAlpha(mSharedElements, 1); @@ -120,6 +131,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { if (!mIsReturning && getDecor() != null) { getDecor().suppressLayout(false); } + moveSharedElementsFromOverlay(); clearState(); } @@ -140,6 +152,15 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { private void startSharedElementExit() { Transition transition = getSharedElementExitTransition(); + transition.addListener(new Transition.TransitionListenerAdapter() { + @Override + public void onTransitionEnd(Transition transition) { + transition.removeListener(this); + if (mExitComplete) { + delayCancel(); + } + } + }); final ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle, mSharedElementNames); getDecor().getViewTreeObserver() @@ -151,11 +172,16 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { return true; } }); + setGhostVisibility(View.INVISIBLE); + scheduleGhostVisibilityChange(View.INVISIBLE); TransitionManager.beginDelayedTransition(getDecor(), transition); + scheduleGhostVisibilityChange(View.VISIBLE); + setGhostVisibility(View.VISIBLE); getDecor().invalidate(); } private void hideSharedElements() { + moveSharedElementsFromOverlay(); if (!mIsHidden) { setTransitionAlpha(mSharedElements, 0); } @@ -169,6 +195,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { if (getDecor() != null) { getDecor().suppressLayout(true); } + moveSharedElementsToOverlay(); startTransition(new Runnable() { @Override public void run() { @@ -191,7 +218,8 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { finish(); } }; - mHandler.sendEmptyMessageDelayed(MSG_CANCEL, MAX_WAIT_MS); + delayCancel(); + moveSharedElementsToOverlay(); if (getDecor().getBackground() == null) { ColorDrawable black = new ColorDrawable(0xFF000000); black.setAlpha(0); @@ -267,11 +295,10 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { if (mIsHidden) { setTransitionAlpha(mTransitioningViews, 1); } - } - - @Override - public void onTransitionCancel(Transition transition) { - super.onTransitionCancel(transition); + if (mSharedElementBundle != null) { + delayCancel(); + } + super.onTransitionEnd(transition); } }); viewsTransition.forceVisibility(View.INVISIBLE, false); @@ -308,7 +335,11 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { Transition transition = mergeTransitions(sharedElementTransition, viewsTransition); if (transition != null) { + setGhostVisibility(View.INVISIBLE); + scheduleGhostVisibilityChange(View.INVISIBLE); TransitionManager.beginDelayedTransition(getDecor(), transition); + scheduleGhostVisibilityChange(View.VISIBLE); + setGhostVisibility(View.VISIBLE); getDecor().invalidate(); } else { transitionStarted(); @@ -351,6 +382,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { if (isReadyToNotify()) { if (!mSharedElementNotified) { mSharedElementNotified = true; + delayCancel(); mResultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, mSharedElementBundle); } if (!mExitNotified && mExitComplete) { @@ -376,6 +408,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { } private void finish() { + stopCancel(); mActivity.mActivityTransitionState.clear(); // Clear the state so that we can't hold any references accidentally and leak memory. mHandler.removeMessages(MSG_CANCEL); @@ -393,6 +426,11 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { } @Override + protected boolean moveSharedElementWithParent() { + return !mIsReturning; + } + + @Override protected Transition getViewsTransition() { if (mIsReturning) { return getWindow().getReturnTransition(); diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java index 53220d0..2fa8d2a 100644 --- a/core/java/android/transition/Transition.java +++ b/core/java/android/transition/Transition.java @@ -1686,12 +1686,12 @@ public abstract class Transition implements Cloneable { void playTransition(ViewGroup sceneRoot) { ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators(); int numOldAnims = runningAnimators.size(); + WindowId windowId = sceneRoot.getWindowId(); for (int i = numOldAnims - 1; i >= 0; i--) { Animator anim = runningAnimators.keyAt(i); if (anim != null) { AnimationInfo oldInfo = runningAnimators.get(anim); - if (oldInfo != null && oldInfo.view != null && - oldInfo.view.getContext() == sceneRoot.getContext()) { + if (oldInfo != null && oldInfo.view != null && oldInfo.windowId == windowId) { TransitionValues oldValues = oldInfo.values; View oldView = oldInfo.view; TransitionValues newValues = mEndValues.viewValues.get(oldView); diff --git a/core/java/android/view/GhostView.java b/core/java/android/view/GhostView.java index 1aa8d99..a79838f 100644 --- a/core/java/android/view/GhostView.java +++ b/core/java/android/view/GhostView.java @@ -27,14 +27,13 @@ import android.graphics.Matrix; * @hide */ public class GhostView extends View { - private final Matrix mMatrix = new Matrix(); private final View mView; - private GhostView(View view, ViewGroup host) { + private GhostView(View view, ViewGroup host, Matrix matrix) { super(view.getContext()); mView = view; - setMatrix(host); mView.mGhostView = this; + mRenderNode.setAnimationMatrix(matrix); final ViewGroup parent = (ViewGroup) mView.getParent(); setLeft(0); setTop(0); @@ -49,17 +48,18 @@ public class GhostView extends View { protected void onDraw(Canvas canvas) { if (canvas instanceof HardwareCanvas) { HardwareCanvas hwCanvas = (HardwareCanvas) canvas; - int saveCount = hwCanvas.save(Canvas.MATRIX_SAVE_FLAG); - canvas.concat(mMatrix); mView.mRecreateDisplayList = true; RenderNode renderNode = mView.getDisplayList(); if (renderNode.isValid()) { hwCanvas.drawRenderNode(renderNode); } - hwCanvas.restoreToCount(saveCount); } } + public void setMatrix(Matrix matrix) { + mRenderNode.setAnimationMatrix(matrix); + } + @Override public void setVisibility(@Visibility int visibility) { super.setVisibility(visibility); @@ -79,18 +79,21 @@ public class GhostView extends View { setGhostedVisibility(View.VISIBLE); mView.mGhostView = null; final ViewGroup parent = (ViewGroup) mView.getParent(); - parent.mRecreateDisplayList = true; - parent.getDisplayList(); + if (parent != null) { + parent.mRecreateDisplayList = true; + parent.getDisplayList(); + } } - private void setMatrix(ViewGroup host) { - host.transformMatrixToLocal(mMatrix); - ViewGroup parent = (ViewGroup) mView.getParent(); - parent.transformMatrixToGlobal(mMatrix); - mMatrix.postTranslate(-parent.getScrollX(), -parent.getScrollY()); + public static void calculateMatrix(View view, ViewGroup host, Matrix matrix) { + ViewGroup parent = (ViewGroup) view.getParent(); + matrix.reset(); + parent.transformMatrixToGlobal(matrix); + matrix.preTranslate(-parent.getScrollX(), -parent.getScrollY()); + host.transformMatrixToLocal(matrix); } - public static GhostView addGhost(View view, ViewGroup viewGroup) { + public static GhostView addGhost(View view, ViewGroup viewGroup, Matrix matrix) { if (!(view.getParent() instanceof ViewGroup)) { throw new IllegalArgumentException("Ghosted views must be parented by a ViewGroup"); } @@ -105,12 +108,20 @@ public class GhostView extends View { } } if (ghostView == null) { - ghostView = new GhostView(view, (ViewGroup) overlayViewGroup.mHostView); + if (matrix == null) { + matrix = new Matrix(); + calculateMatrix(view, viewGroup, matrix); + } + ghostView = new GhostView(view, (ViewGroup) overlayViewGroup.mHostView, matrix); overlay.add(ghostView); } return ghostView; } + public static GhostView addGhost(View view, ViewGroup viewGroup) { + return addGhost(view, viewGroup, null); + } + public static void removeGhost(View view) { GhostView ghostView = view.mGhostView; if (ghostView != null) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 8c2048d..11ebc9c 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -19007,7 +19007,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @hide */ public void findNamedViews(Map<String, View> namedElements) { - if (getVisibility() == VISIBLE) { + if (getVisibility() == VISIBLE || mGhostView != null) { String transitionName = getTransitionName(); if (transitionName != null) { namedElements.put(transitionName, this); diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 77f4b90..7f15381 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -6123,7 +6123,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager /** @hide */ @Override public void findNamedViews(Map<String, View> namedElements) { - if (getVisibility() != VISIBLE) { + if (getVisibility() != VISIBLE && mGhostView == null) { return; } super.findNamedViews(namedElements); |