summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/ActivityTransitionCoordinator.java145
-rw-r--r--core/java/android/app/EnterTransitionCoordinator.java160
-rw-r--r--core/java/android/app/ExitTransitionCoordinator.java60
-rw-r--r--core/java/android/transition/Transition.java4
-rw-r--r--core/java/android/view/GhostView.java41
-rw-r--r--core/java/android/view/View.java2
-rw-r--r--core/java/android/view/ViewGroup.java2
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);