diff --git a/api/current.txt b/api/current.txt index 1e57d19edc557..5e81c3946bc11 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5310,6 +5310,11 @@ package android.app { method public void onRejectSharedElements(java.util.List); method public void onSharedElementEnd(java.util.List, java.util.List, java.util.List); method public void onSharedElementStart(java.util.List, java.util.List, java.util.List); + method public void onSharedElementsArrived(java.util.List, java.util.List, android.app.SharedElementCallback.OnSharedElementsReadyListener); + } + + public static abstract interface SharedElementCallback.OnSharedElementsReadyListener { + method public abstract void onSharedElementsReady(); } public deprecated class TabActivity extends android.app.ActivityGroup { diff --git a/api/system-current.txt b/api/system-current.txt index 544cbb3069bb8..1b07b1db48814 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5401,6 +5401,11 @@ package android.app { method public void onRejectSharedElements(java.util.List); method public void onSharedElementEnd(java.util.List, java.util.List, java.util.List); method public void onSharedElementStart(java.util.List, java.util.List, java.util.List); + method public void onSharedElementsArrived(java.util.List, java.util.List, android.app.SharedElementCallback.OnSharedElementsReadyListener); + } + + public static abstract interface SharedElementCallback.OnSharedElementsReadyListener { + method public abstract void onSharedElementsReady(); } public deprecated class TabActivity extends android.app.ActivityGroup { diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java index c053c830adfc7..e84a8dabf3b7d 100644 --- a/core/java/android/app/EnterTransitionCoordinator.java +++ b/core/java/android/app/EnterTransitionCoordinator.java @@ -18,6 +18,7 @@ package android.app; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; +import android.app.SharedElementCallback.OnSharedElementsReadyListener; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.ResultReceiver; @@ -140,13 +141,13 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { } else { decor.getViewTreeObserver() .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - decor.getViewTreeObserver().removeOnPreDrawListener(this); - viewsReady(sharedElements); - return true; - } - }); + @Override + public boolean onPreDraw() { + decor.getViewTreeObserver().removeOnPreDrawListener(this); + viewsReady(sharedElements); + return true; + } + }); } } @@ -383,23 +384,33 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { } final Bundle sharedElementState = mSharedElementsBundle; mSharedElementsBundle = null; - final View decorView = getDecor(); - if (decorView != null) { - decorView.getViewTreeObserver() - .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - decorView.getViewTreeObserver().removeOnPreDrawListener(this); - startTransition(new Runnable() { + OnSharedElementsReadyListener listener = new OnSharedElementsReadyListener() { + @Override + public void onSharedElementsReady() { + final View decorView = getDecor(); + if (decorView != null) { + decorView.getViewTreeObserver() + .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override - public void run() { - startSharedElementTransition(sharedElementState); + public boolean onPreDraw() { + decorView.getViewTreeObserver().removeOnPreDrawListener(this); + startTransition(new Runnable() { + @Override + public void run() { + startSharedElementTransition(sharedElementState); + } + }); + return false; } }); - return false; - } - }); - decorView.invalidate(); + decorView.invalidate(); + } + } + }; + if (mListener == null) { + listener.onSharedElementsReady(); + } else { + mListener.onSharedElementsArrived(mSharedElementNames, mSharedElements, listener); } } diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java index dd3df47942ccb..169952ad1a0b0 100644 --- a/core/java/android/app/ExitTransitionCoordinator.java +++ b/core/java/android/app/ExitTransitionCoordinator.java @@ -18,6 +18,7 @@ package android.app; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; +import android.app.SharedElementCallback.OnSharedElementsReadyListener; import android.content.Intent; import android.graphics.Color; import android.graphics.Matrix; @@ -27,6 +28,7 @@ import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.os.ResultReceiver; import android.transition.Transition; import android.transition.TransitionManager; import android.view.View; @@ -408,21 +410,41 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { if (!mSharedElementNotified) { mSharedElementNotified = true; delayCancel(); - mResultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, mSharedElementBundle); - } - if (!mExitNotified && mExitComplete) { - mExitNotified = true; - mResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null); - mResultReceiver = null; // done talking - ViewGroup decorView = getDecor(); - if (!mIsReturning && decorView != null) { - decorView.suppressLayout(false); + if (mListener == null) { + mResultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, mSharedElementBundle); + notifyExitComplete(); + } else { + final ResultReceiver resultReceiver = mResultReceiver; + final Bundle sharedElementBundle = mSharedElementBundle; + mListener.onSharedElementsArrived(mSharedElementNames, mSharedElements, + new OnSharedElementsReadyListener() { + @Override + public void onSharedElementsReady() { + resultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, + sharedElementBundle); + notifyExitComplete(); + } + }); } - finishIfNecessary(); + } else { + notifyExitComplete(); } } } + private void notifyExitComplete() { + if (!mExitNotified && mExitComplete) { + mExitNotified = true; + mResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null); + mResultReceiver = null; // done talking + ViewGroup decorView = getDecor(); + if (!mIsReturning && decorView != null) { + decorView.suppressLayout(false); + } + finishIfNecessary(); + } + } + private void finishIfNecessary() { if (mIsReturning && mExitNotified && mActivity != null && (mSharedElements.isEmpty() || mSharedElementsHidden)) { diff --git a/core/java/android/app/SharedElementCallback.java b/core/java/android/app/SharedElementCallback.java index 6ac24013672c3..9c70f1d25a2cc 100644 --- a/core/java/android/app/SharedElementCallback.java +++ b/core/java/android/app/SharedElementCallback.java @@ -221,4 +221,42 @@ public abstract class SharedElementCallback { } return view; } + + /** + * Called during an Activity Transition when the shared elements have arrived at the + * final location and are ready to be transferred. This method is called for both the + * source and destination Activities. + *

+ * When the shared elements are ready to be transferred, + * {@link OnSharedElementsReadyListener#onSharedElementsReady()} + * must be called to trigger the transfer. + *

+ * The default behavior is to trigger the transfer immediately. + * + * @param sharedElementNames The names of the shared elements that are being transferred.. + * @param sharedElements The shared elements that are part of the View hierarchy. + * @param listener The listener to call when the shared elements are ready to be hidden + * in the source Activity or shown in the destination Activity. + */ + public void onSharedElementsArrived(List sharedElementNames, + List sharedElements, OnSharedElementsReadyListener listener) { + listener.onSharedElementsReady(); + } + + /** + * Listener to be called after {@link + * SharedElementCallback#onSharedElementsArrived(OnSharedElementsReadyListener)} + * when the shared elements are ready to be hidden in the source Activity and shown in the + * destination Activity. + */ + public interface OnSharedElementsReadyListener { + + /** + * Call this method during or after the OnSharedElementsReadyListener has been received + * in {@link SharedElementCallback#onSharedElementsArrived(OnSharedElementsReadyListener)} + * to indicate that the shared elements are ready to be hidden in the source and shown + * in the destination Activity. + */ + void onSharedElementsReady(); + } }