Split Activity Transitions out of PhoneWindow.

Bug 13622834
Made it possible to use shared elements without making
Views invisible.

Change-Id: I1e85c6bc19e634a9af225ad7f0309b4f003ea462
diff --git a/api/current.txt b/api/current.txt
index 7b09a85..894dabf8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1284,6 +1284,8 @@
     field public static final int windowActionBar = 16843469; // 0x10102cd
     field public static final int windowActionBarOverlay = 16843492; // 0x10102e4
     field public static final int windowActionModeOverlay = 16843485; // 0x10102dd
+    field public static final int windowAllowEnterTransitionOverlap = 16843848; // 0x1010448
+    field public static final int windowAllowExitTransitionOverlap = 16843847; // 0x1010447
     field public static final int windowAnimationStyle = 16842926; // 0x10100ae
     field public static final int windowBackground = 16842836; // 0x1010054
     field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b
@@ -1293,7 +1295,9 @@
     field public static final int windowDisablePreview = 16843298; // 0x1010222
     field public static final int windowEnableSplitTouch = 16843543; // 0x1010317
     field public static final int windowEnterAnimation = 16842932; // 0x10100b4
+    field public static final int windowEnterTransition = 16843843; // 0x1010443
     field public static final int windowExitAnimation = 16842933; // 0x10100b5
+    field public static final int windowExitTransition = 16843844; // 0x1010444
     field public static final int windowFrame = 16842837; // 0x1010055
     field public static final int windowFullscreen = 16843277; // 0x101020d
     field public static final int windowHideAnimation = 16842935; // 0x10100b7
@@ -1304,6 +1308,8 @@
     field public static final int windowNoDisplay = 16843294; // 0x101021e
     field public static final int windowNoTitle = 16842838; // 0x1010056
     field public static final int windowOverscan = 16843727; // 0x10103cf
+    field public static final int windowSharedElementEnterTransition = 16843845; // 0x1010445
+    field public static final int windowSharedElementExitTransition = 16843846; // 0x1010446
     field public static final int windowShowAnimation = 16842934; // 0x10100b6
     field public static final int windowShowWallpaper = 16843410; // 0x1010292
     field public static final int windowSoftInputMode = 16843307; // 0x101022b
@@ -2454,6 +2460,11 @@
     field public static final int l_resource_pad9 = 16974328; // 0x10301f8
   }
 
+  public static final class R.transition {
+    ctor public R.transition();
+    field public static final int no_transition = 17760256; // 0x10f0000
+  }
+
   public static final class R.xml {
     ctor public R.xml();
   }
@@ -3209,8 +3220,6 @@
     method public void onAttachFragment(android.app.Fragment);
     method public void onAttachedToWindow();
     method public void onBackPressed();
-    method public void onCaptureSharedElementEnd();
-    method public void onCaptureSharedElementStart(android.transition.Transition);
     method protected void onChildTitleChanged(android.app.Activity, java.lang.CharSequence);
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onContentChanged();
@@ -3283,6 +3292,7 @@
     method public final void runOnUiThread(java.lang.Runnable);
     method public void setActionBar(android.widget.Toolbar);
     method public void setActivityLabelAndIcon(java.lang.CharSequence, android.graphics.Bitmap);
+    method public void setActivityTransitionListener(android.app.ActivityOptions.ActivityTransitionListener);
     method public void setContentTransitionManager(android.transition.TransitionManager);
     method public void setContentView(int);
     method public void setContentView(android.view.View);
@@ -3500,13 +3510,27 @@
   public class ActivityOptions {
     method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
     method public static android.app.ActivityOptions makeScaleUpAnimation(android.view.View, int, int, int, int);
-    method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.view.View, java.lang.String);
-    method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.util.Pair<android.view.View, java.lang.String>...);
+    method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.view.Window, android.view.View, java.lang.String);
+    method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.view.Window, android.app.ActivityOptions.ActivityTransitionListener);
     method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
     method public android.os.Bundle toBundle();
     method public void update(android.app.ActivityOptions);
   }
 
+  public static class ActivityOptions.ActivityTransitionListener {
+    ctor public ActivityOptions.ActivityTransitionListener();
+    method public android.util.Pair<android.view.View, java.lang.String>[] getSharedElementsMapping();
+    method public void onCaptureSharedElementEnd();
+    method public void onCaptureSharedElementStart();
+    method public void onEnterReady();
+    method public void onExitTransitionComplete();
+    method public void onRemoteExitComplete();
+    method public void onSharedElementExitTransitionComplete();
+    method public void onSharedElementTransferred(java.util.List<java.lang.String>, java.util.List<android.view.View>);
+    method public void onStartEnterTransition(java.util.List<java.lang.String>, java.util.List<android.view.View>);
+    method public void onStartExitTransition(java.util.List<java.lang.String>, java.util.List<android.view.View>);
+  }
+
   public class AlarmManager {
     method public void cancel(android.app.PendingIntent);
     method public void set(int, long, android.app.PendingIntent);
@@ -27750,7 +27774,6 @@
     method public static void beginDelayedTransition(android.view.ViewGroup, android.transition.Transition);
     method public static void go(android.transition.Scene);
     method public static void go(android.transition.Scene, android.transition.Transition);
-    method public void setExitTransition(android.transition.Scene, android.transition.Transition);
     method public void setTransition(android.transition.Scene, android.transition.Transition);
     method public void setTransition(android.transition.Scene, android.transition.Scene, android.transition.Transition);
     method public void transitionTo(android.transition.Scene);
@@ -30787,6 +30810,8 @@
     method public abstract void closeAllPanels();
     method public abstract void closePanel(int);
     method public android.view.View findViewById(int);
+    method public boolean getAllowEnterTransitionOverlap();
+    method public boolean getAllowExitTransitionOverlap();
     method public final android.view.WindowManager.LayoutParams getAttributes();
     method public final android.view.Window.Callback getCallback();
     method public final android.view.Window getContainer();
@@ -30794,10 +30819,14 @@
     method public final android.content.Context getContext();
     method public abstract android.view.View getCurrentFocus();
     method public abstract android.view.View getDecorView();
+    method public android.transition.Transition getEnterTransition();
+    method public android.transition.Transition getExitTransition();
     method protected final int getFeatures();
     method protected final int getForcedWindowFlags();
     method public abstract android.view.LayoutInflater getLayoutInflater();
     method protected final int getLocalFeatures();
+    method public android.transition.Transition getSharedElementEnterTransition();
+    method public android.transition.Transition getSharedElementExitTransition();
     method public android.transition.TransitionManager getTransitionManager();
     method public abstract int getVolumeControlStream();
     method public android.view.WindowManager getWindowManager();
@@ -30811,7 +30840,6 @@
     method public abstract boolean isFloating();
     method public abstract boolean isShortcutKey(int, android.view.KeyEvent);
     method public final void makeActive();
-    method public void mapTransitionTargets(java.util.Map<java.lang.String, java.lang.String>);
     method protected abstract void onActive();
     method public abstract void onConfigurationChanged(android.content.res.Configuration);
     method public abstract void openPanel(int, android.view.KeyEvent);
@@ -30822,8 +30850,8 @@
     method public boolean requestFeature(int);
     method public abstract void restoreHierarchyState(android.os.Bundle);
     method public abstract android.os.Bundle saveHierarchyState();
-    method public void setAllowOverlappingEnterTransition(boolean);
-    method public void setAllowOverlappingExitTransition(boolean);
+    method public void setAllowEnterTransitionOverlap(boolean);
+    method public void setAllowExitTransitionOverlap(boolean);
     method public void setAttributes(android.view.WindowManager.LayoutParams);
     method public abstract void setBackgroundDrawable(android.graphics.drawable.Drawable);
     method public void setBackgroundDrawableResource(int);
@@ -30836,6 +30864,8 @@
     method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
     method protected void setDefaultWindowFormat(int);
     method public void setDimAmount(float);
+    method public void setEnterTransition(android.transition.Transition);
+    method public void setExitTransition(android.transition.Transition);
     method public abstract void setFeatureDrawable(int, android.graphics.drawable.Drawable);
     method public abstract void setFeatureDrawableAlpha(int, int);
     method public abstract void setFeatureDrawableResource(int, int);
@@ -30848,6 +30878,8 @@
     method public void setLayout(int, int);
     method public void setLocalFocus(boolean, boolean);
     method public void setLogo(int);
+    method public void setSharedElementEnterTransition(android.transition.Transition);
+    method public void setSharedElementExitTransition(android.transition.Transition);
     method public void setSoftInputMode(int);
     method public abstract void setTitle(java.lang.CharSequence);
     method public abstract deprecated void setTitleColor(int);
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 9818c33..04f62e3 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -949,10 +949,6 @@
     }
 
     /** @hide */
-    public void captureSharedElements(Map<String, View> sharedElements) {
-    }
-
-    /** @hide */
     public ActionMode startActionMode(ActionMode.Callback callback) {
         return null;
     }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index b18eb98..a5a06e3 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.transition.Scene;
-import android.transition.Transition;
 import android.transition.TransitionManager;
 import android.util.ArrayMap;
 import android.util.SuperNotCalledException;
@@ -773,6 +772,8 @@
 
     private Thread mUiThread;
     final Handler mHandler = new Handler();
+    private ActivityOptions mCalledActivityOptions;
+    private EnterTransitionCoordinator mEnterTransitionCoordinator;
 
     /** Return the intent that started this activity. */
     public Intent getIntent() {
@@ -1026,6 +1027,9 @@
             mTitleReady = true;
             onTitleChanged(getTitle(), getTitleColor());
         }
+        if (mEnterTransitionCoordinator != null) {
+            mEnterTransitionCoordinator.readyToEnter();
+        }
         mCalled = true;
     }
 
@@ -1106,6 +1110,7 @@
     protected void onResume() {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
         getApplication().dispatchActivityResumed(this);
+        mCalledActivityOptions = null;
         mCalled = true;
     }
 
@@ -1398,8 +1403,9 @@
     protected void onStop() {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this);
         if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
-        if (mWindow != null) {
-            mWindow.restoreViewVisibilityAfterTransitionToCallee();
+        if (mCalledActivityOptions != null) {
+            mCalledActivityOptions.dispatchActivityStopped();
+            mCalledActivityOptions = null;
         }
         getApplication().dispatchActivityStopped(this);
         mTranslucentCallback = null;
@@ -3484,7 +3490,7 @@
     public void startActivityForResult(Intent intent, int requestCode) {
         Bundle options = null;
         if (mWindow.hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
-            options = ActivityOptions.makeSceneTransitionAnimation().toBundle();
+            options = ActivityOptions.makeSceneTransitionAnimation(mWindow, null).toBundle();
         }
         startActivityForResult(intent, requestCode, options);
     }
@@ -3526,14 +3532,8 @@
     public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
         if (options != null) {
             ActivityOptions activityOptions = new ActivityOptions(options);
-            if (activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
-                if (mActionBar != null) {
-                    ArrayMap<String, View> sharedElementMap = new ArrayMap<String, View>();
-                    mActionBar.captureSharedElements(sharedElementMap);
-                    activityOptions.addSharedElements(sharedElementMap);
-                }
-                options = mWindow.startExitTransitionToCallee(options);
-            }
+            activityOptions.dispatchStartExit();
+            mCalledActivityOptions = activityOptions;
         }
         if (mParent == null) {
             Instrumentation.ActivityResult ar =
@@ -4391,16 +4391,15 @@
      * to reverse its exit Transition. When the exit Transition completes,
      * {@link #finish()} is called. If no entry Transition was used, finish() is called
      * immediately and the Activity exit Transition is run.
-     * @see android.view.Window#setTriggerEarlySceneTransition(boolean, boolean)
-     * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.View, String)
+     * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
+     * android.app.ActivityOptions.ActivityTransitionListener)
      */
     public void finishWithTransition() {
-        mWindow.startExitTransitionToCaller(new Runnable() {
-            @Override
-            public void run() {
-                finish();
-            }
-        });
+        if (mEnterTransitionCoordinator != null) {
+            mEnterTransitionCoordinator.startExit();
+        } else {
+            finish();
+        }
     }
 
     /**
@@ -5346,6 +5345,21 @@
         }
     }
 
+    /**
+     * When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
+     * android.app.ActivityOptions.ActivityTransitionListener)} was used to start an Activity,
+     * the Window will be triggered to enter with a Transition. <code>listener</code> allows
+     * The Activity to listen to events of the entering transition and control the mapping of
+     * shared elements. This requires {@link Window#FEATURE_CONTENT_TRANSITIONS}.
+     *
+     * @param listener Used to listen to events in the entering transition.
+     */
+    public void setActivityTransitionListener(ActivityOptions.ActivityTransitionListener listener) {
+        if (mEnterTransitionCoordinator != null) {
+            mEnterTransitionCoordinator.setActivityTransitionListener(listener);
+        }
+    }
+
     // ------------------ Internal API ------------------
     
     final void setParent(Activity parent) {
@@ -5413,34 +5427,12 @@
         }
         mWindowManager = mWindow.getWindowManager();
         mCurrentConfig = config;
-        Window.SceneTransitionListener sceneTransitionListener
-                = new Window.SceneTransitionListener() {
-            @Override
-            public void nullPendingTransition() {
-                overridePendingTransition(0, 0);
+        if (options != null) {
+            ActivityOptions activityOptions = new ActivityOptions(options);
+            if (activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
+                mEnterTransitionCoordinator = activityOptions.createEnterActivityTransition(this);
             }
-
-            @Override
-            public void convertFromTranslucent() {
-                Activity.this.convertFromTranslucent();
-            }
-
-            @Override
-            public void convertToTranslucent() {
-                Activity.this.convertToTranslucent(null);
-            }
-
-            @Override
-            public void sharedElementStart(Transition transition) {
-                Activity.this.onCaptureSharedElementStart(transition);
-            }
-
-            @Override
-            public void sharedElementEnd() {
-                Activity.this.onCaptureSharedElementEnd();
-            }
-        };
-        mWindow.setTransitionOptions(options, sceneTransitionListener);
+        }
     }
 
     /** @hide */
@@ -5628,26 +5620,6 @@
     }
 
     /**
-     * Called when setting up Activity Scene transitions when the start state for shared
-     * elements has been captured. Override this method to modify the start position of shared
-     * elements for the entry Transition.
-     *
-     * @param transition The <code>Transition</code> being used to change
-     *                   bounds of shared elements in the source Activity to
-     *                   the bounds defined by the entering Scene.
-     */
-    public void onCaptureSharedElementStart(Transition transition) {
-    }
-
-    /**
-     * Called when setting up Activity Scene transitions when the final state for
-     * shared elements state has been captured. Override this method to modify the destination
-     * position of shared elements for the entry Transition.
-     */
-    public void onCaptureSharedElementEnd() {
-    }
-
-    /**
      * @hide
      */
     public final boolean isResumed() {
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 4384580..85464c47 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -20,16 +20,16 @@
 import android.graphics.Bitmap;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.IRemoteCallback;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.transition.Transition;
-import android.util.Log;
+import android.util.ArrayMap;
 import android.util.Pair;
 import android.view.View;
+import android.view.Window;
 
-import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -108,23 +108,6 @@
     private static final String KEY_TRANSITION_COMPLETE_LISTENER
             = "android:transitionCompleteListener";
 
-    /**
-     * For Activity transitions, the called Activity's listener to receive calls
-     * when transitions complete.
-     */
-    private static final String KEY_TRANSITION_TARGET_LISTENER = "android:transitionTargetListener";
-
-    /**
-     * The names of shared elements that are transitioned to the started Activity.
-     * This is also the name of shared elements that the started Activity accepted.
-     */
-    private static final String KEY_SHARED_ELEMENT_NAMES = "android:shared_element_names";
-
-    /**
-     * The shared elements names of the views in the calling Activity.
-     */
-    private static final String KEY_LOCAL_ELEMENT_NAMES = "android:local_element_names";
-
     /** @hide */
     public static final int ANIM_NONE = 0;
     /** @hide */
@@ -138,11 +121,6 @@
     /** @hide */
     public static final int ANIM_SCENE_TRANSITION = 5;
 
-    private static final int MSG_SET_LISTENER = 100;
-    private static final int MSG_HIDE_SHARED_ELEMENTS = 101;
-    private static final int MSG_PREPARE_RESTORE = 102;
-    private static final int MSG_RESTORE = 103;
-
     private String mPackageName;
     private int mAnimationType = ANIM_NONE;
     private int mCustomEnterResId;
@@ -153,9 +131,7 @@
     private int mStartWidth;
     private int mStartHeight;
     private IRemoteCallback mAnimationStartedListener;
-    private ResultReceiver mTransitionCompleteListener;
-    private ArrayList<String> mSharedElementNames;
-    private ArrayList<String> mLocalElementNames;
+    private ResultReceiver mExitReceiver;
 
     /**
      * Create an ActivityOptions specifying a custom animation to run when
@@ -231,12 +207,6 @@
         void onAnimationStarted();
     }
 
-    /** @hide */
-    public interface ActivityTransitionTarget {
-        void sharedElementTransitionComplete(Bundle transitionArgs);
-        void exitTransitionComplete();
-    }
-
     /**
      * Create an ActivityOptions specifying an animation where the new
      * activity is scaled from a small originating area of the screen to
@@ -357,49 +327,53 @@
     /**
      * Create an ActivityOptions to transition between Activities using cross-Activity scene
      * animations. This method carries the position of one shared element to the started Activity.
+     * The position of <code>sharedElement</code> will be used as the epicenter for the
+     * exit Transition. The position of the shared element in the launched Activity will be the
+     * epicenter of its entering Transition.
      *
      * <p>This requires {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS} to be
      * enabled on the calling Activity to cause an exit transition. The same must be in
      * the called Activity to get an entering transition.</p>
+     * @param window The window containing shared elements.
      * @param sharedElement The View to transition to the started Activity. sharedElement must
      *                      have a non-null sharedElementName.
      * @param sharedElementName The shared element name as used in the target Activity. This may
      *                          be null if it has the same name as sharedElement.
      * @return Returns a new ActivityOptions object that you can use to
      *         supply these options as the options Bundle when starting an activity.
+     * @see android.transition.Transition#setEpicenterCallback(
+     *          android.transition.Transition.EpicenterCallback)
      */
-    public static ActivityOptions makeSceneTransitionAnimation(View sharedElement,
-            String sharedElementName) {
-        return makeSceneTransitionAnimation(
-                new Pair<View, String>(sharedElement, sharedElementName));
+    public static ActivityOptions makeSceneTransitionAnimation(Window window,
+            View sharedElement, String sharedElementName) {
+        return makeSceneTransitionAnimation(window,
+                new SharedElementMappingListener(sharedElement, sharedElementName));
     }
 
     /**
      * Create an ActivityOptions to transition between Activities using cross-Activity scene
      * animations. This method carries the position of multiple shared elements to the started
-     * Activity.
+     * Activity. The position of the first element in the value returned from
+     * {@link android.app.ActivityOptions.ActivityTransitionListener#getSharedElementsMapping()}
+     * will be used as the epicenter for the exit Transition. The position of the associated
+     * shared element in the launched Activity will be the epicenter of its entering Transition.
      *
      * <p>This requires {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS} to be
      * enabled on the calling Activity to cause an exit transition. The same must be in
      * the called Activity to get an entering transition.</p>
-     * @param sharedElements The View to transition to the started Activity along with the
-     *                       shared element name as used in the started Activity. The view
-     *                       must have a non-null sharedElementName.
+     * @param window The window containing shared elements.
+     * @param listener The listener to use to monitor activity transition events.
      * @return Returns a new ActivityOptions object that you can use to
      *         supply these options as the options Bundle when starting an activity.
+     * @see android.transition.Transition#setEpicenterCallback(
+     *          android.transition.Transition.EpicenterCallback)
      */
-    public static ActivityOptions makeSceneTransitionAnimation(
-            Pair<View, String>... sharedElements) {
+    public static ActivityOptions makeSceneTransitionAnimation(Window window,
+            ActivityTransitionListener listener) {
         ActivityOptions opts = new ActivityOptions();
         opts.mAnimationType = ANIM_SCENE_TRANSITION;
-        opts.mSharedElementNames = new ArrayList<String>();
-        opts.mLocalElementNames = new ArrayList<String>();
-
-        if (sharedElements != null) {
-            for (Pair<View, String> sharedElement : sharedElements) {
-                opts.addSharedElement(sharedElement.first, sharedElement.second);
-            }
-        }
+        ExitTransitionCoordinator exit = new ExitTransitionCoordinator(window, listener);
+        opts.mExitReceiver = exit;
         return opts;
     }
 
@@ -435,9 +409,7 @@
                 break;
 
             case ANIM_SCENE_TRANSITION:
-                mTransitionCompleteListener = opts.getParcelable(KEY_TRANSITION_COMPLETE_LISTENER);
-                mSharedElementNames = opts.getStringArrayList(KEY_SHARED_ELEMENT_NAMES);
-                mLocalElementNames = opts.getStringArrayList(KEY_LOCAL_ELEMENT_NAMES);
+                mExitReceiver = opts.getParcelable(KEY_TRANSITION_COMPLETE_LISTENER);
                 break;
         }
     }
@@ -493,50 +465,16 @@
     }
 
     /** @hide */
-    public ArrayList<String> getSharedElementNames() { return mSharedElementNames; }
-
-    /** @hide */
-    public ArrayList<String> getLocalElementNames() { return mLocalElementNames; }
-
-    /** @hide */
-    public void dispatchSceneTransitionStarted(final ActivityTransitionTarget target,
-            ArrayList<String> sharedElementNames) {
-        if (mTransitionCompleteListener != null) {
-            IRemoteCallback callback = new IRemoteCallback.Stub() {
-                @Override
-                public void sendResult(Bundle data) throws RemoteException {
-                    if (data == null) {
-                        target.exitTransitionComplete();
-                    } else {
-                        target.sharedElementTransitionComplete(data);
-                    }
-                }
-            };
-            Bundle bundle = new Bundle();
-            bundle.putBinder(KEY_TRANSITION_TARGET_LISTENER, callback.asBinder());
-            bundle.putStringArrayList(KEY_SHARED_ELEMENT_NAMES, sharedElementNames);
-            mTransitionCompleteListener.send(MSG_SET_LISTENER, bundle);
+    public void dispatchActivityStopped() {
+        if (mExitReceiver != null) {
+            mExitReceiver.send(ActivityTransitionCoordinator.MSG_ACTIVITY_STOPPED, null);
         }
     }
 
     /** @hide */
-    public void dispatchSharedElementsReady() {
-        if (mTransitionCompleteListener != null) {
-            mTransitionCompleteListener.send(MSG_HIDE_SHARED_ELEMENTS, null);
-        }
-    }
-
-    /** @hide */
-    public void dispatchPrepareRestore() {
-        if (mTransitionCompleteListener != null) {
-            mTransitionCompleteListener.send(MSG_PREPARE_RESTORE, null);
-        }
-    }
-
-    /** @hide */
-    public void dispatchRestore(Bundle sharedElementsArgs) {
-        if (mTransitionCompleteListener != null) {
-            mTransitionCompleteListener.send(MSG_RESTORE, sharedElementsArgs);
+    public void dispatchStartExit() {
+        if (mExitReceiver != null) {
+            mExitReceiver.send(ActivityTransitionCoordinator.MSG_START_EXIT_TRANSITION, null);
         }
     }
 
@@ -557,6 +495,15 @@
         }
     }
 
+    /** @hide */
+    public EnterTransitionCoordinator createEnterActivityTransition(Activity activity) {
+        EnterTransitionCoordinator coordinator = null;
+        if (mAnimationType == ANIM_SCENE_TRANSITION) {
+            coordinator = new EnterTransitionCoordinator(activity, mExitReceiver);
+        }
+        return coordinator;
+    }
+
     /**
      * Update the current values in this ActivityOptions from those supplied
      * in <var>otherOptions</var>.  Any values
@@ -566,8 +513,7 @@
         if (otherOptions.mPackageName != null) {
             mPackageName = otherOptions.mPackageName;
         }
-        mSharedElementNames = null;
-        mLocalElementNames = null;
+        mExitReceiver = null;
         switch (otherOptions.mAnimationType) {
             case ANIM_CUSTOM:
                 mAnimationType = otherOptions.mAnimationType;
@@ -581,7 +527,6 @@
                     }
                 }
                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
-                mTransitionCompleteListener = null;
                 break;
             case ANIM_SCALE_UP:
                 mAnimationType = otherOptions.mAnimationType;
@@ -596,7 +541,6 @@
                     }
                 }
                 mAnimationStartedListener = null;
-                mTransitionCompleteListener = null;
                 break;
             case ANIM_THUMBNAIL_SCALE_UP:
             case ANIM_THUMBNAIL_SCALE_DOWN:
@@ -611,15 +555,12 @@
                     }
                 }
                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
-                mTransitionCompleteListener = null;
                 break;
             case ANIM_SCENE_TRANSITION:
                 mAnimationType = otherOptions.mAnimationType;
-                mTransitionCompleteListener = otherOptions.mTransitionCompleteListener;
+                mExitReceiver = otherOptions.mExitReceiver;
                 mThumbnail = null;
                 mAnimationStartedListener = null;
-                mSharedElementNames = otherOptions.mSharedElementNames;
-                mLocalElementNames = otherOptions.mLocalElementNames;
                 break;
         }
     }
@@ -663,11 +604,9 @@
                 break;
             case ANIM_SCENE_TRANSITION:
                 b.putInt(KEY_ANIM_TYPE, mAnimationType);
-                if (mTransitionCompleteListener != null) {
-                    b.putParcelable(KEY_TRANSITION_COMPLETE_LISTENER, mTransitionCompleteListener);
+                if (mExitReceiver != null) {
+                    b.putParcelable(KEY_TRANSITION_COMPLETE_LISTENER, mExitReceiver);
                 }
-                b.putStringArrayList(KEY_SHARED_ELEMENT_NAMES, mSharedElementNames);
-                b.putStringArrayList(KEY_LOCAL_ELEMENT_NAMES, mLocalElementNames);
                 break;
         }
         return b;
@@ -687,130 +626,92 @@
         return null;
     }
 
-    /** @hide */
-    public void addSharedElements(Map<String, View> sharedElements) {
-        for (Map.Entry<String, View> entry : sharedElements.entrySet()) {
-            addSharedElement(entry.getValue(), entry.getKey());
-        }
+    /**
+     * Listener provided in
+     * {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
+     * android.app.ActivityOptions.ActivityTransitionListener)} or in
+     * {@link android.app.Activity#setActivityTransitionListener(
+     * android.app.ActivityOptions.ActivityTransitionListener)} to monitor the Activity transitions.
+     * The events can be used to customize or override Activity Transition behavior.
+     */
+    public static class ActivityTransitionListener {
+        /**
+         * Called when the enter Transition is ready to start, but hasn't started yet. If
+         * {@link android.view.Window#getEnterTransition()} is non-null,
+         * The entering views will be {@link View#INVISIBLE}.
+         */
+        public void onEnterReady() {}
+
+        /**
+         * Called when the remote exiting transition completes.
+         */
+        public void onRemoteExitComplete() {}
+
+        /**
+         * Called when the start state for shared elements is captured on enter.
+         */
+        public void onCaptureSharedElementStart() {}
+
+        /**
+         * Called when the end state for shared elements is captured on enter.
+         */
+        public void onCaptureSharedElementEnd() {}
+
+        /**
+         * Called when the enter Transition has been started.
+         * @param sharedElementNames The names of shared elements that were transferred.
+         * @param sharedElements The shared elements that were transferred.
+         */
+        public void onStartEnterTransition(List<String> sharedElementNames,
+                List<View> sharedElements) {}
+
+        /**
+         * Called when the exit Transition has been started.
+         * @param sharedElementNames The names of all shared elements that will be transferred.
+         * @param sharedElements All shared elements that will be transferred.
+         */
+        public void onStartExitTransition(List<String> sharedElementNames,
+                List<View> sharedElements) {}
+
+        /**
+         * Called when the exiting shared element transition completes.
+         */
+        public void onSharedElementExitTransitionComplete() {}
+
+        /**
+         * Called on exit when the shared element has been transferred.
+         * @param sharedElementNames The names of all shared elements that were transferred.
+         * @param sharedElements All shared elements that will were transferred.
+         */
+        public void onSharedElementTransferred(List<String> sharedElementNames,
+                List<View> sharedElements) {}
+
+        /**
+         * Called when the exit transition has completed.
+         */
+        public void onExitTransitionComplete() {}
+
+        /**
+         * Returns a mapping from a View in the View hierarchy to the shared element name used
+         * in the call. This is called twice -- once when the view is
+         * entering and again when it exits. A null return value indicates that the
+         * View hierachy can be trusted without any remapping.
+         * @return A map from a View in the hierarchy to the shared element name used in the
+         * call.
+         */
+        public Pair<View, String>[] getSharedElementsMapping() { return null; }
     }
 
-    /** @hide */
-    public void updateSceneTransitionAnimation(Transition exitTransition,
-            Transition sharedElementTransition, SharedElementSource sharedElementSource) {
-        mTransitionCompleteListener = new ExitTransitionListener(exitTransition,
-                sharedElementTransition, sharedElementSource);
-    }
+    private static class SharedElementMappingListener extends ActivityTransitionListener {
+        Pair<View, String>[] mSharedElementsMapping = new Pair[1];
 
-    private void addSharedElement(View view, String name) {
-        String sharedElementName = view.getSharedElementName();
-        if (name == null) {
-            name = sharedElementName;
-        }
-        mSharedElementNames.add(name);
-        mLocalElementNames.add(sharedElementName);
-    }
-
-    /** @hide */
-    public interface SharedElementSource {
-        Bundle getSharedElementExitState();
-        void acceptedSharedElements(ArrayList<String> sharedElementNames);
-        void hideSharedElements();
-        void restore(Bundle sharedElementState);
-        void prepareForRestore();
-    }
-
-    private static class ExitTransitionListener extends ResultReceiver
-            implements Transition.TransitionListener {
-        private boolean mSharedElementNotified;
-        private IRemoteCallback mTransitionCompleteCallback;
-        private boolean mExitComplete;
-        private boolean mSharedElementComplete;
-        private SharedElementSource mSharedElementSource;
-
-        public ExitTransitionListener(Transition exitTransition, Transition sharedElementTransition,
-                SharedElementSource sharedElementSource) {
-            super(null);
-            mSharedElementSource = sharedElementSource;
-            exitTransition.addListener(this);
-            sharedElementTransition.addListener(new Transition.TransitionListenerAdapter() {
-                @Override
-                public void onTransitionEnd(Transition transition) {
-                    mSharedElementComplete = true;
-                    notifySharedElement();
-                    transition.removeListener(this);
-                }
-            });
+        public SharedElementMappingListener(View view, String name) {
+            mSharedElementsMapping[0] = Pair.create(view, name);
         }
 
         @Override
-        protected void onReceiveResult(int resultCode, Bundle resultData) {
-            switch (resultCode) {
-                case MSG_SET_LISTENER:
-                    IBinder listener = resultData.getBinder(KEY_TRANSITION_TARGET_LISTENER);
-                    mTransitionCompleteCallback = IRemoteCallback.Stub.asInterface(listener);
-                    ArrayList<String> sharedElementNames
-                            = resultData.getStringArrayList(KEY_SHARED_ELEMENT_NAMES);
-                    mSharedElementSource.acceptedSharedElements(sharedElementNames);
-                    notifySharedElement();
-                    notifyExit();
-                    break;
-                case MSG_HIDE_SHARED_ELEMENTS:
-                    mSharedElementSource.hideSharedElements();
-                    break;
-                case MSG_PREPARE_RESTORE:
-                    mSharedElementSource.prepareForRestore();
-                    break;
-                case MSG_RESTORE:
-                    mSharedElementSource.restore(resultData);
-                    break;
-            }
-        }
-
-        @Override
-        public void onTransitionStart(Transition transition) {
-        }
-
-        @Override
-        public void onTransitionEnd(Transition transition) {
-            mExitComplete = true;
-            notifyExit();
-            transition.removeListener(this);
-        }
-
-        @Override
-        public void onTransitionCancel(Transition transition) {
-            onTransitionEnd(transition);
-        }
-
-        @Override
-        public void onTransitionPause(Transition transition) {
-        }
-
-        @Override
-        public void onTransitionResume(Transition transition) {
-        }
-
-        private void notifySharedElement() {
-            if (!mSharedElementNotified && mSharedElementComplete
-                    && mTransitionCompleteCallback != null) {
-                mSharedElementNotified = true;
-                try {
-                    Bundle sharedElementState = mSharedElementSource.getSharedElementExitState();
-                    mTransitionCompleteCallback.sendResult(sharedElementState);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Couldn't notify that the transition ended", e);
-                }
-            }
-        }
-
-        private void notifyExit() {
-            if (mExitComplete && mTransitionCompleteCallback != null) {
-                try {
-                    mTransitionCompleteCallback.sendResult(null);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Couldn't notify that the transition ended", e);
-                }
-            }
+        public Pair<View, String>[] getSharedElementsMapping() {
+            return mSharedElementsMapping;
         }
     }
 }
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
new file mode 100644
index 0000000..d8a356f
--- /dev/null
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -0,0 +1,736 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app;
+
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.ResultReceiver;
+import android.transition.Transition;
+import android.transition.TransitionManager;
+import android.transition.TransitionSet;
+import android.util.ArrayMap;
+import android.util.Pair;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.Window;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * Base class for ExitTransitionCoordinator and EnterTransitionCoordinator, classes
+ * that manage activity transitions and the communications coordinating them between
+ * Activities. The ExitTransitionCoordinator is created in the
+ * ActivityOptions#makeSceneTransitionAnimation. The EnterTransitionCoordinator
+ * is created by ActivityOptions#createEnterActivityTransition by Activity when the window is
+ * attached.
+ *
+ * Typical startActivity goes like this:
+ * 1) ExitTransitionCoordinator created with ActivityOptions#makeSceneTransitionAnimation
+ * 2) Activity#startActivity called and that calls startExit() through
+ *    ActivityOptions#dispatchStartExit
+ *    - Exit transition starts by setting transitioning Views to INVISIBLE
+ * 3) Launched Activity starts, creating an EnterTransitionCoordinator.
+ *    - The Window is made translucent
+ *    - The Window background alpha is set to 0
+ *    - The transitioning views are made INVISIBLE
+ *    - MSG_SET_LISTENER is sent back to the ExitTransitionCoordinator.
+ * 4) The shared element transition completes.
+ *    - MSG_TAKE_SHARED_ELEMENTS is sent to the EnterTransitionCoordinator
+ * 5) The MSG_TAKE_SHARED_ELEMENTS is received by the EnterTransitionCoordinator.
+ *    - Shared elements are made VISIBLE
+ *    - Shared elements positions and size are set to match the end state of the calling
+ *      Activity.
+ *    - The shared element transition is started
+ *    - If the window allows overlapping transitions, the views transition is started by setting
+ *      the entering Views to VISIBLE and the background alpha is animated to opaque.
+ *    - MSG_HIDE_SHARED_ELEMENTS is sent to the ExitTransitionCoordinator
+ * 6) MSG_HIDE_SHARED_ELEMENTS is received by the ExitTransitionCoordinator
+ *    - The shared elements are made INVISIBLE
+ * 7) The exit transition completes in the calling Activity.
+ *    - MSG_EXIT_TRANSITION_COMPLETE is sent to the EnterTransitionCoordinator.
+ * 8) The MSG_EXIT_TRANSITION_COMPLETE is received by the EnterTransitionCoordinator.
+ *    - If the window doesn't allow overlapping enter transitions, the enter transition is started
+ *      by setting entering views to VISIBLE and the background is animated to opaque.
+ * 9) The background opacity animation completes.
+ *    - The window is made opaque
+ * 10) The calling Activity gets an onStop() call
+ *    - onActivityStopped() is called and all exited Views are made VISIBLE.
+ *
+ * Typical finishWithTransition goes like this:
+ * 1) finishWithTransition() calls startExit()
+ *    - The Window start transitioning to Translucent
+ *    - If no background exists, a black background is substituted
+ *    - MSG_PREPARE_RESTORE is sent to the ExitTransitionCoordinator
+ *    - The shared elements in the scene are matched against those shared elements
+ *      that were sent by comparing the names.
+ *    - The exit transition is started by setting Views to INVISIBLE.
+ * 2) MSG_PREPARE_RESTORE is received by the EnterTransitionCoordinator
+ *    - All transitioning views are made VISIBLE to reverse what was done when onActivityStopped()
+ *      was called
+ * 3) The Window is made translucent and a callback is received
+ *    - The background alpha is animated to 0
+ * 4) The background alpha animation completes
+ * 5) The shared element transition completes
+ *    - After both 4 & 5 complete, MSG_TAKE_SHARED_ELEMENTS is sent to the
+ *      ExitTransitionCoordinator
+ * 6) MSG_TAKE_SHARED_ELEMENTS is received by ExitTransitionCoordinator
+ *    - Shared elements are made VISIBLE
+ *    - Shared elements positions and size are set to match the end state of the calling
+ *      Activity.
+ *    - The shared element transition is started
+ *    - If the window allows overlapping transitions, the views transition is started by setting
+ *      the entering Views to VISIBLE.
+ *    - MSG_HIDE_SHARED_ELEMENTS is sent to the EnterTransitionCoordinator
+ * 7) MSG_HIDE_SHARED_ELEMENTS is received by the EnterTransitionCoordinator
+ *    - The shared elements are made INVISIBLE
+ * 8) The exit transition completes in the finishing Activity.
+ *    - MSG_EXIT_TRANSITION_COMPLETE is sent to the ExitTransitionCoordinator.
+ *    - finish() is called on the exiting Activity
+ * 9) The MSG_EXIT_TRANSITION_COMPLETE is received by the ExitTransitionCoordinator.
+ *    - If the window doesn't allow overlapping enter transitions, the enter transition is started
+ *      by setting entering views to VISIBLE.
+ */
+abstract class ActivityTransitionCoordinator extends ResultReceiver {
+    private static final String TAG = "ActivityTransitionCoordinator";
+
+    /**
+     * The names of shared elements that are transitioned to the started Activity.
+     * This is also the name of shared elements that the started Activity accepted.
+     */
+    public static final String KEY_SHARED_ELEMENT_NAMES = "android:shared_element_names";
+
+    public static final String KEY_SHARED_ELEMENT_STATE = "android:shared_element_state";
+
+    /**
+     * For Activity transitions, the called Activity's listener to receive calls
+     * when transitions complete.
+     */
+    static final String KEY_TRANSITION_RESULTS_RECEIVER = "android:transitionTargetListener";
+
+    private static final String KEY_SCREEN_X = "shared_element:screenX";
+    private static final String KEY_SCREEN_Y = "shared_element:screenY";
+    private static final String KEY_TRANSLATION_Z = "shared_element:translationZ";
+    private static final String KEY_WIDTH = "shared_element:width";
+    private static final String KEY_HEIGHT = "shared_element:height";
+    private static final String KEY_NAME = "shared_element:name";
+
+    /**
+     * Sent by the exiting coordinator (either EnterTransitionCoordinator
+     * or ExitTransitionCoordinator) after the shared elements have
+     * become stationary (shared element transition completes). This tells
+     * the remote coordinator to take control of the shared elements and
+     * that animations may begin. The remote Activity won't start entering
+     * until this message is received, but may wait for
+     * MSG_EXIT_TRANSITION_COMPLETE if allowOverlappingTransitions() is true.
+     */
+    public static final int MSG_SET_LISTENER = 100;
+
+    /**
+     * Sent by the entering coordinator to tell the exiting coordinator
+     * to hide its shared elements after it has started its shared
+     * element transition. This is temporary until the
+     * interlock of shared elements is figured out.
+     */
+    public static final int MSG_HIDE_SHARED_ELEMENTS = 101;
+
+    /**
+     * Sent by the EnterTransitionCoordinator to tell the
+     * ExitTransitionCoordinator to hide all of its exited views after
+     * MSG_ACTIVITY_STOPPED has caused them all to show.
+     */
+    public static final int MSG_PREPARE_RESTORE = 102;
+
+    /**
+     * Sent by the exiting Activity in ActivityOptions#dispatchActivityStopped
+     * to leave the Activity in a good state after it has been hidden.
+     */
+    public static final int MSG_ACTIVITY_STOPPED = 103;
+
+    /**
+     * Sent by the exiting coordinator (either EnterTransitionCoordinator
+     * or ExitTransitionCoordinator) after the shared elements have
+     * become stationary (shared element transition completes). This tells
+     * the remote coordinator to take control of the shared elements and
+     * that animations may begin. The remote Activity won't start entering
+     * until this message is received, but may wait for
+     * MSG_EXIT_TRANSITION_COMPLETE if allowOverlappingTransitions() is true.
+     */
+    public static final int MSG_TAKE_SHARED_ELEMENTS = 104;
+
+    /**
+     * Sent by the exiting coordinator (either
+     * EnterTransitionCoordinator or ExitTransitionCoordinator) after
+     * the exiting Views have finished leaving the scene. This will
+     * be ignored if allowOverlappingTransitions() is true on the
+     * remote coordinator. If it is false, it will trigger the enter
+     * transition to start.
+     */
+    public static final int MSG_EXIT_TRANSITION_COMPLETE = 105;
+
+    /**
+     * Sent by Activity#startActivity to begin the exit transition.
+     */
+    public static final int MSG_START_EXIT_TRANSITION = 106;
+
+    private Window mWindow;
+    private ArrayList<View> mSharedElements = new ArrayList<View>();
+    private ArrayList<String> mTargetSharedNames = new ArrayList<String>();
+    private ActivityOptions.ActivityTransitionListener mListener =
+            new ActivityOptions.ActivityTransitionListener();
+    private ArrayList<View> mEnteringViews;
+    private ResultReceiver mRemoteResultReceiver;
+    private boolean mNotifiedSharedElementTransitionComplete;
+    private boolean mNotifiedExitTransitionComplete;
+
+    private FixedEpicenterCallback mEpicenterCallback = new FixedEpicenterCallback();
+
+    private Transition.TransitionListener mSharedElementListener =
+            new Transition.TransitionListenerAdapter() {
+        @Override
+        public void onTransitionEnd(Transition transition) {
+            transition.removeListener(this);
+            onSharedElementTransitionEnd();
+        }
+    };
+
+    private Transition.TransitionListener mExitListener =
+            new Transition.TransitionListenerAdapter() {
+        @Override
+        public void onTransitionEnd(Transition transition) {
+            transition.removeListener(this);
+            onExitTransitionEnd();
+        }
+    };
+
+    public ActivityTransitionCoordinator(Window window)
+    {
+        super(new Handler());
+        mWindow = window;
+    }
+
+    // -------------------- ResultsReceiver Overrides ----------------------
+    @Override
+    protected void onReceiveResult(int resultCode, Bundle resultData) {
+        switch (resultCode) {
+            case MSG_SET_LISTENER:
+                ResultReceiver resultReceiver
+                        = resultData.getParcelable(KEY_TRANSITION_RESULTS_RECEIVER);
+                setRemoteResultReceiver(resultReceiver);
+                onSetResultReceiver();
+                break;
+            case MSG_HIDE_SHARED_ELEMENTS:
+                onHideSharedElements();
+                break;
+            case MSG_PREPARE_RESTORE:
+                onPrepareRestore();
+                break;
+            case MSG_EXIT_TRANSITION_COMPLETE:
+                onRemoteSceneExitComplete();
+                break;
+            case MSG_TAKE_SHARED_ELEMENTS:
+                ArrayList<String> sharedElementNames
+                        = resultData.getStringArrayList(KEY_SHARED_ELEMENT_NAMES);
+                Bundle sharedElementState = resultData.getBundle(KEY_SHARED_ELEMENT_STATE);
+                onTakeSharedElements(sharedElementNames, sharedElementState);
+                break;
+            case MSG_ACTIVITY_STOPPED:
+                onActivityStopped();
+                break;
+            case MSG_START_EXIT_TRANSITION:
+                startExit();
+                break;
+        }
+    }
+
+    // -------------------- calls that can be overridden by subclasses --------------------
+
+    /**
+     * Called when MSG_SET_LISTENER is received. This will only be received by
+     * ExitTransitionCoordinator.
+     */
+    protected void onSetResultReceiver() {}
+
+    /**
+     * Called when MSG_HIDE_SHARED_ELEMENTS is received
+     */
+    protected void onHideSharedElements() {
+        setViewVisibility(getSharedElements(), View.INVISIBLE);
+        mListener.onSharedElementTransferred(getSharedElementNames(), getSharedElements());
+    }
+
+    /**
+     * Called when MSG_PREPARE_RESTORE is called. This will only be received by
+     * ExitTransitionCoordinator.
+     */
+    protected void onPrepareRestore() {
+        mListener.onEnterReady();
+    }
+
+    /**
+     * Called when MSG_EXIT_TRANSITION_COMPLETE is received -- the remote coordinator has
+     * completed its exit transition. This can be called by the ExitTransitionCoordinator when
+     * starting an Activity or EnterTransitionCoordinator when called with finishWithTransition.
+     */
+    protected void onRemoteSceneExitComplete() {
+        if (!allowOverlappingTransitions()) {
+            Transition transition = beginTransition(mEnteringViews, false, true, true);
+            onStartEnterTransition(transition, mEnteringViews);
+        }
+        mListener.onRemoteExitComplete();
+    }
+
+    /**
+     * Called when MSG_TAKE_SHARED_ELEMENTS is received. This means that the shared elements are
+     * in a stable state and ready to move to the Window.
+     * @param sharedElementNames The names of the shared elements to move.
+     * @param state Contains the shared element states (size & position)
+     */
+    protected void onTakeSharedElements(ArrayList<String> sharedElementNames, Bundle state) {
+        setSharedElements();
+        reconcileSharedElements(sharedElementNames);
+        mEnteringViews.removeAll(mSharedElements);
+        setSharedElementState(state);
+        if (getViewsTransition() != null) {
+            setViewVisibility(mEnteringViews, View.INVISIBLE);
+        }
+        setViewVisibility(mSharedElements, View.VISIBLE);
+        Transition transition = beginTransition(mEnteringViews, true, allowOverlappingTransitions(),
+                true);
+        if (allowOverlappingTransitions()) {
+            onStartEnterTransition(transition, mEnteringViews);
+        }
+        mRemoteResultReceiver.send(MSG_HIDE_SHARED_ELEMENTS, null);
+    }
+
+    /**
+     * Called when MSG_ACTIVITY_STOPPED is received. This is received when Activity.onStop is
+     * called after running startActivity* is called using an Activity Transition.
+     */
+    protected void onActivityStopped() {}
+
+    /**
+     * Called when the start transition is ready to run. This may be immediately after
+     * MSG_TAKE_SHARED_ELEMENTS or MSG_EXIT_TRANSITION_COMPLETE, depending on whether
+     * overlapping transitions are allowed.
+     * @param transition The transition currently started.
+     * @param enteringViews The views entering the scene. This won't include shared elements.
+     */
+    protected void onStartEnterTransition(Transition transition, ArrayList<View> enteringViews) {
+        if (getViewsTransition() != null) {
+            setViewVisibility(enteringViews, View.VISIBLE);
+        }
+        mEnteringViews = null;
+        mListener.onStartEnterTransition(getSharedElementNames(), getSharedElements());
+    }
+
+    /**
+     * Called when the exit transition has started.
+     * @param exitingViews The views leaving the scene. This won't include shared elements.
+     */
+    protected void onStartExitTransition(ArrayList<View> exitingViews) {}
+
+    /**
+     * Called during the exit when the shared element transition has completed.
+     */
+    protected void onSharedElementTransitionEnd() {
+        Bundle bundle = new Bundle();
+        int[] tempLoc = new int[2];
+        for (int i = 0; i < mSharedElements.size(); i++) {
+            View sharedElement = mSharedElements.get(i);
+            String name = mTargetSharedNames.get(i);
+            captureSharedElementState(sharedElement, name, bundle, tempLoc);
+        }
+        Bundle allValues = new Bundle();
+        allValues.putStringArrayList(KEY_SHARED_ELEMENT_NAMES, getSharedElementNames());
+        allValues.putBundle(KEY_SHARED_ELEMENT_STATE, bundle);
+        sharedElementTransitionComplete(allValues);
+        mListener.onSharedElementExitTransitionComplete();
+    }
+
+    /**
+     * Called after the shared element transition is complete to pass the shared element state
+     * to the remote coordinator.
+     * @param bundle The Bundle to send to the coordinator containing the shared element state.
+     */
+    protected abstract void sharedElementTransitionComplete(Bundle bundle);
+
+    /**
+     * Called when the exit transition finishes.
+     */
+    protected void onExitTransitionEnd() {
+        mListener.onExitTransitionComplete();
+    }
+
+    /**
+     * Called to start the exit transition. Launched from ActivityOptions#dispatchStartExit
+     */
+    protected abstract void startExit();
+
+    /**
+     * A non-null transition indicates that the Views of the Window should be made INVISIBLE.
+     * @return The Transition used to cause transitioning views to either enter or exit the scene.
+     */
+    protected abstract Transition getViewsTransition();
+
+    /**
+     * @return The Transition used to move the shared elements from the start position and size
+     * to the end position and size.
+     */
+    protected abstract Transition getSharedElementTransition();
+
+    /**
+     * @return When the enter transition should overlap with the exit transition of the
+     * remote controller.
+     */
+    protected abstract boolean allowOverlappingTransitions();
+
+    // called by subclasses
+
+    protected void notifySharedElementTransitionComplete(Bundle sharedElements) {
+        if (!mNotifiedSharedElementTransitionComplete) {
+            mNotifiedSharedElementTransitionComplete = true;
+            mRemoteResultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, sharedElements);
+        }
+    }
+
+    protected void notifyExitTransitionComplete() {
+        if (!mNotifiedExitTransitionComplete) {
+            mNotifiedExitTransitionComplete = true;
+            mRemoteResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null);
+        }
+    }
+
+    protected void notifyPrepareRestore() {
+        mRemoteResultReceiver.send(MSG_PREPARE_RESTORE, null);
+    }
+
+    protected void setRemoteResultReceiver(ResultReceiver resultReceiver) {
+        mRemoteResultReceiver = resultReceiver;
+    }
+
+    protected void notifySetListener() {
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(KEY_TRANSITION_RESULTS_RECEIVER, this);
+        mRemoteResultReceiver.send(MSG_SET_LISTENER, bundle);
+    }
+
+    protected void setEnteringViews(ArrayList<View> views) {
+        mEnteringViews = views;
+    }
+
+    protected void setSharedElements() {
+        Pair<View, String>[] sharedElements = mListener.getSharedElementsMapping();
+        mSharedElements.clear();
+        mTargetSharedNames.clear();
+        if (sharedElements == null) {
+            ArrayMap<String, View> map = new ArrayMap<String, View>();
+            setViewVisibility(mEnteringViews, View.VISIBLE);
+            getDecor().findSharedElements(map);
+            setViewVisibility(mEnteringViews, View.INVISIBLE);
+            for (int i = 0; i < map.size(); i++) {
+                View view = map.valueAt(i);
+                String name = map.keyAt(i);
+                mSharedElements.add(view);
+                mTargetSharedNames.add(name);
+            }
+        } else {
+            for (int i = 0; i < sharedElements.length; i++) {
+                Pair<View, String> viewStringPair = sharedElements[i];
+                View view = viewStringPair.first;
+                String name = viewStringPair.second;
+                mSharedElements.add(view);
+                mTargetSharedNames.add(name);
+            }
+        }
+    }
+
+    protected ArrayList<View> getSharedElements() {
+        return mSharedElements;
+    }
+
+    protected ArrayList<String> getSharedElementNames() {
+        return mTargetSharedNames;
+    }
+
+    protected Window getWindow() {
+        return mWindow;
+    }
+
+    protected ViewGroup getDecor() {
+        return (mWindow == null) ? null : (ViewGroup) mWindow.getDecorView();
+    }
+
+    protected void startExitTransition(ArrayList<String> sharedElements) {
+        setSharedElements();
+        reconcileSharedElements(sharedElements);
+        ArrayList<View> transitioningViews = captureTransitioningViews();
+        beginTransition(transitioningViews, true, true, false);
+        onStartExitTransition(transitioningViews);
+        if (getViewsTransition() != null) {
+            setViewVisibility(transitioningViews, View.INVISIBLE);
+        }
+        mListener.onStartExitTransition(getSharedElementNames(), getSharedElements());
+    }
+
+    protected void clearConnections() {
+        mRemoteResultReceiver = null;
+    }
+
+    // public API
+
+    public void setActivityTransitionListener(ActivityOptions.ActivityTransitionListener listener) {
+        if (listener == null) {
+            mListener = new ActivityOptions.ActivityTransitionListener();
+        } else {
+            mListener = listener;
+        }
+    }
+
+    // private methods
+
+    private Transition configureTransition(Transition transition) {
+        if (transition != null) {
+            transition = transition.clone();
+            transition.setEpicenterCallback(mEpicenterCallback);
+        }
+        return transition;
+    }
+
+    private void reconcileSharedElements(ArrayList<String> sharedElementNames) {
+        Rect epicenter = null;
+        for (int i = mTargetSharedNames.size() - 1; i >= 0; i--) {
+            if (!sharedElementNames.contains(mTargetSharedNames.get(i))) {
+                mTargetSharedNames.remove(i);
+                mSharedElements.remove(i);
+            }
+        }
+        if (!mSharedElements.isEmpty()) {
+            epicenter = calcEpicenter(mSharedElements.get(0));
+        }
+        mEpicenterCallback.setEpicenter(epicenter);
+    }
+
+    private void setSharedElementState(Bundle sharedElementState) {
+        if (sharedElementState != null) {
+            int[] tempLoc = new int[2];
+            for (int i = 0; i < mSharedElements.size(); i++) {
+                View sharedElement = mSharedElements.get(i);
+                String name = mTargetSharedNames.get(i);
+                setSharedElementState(sharedElement, name, sharedElementState, tempLoc);
+            }
+        }
+        mListener.onCaptureSharedElementStart();
+        getDecor().getViewTreeObserver().addOnPreDrawListener(
+                new ViewTreeObserver.OnPreDrawListener() {
+                    @Override
+                    public boolean onPreDraw() {
+                        getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
+                        mListener.onCaptureSharedElementEnd();
+                        return true;
+                    }
+                }
+        );
+    }
+
+    /**
+     * Sets the captured values from a previous
+     * {@link #captureSharedElementState(android.view.View, String, android.os.Bundle, int[])}
+     * @param view The View to apply placement changes to.
+     * @param name The shared element name given from the source Activity.
+     * @param transitionArgs A <code>Bundle</code> containing all placementinformation for named
+     *                       shared elements in the scene.
+     * @param tempLoc A temporary int[2] for capturing the current location of views.
+     */
+    private static void setSharedElementState(View view, String name, Bundle transitionArgs,
+            int[] tempLoc) {
+        Bundle sharedElementBundle = transitionArgs.getBundle(name);
+        if (sharedElementBundle == null) {
+            return;
+        }
+
+        float z = sharedElementBundle.getFloat(KEY_TRANSLATION_Z);
+        view.setTranslationZ(z);
+
+        int x = sharedElementBundle.getInt(KEY_SCREEN_X);
+        int y = sharedElementBundle.getInt(KEY_SCREEN_Y);
+        int width = sharedElementBundle.getInt(KEY_WIDTH);
+        int height = sharedElementBundle.getInt(KEY_HEIGHT);
+
+        int widthSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
+        int heightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
+        view.measure(widthSpec, heightSpec);
+
+        ViewGroup parent = (ViewGroup) view.getParent();
+        parent.getLocationOnScreen(tempLoc);
+        int left = x - tempLoc[0];
+        int top = y - tempLoc[1];
+        int right = left + width;
+        int bottom = top + height;
+        view.layout(left, top, right, bottom);
+
+        view.requestLayout();
+    }
+
+    /**
+     * Captures placement information for Views with a shared element name for
+     * Activity Transitions.
+     * @param view The View to capture the placement information for.
+     * @param name The shared element name in the target Activity to apply the placement
+     *             information for.
+     * @param transitionArgs Bundle to store shared element placement information.
+     * @param tempLoc A temporary int[2] for capturing the current location of views.
+     * @see #setSharedElementState(android.view.View, String, android.os.Bundle, int[])
+     */
+    private static void captureSharedElementState(View view, String name, Bundle transitionArgs,
+            int[] tempLoc) {
+        Bundle sharedElementBundle = new Bundle();
+        view.getLocationOnScreen(tempLoc);
+        float scaleX = view.getScaleX();
+        sharedElementBundle.putInt(KEY_SCREEN_X, tempLoc[0]);
+        int width = Math.round(view.getWidth() * scaleX);
+        sharedElementBundle.putInt(KEY_WIDTH, width);
+
+        float scaleY = view.getScaleY();
+        sharedElementBundle.putInt(KEY_SCREEN_Y, tempLoc[1]);
+        int height= Math.round(view.getHeight() * scaleY);
+        sharedElementBundle.putInt(KEY_HEIGHT, height);
+
+        sharedElementBundle.putFloat(KEY_TRANSLATION_Z, view.getTranslationZ());
+
+        sharedElementBundle.putString(KEY_NAME, view.getSharedElementName());
+
+        transitionArgs.putBundle(name, sharedElementBundle);
+    }
+
+    private static Rect calcEpicenter(View view) {
+        int[] loc = new int[2];
+        view.getLocationOnScreen(loc);
+        int left = loc[0] + Math.round(view.getTranslationX());
+        int top = loc[1] + Math.round(view.getTranslationY());
+        int right = left + view.getWidth();
+        int bottom = top + view.getHeight();
+        return new Rect(left, top, right, bottom);
+    }
+
+    public static void setViewVisibility(Collection<View> views, int visibility) {
+        if (views != null) {
+            for (View view : views) {
+                view.setVisibility(visibility);
+            }
+        }
+    }
+
+    private static Transition addTransitionTargets(Transition transition, Collection<View> views) {
+        if (transition == null || views == null || views.isEmpty()) {
+            return null;
+        }
+        TransitionSet set = new TransitionSet();
+        set.addTransition(transition.clone());
+        if (views != null) {
+            for (View view: views) {
+                set.addTarget(view);
+            }
+        }
+        return set;
+    }
+
+    private ArrayList<View> captureTransitioningViews() {
+        if (getViewsTransition() == null) {
+            return null;
+        }
+        ArrayList<View> transitioningViews = new ArrayList<View>();
+        getDecor().captureTransitioningViews(transitioningViews);
+        transitioningViews.removeAll(getSharedElements());
+        return transitioningViews;
+    }
+
+    private Transition getSharedElementTransition(boolean isEnter) {
+        Transition transition = getSharedElementTransition();
+        if (transition == null) {
+            return null;
+        }
+        transition = configureTransition(transition);
+        if (!isEnter) {
+            transition.addListener(mSharedElementListener);
+        }
+        return transition;
+    }
+
+    private Transition getViewsTransition(ArrayList<View> transitioningViews, boolean isEnter) {
+        Transition transition = getViewsTransition();
+        if (transition == null) {
+            return null;
+        }
+        transition = configureTransition(transition);
+        if (!isEnter) {
+            transition.addListener(mExitListener);
+        }
+        return addTransitionTargets(transition, transitioningViews);
+    }
+
+    private Transition beginTransition(ArrayList<View> transitioningViews,
+            boolean transitionSharedElement, boolean transitionViews, boolean isEnter) {
+        Transition sharedElementTransition = null;
+        if (transitionSharedElement) {
+            sharedElementTransition = getSharedElementTransition(isEnter);
+            if (!isEnter && sharedElementTransition == null) {
+                onSharedElementTransitionEnd();
+            }
+        }
+        Transition viewsTransition = null;
+        if (transitionViews) {
+            viewsTransition = getViewsTransition(transitioningViews, isEnter);
+            if (!isEnter && viewsTransition == null) {
+                onExitTransitionEnd();
+            }
+        }
+
+        Transition transition = null;
+        if (sharedElementTransition == null) {
+            transition = viewsTransition;
+        } else if (viewsTransition == null) {
+            transition = sharedElementTransition;
+        } else {
+            TransitionSet set = new TransitionSet();
+            set.addTransition(sharedElementTransition);
+            set.addTransition(viewsTransition);
+            transition = set;
+        }
+        if (transition != null) {
+            TransitionManager.beginDelayedTransition(getDecor(), transition);
+            if (transitionSharedElement && !mSharedElements.isEmpty()) {
+                mSharedElements.get(0).invalidate();
+            } else if (transitionViews && !transitioningViews.isEmpty()) {
+                transitioningViews.get(0).invalidate();
+            }
+        }
+        return transition;
+    }
+
+    private static class FixedEpicenterCallback extends Transition.EpicenterCallback {
+        private Rect mEpicenter;
+
+        public void setEpicenter(Rect epicenter) { mEpicenter = epicenter; }
+
+        @Override
+        public Rect getEpicenter(Transition transition) {
+            return mEpicenter;
+        }
+    }
+}
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
new file mode 100644
index 0000000..aa097e0
--- /dev/null
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.ResultReceiver;
+import android.transition.Transition;
+import android.util.ArrayMap;
+import android.util.Pair;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.Window;
+
+import java.util.ArrayList;
+
+/**
+ * This ActivityTransitionCoordinator is created by the Activity to manage
+ * the enter scene and shared element transfer as well as Activity#finishWithTransition
+ * exiting the Scene and transferring shared elements back to the called Activity.
+ */
+class EnterTransitionCoordinator extends ActivityTransitionCoordinator
+        implements ViewTreeObserver.OnPreDrawListener {
+    private static final String TAG = "EnterTransitionCoordinator";
+
+    // The background fade in/out duration. 150ms is pretty quick, but not abrupt.
+    private static final int FADE_BACKGROUND_DURATION_MS = 150;
+
+    /**
+     * The shared element names sent by the ExitTransitionCoordinator and may be
+     * shared when exiting back.
+     */
+    private ArrayList<String> mEnteringSharedElementNames;
+
+    /**
+     * The Activity that has created this coordinator. This is used solely to make the
+     * Window translucent/opaque.
+     */
+    private Activity mActivity;
+
+    /**
+     * True if the Window was opaque at the start and we should make it opaque again after
+     * enter transitions have completed.
+     */
+    private boolean mWasOpaque;
+
+    /**
+     * During exit, is the background alpha == 0?
+     */
+    private boolean mBackgroundFadedOut;
+
+    /**
+     * During exit, has the shared element transition completed?
+     */
+    private boolean mSharedElementTransitionComplete;
+
+    /**
+     * Has the exit started? We don't want to accidentally exit multiple times. e.g. when
+     * back is hit twice during the exit animation.
+     */
+    private boolean mExitTransitionStarted;
+
+    /**
+     * Has the exit transition ended?
+     */
+    private boolean mExitTransitionComplete;
+
+    /**
+     * We only want to make the Window transparent and set the background alpha once. After that,
+     * the Activity won't want the same enter transition.
+     */
+    private boolean mMadeReady;
+
+    /**
+     * True if Window.hasFeature(Window.FEATURE_CONTENT_TRANSITIONS) -- this means that
+     * enter and exit transitions should be active.
+     */
+    private boolean mSupportsTransition;
+
+    /**
+     * Background alpha animations may complete prior to receiving the callback for
+     * onTranslucentConversionComplete. If so, we need to immediately call to make the Window
+     * opaque.
+     */
+    private boolean mMakeOpaque;
+
+    public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver) {
+        super(activity.getWindow());
+        mActivity = activity;
+        setRemoteResultReceiver(resultReceiver);
+    }
+
+    public void readyToEnter() {
+        if (!mMadeReady) {
+            mMadeReady = true;
+            mSupportsTransition = getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS);
+            if (mSupportsTransition) {
+                Window window = getWindow();
+                window.getDecorView().getViewTreeObserver().addOnPreDrawListener(this);
+                mActivity.overridePendingTransition(0, 0);
+                mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
+                    @Override
+                    public void onTranslucentConversionComplete(boolean drawComplete) {
+                        mWasOpaque = true;
+                        if (mMakeOpaque) {
+                            mActivity.convertFromTranslucent();
+                        }
+                    }
+                });
+                Drawable background = getDecor().getBackground();
+                if (background != null) {
+                    window.setBackgroundDrawable(null);
+                    background.setAlpha(0);
+                    window.setBackgroundDrawable(background);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void onRemoteSceneExitComplete() {
+        super.onRemoteSceneExitComplete();
+    }
+
+    @Override
+    protected void onTakeSharedElements(ArrayList<String> sharedElementNames, Bundle state) {
+        mEnteringSharedElementNames = new ArrayList<String>();
+        mEnteringSharedElementNames.addAll(sharedElementNames);
+        super.onTakeSharedElements(sharedElementNames, state);
+    }
+
+    @Override
+    protected void sharedElementTransitionComplete(Bundle bundle) {
+        notifySharedElementTransitionComplete(bundle);
+    }
+
+    @Override
+    public boolean onPreDraw() {
+        getWindow().getDecorView().getViewTreeObserver().removeOnPreDrawListener(this);
+        setEnteringViews(readyEnteringViews());
+        notifySetListener();
+        onPrepareRestore();
+        return false;
+    }
+
+    @Override
+    public void startExit() {
+        if (!mExitTransitionStarted) {
+            mExitTransitionStarted = true;
+            startExitTransition(mEnteringSharedElementNames);
+        }
+    }
+
+    @Override
+    protected Transition getViewsTransition() {
+        if (!mSupportsTransition) {
+            return null;
+        }
+        return getWindow().getEnterTransition();
+    }
+
+    @Override
+    protected Transition getSharedElementTransition() {
+        if (!mSupportsTransition) {
+            return null;
+        }
+        return getWindow().getSharedElementEnterTransition();
+    }
+
+    @Override
+    protected void onStartEnterTransition(Transition transition, ArrayList<View> enteringViews) {
+        Drawable background = getDecor().getBackground();
+        if (background != null) {
+            ObjectAnimator animator = ObjectAnimator.ofInt(background, "alpha", 255);
+            animator.setDuration(FADE_BACKGROUND_DURATION_MS);
+            animator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mMakeOpaque = true;
+                    if (mWasOpaque) {
+                        mActivity.convertFromTranslucent();
+                    }
+                }
+            });
+            animator.start();
+        } else if (mWasOpaque) {
+            transition.addListener(new Transition.TransitionListenerAdapter() {
+                @Override
+                public void onTransitionEnd(Transition transition) {
+                    mMakeOpaque = true;
+                    mActivity.convertFromTranslucent();
+                }
+            });
+        }
+        super.onStartEnterTransition(transition, enteringViews);
+    }
+
+    public ArrayList<View> readyEnteringViews() {
+        ArrayList<View> enteringViews = new ArrayList<View>();
+        getDecor().captureTransitioningViews(enteringViews);
+        if (getViewsTransition() != null) {
+            setViewVisibility(enteringViews, View.INVISIBLE);
+        }
+        return enteringViews;
+    }
+
+    @Override
+    protected void startExitTransition(ArrayList<String> sharedElements) {
+        notifyPrepareRestore();
+
+        if (getDecor().getBackground() == null) {
+            ColorDrawable black = new ColorDrawable(0xFF000000);
+            getWindow().setBackgroundDrawable(black);
+        }
+        if (mWasOpaque) {
+            mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
+                @Override
+                public void onTranslucentConversionComplete(boolean drawComplete) {
+                    fadeOutBackground();
+                }
+            });
+        } else {
+            fadeOutBackground();
+        }
+
+        super.startExitTransition(sharedElements);
+    }
+
+    private void fadeOutBackground() {
+        ObjectAnimator animator = ObjectAnimator.ofInt(getDecor().getBackground(),
+                "alpha", 0);
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mBackgroundFadedOut = true;
+                if (mSharedElementTransitionComplete) {
+                    EnterTransitionCoordinator.super.onSharedElementTransitionEnd();
+                }
+            }
+        });
+        animator.setDuration(FADE_BACKGROUND_DURATION_MS);
+        animator.start();
+    }
+
+    @Override
+    protected void onExitTransitionEnd() {
+        mExitTransitionComplete = true;
+        exitAfterSharedElementTransition();
+        super.onExitTransitionEnd();
+        clearConnections();
+    }
+
+    @Override
+    protected void onSharedElementTransitionEnd() {
+        mSharedElementTransitionComplete = true;
+        if (mBackgroundFadedOut) {
+            super.onSharedElementTransitionEnd();
+        }
+    }
+
+    @Override
+    protected boolean allowOverlappingTransitions() {
+        return getWindow().getAllowEnterTransitionOverlap();
+    }
+
+    private void exitAfterSharedElementTransition() {
+        if (mSharedElementTransitionComplete && mExitTransitionComplete) {
+            mActivity.finish();
+            if (mSupportsTransition) {
+                mActivity.overridePendingTransition(0, 0);
+            }
+            notifyExitTransitionComplete();
+        }
+    }
+}
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
new file mode 100644
index 0000000..d920787
--- /dev/null
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app;
+
+import android.os.Bundle;
+import android.transition.Transition;
+import android.util.Pair;
+import android.view.View;
+import android.view.Window;
+
+import java.util.ArrayList;
+
+/**
+ * This ActivityTransitionCoordinator is created in ActivityOptions#makeSceneTransitionAnimation
+ * to govern the exit of the Scene and the shared elements when calling an Activity as well as
+ * the reentry of the Scene when coming back from the called Activity.
+ */
+class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
+    private static final String TAG = "ExitTransitionCoordinator";
+
+    /**
+     * The Views that have exited and need to be restored to VISIBLE when returning to the
+     * normal state.
+     */
+    private ArrayList<View> mTransitioningViews;
+
+    /**
+     * Has the exit started? We don't want to accidentally exit multiple times.
+     */
+    private boolean mExitStarted;
+
+    /**
+     * Has the called Activity's ResultReceiver been set?
+     */
+    private boolean mIsResultReceiverSet;
+
+    /**
+     * Has the exit transition completed? If so, we can notify as soon as the ResultReceiver
+     * has been set.
+     */
+    private boolean mExitComplete;
+
+    /**
+     * Has the shared element transition completed? If so, we can notify as soon as the
+     * ResultReceiver has been set.
+     */
+    private Bundle mSharedElements;
+
+    /**
+     * Has the shared element transition completed?
+     */
+    private boolean mSharedElementsComplete;
+
+    public ExitTransitionCoordinator(Window window,
+            ActivityOptions.ActivityTransitionListener listener) {
+        super(window);
+        setActivityTransitionListener(listener);
+    }
+
+    @Override
+    protected void onSetResultReceiver() {
+        mIsResultReceiverSet = true;
+        notifyCompletions();
+    }
+
+    @Override
+    protected void onPrepareRestore() {
+        makeTransitioningViewsInvisible();
+        setEnteringViews(mTransitioningViews);
+        mTransitioningViews = null;
+        super.onPrepareRestore();
+    }
+
+    @Override
+    protected void onTakeSharedElements(ArrayList<String> sharedElementNames, Bundle state) {
+        super.onTakeSharedElements(sharedElementNames, state);
+        clearConnections();
+    }
+
+    @Override
+    protected void onActivityStopped() {
+        if (getViewsTransition() != null) {
+            setViewVisibility(mTransitioningViews, View.VISIBLE);
+        }
+        super.onActivityStopped();
+    }
+
+    @Override
+    protected void sharedElementTransitionComplete(Bundle bundle) {
+        mSharedElements = bundle;
+        mSharedElementsComplete = true;
+        notifyCompletions();
+    }
+
+    @Override
+    protected void onExitTransitionEnd() {
+        mExitComplete = true;
+        notifyCompletions();
+        super.onExitTransitionEnd();
+    }
+
+    private void notifyCompletions() {
+        if (mIsResultReceiverSet && mSharedElementsComplete) {
+            if (mSharedElements != null) {
+                notifySharedElementTransitionComplete(mSharedElements);
+                mSharedElements = null;
+            }
+            if (mExitComplete) {
+                notifyExitTransitionComplete();
+            }
+        }
+    }
+
+    @Override
+    public void startExit() {
+        if (!mExitStarted) {
+            mExitStarted = true;
+            setSharedElements();
+            startExitTransition(getSharedElementNames());
+        }
+    }
+
+    @Override
+    protected Transition getViewsTransition() {
+        if (!getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
+            return null;
+        }
+        return getWindow().getExitTransition();
+    }
+
+    @Override
+    protected Transition getSharedElementTransition() {
+        if (!getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
+            return null;
+        }
+        return getWindow().getSharedElementExitTransition();
+    }
+
+    private void makeTransitioningViewsInvisible() {
+        if (getViewsTransition() != null) {
+            setViewVisibility(mTransitioningViews, View.INVISIBLE);
+        }
+    }
+
+    @Override
+    protected void onStartExitTransition(ArrayList<View> exitingViews) {
+        mTransitioningViews = new ArrayList<View>();
+        if (exitingViews != null) {
+            mTransitioningViews.addAll(exitingViews);
+        }
+        mTransitioningViews.addAll(getSharedElements());
+    }
+
+    @Override
+    protected boolean allowOverlappingTransitions() {
+        return getWindow().getAllowExitTransitionOverlap();
+    }
+}
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index b7ae31e..c67d6fa 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -1585,7 +1585,7 @@
      * hierarchy underneath it.
      */
     void capturePropagationValues(TransitionValues transitionValues) {
-        if (mPropagation != null) {
+        if (mPropagation != null && !transitionValues.values.isEmpty()) {
             String[] propertyNames = mPropagation.getPropagationProperties();
             if (propertyNames == null) {
                 return;
diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java
index f675c6a..14ecc15 100644
--- a/core/java/android/transition/TransitionInflater.java
+++ b/core/java/android/transition/TransitionInflater.java
@@ -309,15 +309,11 @@
         if (transitionId >= 0) {
             Transition transition = inflateTransition(transitionId);
             if (transition != null) {
+                if (toScene == null) {
+                    throw new RuntimeException("No toScene for transition ID " + transitionId);
+                }
                 if (fromScene == null) {
-                    if (toScene == null) {
-                        throw new RuntimeException("No matching fromScene or toScene " +
-                                "for transition ID " + transitionId);
-                    } else {
-                        transitionManager.setTransition(toScene, transition);
-                    }
-                } else if (toScene == null) {
-                    transitionManager.setExitTransition(fromScene, transition);
+                    transitionManager.setTransition(toScene, transition);
                 } else {
                     transitionManager.setTransition(fromScene, toScene, transition);
                 }
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index 1614d34..ce3cc2f 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -70,7 +70,6 @@
     private static final String[] EMPTY_STRINGS = new String[0];
 
     ArrayMap<Scene, Transition> mSceneTransitions = new ArrayMap<Scene, Transition>();
-    ArrayMap<Scene, Transition> mExitSceneTransitions = new ArrayMap<Scene, Transition>();
     ArrayMap<Scene, ArrayMap<Scene, Transition>> mScenePairTransitions =
             new ArrayMap<Scene, ArrayMap<Scene, Transition>>();
     private static ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>>
@@ -119,21 +118,6 @@
     }
 
     /**
-     * Sets a specific transition to occur when the given scene is exited. This
-     * has the lowest priority -- if a Scene-to-Scene transition or
-     * Scene enter transition can be applied, it will.
-     *
-     * @param scene The scene which, when exited, will cause the given
-     * transition to run.
-     * @param transition The transition that will play when the given scene is
-     * exited. A value of null will result in the default behavior of
-     * using the default transition instead.
-     */
-    public void setExitTransition(Scene scene, Transition transition) {
-        mExitSceneTransitions.put(scene, transition);
-    }
-
-    /**
      * Sets a specific transition to occur when the given pair of scenes is
      * exited/entered.
      *
@@ -181,9 +165,6 @@
             }
         }
         transition = mSceneTransitions.get(scene);
-        if (transition == null && sceneRoot != null) {
-            transition = mExitSceneTransitions.get(Scene.getCurrentScene(sceneRoot));
-        }
         return (transition != null) ? transition : sDefaultTransition;
     }
 
@@ -239,34 +220,6 @@
     }
 
     /**
-     * Retrieve the transition to a target defined scene if one has been
-     * associated with this TransitionManager.
-     *
-     * @param toScene Target scene that this transition will move to
-     * @return Transition corresponding to the given toScene or null
-     *         if no association exists in this TransitionManager
-     *
-     * @see #setTransition(Scene, Transition)
-     * @hide
-     */
-    public Transition getEnterTransition(Scene toScene) {
-        return mSceneTransitions.get(toScene);
-    }
-
-    /**
-     * Retrieve the transition from a defined scene to a target named scene if one has been
-     * associated with this TransitionManager.
-     *
-     * @param fromScene Scene that this transition starts from
-     * @return Transition corresponding to the given fromScene or null
-     *         if no association exists in this TransitionManager
-     * @hide
-     */
-    public Transition getExitTransition(Scene fromScene) {
-        return mExitSceneTransitions.get(fromScene);
-    }
-
-    /**
      * This private utility class is used to listen for both OnPreDraw and
      * OnAttachStateChange events. OnPreDraw events are the main ones we care
      * about since that's what triggers the transition to take place.
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 7783b6f..526803a 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -109,14 +109,14 @@
         final VisibilityInfo visInfo = new VisibilityInfo();
         visInfo.visibilityChange = false;
         visInfo.fadeIn = false;
-        if (startValues != null) {
+        if (startValues != null && startValues.values.containsKey(PROPNAME_VISIBILITY)) {
             visInfo.startVisibility = (Integer) startValues.values.get(PROPNAME_VISIBILITY);
             visInfo.startParent = (ViewGroup) startValues.values.get(PROPNAME_PARENT);
         } else {
             visInfo.startVisibility = -1;
             visInfo.startParent = null;
         }
-        if (endValues != null) {
+        if (endValues != null && endValues.values.containsKey(PROPNAME_VISIBILITY)) {
             visInfo.endVisibility = (Integer) endValues.values.get(PROPNAME_VISIBILITY);
             visInfo.endParent = (ViewGroup) endValues.values.get(PROPNAME_PARENT);
         } else {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index d2c6302..a64bdc7 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2305,11 +2305,13 @@
 
     /**
      * Changes whether or not this ViewGroup should be treated as a single entity during
-     * ActivityTransitions.
+     * Activity Transitions.
      * @param isTransitionGroup Whether or not the ViewGroup should be treated as a unit
      *                          in Activity transitions. If false, the ViewGroup won't transition,
      *                          only its children. If true, the entire ViewGroup will transition
      *                          together.
+     * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
+     * android.app.ActivityOptions.ActivityTransitionListener)
      */
     public void setTransitionGroup(boolean isTransitionGroup) {
         mGroupFlags |= FLAG_IS_TRANSITION_GROUP_SET;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 7bd1f56..9c44bd1 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -32,8 +32,6 @@
 import android.transition.TransitionManager;
 import android.view.accessibility.AccessibilityEvent;
 
-import java.util.Map;
-
 /**
  * Abstract base class for a top-level window look and behavior policy.  An
  * instance of this class should be used as the top-level view added to the
@@ -1385,86 +1383,132 @@
     }
 
     /**
-     * Set options that can affect the transition behavior within this window.
-     * @param options Options to set or null for none
-     * @hide
+     * Sets the Transition that will be used to move Views into the initial scene. The entering
+     * Views will be those that are regular Views or ViewGroups that have
+     * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
+     * {@link android.transition.Visibility} as entering is governed by changing visibility from
+     * {@link View#INVISIBLE} to {@link View#VISIBLE}. If <code>transition</code> is null,
+     * entering Views will remain unaffected.
+     * @param transition The Transition to use to move Views into the initial Scene.
      */
-    public void setTransitionOptions(Bundle options, SceneTransitionListener listener) {
-    }
+    public void setEnterTransition(Transition transition) {}
 
     /**
-     * A callback for Window transitions to be told when the shared element is ready to be shown
-     * and start the transition to its target location.
-     * @hide
+     * Sets the Transition that will be used to move Views out of the scene when starting a
+     * new Activity. The exiting Views will be those that are regular Views or ViewGroups that
+     * have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
+     * {@link android.transition.Visibility} as exiting is governed by changing visibility
+     * from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, the views will
+     * remain unaffected. Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+     * @param transition The Transition to use to move Views out of the scene when calling a
+     *                   new Activity.
      */
-    public interface SceneTransitionListener {
-        void nullPendingTransition();
-        void convertFromTranslucent();
-        void convertToTranslucent();
-        void sharedElementStart(Transition transition);
-        void sharedElementEnd();
-    }
+    public void setExitTransition(Transition transition) {}
 
     /**
-     * Controls how the Activity's start Scene is faded in and when the enter scene
-     * is triggered to start.
-     * <p>When allow is true, the enter Scene will begin as soon as possible
-     * and the background will fade in when all shared elements are ready to begin
-     * transitioning. If allow is false, the Activity enter Scene and
-     * background fade will be triggered when the calling Activity's exit transition
-     * completes.</p>
-     * @param allow Set to true to have the Activity enter scene transition in
-     *              as early as possible or set to false to wait for the calling
-     *              Activity to exit first. The default value is true.
+     * Returns the transition used to move Views into the initial scene. The entering
+     * Views will be those that are regular Views or ViewGroups that have
+     * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
+     * {@link android.transition.Visibility} as entering is governed by changing visibility from
+     * {@link View#INVISIBLE} to {@link View#VISIBLE}. If <code>transition</code> is null,
+     * entering Views will remain unaffected.  Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+     *
+     * @return the Transition to use to move Views into the initial Scene.
      */
-    public void setAllowOverlappingEnterTransition(boolean allow) {
-    }
+    public Transition getEnterTransition() { return null; }
 
     /**
-     * Controls how the Activity's Scene fades out and when the calling Activity's
-     * enter scene is triggered when finishing to return to a calling Activity.
-     * <p>When allow is true, the Scene will fade out quickly
-     * and inform the calling Activity to transition in when the fade completes.
-     * When allow is false, the calling Activity will transition in after
-     * the Activity's Scene has exited.
-     * </p>
-     * @param allow Set to true to have the Activity fade out as soon as possible
-     *              and transition in the calling Activity. The default value is
-     *              true.
+     * Returns the Transition that will be used to move Views out of the scene when starting a
+     * new Activity. The exiting Views will be those that are regular Views or ViewGroups that
+     * have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
+     * {@link android.transition.Visibility} as exiting is governed by changing visibility
+     * from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, the views will
+     * remain unaffected. Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+     * @return the Transition to use to move Views out of the scene when calling a
+     * new Activity.
      */
-    public void setAllowOverlappingExitTransition(boolean allow) {
-    }
+    public Transition getExitTransition() { return null; }
 
     /**
-     * Start the exit transition.
-     * @hide
+     * Sets the Transition that will be used for shared elements transferred into the content
+     * Scene. Typical Transitions will affect size and location, such as
+     * {@link android.transition.MoveImage} and {@link android.transition.ChangeBounds}. A null
+     * value will cause transferred shared elements to blink to the final position.
+     * Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+     * @param transition The Transition to use for shared elements transferred into the content
+     *                   Scene.
      */
-    public Bundle startExitTransitionToCallee(Bundle options) {
-        return null;
-    }
+    public void setSharedElementEnterTransition(Transition transition) {}
 
     /**
-     * Starts the transition back to the calling Activity.
-     * onTransitionEnd will be called on the current thread if there is no exit transition.
-     * @hide
+     * Returns the Transition that will be used for shared elements transferred into the content
+     * Scene. Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+     * @return Transition to use for sharend elements transferred into the content Scene.
      */
-    public void startExitTransitionToCaller(Runnable onTransitionEnd) {
-        onTransitionEnd.run();
-    }
-
-    /** @hide */
-    public void restoreViewVisibilityAfterTransitionToCallee() {
-    }
+    public Transition getSharedElementEnterTransition() { return null; }
 
     /**
-     * On entering Activity Scene transitions, shared element names may be mapped from a
-     * source Activity's specified name to a unique shared element name in the View hierarchy.
-     * Under most circumstances, mapping is not necessary - a single View will have the
-     * shared element name given by the calling Activity. However, if there are several similar
-     * Views (e.g. in a ListView), the correct shared element must be mapped.
-     * @param sharedElementNames A mapping from the calling Activity's assigned shared element
-     *                           name to a unique shared element name in the View hierarchy.
+     * Sets the Transition that will be used for shared elements after starting a new Activity
+     * before the shared elements are transferred to the called Activity. If the shared elements
+     * must animate during the exit transition, this Transition should be used. Upon completion,
+     * the shared elements may be transferred to the started Activity.
+     * Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+     * @param transition The Transition to use for shared elements in the launching Window
+     *                   prior to transferring to the launched Activity's Window.
      */
-    public void mapTransitionTargets(Map<String, String> sharedElementNames) {
-    }
+    public void setSharedElementExitTransition(Transition transition) {}
+
+    /**
+     * Returns the Transition to use for shared elements in the launching Window prior
+     * to transferring to the launched Activity's Window.
+     * Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+     *
+     * @return the Transition to use for shared elements in the launching Window prior
+     * to transferring to the launched Activity's Window.
+     */
+    public Transition getSharedElementExitTransition() { return null; }
+
+    /**
+     * Controls how the transition set in
+     * {@link #setEnterTransition(android.transition.Transition)} overlaps with the exit
+     * transition of the calling Activity. When true, the transition will start as soon as possible.
+     * When false, the transition will wait until the remote exiting transition completes before
+     * starting.
+     * @param allow true to start the enter transition when possible or false to
+     *              wait until the exiting transition completes.
+     */
+    public void setAllowEnterTransitionOverlap(boolean allow) {}
+
+    /**
+     * Returns how the transition set in
+     * {@link #setEnterTransition(android.transition.Transition)} overlaps with the exit
+     * transition of the calling Activity. When true, the transition will start as soon as possible.
+     * When false, the transition will wait until the remote exiting transition completes before
+     * starting.
+     * @return true when the enter transition should start as soon as possible or false to
+     * when it should wait until the exiting transition completes.
+     */
+    public boolean getAllowEnterTransitionOverlap() { return true; }
+
+    /**
+     * Controls how the transition set in
+     * {@link #setExitTransition(android.transition.Transition)} overlaps with the exit
+     * transition of the called Activity when reentering after if finishes. When true,
+     * the transition will start as soon as possible. When false, the transition will wait
+     * until the called Activity's exiting transition completes before starting.
+     * @param allow true to start the transition when possible or false to wait until the
+     *              called Activity's exiting transition completes.
+     */
+    public void setAllowExitTransitionOverlap(boolean allow) {}
+
+    /**
+     * Returns how the transition set in
+     * {@link #setExitTransition(android.transition.Transition)} overlaps with the exit
+     * transition of the called Activity when reentering after if finishes. When true,
+     * the transition will start as soon as possible. When false, the transition will wait
+     * until the called Activity's exiting transition completes before starting.
+     * @return true when the transition should start when possible or false when it should wait
+     * until the called Activity's exiting transition completes.
+     */
+    public boolean getAllowExitTransitionOverlap() { return true; }
 }
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
index 34156e5..afb6f7c 100644
--- a/core/java/com/android/internal/app/ToolbarActionBar.java
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -444,9 +444,4 @@
             mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible);
         }
     }
-
-    @Override
-    public void captureSharedElements(Map<String, View> sharedElements) {
-        mToolbar.findSharedElements(sharedElements);
-    }
 }
diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
index fb93ddd..131f828 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -362,10 +362,6 @@
         setSubtitle(mContext.getString(resId));
     }
 
-    public void captureSharedElements(Map<String, View> sharedElements) {
-        mContainerView.findSharedElements(sharedElements);
-    }
-
     public void setSelectedNavigationItem(int position) {
         switch (mActionView.getNavigationMode()) {
         case NAVIGATION_MODE_TABS:
diff --git a/core/res/res/transition/no_transition.xml b/core/res/res/transition/no_transition.xml
new file mode 100644
index 0000000..5679738
--- /dev/null
+++ b/core/res/res/transition/no_transition.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<transitionSet/>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index f364bd0..53fed98 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -462,6 +462,41 @@
              transitions between different window content. -->
         <attr name="windowContentTransitionManager" format="reference" />
 
+        <!-- Reference to a TransitionManager XML resource defining the desired Transition
+             used to move Views into the initial Window's content Scene. Corresponds to
+             {@link android.view.Window#setEnterTransition(android.transition.Transition)}. -->
+        <attr name="windowEnterTransition" format="reference"/>
+
+        <!-- Reference to a TransitionManager XML resource defining the desired Transition
+             used to move Views out of the Window's content Scene when launching a new Activity.
+             Corresponds to
+             {@link android.view.Window#setExitTransition(android.transition.Transition)}. -->
+        <attr name="windowExitTransition" format="reference"/>
+
+        <!-- Reference to a TransitionManager XML resource defining the desired Transition
+             used to move shared elements transferred into the Window's initial content Scene.
+             Corresponds to {@link android.view.Window#setSharedElementEnterTransition(
+             android.transition.Transition)}. -->
+        <attr name="windowSharedElementEnterTransition" format="reference"/>
+
+        <!-- Reference to a TransitionManager XML resource defining the desired Transition
+             used when starting a new Activity to move shared elements prior to transferring
+             to the called Activity.
+             Corresponds to {@link android.view.Window#setSharedElementExitTransition(
+             android.transition.Transition)}. -->
+        <attr name="windowSharedElementExitTransition" format="reference"/>
+
+        <!-- Flag indicating whether this Window's transition should overlap with
+             the exiting transition of the calling Activity. Corresponds to
+             {@link android.view.Window#setAllowEnterTransitionOverlap(boolean)}. -->
+        <attr name="windowAllowEnterTransitionOverlap" format="boolean"/>
+
+        <!-- Flag indicating whether this Window's transition should overlap with
+             the exiting transition of the called Activity when the called Activity
+             finishes. Corresponds to
+             {@link android.view.Window#setAllowExitTransitionOverlap(boolean)}. -->
+        <attr name="windowAllowExitTransitionOverlap" format="boolean"/>
+
         <!-- ============ -->
         <!-- Alert Dialog styles -->
         <!-- ============ -->
@@ -1690,6 +1725,41 @@
              or a fraction of the screen size in that dimension. -->
         <attr name="windowFixedHeightMajor" format="dimension|fraction" />
         <attr name="windowOutsetBottom" format="dimension" />
+        <!-- Reference to a TransitionManager XML resource defining the desired Transition
+             used to move Views into the initial Window's content Scene. Corresponds to
+             {@link android.view.Window#setEnterTransition(android.transition.Transition)}. -->
+        <attr name="windowEnterTransition"/>
+
+        <!-- Reference to a TransitionManager XML resource defining the desired Transition
+             used to move Views out of the Window's content Scene when launching a new Activity.
+             Corresponds to
+             {@link android.view.Window#setExitTransition(android.transition.Transition)}. -->
+        <attr name="windowExitTransition"/>
+
+        <!-- Reference to a TransitionManager XML resource defining the desired Transition
+             used to move shared elements transferred into the Window's initial content Scene.
+             Corresponds to {@link android.view.Window#setSharedElementEnterTransition(
+             android.transition.Transition)}. -->
+        <attr name="windowSharedElementEnterTransition"/>
+
+        <!-- Reference to a TransitionManager XML resource defining the desired Transition
+             used when starting a new Activity to move shared elements prior to transferring
+             to the called Activity.
+             Corresponds to {@link android.view.Window#setSharedElementExitTransition(
+             android.transition.Transition)}. -->
+        <attr name="windowSharedElementExitTransition"/>
+
+
+        <!-- Flag indicating whether this Window's transition should overlap with
+             the exiting transition of the calling Activity. Corresponds to
+             {@link android.view.Window#setAllowEnterTransitionOverlap(boolean)}. -->
+        <attr name="windowAllowEnterTransitionOverlap"/>
+
+        <!-- Flag indicating whether this Window's transition should overlap with
+             the exiting transition of the called Activity when the called Activity
+             finishes. Corresponds to
+             {@link android.view.Window#setAllowExitTransitionOverlap(boolean)}. -->
+        <attr name="windowAllowExitTransitionOverlap"/>
     </declare-styleable>
 
     <!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -2383,8 +2453,9 @@
              when doing an Activity transition. Typically, the elements inside a
              ViewGroup are each transitioned from the scene individually. The default
              for a ViewGroup is false unless it has a background. See
-             {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.View, String)}
-             for more information. -->
+             {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
+             android.view.View, String)} for more information. Corresponds to
+             {@link android.view.ViewGroup#setTransitionGroup(boolean)}.-->
         <attr name="transitionGroup" format="boolean" />
     </declare-styleable>
 
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 32b674e..9712c03 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2389,4 +2389,11 @@
   <public type="interpolator" name="linear_out_slow_in" />
   <!-- An interpolator which accelerates fast and keeps accelerating until the end. -->
   <public type="interpolator" name="fast_out_linear_in" />
+  <public type="attr" name="windowEnterTransition" />
+  <public type="attr" name="windowExitTransition" />
+  <public type="attr" name="windowSharedElementEnterTransition" />
+  <public type="attr" name="windowSharedElementExitTransition" />
+  <public type="attr" name="windowAllowExitTransitionOverlap" />
+  <public type="attr" name="windowAllowEnterTransitionOverlap" />
+  <public type="transition" name="no_transition" id="0x010f0000"/>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 563272b..b0f19ec 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1839,5 +1839,6 @@
   <java-symbol type="drawable" name="ic_lock_bugreport" />
   <java-symbol type="id" name="icon_frame" />
   <java-symbol type="style" name="Animation.VolumePanel" />
+  <java-symbol type="transition" name="no_transition" />
 
 </resources>
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 79ed866..2cf94d0 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -22,19 +22,6 @@
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.WindowManager.LayoutParams.*;
 
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
-import android.app.ActivityOptions;
-import android.os.Looper;
-import android.transition.Fade;
-import android.transition.Scene;
-import android.transition.Transition;
-import android.transition.TransitionInflater;
-import android.transition.TransitionManager;
-import android.transition.TransitionSet;
-import android.util.ArrayMap;
-import android.view.ViewConfiguration;
-
 import com.android.internal.R;
 import com.android.internal.view.RootViewSurfaceTaker;
 import com.android.internal.view.StandaloneActionMode;
@@ -51,6 +38,9 @@
 import com.android.internal.widget.ActionBarView;
 import com.android.internal.widget.SwipeDismissLayout;
 
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.app.ActivityOptions;
 import android.app.KeyguardManager;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
@@ -65,11 +55,22 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.transition.ChangeBounds;
+import android.transition.Explode;
+import android.transition.Fade;
+import android.transition.MoveImage;
+import android.transition.Scene;
+import android.transition.Transition;
+import android.transition.TransitionInflater;
+import android.transition.TransitionManager;
+import android.transition.TransitionSet;
 import android.util.AndroidRuntimeException;
+import android.util.ArrayMap;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
@@ -90,6 +91,7 @@
 import android.view.MotionEvent;
 import android.view.SurfaceHolder;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewManager;
 import android.view.ViewParent;
@@ -124,16 +126,6 @@
     private final static String TAG = "PhoneWindow";
 
     private final static boolean SWEEP_OPEN_MENU = false;
-    private static final long MAX_TRANSITION_START_WAIT = 500;
-    private static final long MAX_TRANSITION_FINISH_WAIT = 1000;
-
-    private static final String KEY_SCREEN_X = "shared_element:screenX";
-    private static final String KEY_SCREEN_Y = "shared_element:screenY";
-    private static final String KEY_TRANSLATION_Z = "shared_element:translationZ";
-    private static final String KEY_WIDTH = "shared_element:width";
-    private static final String KEY_HEIGHT = "shared_element:height";
-    private static final String KEY_NAME = "shared_element:name";
-
     /**
      * Simple callback used by the context menu and its submenus. The options
      * menu submenus do not use this (their behavior is more complex).
@@ -252,12 +244,12 @@
         }
     };
 
-    private ActivityOptions mActivityOptions;
-    private SceneTransitionListener mSceneTransitionListener;
-    private boolean mAllowEnterOverlap = true;
-    private boolean mAllowExitOverlap = true;
-    private Map<String, String> mSharedElementsMap;
-    private ArrayList<View> mTransitioningViews;
+    private Transition mEnterTransition;
+    private Transition mExitTransition;
+    private Transition mSharedElementEnterTransition;
+    private Transition mSharedElementExitTransition;
+    private Boolean mAllowExitTransitionOverlap;
+    private Boolean mAllowEnterTransitionOverlap;
 
     static class WindowManagerHolder {
         static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
@@ -410,9 +402,6 @@
     private void transitionTo(Scene scene) {
         if (mContentScene == null) {
             scene.enter();
-            if (mActivityOptions != null) {
-                new EnterScene().start();
-            }
         } else {
             mTransitionManager.transitionTo(scene);
         }
@@ -3307,20 +3296,55 @@
 
             // Only inflate or create a new TransitionManager if the caller hasn't
             // already set a custom one.
-            if (hasFeature(FEATURE_CONTENT_TRANSITIONS) && mTransitionManager == null) {
-                final int transitionRes = getWindowStyle().getResourceId(
-                        com.android.internal.R.styleable.Window_windowContentTransitionManager, 0);
-                if (transitionRes != 0) {
-                    final TransitionInflater inflater = TransitionInflater.from(getContext());
-                    mTransitionManager = inflater.inflateTransitionManager(transitionRes,
-                            mContentParent);
-                } else {
-                    mTransitionManager = new TransitionManager();
+            if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
+                if (mTransitionManager == null) {
+                    final int transitionRes = getWindowStyle().getResourceId(
+                            com.android.internal.R.styleable.Window_windowContentTransitionManager,
+                            0);
+                    if (transitionRes != 0) {
+                        final TransitionInflater inflater = TransitionInflater.from(getContext());
+                        mTransitionManager = inflater.inflateTransitionManager(transitionRes,
+                                mContentParent);
+                    } else {
+                        mTransitionManager = new TransitionManager();
+                    }
+                }
+
+                mEnterTransition = getTransition(mEnterTransition,
+                        com.android.internal.R.styleable.Window_windowEnterTransition);
+                mExitTransition = getTransition(mExitTransition,
+                        com.android.internal.R.styleable.Window_windowExitTransition);
+                mSharedElementEnterTransition = getTransition(mSharedElementEnterTransition,
+                        com.android.internal.R.styleable.Window_windowSharedElementEnterTransition);
+                mSharedElementExitTransition = getTransition(mSharedElementExitTransition,
+                        com.android.internal.R.styleable.Window_windowSharedElementExitTransition);
+                if (mAllowEnterTransitionOverlap == null) {
+                    mAllowEnterTransitionOverlap = getWindowStyle().getBoolean(
+                            com.android.internal.R.styleable.
+                                    Window_windowAllowEnterTransitionOverlap, true);
+                }
+                if (mAllowExitTransitionOverlap == null) {
+                    mAllowExitTransitionOverlap = getWindowStyle().getBoolean(
+                            com.android.internal.R.styleable.
+                                    Window_windowAllowExitTransitionOverlap, true);
                 }
             }
         }
     }
 
+    private Transition getTransition(Transition currentValue, int id) {
+        if (currentValue != null) {
+            return currentValue;
+        }
+        int transitionId = getWindowStyle().getResourceId(id, -1);
+        Transition transition = null;
+        if (transitionId != -1 && transitionId != com.android.internal.R.transition.no_transition) {
+            TransitionInflater inflater = TransitionInflater.from(getContext());
+            transition = inflater.inflateTransition(transitionId);
+        }
+        return transition;
+    }
+
     private Drawable loadImageURI(Uri uri) {
         try {
             final Context context = getContext();
@@ -3649,6 +3673,66 @@
                 com.android.internal.R.styleable.Window_windowIsTranslucent, 0), false);
     }
 
+    @Override
+    public void setEnterTransition(Transition enterTransition) {
+        mEnterTransition = enterTransition;
+    }
+
+    @Override
+    public void setExitTransition(Transition exitTransition) {
+        mExitTransition = exitTransition;
+    }
+
+    @Override
+    public void setSharedElementEnterTransition(Transition sharedElementEnterTransition) {
+        mSharedElementEnterTransition = sharedElementEnterTransition;
+    }
+
+    @Override
+    public void setSharedElementExitTransition(Transition sharedElementExitTransition) {
+        mSharedElementExitTransition = sharedElementExitTransition;
+    }
+
+    @Override
+    public Transition getEnterTransition() {
+        return mEnterTransition;
+    }
+
+    @Override
+    public Transition getExitTransition() {
+        return mExitTransition;
+    }
+
+    @Override
+    public Transition getSharedElementEnterTransition() {
+        return mSharedElementEnterTransition;
+    }
+
+    @Override
+    public Transition getSharedElementExitTransition() {
+        return mSharedElementExitTransition;
+    }
+
+    @Override
+    public void setAllowEnterTransitionOverlap(boolean allow) {
+        mAllowEnterTransitionOverlap = allow;
+    }
+
+    @Override
+    public boolean getAllowEnterTransitionOverlap() {
+        return (mAllowEnterTransitionOverlap == null) ? true : mAllowEnterTransitionOverlap;
+    }
+
+    @Override
+    public void setAllowExitTransitionOverlap(boolean allowExitTransitionOverlap) {
+        mAllowExitTransitionOverlap = allowExitTransitionOverlap;
+    }
+
+    @Override
+    public boolean getAllowExitTransitionOverlap() {
+        return (mAllowExitTransitionOverlap == null) ? true : mAllowExitTransitionOverlap;
+    }
+
     private static final class DrawableFeatureState {
         DrawableFeatureState(int _featureId) {
             featureId = _featureId;
@@ -4082,670 +4166,4 @@
     void sendCloseSystemWindows(String reason) {
         PhoneWindowManager.sendCloseSystemWindows(getContext(), reason);
     }
-
-    @Override
-    public void setTransitionOptions(Bundle options, SceneTransitionListener listener) {
-        mSceneTransitionListener = listener;
-        ActivityOptions activityOptions = null;
-        if (options != null) {
-            activityOptions = new ActivityOptions(options);
-            if (activityOptions.getAnimationType() != ActivityOptions.ANIM_SCENE_TRANSITION) {
-                activityOptions = null;
-            }
-        }
-        mActivityOptions = activityOptions;
-    }
-
-    @Override
-    public void setAllowOverlappingEnterTransition(boolean allow) {
-        mAllowEnterOverlap = allow;
-    }
-
-    @Override
-    public void setAllowOverlappingExitTransition(boolean allow) {
-        mAllowExitOverlap = allow;
-    }
-
-    @Override
-    public void mapTransitionTargets(Map<String, String> sharedElementNames) {
-        mSharedElementsMap = sharedElementNames;
-    }
-
-    @Override
-    public void restoreViewVisibilityAfterTransitionToCallee() {
-        if (mTransitioningViews != null) {
-            setViewVisibility(mTransitioningViews, View.VISIBLE);
-        }
-    }
-
-    @Override
-    public void startExitTransitionToCaller(final Runnable onTransitionEnd) {
-        Transition transition;
-        if (mContentScene == null || mTransitionManager == null || mActivityOptions == null
-                || (transition = mTransitionManager.getEnterTransition(mContentScene)) == null) {
-            onTransitionEnd.run();
-            return;
-        }
-        if (mAllowExitOverlap) {
-            TransitionSet transitionSet = new TransitionSet();
-            transitionSet.addTransition(transition);
-            Fade fade = new Fade();
-            transitionSet.addTransition(fade);
-            transition = transitionSet;
-        }
-
-        final ArrayMap<String, View> sharedElements = new ArrayMap<String, View>();
-        mapSharedElements(sharedElements);
-        final Bundle sharedElementArgs = new Bundle();
-        captureTerminalSharedElementState(sharedElements, sharedElementArgs);
-
-        final ArrayList<View> transitioningViews = new ArrayList<View>();
-        mDecor.captureTransitioningViews(transitioningViews);
-        transitioningViews.removeAll(sharedElements.values());
-
-        mSceneTransitionListener.convertToTranslucent();
-        transition = transition.clone();
-        Rect epicenter = calcEpicenter(sharedElements, mActivityOptions.getSharedElementNames());
-        transition.setEpicenterCallback(new FixedEpicenterCallback(epicenter));
-        ExitSceneBack exitScene =
-                new ExitSceneBack(onTransitionEnd, sharedElementArgs, sharedElements.values());
-        exitScene.start(transition);
-        mTransitionManager.beginDelayedTransition(mDecor, transition);
-        setViewVisibility(transitioningViews, View.INVISIBLE);
-    }
-
-    @Override
-    public Bundle startExitTransitionToCallee(Bundle options) {
-        if (mContentScene == null) {
-            return null;
-        }
-        Transition transition = mTransitionManager.getExitTransition(mContentScene);
-        if (transition == null) {
-            return null;
-        }
-
-        ActivityOptions activityOptions = new ActivityOptions(options);
-        ArrayMap<String, View> sharedElements = findSharedElements(activityOptions);
-
-        // Find exiting Views and shared elements
-        ArrayList<View> transitioningViews = captureTransitioningViews(sharedElements.values());
-
-        Transition exitTransition = addTransitionTargets(transition,
-                transitioningViews, true);
-        Transition sharedElementTransition = addTransitionTargets(transition,
-                transitioningViews, false);
-
-        // transitionSet is the total exit transition, including hero animation.
-        TransitionSet transitionSet = new TransitionSet();
-        transitionSet.addTransition(exitTransition);
-        transitionSet.addTransition(sharedElementTransition);
-
-        Rect epicenter = calcEpicenter(sharedElements, activityOptions.getSharedElementNames());
-        FixedEpicenterCallback epicenterCallback = new FixedEpicenterCallback(epicenter);
-        transitionSet.setEpicenterCallback(epicenterCallback);
-
-        updateExitActivityOptions(activityOptions, sharedElements,
-                sharedElementTransition, transitioningViews, exitTransition, epicenterCallback);
-
-        // Start exiting the Views that need to exit
-        TransitionManager.beginDelayedTransition(mDecor, transitionSet);
-        setViewVisibility(transitioningViews, View.INVISIBLE);
-
-        return activityOptions.toBundle();
-    }
-
-    private ArrayList<View> captureTransitioningViews(Collection<View> sharedElements) {
-        mTransitioningViews = new ArrayList<View>();
-        mDecor.captureTransitioningViews(mTransitioningViews);
-        ArrayList<View> transitioningViews = (ArrayList<View>) mTransitioningViews.clone();
-        transitioningViews.removeAll(sharedElements);
-        return transitioningViews;
-    }
-
-    private ArrayMap<String, View> findSharedElements(ActivityOptions activityOptions) {
-        ArrayMap<String, View> sharedElements = new ArrayMap<String, View>();
-        mDecor.findSharedElements(sharedElements);
-        ArrayList<String> localNames = activityOptions.getLocalElementNames();
-        sharedElements.keySet().retainAll(localNames);
-
-        ArrayList<String> targetNames = activityOptions.getSharedElementNames();
-        for (int i = 0; i < localNames.size(); i++) {
-            String localName = localNames.get(i);
-            View sharedElement = sharedElements.remove(localName);
-            String targetName = targetNames.get(i);
-            sharedElements.put(targetName, sharedElement);
-        }
-        return sharedElements;
-    }
-
-    private static void runOnUiThread(Handler handler, Runnable runnable) {
-        if (handler.getLooper() != Looper.myLooper()) {
-            handler.post(runnable);
-        } else {
-            runnable.run();
-        }
-    }
-
-    private void updateExitActivityOptions(ActivityOptions activityOptions,
-            final Map<String, View> sharedElements, Transition sharedElementTransition,
-            final ArrayList<View> transitioningViews, Transition exitTransition,
-            final Transition.EpicenterCallback epicenterCallback) {
-
-        // Schedule capturing of the shared element state
-        final Bundle sharedElementArgs = new Bundle();
-        captureTerminalSharedElementState(sharedElements, sharedElementArgs);
-
-        ActivityOptions.SharedElementSource sharedElementSource
-                = new ActivityOptions.SharedElementSource() {
-            private Handler mHandler = new Handler();
-
-            @Override
-            public Bundle getSharedElementExitState() {
-                return sharedElementArgs;
-            }
-
-            @Override
-            public void acceptedSharedElements(final ArrayList<String> sharedElementNames) {
-                if (sharedElementNames.size() == sharedElements.size()) {
-                    return; // They were all accepted
-                }
-                runOnUiThread(mHandler, new Runnable() {
-                    @Override
-                    public void run() {
-                        Transition transition = mTransitionManager.getExitTransition(mContentScene);
-                        transition = transition.clone();
-                        transition.setEpicenterCallback(epicenterCallback);
-                        TransitionManager.beginDelayedTransition(mDecor, transition);
-                        for (String name : sharedElements.keySet()) {
-                            if (!sharedElementNames.contains(name)) {
-                                sharedElements.get(name).setVisibility(View.INVISIBLE);
-                            }
-                        }
-                        sharedElements.keySet().retainAll(sharedElementNames);
-                    }
-                });
-            }
-
-            @Override
-            public void hideSharedElements() {
-                if (sharedElements != null) {
-                    runOnUiThread(mHandler, new Runnable() {
-                        @Override
-                        public void run() {
-                            setViewVisibility(sharedElements.values(), View.INVISIBLE);
-                        }
-                    });
-                }
-            }
-
-            @Override
-            public void restore(final Bundle sharedElementState) {
-                runOnUiThread(mHandler, new Runnable() {
-                    @Override
-                    public void run() {
-                        mTransitioningViews = null;
-                        Transition transition = mTransitionManager.getExitTransition(mContentScene);
-                        transition = transition.clone();
-                        transition.setEpicenterCallback(epicenterCallback);
-                        setSharedElementState(sharedElements, sharedElementState);
-                        setViewVisibility(sharedElements.values(), View.VISIBLE);
-                        if (mSceneTransitionListener != null) {
-                            mSceneTransitionListener.sharedElementStart(transition);
-                            mDecor.getViewTreeObserver().addOnPreDrawListener(
-                                    new ViewTreeObserver.OnPreDrawListener() {
-                                        @Override
-                                        public boolean onPreDraw() {
-                                            mDecor.getViewTreeObserver().removeOnPreDrawListener(this);
-                                            mSceneTransitionListener.sharedElementEnd();
-                                            return true;
-                                        }
-                                    });
-                        }
-                        TransitionManager.beginDelayedTransition(mDecor, transition);
-                        setViewVisibility(transitioningViews, View.VISIBLE);
-                        for (View sharedElement: sharedElements.values()) {
-                            sharedElement.requestLayout();
-                        }
-                    }
-                });
-            }
-
-            @Override
-            public void prepareForRestore() {
-                if (mTransitioningViews != null) {
-                    runOnUiThread(mHandler, new Runnable() {
-                        @Override
-                        public void run() {
-                            setViewVisibility(mTransitioningViews, View.INVISIBLE);
-                        }
-                    });
-                }
-            }
-        };
-
-        activityOptions.updateSceneTransitionAnimation(
-                exitTransition, sharedElementTransition, sharedElementSource);
-    }
-
-    private void captureTerminalSharedElementState(final Map<String, View> sharedElements,
-            final Bundle sharedElementArgs) {
-        mDecor.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
-            @Override
-            public boolean onPreDraw() {
-                mDecor.getViewTreeObserver().removeOnPreDrawListener(this);
-                int[] tempLoc = new int[2];
-                for (String name : sharedElements.keySet()) {
-                    View sharedElement = sharedElements.get(name);
-                    captureSharedElementState(sharedElement, name, sharedElementArgs, tempLoc);
-                }
-                return true;
-            }
-        });
-    }
-
-    private static Transition addTransitionTargets(Transition transition, Collection<View> views,
-            boolean add) {
-        TransitionSet set = new TransitionSet();
-        set.addTransition(transition.clone());
-        for (View view: views) {
-            if (add) {
-                set.addTarget(view);
-            } else {
-                set.excludeTarget(view, true);
-            }
-        }
-        return set;
-    }
-
-    private static void setViewVisibility(Collection<View> views, int visibility) {
-        for (View view : views) {
-            view.setVisibility(visibility);
-        }
-    }
-
-    private static void setSharedElementState(Map<String, View> sharedElements,
-            Bundle sharedElementState) {
-        int[] tempLoc = new int[2];
-        for (Map.Entry<String, View> entry: sharedElements.entrySet()) {
-            setSharedElementState(entry.getValue(), entry.getKey(), sharedElementState, tempLoc);
-        }
-    }
-
-    /**
-     * Sets the captured values from a previous
-     * {@link #captureSharedElementState(android.view.View, String, android.os.Bundle, int[])}
-     * @param view The View to apply placement changes to.
-     * @param name The shared element name given from the source Activity.
-     * @param transitionArgs A <code>Bundle</code> containing all placementinformation for named
-     *                       shared elements in the scene.
-     * @param tempLoc A temporary int[2] for capturing the current location of views.
-     */
-    private static void setSharedElementState(View view, String name, Bundle transitionArgs,
-            int[] tempLoc) {
-        Bundle sharedElementBundle = transitionArgs.getBundle(name);
-        if (sharedElementBundle == null) {
-            return;
-        }
-
-        float z = sharedElementBundle.getFloat(KEY_TRANSLATION_Z);
-        view.setTranslationZ(z);
-
-        int x = sharedElementBundle.getInt(KEY_SCREEN_X);
-        int y = sharedElementBundle.getInt(KEY_SCREEN_Y);
-        int width = sharedElementBundle.getInt(KEY_WIDTH);
-        int height = sharedElementBundle.getInt(KEY_HEIGHT);
-
-        int widthSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
-        int heightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
-        view.measure(widthSpec, heightSpec);
-
-        ViewGroup parent = (ViewGroup) view.getParent();
-        parent.getLocationOnScreen(tempLoc);
-        int left = x - tempLoc[0];
-        int top = y - tempLoc[1];
-        int right = left + width;
-        int bottom = top + height;
-        view.layout(left, top, right, bottom);
-
-        view.requestLayout();
-    }
-
-    /**
-     * Captures placement information for Views with a shared element name for
-     * Activity Transitions.
-     * @param view The View to capture the placement information for.
-     * @param name The shared element name in the target Activity to apply the placement
-     *             information for.
-     * @param transitionArgs Bundle to store shared element placement information.
-     * @param tempLoc A temporary int[2] for capturing the current location of views.
-     * @see #setSharedElementState(android.view.View, String, android.os.Bundle, int[])
-     */
-    private static void captureSharedElementState(View view, String name, Bundle transitionArgs,
-            int[] tempLoc) {
-        Bundle sharedElementBundle = new Bundle();
-        view.getLocationOnScreen(tempLoc);
-        float scaleX = view.getScaleX();
-        sharedElementBundle.putInt(KEY_SCREEN_X, tempLoc[0]);
-        int width = Math.round(view.getWidth() * scaleX);
-        sharedElementBundle.putInt(KEY_WIDTH, width);
-
-        float scaleY = view.getScaleY();
-        sharedElementBundle.putInt(KEY_SCREEN_Y, tempLoc[1]);
-        int height= Math.round(view.getHeight() * scaleY);
-        sharedElementBundle.putInt(KEY_HEIGHT, height);
-
-        sharedElementBundle.putFloat(KEY_TRANSLATION_Z, view.getTranslationZ());
-
-        sharedElementBundle.putString(KEY_NAME, view.getSharedElementName());
-
-        transitionArgs.putBundle(name, sharedElementBundle);
-    }
-
-    private void mapSharedElements(ArrayMap<String, View> sharedElements) {
-        ArrayList<String> sharedElementNames = mActivityOptions.getSharedElementNames();
-        if (sharedElementNames != null) {
-            mDecor.findSharedElements(sharedElements);
-            if (mSharedElementsMap != null) {
-                for (Map.Entry<String, String> entry : mSharedElementsMap.entrySet()) {
-                    View sharedElement = sharedElements.remove(entry.getValue());
-                    if (sharedElement != null) {
-                        sharedElements.put(entry.getKey(), sharedElement);
-                    }
-                }
-            }
-            sharedElements.keySet().retainAll(sharedElementNames);
-        }
-    }
-
-    private static Rect calcEpicenter(ArrayMap<String, View> sharedElements,
-            ArrayList<String> sharedElementNames) {
-        if (sharedElementNames != null) {
-            for (String name: sharedElementNames) {
-                if (name.startsWith("android:")) {
-                    return null;
-                }
-                View view = sharedElements.get(name);
-                if (view != null) {
-                    int[] loc = new int[2];
-                    view.getLocationOnScreen(loc);
-                    int left = loc[0] + Math.round(view.getTranslationX());
-                    int top = loc[1] + Math.round(view.getTranslationY());
-                    int right = left + view.getWidth();
-                    int bottom = top + view.getHeight();
-                    return new Rect(left, top, right, bottom);
-                }
-            }
-        }
-        return null;
-    }
-
-    private class ExitSceneBack extends Transition.TransitionListenerAdapter implements
-            Animator.AnimatorListener {
-        private boolean mExitTransitionComplete;
-        private boolean mBackgroundFadeComplete;
-        private boolean mOnCompleteExecuted;
-        private boolean mSharedElementTransitioned;
-        private Runnable mOnComplete;
-        private Bundle mSharedElementArgs;
-        private Collection<View> mSharedElements;
-
-        public ExitSceneBack(Runnable onComplete, Bundle sharedElementArgs,
-                Collection<View> sharedElements) {
-            mOnComplete = onComplete;
-            mSharedElementArgs = sharedElementArgs;
-            mSharedElements = sharedElements;
-        }
-
-        public void start(Transition exitTransition) {
-            if (mActivityOptions != null) {
-                mActivityOptions.dispatchPrepareRestore();
-            }
-            exitTransition.addListener(this);
-            Drawable background = mDecor.getBackground();
-            if (background != null) {
-                ObjectAnimator animator = ObjectAnimator.ofInt(background, "alpha", 0);
-                animator.addListener(this);
-                animator.start();
-            } else {
-                mBackgroundFadeComplete = true;
-                startCalledActivityEnter();
-            }
-        }
-
-        @Override
-        public void onTransitionEnd(Transition transition) {
-            transition.removeListener(this);
-            mExitTransitionComplete = true;
-            notifyComplete();
-            if (!mAllowExitOverlap) {
-                startCalledActivityEnter();
-            }
-        }
-
-        private void notifyComplete() {
-            if (mExitTransitionComplete && mBackgroundFadeComplete
-                    && mSharedElementTransitioned && !mOnCompleteExecuted) {
-                mOnComplete.run();
-                mSceneTransitionListener.nullPendingTransition();
-                mOnCompleteExecuted = true;
-            }
-        }
-
-        @Override
-        public void onAnimationStart(Animator animation) {
-        }
-
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            mBackgroundFadeComplete = true;
-            if (mAllowExitOverlap) {
-                startCalledActivityEnter();
-            }
-        }
-
-        @Override
-        public void onAnimationCancel(Animator animation) {
-        }
-
-        @Override
-        public void onAnimationRepeat(Animator animation) {
-        }
-
-        private void startCalledActivityEnter() {
-            mActivityOptions.dispatchRestore(mSharedElementArgs);
-            setViewVisibility(mSharedElements, View.INVISIBLE);
-            mSharedElementTransitioned = true;
-            notifyComplete();
-        }
-    }
-
-    /**
-     * Provides code for handling the Activity transition entering scene.
-     * When the first scene is laid out (onPreDraw), it makes views invisible.
-     * It then starts the entering transition by making non-shared elements visible. When
-     * the entering transition is started, the calling Activity is notified that
-     * this Activity is ready to receive the shared element. When the calling Activity notifies
-     * that the shared element is ready, this Activity is notified through the
-     * SceneTransitionListener.
-     *
-     * This class also takes into account fading the background -- either waiting until the
-     * shared element is ready or the calling Activity's exit transition is complete.
-     */
-    private class EnterScene implements ViewTreeObserver.OnPreDrawListener, Runnable,
-            ActivityOptions.ActivityTransitionTarget, Animator.AnimatorListener {
-        private boolean mSharedElementReadyReceived;
-        private boolean mAllDone;
-        private Handler mHandler = new Handler();
-        private boolean mEnterTransitionStarted;
-        private ArrayMap<String, View> mSharedElementTargets = new ArrayMap<String, View>();
-        private ArrayList<View> mEnteringViews = new ArrayList<View>();
-        private Transition.EpicenterCallback mEpicenterCallback;
-
-        public EnterScene() {
-            mSceneTransitionListener.nullPendingTransition();
-            Drawable background = getDecorView().getBackground();
-            if (background != null) {
-                background.setAlpha(0);
-                mDecor.drawableChanged();
-            }
-            mSceneTransitionListener.convertToTranslucent();
-        }
-
-        @Override
-        public boolean onPreDraw() {
-            ViewTreeObserver observer = mDecor.getViewTreeObserver();
-            observer.removeOnPreDrawListener(this);
-            if (!mEnterTransitionStarted && mSceneTransitionListener != null) {
-                mEnterTransitionStarted = true;
-                mDecor.captureTransitioningViews(mEnteringViews);
-                mapSharedElements(mSharedElementTargets);
-                mEnteringViews.removeAll(mSharedElementTargets.values());
-                Rect epicenter = calcEpicenter(mSharedElementTargets,
-                        mActivityOptions.getSharedElementNames());
-                mEpicenterCallback = new FixedEpicenterCallback(epicenter);
-
-                setViewVisibility(mEnteringViews, View.INVISIBLE);
-                setViewVisibility(mSharedElementTargets.values(), View.INVISIBLE);
-                if (mAllowEnterOverlap) {
-                    beginEnterScene();
-                }
-                observer.addOnPreDrawListener(this);
-                return false;
-            } else {
-                mHandler.postDelayed(this, MAX_TRANSITION_START_WAIT);
-                mActivityOptions.dispatchSceneTransitionStarted(this,
-                        new ArrayList<String>(mSharedElementTargets.keySet()));
-                return !mSharedElementReadyReceived;
-            }
-        }
-
-        public void start() {
-            ViewTreeObserver observer = mDecor.getViewTreeObserver();
-            observer.addOnPreDrawListener(this);
-        }
-
-        @Override
-        public void run() {
-            exitTransitionComplete();
-        }
-
-        @Override
-        public void sharedElementTransitionComplete(final Bundle transitionArgs) {
-            if (!mSharedElementReadyReceived) {
-                mSharedElementReadyReceived = true;
-                mHandler.removeCallbacks(this);
-                mHandler.postDelayed(this, MAX_TRANSITION_FINISH_WAIT);
-                if (!mSharedElementTargets.isEmpty()) {
-                    runOnUiThread(mHandler, new Runnable() {
-                        @Override
-                        public void run() {
-                            Transition transition = getTransitionManager().getEnterTransition(
-                                    mContentScene);
-                            if (transition == null) {
-                                transition = TransitionManager.getDefaultTransition();
-                            }
-                            transition = addTransitionTargets(transition,
-                                    mSharedElementTargets.values(),
-                                    true);
-                            transition.setEpicenterCallback(mEpicenterCallback);
-                            if (transitionArgs == null) {
-                                TransitionManager.beginDelayedTransition(mDecor, transition);
-                                setViewVisibility(mSharedElementTargets.values(), View.VISIBLE);
-                            } else {
-                                mSceneTransitionListener.sharedElementStart(transition);
-                                setSharedElementState(mSharedElementTargets, transitionArgs);
-                                setViewVisibility(mSharedElementTargets.values(), View.VISIBLE);
-                                mDecor.getViewTreeObserver().addOnPreDrawListener(
-                                        new ViewTreeObserver.OnPreDrawListener() {
-                                            @Override
-                                            public boolean onPreDraw() {
-                                                mDecor.getViewTreeObserver()
-                                                        .removeOnPreDrawListener(this);
-                                                mSceneTransitionListener.sharedElementEnd();
-                                                mActivityOptions.dispatchSharedElementsReady();
-                                                return true;
-                                            }
-                                        });
-                                TransitionManager.beginDelayedTransition(mDecor, transition);
-                            }
-                        }
-                    });
-                }
-                if (mAllowEnterOverlap) {
-                    fadeInBackground();
-                }
-            }
-        }
-
-        private void fadeInBackground() {
-            Drawable background = getDecorView().getBackground();
-            if (background == null) {
-                mSceneTransitionListener.convertFromTranslucent();
-            } else {
-                ObjectAnimator animator = ObjectAnimator.ofInt(background, "alpha", 255);
-                animator.addListener(this);
-                animator.start();
-            }
-        }
-
-        @Override
-        public void exitTransitionComplete() {
-            if (mAllDone) {
-                return;
-            }
-            mAllDone = true;
-            sharedElementTransitionComplete(null);
-            mHandler.removeCallbacks(this);
-            if (!mAllowEnterOverlap) {
-                runOnUiThread(mHandler, new Runnable() {
-                    @Override
-                    public void run() {
-                        beginEnterScene();
-                        fadeInBackground();
-                    }
-                });
-            }
-        }
-
-        @Override
-        public void onAnimationStart(Animator animation) {
-        }
-
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            mSceneTransitionListener.convertFromTranslucent();
-        }
-
-        @Override
-        public void onAnimationCancel(Animator animation) {
-        }
-
-        @Override
-        public void onAnimationRepeat(Animator animation) {
-        }
-
-        private void beginEnterScene() {
-            Transition transition = getTransitionManager().getEnterTransition(mContentScene);
-            if (transition == null) {
-                transition = TransitionManager.getDefaultTransition();
-            }
-            transition = addTransitionTargets(transition, mEnteringViews, true);
-            transition.setEpicenterCallback(mEpicenterCallback);
-            TransitionManager.beginDelayedTransition(mDecor, transition);
-            setViewVisibility(mEnteringViews, View.VISIBLE);
-        }
-    }
-
-    private static class FixedEpicenterCallback extends Transition.EpicenterCallback {
-        private Rect mEpicenter;
-
-        public FixedEpicenterCallback(Rect epicenter) {
-            mEpicenter = epicenter;
-        }
-
-        @Override
-        public Rect getEpicenter(Transition transition) {
-            return mEpicenter;
-        }
-    };
 }