Merge "Directly propagate Activity titles to action bars" into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index de3723c..04771b4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1028,6 +1028,8 @@
     field public static final int readPermission = 16842759; // 0x1010007
     field public static final int recognitionService = 16843932; // 0x101049c
     field public static final int relinquishTaskIdentity = 16843894; // 0x1010476
+    field public static final int reparent = 16843965; // 0x10104bd
+    field public static final int reparentWithOverlay = 16843966; // 0x10104be
     field public static final int repeatCount = 16843199; // 0x10101bf
     field public static final int repeatMode = 16843200; // 0x10101c0
     field public static final int reqFiveWayNav = 16843314; // 0x1010232
@@ -1445,6 +1447,7 @@
     field public static final int windowSharedElementExitTransition = 16843834; // 0x101043a
     field public static final int windowSharedElementReenterTransition = 16843954; // 0x10104b2
     field public static final int windowSharedElementReturnTransition = 16843953; // 0x10104b1
+    field public static final int windowSharedElementsUseOverlay = 16843964; // 0x10104bc
     field public static final int windowShowAnimation = 16842934; // 0x10100b6
     field public static final int windowShowWallpaper = 16843410; // 0x1010292
     field public static final int windowSoftInputMode = 16843307; // 0x101022b
@@ -12978,7 +12981,7 @@
   }
 
   public class CaptureFailure {
-    method public int getFrameNumber();
+    method public long getFrameNumber();
     method public int getReason();
     method public android.hardware.camera2.CaptureRequest getRequest();
     method public int getSequenceId();
@@ -31802,7 +31805,7 @@
     ctor public ChangeBounds(android.content.Context, android.util.AttributeSet);
     method public void captureEndValues(android.transition.TransitionValues);
     method public void captureStartValues(android.transition.TransitionValues);
-    method public void setReparent(boolean);
+    method public deprecated void setReparent(boolean);
     method public void setResizeClip(boolean);
   }
 
@@ -31825,6 +31828,10 @@
     ctor public ChangeTransform(android.content.Context, android.util.AttributeSet);
     method public void captureEndValues(android.transition.TransitionValues);
     method public void captureStartValues(android.transition.TransitionValues);
+    method public boolean getReparent();
+    method public boolean getReparentWithOverlay();
+    method public void setReparent(boolean);
+    method public void setReparentWithOverlay(boolean);
   }
 
   public class CircularPropagation extends android.transition.VisibilityPropagation {
@@ -35137,6 +35144,7 @@
     method public android.transition.Transition getSharedElementExitTransition();
     method public android.transition.Transition getSharedElementReenterTransition();
     method public android.transition.Transition getSharedElementReturnTransition();
+    method public boolean getSharedElementsUseOverlay();
     method public abstract int getStatusBarColor();
     method public long getTransitionBackgroundFadeDuration();
     method public android.transition.TransitionManager getTransitionManager();
@@ -35198,6 +35206,7 @@
     method public void setSharedElementExitTransition(android.transition.Transition);
     method public void setSharedElementReenterTransition(android.transition.Transition);
     method public void setSharedElementReturnTransition(android.transition.Transition);
+    method public void setSharedElementsUseOverlay(boolean);
     method public void setSoftInputMode(int);
     method public abstract void setStatusBarColor(int);
     method public abstract void setTitle(java.lang.CharSequence);
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 7d2f677..e4f2b88 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -665,6 +665,9 @@
     }
 
     protected void moveSharedElementsToOverlay() {
+        if (!mWindow.getSharedElementsUseOverlay()) {
+            return;
+        }
         int numSharedElements = mSharedElements.size();
         ViewGroup decor = getDecor();
         if (decor != null) {
@@ -700,6 +703,17 @@
     }
 
     protected void moveSharedElementsFromOverlay() {
+        int numListeners = mGhostViewListeners.size();
+        for (int i = 0; i < numListeners; i++) {
+            GhostViewListeners listener = mGhostViewListeners.get(i);
+            ViewGroup parent = (ViewGroup) listener.getView().getParent();
+            parent.getViewTreeObserver().removeOnPreDrawListener(listener);
+        }
+        mGhostViewListeners.clear();
+
+        if (mWindow == null || !mWindow.getSharedElementsUseOverlay()) {
+            return;
+        }
         ViewGroup decor = getDecor();
         if (decor != null) {
             ViewGroupOverlay overlay = decor.getOverlay();
@@ -709,13 +723,6 @@
                 GhostView.removeGhost(sharedElement);
             }
         }
-        int numListeners = mGhostViewListeners.size();
-        for (int i = 0; i < numListeners; i++) {
-            GhostViewListeners listener = mGhostViewListeners.get(i);
-            ViewGroup parent = (ViewGroup) listener.getView().getParent();
-            parent.getViewTreeObserver().removeOnPreDrawListener(listener);
-        }
-        mGhostViewListeners.clear();
     }
 
     protected void setGhostVisibility(int visibility) {
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 936e205..b7af544 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -434,6 +434,12 @@
          * @return The job object to hand to the JobScheduler. This object is immutable.
          */
         public JobInfo build() {
+            // Allow tasks with no constraints. What am I, a database?
+            if (!mHasEarlyConstraint && !mHasLateConstraint && !mRequiresCharging &&
+                    !mRequiresDeviceIdle && mNetworkCapabilities == NetworkType.NONE) {
+                throw new IllegalArgumentException("You're trying to build a job with no " +
+                        "constraints, this is not allowed.");
+            }
             mExtras = new PersistableBundle(mExtras);  // Make our own copy.
             // Check that a deadline was not set on a periodic job.
             if (mIsPeriodic && (mMaxExecutionDelayMillis != 0L)) {
diff --git a/core/java/android/app/job/JobScheduler.java b/core/java/android/app/job/JobScheduler.java
index 7fe192c..ca7022d 100644
--- a/core/java/android/app/job/JobScheduler.java
+++ b/core/java/android/app/job/JobScheduler.java
@@ -22,7 +22,13 @@
 
 /**
  * Class for scheduling various types of jobs with the scheduling framework on the device.
- *
+ * See {@link android.app.job.JobInfo} for more description of the types of jobs that can be run
+ * and how to construct them.
+ * The framework will be intelligent about when you receive your callbacks, and attempt to batch
+ * and defer them as much as possible. Typically if you don't specify a deadline on your job, it
+ * can be run at any moment depending on the current state of the JobScheduler's internal queue,
+ * however it might be deferred as long as until the next time the device is connected to a power
+ * source.
  * <p>You do not
  * instantiate this class directly; instead, retrieve it through
  * {@link android.content.Context#getSystemService
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index a83bd4a..d19418b 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1470,6 +1470,12 @@
             case 320:
                 parts.add("xhdpi");
                 break;
+            case 480:
+                parts.add("xxhdpi");
+                break;
+            case 640:
+                parts.add("xxxhdpi");
+                break;
             default:
                 parts.add(config.densityDpi + "dpi");
                 break;
@@ -1542,7 +1548,7 @@
                 break;
         }
 
-        parts.add("v" + Build.VERSION.SDK_INT);
+        parts.add("v" + Build.VERSION.RESOURCES_SDK_INT);
         return TextUtils.join("-", parts);
     }
 }
diff --git a/core/java/android/hardware/camera2/CaptureFailure.java b/core/java/android/hardware/camera2/CaptureFailure.java
index 2c505e5..b6d3b08 100644
--- a/core/java/android/hardware/camera2/CaptureFailure.java
+++ b/core/java/android/hardware/camera2/CaptureFailure.java
@@ -47,13 +47,13 @@
     private final int mReason;
     private final boolean mDropped;
     private final int mSequenceId;
-    private final int mFrameNumber;
+    private final long mFrameNumber;
 
     /**
      * @hide
      */
     public CaptureFailure(CaptureRequest request, int reason, boolean dropped, int sequenceId,
-            int frameNumber) {
+            long frameNumber) {
         mRequest = request;
         mReason = reason;
         mDropped = dropped;
@@ -95,9 +95,9 @@
      * for every new result or failure; and the scope is the lifetime of the
      * {@link CameraDevice}.</p>
      *
-     * @return int frame number
+     * @return long frame number
      */
-    public int getFrameNumber() {
+    public long getFrameNumber() {
         return mFrameNumber;
     }
 
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index a15028c..621968b 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -68,6 +68,8 @@
 
     /** This session is closed; all further calls will throw ISE */
     private boolean mClosed = false;
+    /** This session failed to be configured successfully */
+    private final boolean mConfigureSuccess;
     /** Do not unconfigure if this is set; another session will overwrite configuration */
     private boolean mSkipUnconfigure = false;
 
@@ -119,10 +121,12 @@
         if (configureSuccess) {
             mStateListener.onConfigured(this);
             if (VERBOSE) Log.v(TAG, "ctor - Created session successfully");
+            mConfigureSuccess = true;
         } else {
             mStateListener.onConfigureFailed(this);
             mClosed = true; // do not fire any other callbacks, do not allow any other work
             Log.e(TAG, "Failed to create capture session; configuration failed");
+            mConfigureSuccess = false;
         }
     }
 
@@ -285,9 +289,9 @@
         // - This session is active, so close() below starts the shutdown drain
         // - This session is mid-shutdown drain, and hasn't yet reached the idle drain listener.
         // - This session is already closed and has executed the idle drain listener, and
-        //   configureOutputs(null) has already been called.
+        //   configureOutputsChecked(null) has already been called.
         //
-        // Do not call configureOutputs(null) going forward, since it would race with the
+        // Do not call configureOutputsChecked(null) going forward, since it would race with the
         // configuration for the new session. If it was already called, then we don't care, since it
         // won't get called again.
         mSkipUnconfigure = true;
@@ -506,7 +510,7 @@
             public void onUnconfigured(CameraDevice camera) {
                 synchronized (session) {
                     // Ignore #onUnconfigured before #close is called
-                    if (mClosed) {
+                    if (mClosed && mConfigureSuccess) {
                         mUnconfigureDrainer.taskFinished();
                     }
                 }
@@ -619,7 +623,7 @@
 
                 try {
                     mUnconfigureDrainer.taskStarted();
-                    mDeviceImpl.configureOutputs(null); // begin transition to unconfigured state
+                    mDeviceImpl.configureOutputsChecked(null); // begin transition to unconfigured
                 } catch (CameraAccessException e) {
                     // OK: do not throw checked exceptions.
                     Log.e(TAG, "Exception while configuring outputs: ", e);
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 71eb0e9..79ce9df 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -312,10 +312,33 @@
     }
 
     public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
+        // Leave this here for backwards compatibility with older code using this directly
+        configureOutputsChecked(outputs);
+    }
+
+    /**
+     * Attempt to configure the outputs; the device goes to idle and then configures the
+     * new outputs if possible.
+     *
+     * <p>The configuration may gracefully fail, if there are too many outputs, if the formats
+     * are not supported, or if the sizes for that format is not supported. In this case this
+     * function will return {@code false} and the unconfigured callback will be fired.</p>
+     *
+     * <p>If the configuration succeeds (with 1 or more outputs), then the idle callback is fired.
+     * Unconfiguring the device always fires the idle callback.</p>
+     *
+     * @param outputs a list of one or more surfaces, or {@code null} to unconfigure
+     * @return whether or not the configuration was successful
+     *
+     * @throws CameraAccessException if there were any unexpected problems during configuration
+     */
+    public boolean configureOutputsChecked(List<Surface> outputs) throws CameraAccessException {
         // Treat a null input the same an empty list
         if (outputs == null) {
             outputs = new ArrayList<Surface>();
         }
+        boolean success = false;
+
         synchronized(mInterfaceLock) {
             checkIfCameraClosedOrInError();
 
@@ -355,7 +378,17 @@
                     mConfiguredOutputs.put(streamId, s);
                 }
 
-                mRemoteDevice.endConfigure();
+                try {
+                    mRemoteDevice.endConfigure();
+                }
+                catch (IllegalArgumentException e) {
+                    // OK. camera service can reject stream config if it's not supported by HAL
+                    // This is only the result of a programmer misusing the camera2 api.
+                    Log.e(TAG, "Stream configuration failed", e);
+                    return false;
+                }
+
+                success = true;
             } catch (CameraRuntimeException e) {
                 if (e.getReason() == CAMERA_IN_USE) {
                     throw new IllegalStateException("The camera is currently busy." +
@@ -365,15 +398,18 @@
                 throw e.asChecked();
             } catch (RemoteException e) {
                 // impossible
-                return;
-            }
-
-            if (outputs.size() > 0) {
-                mDeviceHandler.post(mCallOnIdle);
-            } else {
-                mDeviceHandler.post(mCallOnUnconfigured);
+                return false;
+            } finally {
+                if (success && outputs.size() > 0) {
+                    mDeviceHandler.post(mCallOnIdle);
+                } else {
+                    // Always return to the 'unconfigured' state if we didn't hit a fatal error
+                    mDeviceHandler.post(mCallOnUnconfigured);
+                }
             }
         }
+
+        return success;
     }
 
     @Override
@@ -397,7 +433,7 @@
             boolean configureSuccess = true;
             CameraAccessException pendingException = null;
             try {
-                configureOutputs(outputs); // and then block until IDLE
+                configureSuccess = configureOutputsChecked(outputs); // and then block until IDLE
             } catch (CameraAccessException e) {
                 configureSuccess = false;
                 pendingException = e;
diff --git a/core/java/android/hardware/camera2/params/ColorSpaceTransform.java b/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
index b4289db2..1e1c4b1 100644
--- a/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
+++ b/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
@@ -225,7 +225,18 @@
         }
         if (obj instanceof ColorSpaceTransform) {
             final ColorSpaceTransform other = (ColorSpaceTransform) obj;
-            return Arrays.equals(mElements, other.mElements);
+            for (int i = 0, j = 0; i < COUNT; ++i, j += RATIONAL_SIZE) {
+                int numerator = mElements[j + OFFSET_NUMERATOR];
+                int denominator = mElements[j + OFFSET_DENOMINATOR];
+                int numeratorOther = other.mElements[j + OFFSET_NUMERATOR];
+                int denominatorOther = other.mElements[j + OFFSET_DENOMINATOR];
+                Rational r = new Rational(numerator, denominator);
+                Rational rOther = new Rational(numeratorOther, denominatorOther);
+                if (!r.equals(rOther)) {
+                    return false;
+                }
+            }
+            return true;
         }
         return false;
     }
@@ -238,5 +249,51 @@
         return HashCodeHelpers.hashCode(mElements);
     }
 
+    /**
+     * Return the color space transform as a string representation.
+     *
+     *  <p> Example:
+     * {@code "ColorSpaceTransform([1/1, 0/1, 0/1], [0/1, 1/1, 0/1], [0/1, 0/1, 1/1])"} is an
+     * identity transform. Elements are printed in row major order. </p>
+     *
+     * @return string representation of color space transform
+     */
+    @Override
+    public String toString() {
+        return String.format("ColorSpaceTransform%s", toShortString());
+    }
+
+    /**
+     * Return the color space transform as a compact string representation.
+     *
+     *  <p> Example:
+     * {@code "([1/1, 0/1, 0/1], [0/1, 1/1, 0/1], [0/1, 0/1, 1/1])"} is an identity transform.
+     * Elements are printed in row major order. </p>
+     *
+     * @return compact string representation of color space transform
+     */
+    private String toShortString() {
+        StringBuilder sb = new StringBuilder("(");
+        for (int row = 0, i = 0; row < ROWS; row++) {
+            sb.append("[");
+            for (int col = 0; col < COLUMNS; col++, i += RATIONAL_SIZE) {
+                int numerator = mElements[i + OFFSET_NUMERATOR];
+                int denominator = mElements[i + OFFSET_DENOMINATOR];
+                sb.append(numerator);
+                sb.append("/");
+                sb.append(denominator);
+                if (col < COLUMNS - 1) {
+                    sb.append(", ");
+                }
+            }
+            sb.append("]");
+            if (row < ROWS - 1) {
+                sb.append(", ");
+            }
+        }
+        sb.append(")");
+        return sb.toString();
+    }
+
     private final int[] mElements;
-};
+}
diff --git a/core/java/android/hardware/camera2/params/RggbChannelVector.java b/core/java/android/hardware/camera2/params/RggbChannelVector.java
index cf3e1de..e08ec55d 100644
--- a/core/java/android/hardware/camera2/params/RggbChannelVector.java
+++ b/core/java/android/hardware/camera2/params/RggbChannelVector.java
@@ -190,6 +190,32 @@
                 Float.floatToIntBits(mBlue);
     }
 
+    /**
+     * Return the RggbChannelVector as a string representation.
+     *
+     * <p> {@code "RggbChannelVector{R:%f, G_even:%f, G_odd:%f, B:%f}"}, where each
+     * {@code %f} respectively represents one of the the four color channels. </p>
+     *
+     * @return string representation of {@link RggbChannelVector}
+     */
+    @Override
+    public String toString() {
+        return String.format("RggbChannelVector%s", toShortString());
+    }
+
+    /**
+     * Return the RggbChannelVector as a string in compact form.
+     *
+     * <p> {@code "{R:%f, G_even:%f, G_odd:%f, B:%f}"}, where each {@code %f}
+     * respectively represents one of the the four color channels. </p>
+     *
+     * @return compact string representation of {@link RggbChannelVector}
+     */
+    private String toShortString() {
+        return String.format("{R:%f, G_even:%f, G_odd:%f, B:%f}",
+                mRed, mGreenEven, mGreenOdd, mBlue);
+    }
+
     private final float mRed;
     private final float mGreenEven;
     private final float mGreenOdd;
diff --git a/core/java/android/os/FileBridge.java b/core/java/android/os/FileBridge.java
index 1e1ad9e..afa5885 100644
--- a/core/java/android/os/FileBridge.java
+++ b/core/java/android/os/FileBridge.java
@@ -95,6 +95,10 @@
                     int len = Memory.peekInt(temp, 4, ByteOrder.BIG_ENDIAN);
                     while (len > 0) {
                         int n = IoBridge.read(mServer, temp, 0, Math.min(temp.length, len));
+                        if (n == -1) {
+                            throw new IOException(
+                                    "Unexpected EOF; still expected " + len + " bytes");
+                        }
                         IoBridge.write(mTarget, temp, 0, n);
                         len -= n;
                     }
diff --git a/core/java/android/transition/ChangeBounds.java b/core/java/android/transition/ChangeBounds.java
index 6246cbe..ebb1a5c 100644
--- a/core/java/android/transition/ChangeBounds.java
+++ b/core/java/android/transition/ChangeBounds.java
@@ -107,6 +107,8 @@
      *
      * @param reparent true if the transition should track the parent
      * container of target views and animate parent changes.
+     * @deprecated Use {@link android.transition.ChangeTransform} to handle
+     * transitions between different parents.
      */
     public void setReparent(boolean reparent) {
         mReparent = reparent;
diff --git a/core/java/android/transition/ChangeImageTransform.java b/core/java/android/transition/ChangeImageTransform.java
index 4b230eb..d7a9120 100644
--- a/core/java/android/transition/ChangeImageTransform.java
+++ b/core/java/android/transition/ChangeImageTransform.java
@@ -16,7 +16,6 @@
 package android.transition;
 
 import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.TypeEvaluator;
 import android.content.Context;
@@ -196,28 +195,6 @@
     private ObjectAnimator createMatrixAnimator(final ImageView imageView, Matrix startMatrix,
             final Matrix endMatrix) {
         return ObjectAnimator.ofObject(imageView, ANIMATED_TRANSFORM_PROPERTY,
-                new MatrixEvaluator(), startMatrix, endMatrix);
+                new TransitionUtils.MatrixEvaluator(), startMatrix, endMatrix);
     }
-
-    private static class MatrixEvaluator implements TypeEvaluator<Matrix> {
-
-        float[] mTempStartValues = new float[9];
-
-        float[] mTempEndValues = new float[9];
-
-        Matrix mTempMatrix = new Matrix();
-
-        @Override
-        public Matrix evaluate(float fraction, Matrix startValue, Matrix endValue) {
-            startValue.getValues(mTempStartValues);
-            endValue.getValues(mTempEndValues);
-            for (int i = 0; i < 9; i++) {
-                float diff = mTempEndValues[i] - mTempStartValues[i];
-                mTempEndValues[i] = mTempStartValues[i] + (fraction * diff);
-            }
-            mTempMatrix.setValues(mTempEndValues);
-            return mTempMatrix;
-        }
-    }
-
 }
diff --git a/core/java/android/transition/ChangeTransform.java b/core/java/android/transition/ChangeTransform.java
index e9be3b9..d579f54 100644
--- a/core/java/android/transition/ChangeTransform.java
+++ b/core/java/android/transition/ChangeTransform.java
@@ -16,72 +16,134 @@
 package android.transition;
 
 import android.animation.Animator;
-import android.animation.FloatArrayEvaluator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
 import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Matrix;
 import android.util.AttributeSet;
-import android.util.FloatProperty;
 import android.util.Property;
+import android.view.GhostView;
 import android.view.View;
 import android.view.ViewGroup;
+import com.android.internal.R;
 
 /**
  * This Transition captures scale and rotation for Views before and after the
  * scene change and animates those changes during the transition.
  *
- * <p>ChangeTransform does not work when the pivot changes between scenes, so either the
- * pivot must be set to prevent automatic pivot adjustment or the View's size must be unchanged.</p>
+ * A change in parent is handled as well by capturing the transforms from
+ * the parent before and after the scene change and animating those during the
+ * transition.
  */
 public class ChangeTransform extends Transition {
 
     private static final String TAG = "ChangeTransform";
 
-    private static final String PROPNAME_SCALE_X = "android:changeTransform:scaleX";
-    private static final String PROPNAME_SCALE_Y = "android:changeTransform:scaleY";
-    private static final String PROPNAME_ROTATION_X = "android:changeTransform:rotationX";
-    private static final String PROPNAME_ROTATION_Y = "android:changeTransform:rotationY";
-    private static final String PROPNAME_ROTATION_Z = "android:changeTransform:rotationZ";
-    private static final String PROPNAME_PIVOT_X = "android:changeTransform:pivotX";
-    private static final String PROPNAME_PIVOT_Y = "android:changeTransform:pivotY";
+    private static final String PROPNAME_MATRIX = "android:changeTransform:matrix";
+    private static final String PROPNAME_TRANSFORMS = "android:changeTransform:transforms";
+    private static final String PROPNAME_PARENT = "android:changeTransform:parent";
+    private static final String PROPNAME_PARENT_MATRIX = "android:changeTransform:parentMatrix";
 
     private static final String[] sTransitionProperties = {
-            PROPNAME_SCALE_X,
-            PROPNAME_SCALE_Y,
-            PROPNAME_ROTATION_X,
-            PROPNAME_ROTATION_Y,
-            PROPNAME_ROTATION_Z,
+            PROPNAME_MATRIX,
+            PROPNAME_TRANSFORMS,
+            PROPNAME_PARENT_MATRIX,
     };
 
-    private static final FloatProperty<View>[] sChangedProperties = new FloatProperty[] {
-            (FloatProperty) View.SCALE_X,
-            (FloatProperty) View.SCALE_Y,
-            (FloatProperty) View.ROTATION_X,
-            (FloatProperty) View.ROTATION_Y,
-            (FloatProperty) View.ROTATION,
-    };
-
-    private static Property<View, float[]> TRANSFORMS = new Property<View, float[]>(float[].class,
-            "transforms") {
-        @Override
-        public float[] get(View object) {
-            return null;
-        }
-
-        @Override
-        public void set(View view, float[] values) {
-            for (int i = 0; i < values.length; i++) {
-                float value = values[i];
-                if (!Float.isNaN(value)) {
-                    sChangedProperties[i].setValue(view, value);
+    private static final Property<View, Matrix> ANIMATION_MATRIX_PROPERTY =
+            new Property<View, Matrix>(Matrix.class, "animationMatrix") {
+                @Override
+                public Matrix get(View object) {
+                    return null;
                 }
-            }
-        }
-    };
+
+                @Override
+                public void set(View object, Matrix value) {
+                    object.setAnimationMatrix(value);
+                }
+            };
+
+    private boolean mUseOverlay = true;
+    private boolean mReparent = true;
+    private Matrix mTempMatrix = new Matrix();
 
     public ChangeTransform() {}
 
     public ChangeTransform(Context context, AttributeSet attrs) {
         super(context, attrs);
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ChangeTransform);
+        mUseOverlay = a.getBoolean(R.styleable.ChangeTransform_reparentWithOverlay, true);
+        mReparent = a.getBoolean(R.styleable.ChangeTransform_reparent, true);
+        a.recycle();
+    }
+
+    /**
+     * Returns whether changes to parent should use an overlay or not. When the parent
+     * change doesn't use an overlay, it affects the transforms of the child. The
+     * default value is <code>true</code>.
+     *
+     * <p>Note: when Overlays are not used when a parent changes, a view can be clipped when
+     * it moves outside the bounds of its parent. Setting
+     * {@link android.view.ViewGroup#setClipChildren(boolean)} and
+     * {@link android.view.ViewGroup#setClipToPadding(boolean)} can help. Also, when
+     * Overlays are not used and the parent is animating its location, the position of the
+     * child view will be relative to its parent's final position, so it may appear to "jump"
+     * at the beginning.</p>
+     *
+     * @return <code>true</code> when a changed parent should execute the transition
+     * inside the scene root's overlay or <code>false</code> if a parent change only
+     * affects the transform of the transitioning view.
+     */
+    public boolean getReparentWithOverlay() {
+        return mUseOverlay;
+    }
+
+    /**
+     * Sets whether changes to parent should use an overlay or not. When the parent
+     * change doesn't use an overlay, it affects the transforms of the child. The
+     * default value is <code>true</code>.
+     *
+     * <p>Note: when Overlays are not used when a parent changes, a view can be clipped when
+     * it moves outside the bounds of its parent. Setting
+     * {@link android.view.ViewGroup#setClipChildren(boolean)} and
+     * {@link android.view.ViewGroup#setClipToPadding(boolean)} can help. Also, when
+     * Overlays are not used and the parent is animating its location, the position of the
+     * child view will be relative to its parent's final position, so it may appear to "jump"
+     * at the beginning.</p>
+     *
+     * @return <code>true</code> when a changed parent should execute the transition
+     * inside the scene root's overlay or <code>false</code> if a parent change only
+     * affects the transform of the transitioning view.
+     */
+    public void setReparentWithOverlay(boolean reparentWithOverlay) {
+        mUseOverlay = reparentWithOverlay;
+    }
+
+    /**
+     * Returns whether parent changes will be tracked by the ChangeTransform. If parent
+     * changes are tracked, then the transform will adjust to the transforms of the
+     * different parents. If they aren't tracked, only the transforms of the transitioning
+     * view will be tracked. Default is true.
+     *
+     * @return whether parent changes will be tracked by the ChangeTransform.
+     */
+    public boolean getReparent() {
+        return mReparent;
+    }
+
+    /**
+     * Sets whether parent changes will be tracked by the ChangeTransform. If parent
+     * changes are tracked, then the transform will adjust to the transforms of the
+     * different parents. If they aren't tracked, only the transforms of the transitioning
+     * view will be tracked. Default is true.
+     *
+     * @param reparent Set to true to track parent changes or false to only track changes
+     *                 of the transitioning view without considering the parent change.
+     */
+    public void setReparent(boolean reparent) {
+        mReparent = reparent;
     }
 
     @Override
@@ -89,19 +151,29 @@
         return sTransitionProperties;
     }
 
-    private void captureValues(TransitionValues values) {
-        View view = values.view;
+    private void captureValues(TransitionValues transitionValues) {
+        View view = transitionValues.view;
         if (view.getVisibility() == View.GONE) {
             return;
         }
-
-        values.values.put(PROPNAME_SCALE_X, view.getScaleX());
-        values.values.put(PROPNAME_SCALE_Y, view.getScaleY());
-        values.values.put(PROPNAME_PIVOT_X, view.getPivotX());
-        values.values.put(PROPNAME_PIVOT_Y, view.getPivotY());
-        values.values.put(PROPNAME_ROTATION_X, view.getRotationX());
-        values.values.put(PROPNAME_ROTATION_Y, view.getRotationY());
-        values.values.put(PROPNAME_ROTATION_Z, view.getRotation());
+        transitionValues.values.put(PROPNAME_PARENT, view.getParent());
+        Transforms transforms = new Transforms(view);
+        transitionValues.values.put(PROPNAME_TRANSFORMS, transforms);
+        Matrix matrix = view.getMatrix();
+        if (matrix == null || matrix.isIdentity()) {
+            matrix = null;
+        } else {
+            matrix = new Matrix(matrix);
+        }
+        transitionValues.values.put(PROPNAME_MATRIX, matrix);
+        if (mReparent) {
+            Matrix parentMatrix = new Matrix();
+            ViewGroup parent = (ViewGroup) view.getParent();
+            parent.transformMatrixToGlobal(parentMatrix);
+            parentMatrix.preTranslate(-parent.getScrollX(), -parent.getScrollY());
+            transitionValues.values.put(PROPNAME_PARENT_MATRIX, parentMatrix);
+        }
+        return;
     }
 
     @Override
@@ -115,57 +187,252 @@
     }
 
     @Override
-    public Animator createAnimator(final ViewGroup sceneRoot, TransitionValues startValues,
+    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
             TransitionValues endValues) {
-        if (startValues == null || endValues == null
-                || !startValues.values.containsKey(PROPNAME_SCALE_X)
-                || !endValues.values.containsKey(PROPNAME_SCALE_X)
-                || !isPivotSame(startValues, endValues)
-                || !isChanged(startValues, endValues)) {
+        if (startValues == null || endValues == null ||
+                !startValues.values.containsKey(PROPNAME_PARENT) ||
+                !endValues.values.containsKey(PROPNAME_PARENT)) {
             return null;
         }
 
-        float[] start = createValues(startValues);
-        float[] end = createValues(endValues);
-        for (int i = 0; i < start.length; i++) {
-            if (start[i] == end[i]) {
-                start[i] = Float.NaN;
-                end[i] = Float.NaN;
-            } else {
-                sChangedProperties[i].setValue(endValues.view, start[i]);
+        ViewGroup startParent = (ViewGroup) startValues.values.get(PROPNAME_PARENT);
+        ViewGroup endParent = (ViewGroup) endValues.values.get(PROPNAME_PARENT);
+        boolean handleParentChange = mReparent && !parentsMatch(startParent, endParent);
+
+        Matrix startMatrix = (Matrix) startValues.view.getTag(R.id.transitionTransform);
+        if (startMatrix != null) {
+            startValues.values.put(PROPNAME_MATRIX, startMatrix);
+        }
+
+        Matrix startParentMatrix = (Matrix) startValues.view.getTag(R.id.parentMatrix);
+        if (startParentMatrix != null) {
+            startValues.values.put(PROPNAME_PARENT_MATRIX, startParentMatrix);
+        }
+
+        // First handle the parent change:
+        if (handleParentChange) {
+            setMatricesForParent(startValues, endValues);
+        }
+
+        // Next handle the normal matrix transform:
+        ObjectAnimator transformAnimator = createTransformAnimator(startValues, endValues);
+
+        if (handleParentChange && transformAnimator != null && mUseOverlay) {
+            createGhostView(sceneRoot, startValues, endValues);
+        }
+
+        return transformAnimator;
+    }
+
+    private ObjectAnimator createTransformAnimator(TransitionValues startValues,
+            TransitionValues endValues) {
+        Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_MATRIX);
+        Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_MATRIX);
+
+        if (startMatrix == null) {
+            startMatrix = Matrix.IDENTITY_MATRIX;
+        }
+
+        if (endMatrix == null) {
+            endMatrix = Matrix.IDENTITY_MATRIX;
+        }
+
+        if (startMatrix.equals(endMatrix)) {
+            return null;
+        }
+
+        final Transforms transforms = (Transforms) endValues.values.get(PROPNAME_TRANSFORMS);
+
+        // clear the transform properties so that we can use the animation matrix instead
+        final View view = endValues.view;
+        setIdentityTransforms(view);
+
+        ObjectAnimator animator = ObjectAnimator.ofObject(view, ANIMATION_MATRIX_PROPERTY,
+                new TransitionUtils.MatrixEvaluator(), startMatrix, endMatrix);
+
+        AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
+            private boolean mIsCanceled;
+            private Matrix mTempMatrix;
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                mIsCanceled = true;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (!mIsCanceled) {
+                    view.setTagInternal(R.id.transitionTransform, null);
+                    view.setTagInternal(R.id.parentMatrix, null);
+                }
+                ANIMATION_MATRIX_PROPERTY.set(view, null);
+                transforms.restore(view);
+            }
+
+            @Override
+            public void onAnimationPause(Animator animation) {
+                ValueAnimator animator = (ValueAnimator) animation;
+                Matrix currentMatrix = (Matrix) animator.getAnimatedValue();
+                if (mTempMatrix == null) {
+                    mTempMatrix = new Matrix(currentMatrix);
+                } else {
+                    mTempMatrix.set(currentMatrix);
+                }
+                view.setTagInternal(R.id.transitionTransform, mTempMatrix);
+                transforms.restore(view);
+            }
+
+            @Override
+            public void onAnimationResume(Animator animation) {
+                setIdentityTransforms(view);
+            }
+        };
+
+        animator.addListener(listener);
+        animator.addPauseListener(listener);
+        return animator;
+    }
+
+    private boolean parentsMatch(ViewGroup startParent, ViewGroup endParent) {
+        boolean parentsMatch = false;
+        if (!isValidTarget(startParent) || !isValidTarget(endParent)) {
+            parentsMatch = startParent == endParent;
+        } else {
+            TransitionValues endValues = getMatchedTransitionValues(startParent, true);
+            if (endValues != null) {
+                parentsMatch = endParent == endValues.view;
             }
         }
-        FloatArrayEvaluator evaluator = new FloatArrayEvaluator(new float[start.length]);
-        return ObjectAnimator.ofObject(endValues.view, TRANSFORMS, evaluator, start, end);
+        return parentsMatch;
     }
 
-    private static float[] createValues(TransitionValues transitionValues) {
-        float[] values = new float[sChangedProperties.length];
-        for (int i = 0; i < values.length; i++) {
-            values[i] = (Float) transitionValues.values.get(sTransitionProperties[i]);
+    private void createGhostView(final ViewGroup sceneRoot, TransitionValues startValues,
+            TransitionValues endValues) {
+        View view = endValues.view;
+
+        Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_PARENT_MATRIX);
+        Matrix localEndMatrix = new Matrix(endMatrix);
+        sceneRoot.transformMatrixToLocal(localEndMatrix);
+
+        GhostView ghostView = GhostView.addGhost(view, sceneRoot, localEndMatrix);
+
+        Transition outerTransition = this;
+        while (outerTransition.mParent != null) {
+            outerTransition = outerTransition.mParent;
         }
-        return values;
+        GhostListener listener = new GhostListener(view, ghostView, endMatrix);
+        outerTransition.addListener(listener);
+
+        if (startValues.view != endValues.view) {
+            startValues.view.setTransitionAlpha(0);
+        }
+        view.setTransitionAlpha(1);
     }
 
-    private static boolean isPivotSame(TransitionValues startValues, TransitionValues endValues) {
-        float startPivotX = (Float) startValues.values.get(PROPNAME_PIVOT_X);
-        float startPivotY = (Float) startValues.values.get(PROPNAME_PIVOT_Y);
-        float endPivotX = (Float) endValues.values.get(PROPNAME_PIVOT_X);
-        float endPivotY = (Float) endValues.values.get(PROPNAME_PIVOT_Y);
+    private void setMatricesForParent(TransitionValues startValues, TransitionValues endValues) {
+        Matrix endParentMatrix = (Matrix) endValues.values.get(PROPNAME_PARENT_MATRIX);
+        endValues.view.setTagInternal(R.id.parentMatrix, endParentMatrix);
 
-        // We don't support pivot changes, because they could be automatically set
-        // and we can't end the state in an automatic state.
-        return startPivotX == endPivotX && startPivotY == endPivotY;
+        Matrix toLocal = mTempMatrix;
+        toLocal.reset();
+        endParentMatrix.invert(toLocal);
+
+        Matrix startLocal = (Matrix) startValues.values.get(PROPNAME_MATRIX);
+        if (startLocal == null) {
+            startLocal = new Matrix();
+            startValues.values.put(PROPNAME_MATRIX, startLocal);
+        }
+
+        Matrix startParentMatrix = (Matrix) startValues.values.get(PROPNAME_PARENT_MATRIX);
+        startLocal.postConcat(startParentMatrix);
+        startLocal.postConcat(toLocal);
     }
 
-    private static boolean isChanged(TransitionValues startValues, TransitionValues endValues) {
-        for (int i = 0; i < sChangedProperties.length; i++) {
-            Object start = startValues.values.get(sTransitionProperties[i]);
-            Object end = endValues.values.get(sTransitionProperties[i]);
-            if (!start.equals(end)) {
-                return true;
+    private static void setIdentityTransforms(View view) {
+        setTransforms(view, 0, 0, 0, 1, 1, 0, 0, 0);
+    }
+
+    private static void setTransforms(View view, float translationX, float translationY,
+            float translationZ, float scaleX, float scaleY, float rotationX,
+            float rotationY, float rotationZ) {
+        view.setTranslationX(translationX);
+        view.setTranslationY(translationY);
+        view.setTranslationZ(translationZ);
+        view.setScaleX(scaleX);
+        view.setScaleY(scaleY);
+        view.setRotationX(rotationX);
+        view.setRotationY(rotationY);
+        view.setRotation(rotationZ);
+    }
+
+    private static class Transforms {
+        public final float translationX;
+        public final float translationY;
+        public final float translationZ;
+        public final float scaleX;
+        public final float scaleY;
+        public final float rotationX;
+        public final float rotationY;
+        public final float rotationZ;
+
+        public Transforms(View view) {
+            translationX = view.getTranslationX();
+            translationY = view.getTranslationY();
+            translationZ = view.getTranslationZ();
+            scaleX = view.getScaleX();
+            scaleY = view.getScaleY();
+            rotationX = view.getRotationX();
+            rotationY = view.getRotationY();
+            rotationZ = view.getRotation();
+        }
+
+        public void restore(View view) {
+            setTransforms(view, translationX, translationY, translationZ, scaleX, scaleY,
+                    rotationX, rotationY, rotationZ);
+        }
+
+        @Override
+        public boolean equals(Object that) {
+            if (!(that instanceof Transforms)) {
+                return false;
             }
+            Transforms thatTransform = (Transforms) that;
+            return thatTransform.translationX == translationX &&
+                    thatTransform.translationY == translationY &&
+                    thatTransform.translationZ == translationZ &&
+                    thatTransform.scaleX == scaleX &&
+                    thatTransform.scaleY == scaleY &&
+                    thatTransform.rotationX == rotationX &&
+                    thatTransform.rotationY == rotationY &&
+                    thatTransform.rotationZ == rotationZ;
         }
-        return false;
+    }
+
+    private static class GhostListener extends Transition.TransitionListenerAdapter {
+        private View mView;
+        private GhostView mGhostView;
+	private Matrix mEndMatrix;
+
+        public GhostListener(View view, GhostView ghostView, Matrix endMatrix) {
+            mView = view;
+            mGhostView = ghostView;
+            mEndMatrix = endMatrix;
+        }
+
+        @Override
+        public void onTransitionEnd(Transition transition) {
+            transition.removeListener(this);
+            GhostView.removeGhost(mView);
+        }
+
+        @Override
+        public void onTransitionPause(Transition transition) {
+            mGhostView.setVisibility(View.INVISIBLE);
+        }
+
+        @Override
+        public void onTransitionResume(Transition transition) {
+            mGhostView.setVisibility(View.VISIBLE);
+        }
     }
 }
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 0d32d40..59ba71f 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -112,8 +112,8 @@
  *
  * Further information on XML resource descriptions for transitions can be found for
  * {@link android.R.styleable#Transition}, {@link android.R.styleable#TransitionSet},
- * {@link android.R.styleable#TransitionTarget}, {@link android.R.styleable#Fade}, and
- * {@link android.R.styleable#Slide}.
+ * {@link android.R.styleable#TransitionTarget}, {@link android.R.styleable#Fade},
+ * {@link android.R.styleable#Slide}, and {@link android.R.styleable#ChangeTransform}.
  *
  */
 public abstract class Transition implements Cloneable {
@@ -1755,24 +1755,40 @@
         // if oldValues null, then transition didn't care to stash values,
         // and won't get canceled
         if (oldValues != null && newValues != null) {
-            for (String key : oldValues.values.keySet()) {
-                Object oldValue = oldValues.values.get(key);
-                Object newValue = newValues.values.get(key);
-                if (oldValue != null && newValue != null &&
-                        !oldValue.equals(newValue)) {
-                    valuesChanged = true;
-                    if (DBG) {
-                        Log.d(LOG_TAG, "Transition.playTransition: " +
-                                "oldValue != newValue for " + key +
-                                ": old, new = " + oldValue + ", " + newValue);
+            String[] properties = getTransitionProperties();
+            if (properties != null) {
+                int count = properties.length;
+                for (int i = 0; i < count; i++) {
+                    if (isValueChanged(oldValues, newValues, properties[i])) {
+                        valuesChanged = true;
+                        break;
                     }
-                    break;
+                }
+            } else {
+                for (String key : oldValues.values.keySet()) {
+                    if (isValueChanged(oldValues, newValues, key)) {
+                        valuesChanged = true;
+                        break;
+                    }
                 }
             }
         }
         return valuesChanged;
     }
 
+    private static boolean isValueChanged(TransitionValues oldValues, TransitionValues newValues,
+            String key) {
+        Object oldValue = oldValues.values.get(key);
+        Object newValue = newValues.values.get(key);
+        boolean changed = (oldValue != null && newValue != null && !oldValue.equals(newValue));
+        if (DBG && changed) {
+            Log.d(LOG_TAG, "Transition.playTransition: " +
+                    "oldValue != newValue for " + key +
+                    ": old, new = " + oldValue + ", " + newValue);
+        }
+        return changed;
+    }
+
     /**
      * This is a utility method used by subclasses to handle standard parts of
      * setting up and running an Animator: it sets the {@link #getDuration()
diff --git a/core/java/android/transition/TransitionUtils.java b/core/java/android/transition/TransitionUtils.java
index 931d46a..b0c9e9a 100644
--- a/core/java/android/transition/TransitionUtils.java
+++ b/core/java/android/transition/TransitionUtils.java
@@ -18,6 +18,8 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorSet;
+import android.animation.TypeEvaluator;
+import android.graphics.Matrix;
 
 /**
  * Static utility methods for Transitions.
@@ -37,4 +39,25 @@
             return animatorSet;
         }
     }
+
+    public static class MatrixEvaluator implements TypeEvaluator<Matrix> {
+
+        float[] mTempStartValues = new float[9];
+
+        float[] mTempEndValues = new float[9];
+
+        Matrix mTempMatrix = new Matrix();
+
+        @Override
+        public Matrix evaluate(float fraction, Matrix startValue, Matrix endValue) {
+            startValue.getValues(mTempStartValues);
+            endValue.getValues(mTempEndValues);
+            for (int i = 0; i < 9; i++) {
+                float diff = mTempEndValues[i] - mTempStartValues[i];
+                mTempEndValues[i] = mTempStartValues[i] + (fraction * diff);
+            }
+            mTempMatrix.setValues(mTempEndValues);
+            return mTempMatrix;
+        }
+    }
 }
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 79dbb49..81c69d1 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -63,8 +63,6 @@
 
     private static final String[] sTransitionProperties = {
             PROPNAME_VISIBILITY,
-            PROPNAME_PARENT,
-            PROPNAME_SCREEN_LOCATION,
     };
 
     private static class VisibilityInfo {
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index a56d448..9433237 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -19,6 +19,7 @@
 import android.animation.Animator;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
+import android.animation.Animator.AnimatorListener;
 import android.graphics.Canvas;
 import android.graphics.CanvasProperty;
 import android.graphics.Paint;
@@ -202,7 +203,7 @@
             mViewTarget.mTransformationInfo.mAlpha = mFinalValue;
         }
 
-        final ArrayList<AnimatorListener> listeners = getListeners();
+        final ArrayList<AnimatorListener> listeners = cloneListeners();
         final int numListeners = listeners == null ? 0 : listeners.size();
         for (int i = 0; i < numListeners; i++) {
             listeners.get(i).onAnimationStart(this);
@@ -220,7 +221,7 @@
             getHelper().removeDelayedAnimation(this);
             nEnd(mNativePtr.get());
 
-            final ArrayList<AnimatorListener> listeners = getListeners();
+            final ArrayList<AnimatorListener> listeners = cloneListeners();
             final int numListeners = listeners == null ? 0 : listeners.size();
             for (int i = 0; i < numListeners; i++) {
                 listeners.get(i).onAnimationCancel(this);
@@ -329,13 +330,22 @@
     protected void onFinished() {
         mFinished = true;
 
-        final ArrayList<AnimatorListener> listeners = getListeners();
+        final ArrayList<AnimatorListener> listeners = cloneListeners();
         final int numListeners = listeners == null ? 0 : listeners.size();
         for (int i = 0; i < numListeners; i++) {
             listeners.get(i).onAnimationEnd(this);
         }
     }
 
+    @SuppressWarnings("unchecked")
+    private ArrayList<AnimatorListener> cloneListeners() {
+        ArrayList<AnimatorListener> listeners = getListeners();
+        if (listeners != null) {
+            listeners = (ArrayList<AnimatorListener>) listeners.clone();
+        }
+        return listeners;
+    }
+
     long getNativeAnimator() {
         return mNativePtr.get();
     }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 243d7d7..6f58582 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10793,6 +10793,15 @@
         }
     }
 
+    /** @hide */
+    public void setAnimationMatrix(Matrix matrix) {
+        invalidateViewProperty(true, false);
+        mRenderNode.setAnimationMatrix(matrix);
+        invalidateViewProperty(false, true);
+
+        invalidateParentIfNeededAndWasQuickRejected();
+    }
+
     /**
      * Returns the current StateListAnimator if exists.
      *
@@ -13090,6 +13099,10 @@
         removeSendViewScrolledAccessibilityEventCallback();
         stopNestedScroll();
 
+        // Anything that started animating right before detach should already
+        // be in its final state when re-attached.
+        jumpDrawablesToCurrentState();
+
         destroyDrawingCache();
 
         cleanupDraw();
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index e7b3152..2c7ea3e 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1662,6 +1662,27 @@
     public void setTransitionBackgroundFadeDuration(long fadeDurationMillis) { }
 
     /**
+     * Returns <code>true</code> when shared elements should use an Overlay during
+     * shared element transitions or <code>false</code> when they should animate as
+     * part of the normal View hierarchy. The default value is true.
+     *
+     * @return <code>true</code> when shared elements should use an Overlay during
+     * shared element transitions or <code>false</code> when they should animate as
+     * part of the normal View hierarchy.
+     */
+    public boolean getSharedElementsUseOverlay() { return true; }
+
+    /**
+     * Sets whether or not shared elements should use an Overlay during shared element transitions.
+     * The default value is true.
+     *
+     * @param sharedElementsUseOverlay <code>true</code> indicates that shared elements should
+     *                                 be transitioned with an Overlay or <code>false</code>
+     *                                 to transition within the normal View hierarchy.
+     */
+    public void setSharedElementsUseOverlay(boolean sharedElementsUseOverlay) { }
+
+    /**
      * @return the color of the status bar.
      */
     public abstract int getStatusBarColor();
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index f4a478a..49d47fe 100644
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -386,7 +386,9 @@
         mCurrentDate.set(Calendar.YEAR, year);
         mCurrentDate.set(Calendar.MONTH, month);
         mCurrentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
-        mDateChangedListener.onDateChanged(mDelegator, year, month, dayOfMonth);
+        if (mDateChangedListener != null) {
+            mDateChangedListener.onDateChanged(mDelegator, year, month, dayOfMonth);
+        }
         updateDisplay(false);
     }
 
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 376e5b4..1b89179 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -73,16 +73,6 @@
     private boolean mHourWithTwoDigit;
     private char mHourFormat;
 
-    /**
-     * A no-op callback used in the constructor to avoid null checks later in
-     * the code.
-     */
-    private static final TimePicker.OnTimeChangedListener NO_OP_CHANGE_LISTENER =
-            new TimePicker.OnTimeChangedListener() {
-                public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
-                }
-            };
-
     public TimePickerClockDelegate(TimePicker delegator, Context context, AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
         super(delegator, context);
@@ -216,8 +206,6 @@
         updateMinuteControl();
         updateAmPmControl();
 
-        setOnTimeChangedListener(NO_OP_CHANGE_LISTENER);
-
         // set to current time
         setCurrentHour(mTempCalendar.get(Calendar.HOUR_OF_DAY));
         setCurrentMinute(mTempCalendar.get(Calendar.MINUTE));
diff --git a/core/res/res/color/switch_thumb_material_dark.xml b/core/res/res/color/switch_thumb_material_dark.xml
new file mode 100644
index 0000000..8fede70
--- /dev/null
+++ b/core/res/res/color/switch_thumb_material_dark.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false" android:color="@color/switch_thumb_disabled_material_dark"/>
+    <item android:color="@color/switch_thumb_normal_material_dark"/>
+</selector>
diff --git a/core/res/res/color/switch_thumb_material_light.xml b/core/res/res/color/switch_thumb_material_light.xml
new file mode 100644
index 0000000..1a34b74
--- /dev/null
+++ b/core/res/res/color/switch_thumb_material_light.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false" android:color="@color/switch_thumb_disabled_material_light"/>
+    <item android:color="@color/switch_thumb_normal_material_light"/>
+</selector>
diff --git a/core/res/res/drawable-hdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/spinner_textfield_activated_mtrl_alpha.9.png
index 8af9ceb4..5e67395 100644
--- a/core/res/res/drawable-hdpi/spinner_textfield_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-hdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/spinner_textfield_default_mtrl_alpha.9.png
index 81c78c6..9c2ee13 100644
--- a/core/res/res/drawable-hdpi/spinner_textfield_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-hdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_activated_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/textfield_search_activated_mtrl_alpha.9.png
index 7bcebcd..ce577e5 100644
--- a/core/res/res/drawable-hdpi/textfield_search_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_default_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/textfield_search_default_mtrl_alpha.9.png
index eb1d945..7c305ab 100644
--- a/core/res/res/drawable-hdpi/textfield_search_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/spinner_textfield_activated_mtrl_alpha.9.png
index 22992c0..cb8f78a 100644
--- a/core/res/res/drawable-mdpi/spinner_textfield_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-mdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/spinner_textfield_default_mtrl_alpha.9.png
index f44a2c2..64d4c81 100644
--- a/core/res/res/drawable-mdpi/spinner_textfield_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-mdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_activated_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/textfield_search_activated_mtrl_alpha.9.png
index ef4ebc0..d7faacf 100644
--- a/core/res/res/drawable-mdpi/textfield_search_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_default_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/textfield_search_default_mtrl_alpha.9.png
index 9ddbcf5..0a36039 100644
--- a/core/res/res/drawable-mdpi/textfield_search_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/spinner_textfield_activated_mtrl_alpha.9.png
index 2d79d59..8e7862f 100644
--- a/core/res/res/drawable-xhdpi/spinner_textfield_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xhdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/spinner_textfield_default_mtrl_alpha.9.png
index 36f9753..95cb83f 100644
--- a/core/res/res/drawable-xhdpi/spinner_textfield_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xhdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_search_activated_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/textfield_search_activated_mtrl_alpha.9.png
index 1a2546f..33c1035 100644
--- a/core/res/res/drawable-xhdpi/textfield_search_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xhdpi/textfield_search_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_search_default_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/textfield_search_default_mtrl_alpha.9.png
index 500ec33..0226f84 100644
--- a/core/res/res/drawable-xhdpi/textfield_search_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xhdpi/textfield_search_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
index 9c0b19e..eb495c6 100644
--- a/core/res/res/drawable-xxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/spinner_textfield_default_mtrl_alpha.9.png
index 0edb4b8..c2268af 100644
--- a/core/res/res/drawable-xxhdpi/spinner_textfield_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_search_activated_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/textfield_search_activated_mtrl_alpha.9.png
index cd5b00f..b6efff3 100644
--- a/core/res/res/drawable-xxhdpi/textfield_search_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/textfield_search_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_search_default_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/textfield_search_default_mtrl_alpha.9.png
index 5ee867c..2b253fb 100644
--- a/core/res/res/drawable-xxhdpi/textfield_search_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/textfield_search_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-xxxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
index 78c5ebd..fbcd7d4 100644
--- a/core/res/res/drawable-xxxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-xxxhdpi/spinner_textfield_default_mtrl_alpha.9.png
index 36974b7..ebc9bf7 100644
--- a/core/res/res/drawable-xxxhdpi/spinner_textfield_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxxhdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_borderless_material.xml b/core/res/res/drawable/btn_borderless_material.xml
index 47cc455..016f0ff 100644
--- a/core/res/res/drawable/btn_borderless_material.xml
+++ b/core/res/res/drawable/btn_borderless_material.xml
@@ -15,10 +15,7 @@
 -->
 
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
-       android:insetLeft="@dimen/control_inset_material"
-       android:insetTop="@dimen/control_inset_material"
-       android:insetBottom="@dimen/control_inset_material"
-       android:insetRight="@dimen/control_inset_material">
+       android:inset="@dimen/control_inset_material">
     <ripple android:color="?attr/colorControlHighlight">
         <item android:id="@id/mask"
               android:drawable="@drawable/btn_default_mtrl_shape" />
diff --git a/core/res/res/drawable/btn_default_material.xml b/core/res/res/drawable/btn_default_material.xml
index b04d4fb..d00a348 100644
--- a/core/res/res/drawable/btn_default_material.xml
+++ b/core/res/res/drawable/btn_default_material.xml
@@ -15,10 +15,7 @@
 -->
 
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
-       android:insetLeft="@dimen/control_inset_material"
-       android:insetTop="@dimen/control_inset_material"
-       android:insetBottom="@dimen/control_inset_material"
-       android:insetRight="@dimen/control_inset_material">
+       android:inset="@dimen/control_inset_material">
     <ripple android:color="?attr/colorControlHighlight">
         <item android:drawable="@drawable/btn_default_mtrl_shape" />
     </ripple>
diff --git a/core/res/res/drawable/btn_toggle_material.xml b/core/res/res/drawable/btn_toggle_material.xml
index a9951e7..9726782 100644
--- a/core/res/res/drawable/btn_toggle_material.xml
+++ b/core/res/res/drawable/btn_toggle_material.xml
@@ -15,10 +15,7 @@
 -->
 
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
-       android:insetLeft="@dimen/control_inset_material"
-       android:insetTop="@dimen/control_inset_material"
-       android:insetBottom="@dimen/control_inset_material"
-       android:insetRight="@dimen/control_inset_material">
+       android:inset="@dimen/control_inset_material">
     <layer-list android:paddingMode="stack">
         <item>
             <ripple android:color="?attr/colorControlHighlight">
diff --git a/core/res/res/drawable/edit_text_material.xml b/core/res/res/drawable/edit_text_material.xml
index eaf5e45..bbc7301 100644
--- a/core/res/res/drawable/edit_text_material.xml
+++ b/core/res/res/drawable/edit_text_material.xml
@@ -15,10 +15,7 @@
 -->
 
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
-    android:insetLeft="@dimen/control_inset_material"
-    android:insetTop="@dimen/control_inset_material"
-    android:insetBottom="@dimen/control_inset_material"
-    android:insetRight="@dimen/control_inset_material">
+        android:inset="@dimen/control_inset_material">
     <ripple android:color="?attr/colorControlActivated">
         <item>
             <selector>
diff --git a/core/res/res/drawable/spinner_textfield_background_material.xml b/core/res/res/drawable/spinner_textfield_background_material.xml
index f818baf..5bdff4a 100644
--- a/core/res/res/drawable/spinner_textfield_background_material.xml
+++ b/core/res/res/drawable/spinner_textfield_background_material.xml
@@ -14,18 +14,20 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:autoMirrored="true">
-    <item android:state_checked="true">
-        <nine-patch android:src="@drawable/spinner_textfield_activated_mtrl_alpha"
-            android:tint="?attr/colorControlActivated" />
-    </item>
-    <item android:state_pressed="true">
-        <nine-patch android:src="@drawable/spinner_textfield_activated_mtrl_alpha"
-            android:tint="?attr/colorControlActivated" />
-    </item>
-    <item>
-        <nine-patch android:src="@drawable/spinner_textfield_default_mtrl_alpha"
-            android:tint="?attr/colorControlNormal" />
-    </item>
-</selector>
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+       android:inset="@dimen/control_inset_material">
+    <selector android:autoMirrored="true">
+        <item android:state_checked="true">
+            <nine-patch android:src="@drawable/spinner_textfield_activated_mtrl_alpha"
+                android:tint="?attr/colorControlActivated" />
+        </item>
+        <item android:state_pressed="true">
+            <nine-patch android:src="@drawable/spinner_textfield_activated_mtrl_alpha"
+                android:tint="?attr/colorControlActivated" />
+        </item>
+        <item>
+            <nine-patch android:src="@drawable/spinner_textfield_default_mtrl_alpha"
+                android:tint="?attr/colorControlNormal" />
+        </item>
+    </selector>
+</inset>
diff --git a/core/res/res/drawable/switch_thumb_material_anim.xml b/core/res/res/drawable/switch_thumb_material_anim.xml
index 30bc8882..0d4d78e 100644
--- a/core/res/res/drawable/switch_thumb_material_anim.xml
+++ b/core/res/res/drawable/switch_thumb_material_anim.xml
@@ -16,22 +16,12 @@
 
 <animated-selector xmlns:android="http://schemas.android.com/apk/res/android"
     android:constantSize="true">
-    <item
-        android:state_enabled="false"
-        android:state_checked="true">
-        <nine-patch
-            android:src="@drawable/btn_switch_to_on_mtrl_00012"
-            android:gravity="center"
-            android:tintMode="multiply"
-            android:tint="?attr/colorControlActivated"
-            android:alpha="?attr/disabledAlpha" />
-    </item>
-    <item android:state_enabled="false">
+    <item android:state_enabled="false" android:id="@+id/off">
         <nine-patch
             android:src="@drawable/btn_switch_to_on_mtrl_00001"
             android:gravity="center"
             android:tintMode="multiply"
-            android:tint="?attr/colorButtonNormal" />
+            android:tint="?attr/colorSwitchThumbNormal" />
     </item>
     <item
         android:state_checked="true"
@@ -47,29 +37,29 @@
             android:src="@drawable/btn_switch_to_on_mtrl_00001"
             android:gravity="center"
             android:tintMode="multiply"
-            android:tint="?attr/colorButtonNormal" />
+            android:tint="?attr/colorSwitchThumbNormal" />
     </item>
     <transition
         android:fromId="@+id/off"
         android:toId="@+id/on">
         <animation-list>
             <item android:duration="15">
-                <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00001" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+                <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00001" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
             </item>
             <item android:duration="15">
-                <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00002" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+                <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00002" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
             </item>
             <item android:duration="15">
-                <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00003" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+                <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00003" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
             </item>
             <item android:duration="15">
-                <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00004" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+                <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00004" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
             </item>
             <item android:duration="15">
-                <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00005" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+                <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00005" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
             </item>
             <item android:duration="15">
-                <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00006" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+                <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00006" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
             </item>
             <item android:duration="15">
                 <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00007" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorControlActivated" />
@@ -112,22 +102,22 @@
                 <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00006" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00007" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+                <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00007" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
             </item>
             <item android:duration="15">
-                <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00008" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+                <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00008" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
             </item>
             <item android:duration="15">
-                <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00009" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+                <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00009" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
             </item>
             <item android:duration="15">
-                <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00010" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+                <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00010" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
             </item>
             <item android:duration="15">
-                <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00011" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+                <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00011" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
             </item>
             <item android:duration="15">
-                <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00012" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+                <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00012" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
             </item>
         </animation-list>
     </transition>
diff --git a/core/res/res/drawable/switch_track_material.xml b/core/res/res/drawable/switch_track_material.xml
index 0728055..1ec2f88 100644
--- a/core/res/res/drawable/switch_track_material.xml
+++ b/core/res/res/drawable/switch_track_material.xml
@@ -15,10 +15,10 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:state_checked="true">
+    <item android:state_enabled="false">
         <nine-patch android:src="@drawable/switch_track_mtrl_alpha"
-            android:tint="?attr/colorControlActivated"
-            android:alpha="0.2" />
+            android:tint="?attr/colorForeground"
+            android:alpha="0.1" />
     </item>
     <item android:state_checked="true">
         <nine-patch android:src="@drawable/switch_track_mtrl_alpha"
@@ -27,7 +27,7 @@
     </item>
     <item>
         <nine-patch android:src="@drawable/switch_track_mtrl_alpha"
-            android:tint="?attr/colorButtonNormal"
+            android:tint="?attr/colorForeground"
             android:alpha="0.3" />
     </item>
 </selector>
diff --git a/core/res/res/values-mcc310-mnc004/config.xml b/core/res/res/values-mcc310-mnc004/config.xml
index 4aac79d..423e250 100644
--- a/core/res/res/values-mcc310-mnc004/config.xml
+++ b/core/res/res/values-mcc310-mnc004/config.xml
@@ -33,4 +33,5 @@
         <item>83</item>
     </string-array>
 
+    <bool name="config_auto_attach_data_on_creation">false</bool>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml
index 1c83644..e5af60b 100644
--- a/core/res/res/values-mcc311-mnc480/config.xml
+++ b/core/res/res/values-mcc311-mnc480/config.xml
@@ -43,4 +43,5 @@
          provisioning, availability etc -->
     <bool name="config_mobile_allow_volte_vt">false</bool>
 
+    <bool name="config_auto_attach_data_on_creation">false</bool>
 </resources>
diff --git a/core/res/res/values-sw720dp/dimens.xml b/core/res/res/values-sw720dp/dimens.xml
index 21235ec..2317d1f 100644
--- a/core/res/res/values-sw720dp/dimens.xml
+++ b/core/res/res/values-sw720dp/dimens.xml
@@ -35,9 +35,9 @@
     <item type="dimen" name="dialog_fixed_height_minor">90%</item>
 
     <!-- The width that is used when creating thumbnails of applications. -->
-    <dimen name="thumbnail_width">640dp</dimen>
+    <dimen name="thumbnail_width">420dp</dimen>
     <!-- The height that is used when creating thumbnails of applications. -->
-    <dimen name="thumbnail_height">640dp</dimen>
+    <dimen name="thumbnail_height">420dp</dimen>
 
     <!-- Preference activity, vertical padding for the header list -->
     <dimen name="preference_screen_header_vertical_padding">32dp</dimen>
diff --git a/core/res/res/values-television/themes.xml b/core/res/res/values-television/themes.xml
index a501fac..377982a 100644
--- a/core/res/res/values-television/themes.xml
+++ b/core/res/res/values-television/themes.xml
@@ -20,6 +20,8 @@
     <style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
     <style name="Theme.Material.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
     <style name="Theme.Material.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
+    <style name="Theme.Material.Settings.Dialog.Alert" parent="Theme.Leanback.Settings.Dialog.Alert" />
     <style name="Theme.Material.Dialog" parent="Theme.Leanback.Dialog" />
     <style name="Theme.Material.Light.Dialog" parent="Theme.Leanback.Light.Dialog" />
+    <style name="Theme.Material.Settings.Dialog" parent="Theme.Leanback.Settings.Dialog" />
 </resources>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 327782d..f843d1f 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -506,12 +506,24 @@
 
     <!-- Used in LocalePicker -->
     <string-array translatable="false" name="special_locale_codes">
+        <!-- http://b/17150708 - ensure that the list of languages says "Arabic"
+             rather than "Arabic (Egypt)". If you're an OEM supporting multiple
+             Arabic locales, you should remove this entry so that ar_EG is shown
+             as "Arabic (Egypt)" in Settings. -->
+        <item>ar_EG</item>
+
         <item>zh_CN</item>
         <item>zh_TW</item>
     </string-array>
 
     <!-- Used in LocalePicker -->
     <string-array translatable="false" name="special_locale_names">
+        <!-- http://b/17150708 - ensure that the list of languages says "Arabic"
+             rather than "Arabic (Egypt)". If you're an OEM supporting multiple
+             Arabic locales, you should remove this entry so that ar_EG is shown
+             as "Arabic (Egypt)" in Settings. -->
+        <item>العربية</item>
+
         <item>中文 (简体)</item>
         <item>中文 (繁體)</item>
     </string-array>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index b00d7e8..3524636 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -517,6 +517,10 @@
              {@link android.view.Window#setAllowExitTransitionOverlap(boolean)}. -->
         <attr name="windowAllowExitTransitionOverlap" format="boolean"/>
 
+        <!-- Indicates whether or not shared elements should use an overlay
+             during transitions. The default value is true. -->
+        <attr name="windowSharedElementsUseOverlay" format="boolean"/>
+
         <!-- Internal layout used internally for window decor -->
         <attr name="windowActionBarFullscreenDecorLayout" format="reference" />
 
@@ -1005,6 +1009,9 @@
         <!-- The color applied to framework buttons in their normal state. -->
         <attr name="colorButtonNormal" format="color" />
 
+        <!-- The color applied to framework switch thumbs in their normal state. -->
+        <attr name="colorSwitchThumbNormal" format="color" />
+
         <!-- ================== -->
         <!-- Hardware rendering -->
         <!-- ================== -->
@@ -1836,6 +1843,10 @@
              {@link android.view.Window#setAllowExitTransitionOverlap(boolean)}. -->
         <attr name="windowAllowExitTransitionOverlap"/>
 
+        <!-- Indicates whether or not shared elements should use an overlay
+             during transitions. The default value is true. -->
+        <attr name="windowSharedElementsUseOverlay"/>
+
         <!-- Flag indicating whether this Window is responsible for drawing the background for the
              system bars. If true and the window is not floating, the system bars are drawn with a
              transparent background and the corresponding areas in this window are filled with the
@@ -5597,6 +5608,19 @@
         </attr>
     </declare-styleable>
 
+    <!-- Use <code>changeTransform</code> as the root tag of the XML resource that
+         describes a {@link android.transition.ChangeTransform} transition. -->
+    <declare-styleable name="ChangeTransform">
+        <!-- A parent change should use an overlay or affect the transform of the
+             transitionining View. Default is true. Corresponds to
+             {@link android.transition.ChangeTransform#setReparentWithOverlay(boolean)}. -->
+        <attr name="reparentWithOverlay" format="boolean"/>
+
+        <!-- Tells ChangeTransform to track parent changes. Default is true. Corresponds to
+             {@link android.transition.ChangeTransform#setReparent(boolean)}. -->
+        <attr name="reparent" format="boolean"/>
+    </declare-styleable>
+
     <!-- Use <code>transitionManager</code> as the root tag of the XML resource that
          describes a {@link android.transition.TransitionManager
          TransitionManager}. -->
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index ccbb8bc..2348951 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -25,6 +25,11 @@
     <color name="button_material_dark">#ff5a595b</color>
     <color name="button_material_light">#ffd6d7d7</color>
 
+    <color name="switch_thumb_normal_material_dark">#ffbdbdbd</color>
+    <color name="switch_thumb_normal_material_light">#fff1f1f1</color>
+    <color name="switch_thumb_disabled_material_dark">#ff616161</color>
+    <color name="switch_thumb_disabled_material_light">#ffbdbdbd</color>
+
     <color name="bright_foreground_material_dark">@color/white</color>
     <color name="bright_foreground_material_light">@color/black</color>
     <!-- White 50% -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index cf9a415..df7268f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1675,4 +1675,6 @@
          Examples: <item>311480;prefix</item> <item>310260;suffix</item>
     -->
     <string-array translatable="false" name="no_ems_support_sim_operators" />
+
+    <bool name="config_auto_attach_data_on_creation">true</bool>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 6022bdc..6fd2bb1 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -19,9 +19,9 @@
 -->
 <resources>
     <!-- The width that is used when creating thumbnails of applications. -->
-    <dimen name="thumbnail_width">256dp</dimen>
+    <dimen name="thumbnail_width">192dp</dimen>
     <!-- The height that is used when creating thumbnails of applications. -->
-    <dimen name="thumbnail_height">256dp</dimen>
+    <dimen name="thumbnail_height">192dp</dimen>
     <!-- The standard size (both width and height) of an application icon that
          will be displayed in the app launcher and elsewhere. -->
     <dimen name="app_icon_size">48dip</dimen>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index c64e910..4c59f73 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -85,4 +85,6 @@
   <item type="id" name="scene_layoutid_cache" />
   <item type="id" name="mask" />
   <item type="id" name="transitionPosition" />
+  <item type="id" name="transitionTransform" />
+  <item type="id" name="parentMatrix" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 4f0c5eb..f2466f7 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2275,6 +2275,9 @@
   <public type="attr" name="outlineProvider" />
   <public type="attr" name="ageHint" />
   <public type="attr" name="country" />
+  <public type="attr" name="windowSharedElementsUseOverlay" />
+  <public type="attr" name="reparent" />
+  <public type="attr" name="reparentWithOverlay" />
 
   <public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index af73c02..b32cd1e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1990,4 +1990,7 @@
   <java-symbol type="color" name="battery_saver_mode_color" />
   <java-symbol type="color" name="system_notification_accent_color" />
   <java-symbol type="dimen" name="text_handle_min_size" />
+  <java-symbol type="id" name="transitionTransform" />
+  <java-symbol type="id" name="parentMatrix" />
+  <java-symbol type="bool" name="config_auto_attach_data_on_creation" />
 </resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index b36cdb9..5445816 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -116,12 +116,12 @@
 
         <!-- Button styles -->
         <item name="buttonStyle">@style/Widget.Button</item>
-
         <item name="buttonStyleSmall">@style/Widget.Button.Small</item>
         <item name="buttonStyleInset">@style/Widget.Button.Inset</item>
-
         <item name="buttonStyleToggle">@style/Widget.Button.Toggle</item>
 
+        <item name="switchStyle">@style/Widget.CompoundButton.Switch</item>
+
         <item name="selectableItemBackground">@drawable/item_background</item>
         <item name="selectableItemBackgroundBorderless">?attr/selectableItemBackground</item>
         <item name="borderlessButtonStyle">?attr/buttonStyle</item>
diff --git a/core/res/res/values/themes_leanback.xml b/core/res/res/values/themes_leanback.xml
index 2b3b8d5..720733f 100644
--- a/core/res/res/values/themes_leanback.xml
+++ b/core/res/res/values/themes_leanback.xml
@@ -34,6 +34,16 @@
       <item name="numberPickerStyle">@style/Widget.Leanback.NumberPicker</item>
     </style>
 
+    <style name="Theme.Leanback.Settings.Dialog" parent="Theme.Material.Settings.BaseDialog">
+        <item name="colorBackground">@color/background_leanback_dark</item>
+        <item name="textColorPrimary">@color/primary_text_leanback_dark</item>
+        <item name="textColorSecondary">@color/secondary_text_leanback_dark</item>
+        <item name="alertDialogStyle">@style/AlertDialog.Leanback</item>
+        <item name="timePickerStyle">@style/Widget.Leanback.TimePicker</item>
+        <item name="datePickerStyle">@style/Widget.Leanback.DatePicker</item>
+        <item name="numberPickerStyle">@style/Widget.Leanback.NumberPicker</item>
+    </style>
+
     <style name="Theme.Leanback.Dialog.Alert" parent="Theme.Material.Dialog.BaseAlert">
       <item name="colorBackground">@color/background_leanback_dark</item>
       <item name="textColorPrimary">@color/primary_text_leanback_dark</item>
@@ -54,6 +64,16 @@
       <item name="numberPickerStyle">@style/Widget.Leanback.NumberPicker</item>
     </style>
 
+    <style name="Theme.Leanback.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.BaseAlert">
+        <item name="colorBackground">@color/background_leanback_light</item>
+        <item name="textColorPrimary">@color/primary_text_leanback_light</item>
+        <item name="textColorSecondary">@color/secondary_text_leanback_light</item>
+        <item name="alertDialogStyle">@style/AlertDialog.Leanback.Light</item>
+        <item name="timePickerStyle">@style/Widget.Leanback.TimePicker</item>
+        <item name="datePickerStyle">@style/Widget.Leanback.DatePicker</item>
+        <item name="numberPickerStyle">@style/Widget.Leanback.NumberPicker</item>
+    </style>
+
     <style name="Theme.Leanback.Dialog.AppError" parent="Theme.Leanback.Dialog">
         <item name="windowContentTransitions">false</item>
         <item name="windowCloseOnTouchOutside">false</item>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 18170ac..23faba8 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -357,10 +357,10 @@
         <item name="timePickerDialogTheme">?attr/dialogTheme</item>
 
         <!-- DatePicker style -->
-        <item name="datePickerStyle">?attr/dialogTheme</item>
+        <item name="datePickerStyle">@style/Widget.Material.DatePicker</item>
 
         <!-- DatePicker dialog theme -->
-        <item name="datePickerDialogTheme">@style/Theme.Material.Dialog.Alert</item>
+        <item name="datePickerDialogTheme">?attr/dialogTheme</item>
 
         <!-- TODO: This belongs in a FastScroll style -->
         <item name="fastScrollThumbDrawable">@drawable/fastscroll_thumb_material</item>
@@ -379,6 +379,7 @@
 
         <item name="colorControlHighlight">@color/ripple_material_dark</item>
         <item name="colorButtonNormal">@color/btn_default_material_dark</item>
+        <item name="colorSwitchThumbNormal">@color/switch_thumb_material_dark</item>
     </style>
 
     <!-- Material theme (light version). -->
@@ -721,6 +722,7 @@
 
         <item name="colorControlHighlight">@color/ripple_material_light</item>
         <item name="colorButtonNormal">@color/btn_default_material_light</item>
+        <item name="colorSwitchThumbNormal">@color/switch_thumb_material_light</item>
     </style>
 
     <!-- Variant of the material (light) theme that has a solid (opaque) action bar
@@ -774,6 +776,7 @@
         <item name="colorControlNormal">?attr/textColorSecondary</item>
         <item name="colorControlHighlight">@color/ripple_material_light</item>
         <item name="colorButtonNormal">@color/btn_default_material_light</item>
+        <item name="colorSwitchThumbNormal">@color/switch_thumb_material_light</item>
     </style>
 
     <!-- Theme overlay that replaces colors with their dark versions but preserves
@@ -811,6 +814,7 @@
         <item name="colorControlNormal">?attr/textColorSecondary</item>
         <item name="colorControlHighlight">@color/ripple_material_dark</item>
         <item name="colorButtonNormal">@color/btn_default_material_dark</item>
+        <item name="colorSwitchThumbNormal">@color/switch_thumb_material_dark</item>
     </style>
 
     <!-- Theme overlay that replaces the normal control color, which by default is the same as the
@@ -1192,7 +1196,7 @@
     <style name="Theme.Material.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.BaseAlert"/>
 
     <!-- Theme for a presentation window on a secondary display. -->
-    <style name="Theme.Material.Light.Dialog.Presentation" parent="@style/Theme.Material.Light.NoActionBar.Fullscreen" />
+    <style name="Theme.Material.Light.Dialog.Presentation" parent="Theme.Material.Light.NoActionBar.Fullscreen" />
 
     <!-- Default material (dark) for windows that want to have the user's selected
          wallpaper appear behind them.  -->
@@ -1209,7 +1213,47 @@
     </style>
 
     <!-- Default theme for Settings and activities launched from Settings. -->
-    <style name="Theme.Material.Settings" parent="@style/Theme.Material.Light.DarkActionBar">
+    <style name="Theme.Material.Settings" parent="Theme.Material.Light.DarkActionBar">
+        <item name="colorPrimary">@color/material_blue_grey_900</item>
+        <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
+        <item name="colorAccent">@color/material_deep_teal_A500</item>
+
+        <item name="dialogTheme">@style/Theme.Material.Settings.Dialog</item>
+        <item name="alertDialogTheme">@style/Theme.Material.Settings.Dialog.Alert</item>
+        <item name="presentationTheme">@style/Theme.Material.Settings.Dialog.Presentation</item>
+        <item name="searchDialogTheme">@style/Theme.Material.Settings.SearchBar</item>
+        <item name="panelMenuListTheme">@style/Theme.Material.Settings.CompactMenu</item>
+    </style>
+
+    <style name="Theme.Material.Settings.BaseDialog" parent="Theme.Material.Light.BaseDialog">
+        <item name="colorPrimary">@color/material_blue_grey_900</item>
+        <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
+        <item name="colorAccent">@color/material_deep_teal_A500</item>
+    </style>
+
+    <style name="Theme.Material.Settings.Dialog" parent="Theme.Material.Settings.BaseDialog" />
+
+    <style name="Theme.Material.Settings.Dialog.BaseAlert" parent="Theme.Material.Light.Dialog.BaseAlert">
+        <item name="colorPrimary">@color/material_blue_grey_900</item>
+        <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
+        <item name="colorAccent">@color/material_deep_teal_A500</item>
+    </style>
+
+    <style name="Theme.Material.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.BaseAlert" />
+
+    <style name="Theme.Material.Settings.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation">
+        <item name="colorPrimary">@color/material_blue_grey_900</item>
+        <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
+        <item name="colorAccent">@color/material_deep_teal_A500</item>
+    </style>
+
+    <style name="Theme.Material.Settings.SearchBar" parent="Theme.Material.Light.SearchBar">
+        <item name="colorPrimary">@color/material_blue_grey_900</item>
+        <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
+        <item name="colorAccent">@color/material_deep_teal_A500</item>
+    </style>
+
+    <style name="Theme.Material.Settings.CompactMenu" parent="Theme.Material.Light.CompactMenu">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
         <item name="colorAccent">@color/material_deep_teal_A500</item>
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 29b9141..2c8611e 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -811,6 +811,11 @@
     }
 
     @Override
+    public ColorFilter getColorFilter() {
+        return mColorFilter;
+    }
+
+    @Override
     public void setColorFilter(ColorFilter cf) {
         if (cf != mColorFilter) {
             mColorFilter = cf;
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index be2241b..063ac09 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -211,7 +211,7 @@
         final boolean canUseHardware = c.isHardwareAccelerated();
         if (mCanUseHardware != canUseHardware && mCanUseHardware) {
             // We've switched from hardware to non-hardware mode. Panic.
-            cancelHardwareAnimations();
+            cancelHardwareAnimations(true);
         }
         mCanUseHardware = canUseHardware;
 
@@ -231,7 +231,7 @@
         final ArrayList<RenderNodeAnimator> pendingAnimations = mPendingAnimations;
         final int N = pendingAnimations.size();
         if (N > 0) {
-            cancelHardwareAnimations();
+            cancelHardwareAnimations(false);
 
             for (int i = 0; i < N; i++) {
                 pendingAnimations.get(i).setTarget(c);
@@ -399,6 +399,45 @@
         invalidateSelf();
     }
 
+    public void jump() {
+        endSoftwareAnimations();
+        endHardwareAnimations();
+    }
+
+    private void endSoftwareAnimations() {
+        if (mAnimRadius != null) {
+            mAnimRadius.end();
+        }
+
+        if (mAnimOpacity != null) {
+            mAnimOpacity.end();
+        }
+
+        if (mAnimX != null) {
+            mAnimX.end();
+        }
+
+        if (mAnimY != null) {
+            mAnimY.end();
+        }
+    }
+
+    private void endHardwareAnimations() {
+        final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
+        final int N = runningAnimations.size();
+        for (int i = 0; i < N; i++) {
+            runningAnimations.get(i).end();
+        }
+        runningAnimations.clear();
+
+        // Abort any pending animations. Since we always have a completion
+        // listener on a pending animation, we also need to remove ourselves.
+        if (!mPendingAnimations.isEmpty()) {
+            mPendingAnimations.clear();
+            removeSelf();
+        }
+    }
+
     private Paint getTempPaint() {
         if (mTempPaint == null) {
             mTempPaint = new Paint();
@@ -444,7 +483,7 @@
      */
     public void cancel() {
         cancelSoftwareAnimations();
-        cancelHardwareAnimations();
+        cancelHardwareAnimations(true);
     }
 
     private void cancelSoftwareAnimations() {
@@ -468,14 +507,18 @@
     /**
      * Cancels any running hardware animations.
      */
-    private void cancelHardwareAnimations() {
+    private void cancelHardwareAnimations(boolean cancelPending) {
         final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
         final int N = runningAnimations.size();
         for (int i = 0; i < N; i++) {
             runningAnimations.get(i).cancel();
         }
-
         runningAnimations.clear();
+
+        if (cancelPending && !mPendingAnimations.isEmpty()) {
+            mPendingAnimations.clear();
+            removeSelf();
+        }
     }
 
     private void removeSelf() {
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index 93df648..49862bc 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -203,7 +203,7 @@
         final boolean canUseHardware = c.isHardwareAccelerated();
         if (mCanUseHardware != canUseHardware && mCanUseHardware) {
             // We've switched from hardware to non-hardware mode. Panic.
-            cancelHardwareAnimations();
+            cancelHardwareAnimations(true);
         }
         mCanUseHardware = canUseHardware;
 
@@ -223,7 +223,7 @@
         final ArrayList<RenderNodeAnimator> pendingAnimations = mPendingAnimations;
         final int N = pendingAnimations.size();
         if (N > 0) {
-            cancelHardwareAnimations();
+            cancelHardwareAnimations(false);
 
             for (int i = 0; i < N; i++) {
                 pendingAnimations.get(i).setTarget(c);
@@ -403,6 +403,41 @@
         invalidateSelf();
     }
 
+    public void jump() {
+        endSoftwareAnimations();
+        endHardwareAnimations();
+    }
+
+    private void endSoftwareAnimations() {
+        if (mAnimOuterOpacity != null) {
+            mAnimOuterOpacity.end();
+        }
+
+        if (mAnimX != null) {
+            mAnimX.end();
+        }
+
+        if (mAnimY != null) {
+            mAnimY.end();
+        }
+    }
+
+    private void endHardwareAnimations() {
+        final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
+        final int N = runningAnimations.size();
+        for (int i = 0; i < N; i++) {
+            runningAnimations.get(i).end();
+        }
+        runningAnimations.clear();
+
+        // Abort any pending animations. Since we always have a completion
+        // listener on a pending animation, we also need to remove ourselves.
+        if (!mPendingAnimations.isEmpty()) {
+            mPendingAnimations.clear();
+            removeSelf();
+        }
+    }
+
     private Paint getTempPaint() {
         if (mTempPaint == null) {
             mTempPaint = new Paint();
@@ -477,7 +512,7 @@
      */
     public void cancel() {
         cancelSoftwareAnimations();
-        cancelHardwareAnimations();
+        cancelHardwareAnimations(true);
     }
 
     private void cancelSoftwareAnimations() {
@@ -497,7 +532,7 @@
     /**
      * Cancels any running hardware animations.
      */
-    private void cancelHardwareAnimations() {
+    private void cancelHardwareAnimations(boolean cancelPending) {
         final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
         final int N = runningAnimations.size();
         for (int i = 0; i < N; i++) {
@@ -505,6 +540,11 @@
         }
 
         runningAnimations.clear();
+
+        if (cancelPending && !mPendingAnimations.isEmpty()) {
+            mPendingAnimations.clear();
+            removeSelf();
+        }
     }
 
     private void removeSelf() {
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 0447e17..ca32751f 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -199,6 +199,29 @@
     }
 
     @Override
+    public void jumpToCurrentState() {
+        super.jumpToCurrentState();
+
+        if (mRipple != null) {
+            mRipple.jump();
+        }
+
+        if (mBackground != null) {
+            mBackground.jump();
+        }
+
+        mClearingHotspots = true;
+        final int count = mAnimatingRipplesCount;
+        final Ripple[] ripples = mAnimatingRipples;
+        for (int i = 0; i < count; i++) {
+            ripples[i].jump();
+            ripples[i] = null;
+        }
+        mAnimatingRipplesCount = 0;
+        mClearingHotspots = false;
+    }
+
+    @Override
     public void setAlpha(int alpha) {
         super.setAlpha(alpha);
 
@@ -534,18 +557,6 @@
     }
 
     private void clearHotspots() {
-        mClearingHotspots = true;
-
-        final int count = mAnimatingRipplesCount;
-        final Ripple[] ripples = mAnimatingRipples;
-        for (int i = 0; i < count; i++) {
-            // Calling cancel may remove the ripple from the animating ripple
-            // array, so cache the reference before nulling it out.
-            final Ripple ripple = ripples[i];
-            ripples[i] = null;
-            ripple.cancel();
-        }
-
         if (mRipple != null) {
             mRipple.cancel();
             mRipple = null;
@@ -556,8 +567,16 @@
             mBackground = null;
         }
 
-        mClearingHotspots = false;
+        mClearingHotspots = true;
+        final int count = mAnimatingRipplesCount;
+        final Ripple[] ripples = mAnimatingRipples;
+        for (int i = 0; i < count; i++) {
+            ripples[i].cancel();
+            ripples[i] = null;
+        }
         mAnimatingRipplesCount = 0;
+        mClearingHotspots = false;
+
         invalidateSelf();
     }
 
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index 054a164..420e331 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -214,7 +214,7 @@
     mHead->pendingDirty.join(left, top, right, bottom);
 }
 
-void DamageAccumulator::peekAtDirty(SkRect* dest) {
+void DamageAccumulator::peekAtDirty(SkRect* dest) const {
     *dest = mHead->pendingDirty;
 }
 
diff --git a/libs/hwui/DamageAccumulator.h b/libs/hwui/DamageAccumulator.h
index 6f0bd8c..dd3365a 100644
--- a/libs/hwui/DamageAccumulator.h
+++ b/libs/hwui/DamageAccumulator.h
@@ -50,7 +50,7 @@
     void dirty(float left, float top, float right, float bottom);
 
     // Returns the current dirty area, *NOT* transformed by pushed transforms
-    void peekAtDirty(SkRect* dest);
+    void peekAtDirty(SkRect* dest) const;
 
     void computeCurrentTransform(Matrix4* outMatrix) const;
 
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 0db6198..977744f 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -179,13 +179,6 @@
         transformUpdateNeeded = true;
     }
 
-    if (transformUpdateNeeded) {
-        // update the transform in window of the layer to reset its origin wrt light source position
-        Matrix4 windowTransform;
-        info.damageAccumulator->computeCurrentTransform(&windowTransform);
-        mLayer->setWindowTransform(windowTransform);
-    }
-
     SkRect dirty;
     info.damageAccumulator->peekAtDirty(&dirty);
 
@@ -198,6 +191,12 @@
         return;
     }
 
+    if (transformUpdateNeeded) {
+        // update the transform in window of the layer to reset its origin wrt light source position
+        Matrix4 windowTransform;
+        info.damageAccumulator->computeCurrentTransform(&windowTransform);
+        mLayer->setWindowTransform(windowTransform);
+    }
 
     if (dirty.intersect(0, 0, getWidth(), getHeight())) {
         dirty.roundOut();
@@ -216,7 +215,10 @@
     if (info.mode == TreeInfo::MODE_FULL) {
         pushStagingPropertiesChanges(info);
     }
-    uint32_t animatorDirtyMask = mAnimatorManager.animate(info);
+    uint32_t animatorDirtyMask = 0;
+    if (CC_LIKELY(info.runAnimations)) {
+        animatorDirtyMask = mAnimatorManager.animate(info);
+    }
     prepareLayer(info, animatorDirtyMask);
     if (info.mode == TreeInfo::MODE_FULL) {
         pushStagingDisplayListChanges(info);
@@ -231,7 +233,9 @@
     // Push the animators first so that setupStartValueIfNecessary() is called
     // before properties() is trampled by stagingProperties(), as they are
     // required by some animators.
-    mAnimatorManager.pushStaging(info);
+    if (CC_LIKELY(info.runAnimations)) {
+        mAnimatorManager.pushStaging(info);
+    }
     if (mDirtyPropertyFields) {
         mDirtyPropertyFields = 0;
         damageSelf(info);
diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp
index 06c5ab4..bdac47b 100644
--- a/libs/hwui/StatefulBaseRenderer.cpp
+++ b/libs/hwui/StatefulBaseRenderer.cpp
@@ -196,12 +196,14 @@
     float radius;
     if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
 
-    if (!MathUtils::isPositive(radius)) {
+    bool outlineIsRounded = MathUtils::isPositive(radius);
+    if (!outlineIsRounded || currentTransform()->isSimple()) {
         // TODO: consider storing this rect separately, so that this can't be replaced with clip ops
         clipRect(bounds.left, bounds.top, bounds.right, bounds.bottom, SkRegion::kIntersect_Op);
-        return;
     }
-    setClippingRoundRect(allocator, bounds, radius);
+    if (outlineIsRounded) {
+        setClippingRoundRect(allocator, bounds, radius);
+    }
 }
 
 void StatefulBaseRenderer::setClippingRoundRect(LinearAllocator& allocator,
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index 331f157..74d52a3 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -65,6 +65,7 @@
         , frameTimeMs(0)
         , animationHook(NULL)
         , prepareTextures(mode == MODE_FULL)
+        , runAnimations(true)
         , damageAccumulator(NULL)
         , renderState(renderState)
         , renderer(NULL)
@@ -76,6 +77,7 @@
         , frameTimeMs(clone.frameTimeMs)
         , animationHook(clone.animationHook)
         , prepareTextures(mode == MODE_FULL)
+        , runAnimations(clone.runAnimations)
         , damageAccumulator(clone.damageAccumulator)
         , renderState(clone.renderState)
         , renderer(clone.renderer)
@@ -88,6 +90,12 @@
     // TODO: Remove this? Currently this is used to signal to stop preparing
     // textures if we run out of cache space.
     bool prepareTextures;
+    // TODO: buildLayer uses this to suppress running any animations, but this
+    // should probably be refactored somehow. The reason this is done is
+    // because buildLayer is not setup for injecting the animationHook, as well
+    // as this being otherwise wasted work as all the animators will be
+    // re-evaluated when the frame is actually drawn
+    bool runAnimations;
 
     // Must not be null during actual usage
     DamageAccumulator* damageAccumulator;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 5922135..4bf5a8a 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -257,6 +257,7 @@
     info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
     info.damageAccumulator = &mDamageAccumulator;
     info.renderer = mCanvas;
+    info.runAnimations = false;
     node->prepareTree(info);
     SkRect ignore;
     mDamageAccumulator.finish(&ignore);
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 7bf9e98..96e6ab9 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -94,9 +94,17 @@
  * and {@link #dequeueOutputBuffer} then transfer ownership from the codec
  * to the client.<p>
  * The client is not required to resubmit/release buffers immediately
- * to the codec, the sample code above simply does this for simplicity's sake.<p>
+ * to the codec, the sample code above simply does this for simplicity's sake.
+ * Nonetheless, it is possible that a codec may hold off on generating
+ * output buffers until all outstanding buffers have been
+ * released/resubmitted.
+ * <p>
  * Once the client has an input buffer available it can fill it with data
- * and submit it it to the codec via a call to {@link #queueInputBuffer}.<p>
+ * and submit it it to the codec via a call to {@link #queueInputBuffer}.
+ * Do not submit multiple input buffers with the same timestamp (unless
+ * it is codec-specific data marked as such using the flag
+ * {@link #BUFFER_FLAG_CODEC_CONFIG}).
+ * <p>
  * The codec in turn will return an output buffer to the client in response
  * to {@link #dequeueOutputBuffer}. After the output buffer has been processed
  * a call to {@link #releaseOutputBuffer} will return it to the codec.
@@ -128,18 +136,64 @@
  * {@link #queueInputBuffer}. The codec will continue to return output buffers
  * until it eventually signals the end of the output stream by specifying
  * the same flag ({@link #BUFFER_FLAG_END_OF_STREAM}) on the BufferInfo returned in
- * {@link #dequeueOutputBuffer}.
+ * {@link #dequeueOutputBuffer}.  Do not submit additional input buffers after
+ * signaling the end of the input stream, unless the codec has been flushed,
+ * or stopped and restarted.
  * <p>
+ * <h3>Seeking &amp; Adaptive Playback Support</h3>
+ *
+ * You can check if a decoder supports adaptive playback via {@link
+ * MediaCodecInfo.CodecCapabilities#isFeatureSupported}.  Adaptive playback
+ * is only supported if you configure the codec to decode onto a {@link
+ * android.view.Surface}.
+ *
+ * <h4>For decoders that do not support adaptive playback (including
+ * when not decoding onto a Surface)</h4>
+ *
  * In order to start decoding data that's not adjacent to previously submitted
- * data (i.e. after a seek) it is necessary to {@link #flush} the decoder.
+ * data (i.e. after a seek) <em>one must</em> {@link #flush} the decoder.
  * Any input or output buffers the client may own at the point of the flush are
  * immediately revoked, i.e. after a call to {@link #flush} the client does not
  * own any buffers anymore.
+ * <p>
+ * It is important that the input data after a flush starts at a suitable
+ * stream boundary.  The first frame must be able to be decoded completely on
+ * its own (for most codecs this means an I-frame), and that no frames should
+ * refer to frames before that first new frame.
  * Note that the format of the data submitted after a flush must not change,
  * flush does not support format discontinuities,
- * for this a full {@link #stop}, {@link #configure}, {@link #start}
+ * for this a full {@link #stop}, {@link #configure configure()}, {@link #start}
  * cycle is necessary.
  *
+ * <h4>For decoders that support adaptive playback</h4>
+ *
+ * In order to start decoding data that's not adjacent to previously submitted
+ * data (i.e. after a seek) it is <em>not necessary</em> to {@link #flush} the
+ * decoder.
+ * <p>
+ * It is still important that the input data after the discontinuity starts
+ * at a suitable stream boundary (e.g. I-frame), and that no new frames refer
+ * to frames before the first frame of the new input data segment.
+ * <p>
+ * For some video formats it is also possible to change the picture size
+ * mid-stream.  To do this for H.264, the new Sequence Parameter Set (SPS) and
+ * Picture Parameter Set (PPS) values must be packaged together with an
+ * Instantaneous Decoder Refresh (IDR) frame in a single buffer, which then
+ * can be enqueued as a regular input buffer.
+ * The client will receive an {@link #INFO_OUTPUT_FORMAT_CHANGED} return
+ * value from {@link #dequeueOutputBuffer dequeueOutputBuffer()} or
+ * {@link Callback#onOutputBufferAvailable onOutputBufferAvailable()}
+ * just after the picture-size change takes place and before any
+ * frames with the new size have been returned.
+ * <p>
+ * Be careful when calling {@link #flush} shortly after you have changed
+ * the picture size.  If you have not received confirmation of the picture
+ * size change, you will need to repeat the request for the new picture size.
+ * E.g. for H.264 you will need to prepend the PPS/SPS to the new IDR
+ * frame to ensure that the codec receives the picture size change request.
+ *
+ * <h3>States and error handling</h3>
+ *
  * <p> During its life, a codec conceptually exists in one of the following states:
  * Initialized, Configured, Executing, Error, Uninitialized, (omitting transitory states
  * between them). When created by one of the factory methods,
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
index d3b1520..05acf90 100644
--- a/media/java/android/media/MediaHTTPConnection.java
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -47,6 +47,7 @@
     private InputStream mInputStream = null;
 
     private boolean mAllowCrossDomainRedirect = true;
+    private boolean mAllowCrossProtocolRedirect = true;
 
     // from com.squareup.okhttp.internal.http
     private final static int HTTP_TEMP_REDIRECT = 307;
@@ -91,6 +92,8 @@
     private boolean filterOutInternalHeaders(String key, String val) {
         if ("android-allow-cross-domain-redirect".equalsIgnoreCase(key)) {
             mAllowCrossDomainRedirect = parseBoolean(val);
+            // cross-protocol redirects are also controlled by this flag
+            mAllowCrossProtocolRedirect = mAllowCrossDomainRedirect;
         } else {
             return false;
         }
@@ -190,8 +193,12 @@
                         !url.getProtocol().equals("http")) {
                     throw new NoRouteToHostException("Unsupported protocol redirect");
                 }
+                boolean sameProtocol = mURL.getProtocol().equals(url.getProtocol());
+                if (!mAllowCrossProtocolRedirect && !sameProtocol) {
+                    throw new NoRouteToHostException("Cross-protocol redirects are disallowed");
+                }
                 boolean sameHost = mURL.getHost().equals(url.getHost());
-                if (!sameHost) {
+                if (!mAllowCrossDomainRedirect && !sameHost) {
                     throw new NoRouteToHostException("Cross-domain redirects are disallowed");
                 }
 
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 1c8d3cc..3c2ad0e 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -389,9 +389,7 @@
     public void registerWithSession(MediaSessionLegacyHelper helper) {
         helper.addRccListener(mRcMediaIntent, mTransportListener);
         mSession = helper.getSession(mRcMediaIntent);
-        if (mTransportControlFlags != 0) {
-            setTransportControlFlags(mTransportControlFlags);
-        }
+        setTransportControlFlags(mTransportControlFlags);
     }
 
     /**
diff --git a/packages/Keyguard/res/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml
index 006b1ee..0d7e6c9 100644
--- a/packages/Keyguard/res/layout/keyguard_status_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_status_view.xml
@@ -27,8 +27,7 @@
     android:layout_height="wrap_content"
     androidprv:layout_maxWidth="@dimen/keyguard_security_width"
     androidprv:layout_maxHeight="@dimen/keyguard_security_height"
-    android:gravity="center_horizontal|top"
-    android:contentDescription="@string/keyguard_accessibility_status">
+    android:gravity="center_horizontal|top">
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 55d8d81..a136acf 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -115,8 +115,6 @@
     <string name="keyguard_accessibility_widget"><xliff:g id="widget_index">%1$s</xliff:g> widget.</string>
     <!-- Accessibility description of the lock screen user selector widget. [CHAR_LIMIT=none] -->
     <string name="keyguard_accessibility_user_selector">User selector</string>
-    <!-- Accessibility description of the lock screen status widget. [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_status">Status</string>
     <!-- Accessibility description of the camera widget. [CHAR_LIMIT=none] -->
     <string name="keyguard_accessibility_camera">Camera</string>
     <!-- Accessibility description of the lock media control widget. [CHAR_LIMIT=none] -->
@@ -176,6 +174,9 @@
     <!-- Accessibility description announced when user drags widget away from delete drop target [CHAR LIMIT=NONE] -->
     <string name="keyguard_accessibility_delete_widget_end"><xliff:g id="widget_index">%1$s</xliff:g> will not be deleted.</string>
 
+    <!-- Accessibility description for the text view that indicates when the next alarm is set (not shown on screen). [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_next_alarm">Next alarm set for <xliff:g id="alarm" example="Fri 8:30 AM">%1$s</xliff:g></string>
+
     <!-- Password keyboard strings. Used by LockScreen and Settings --><skip />
     <!-- Label for "switch to symbols" key.  Must be short to fit on key! -->
     <string name="password_keyboard_label_symbol_key">\?123</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
index 51a276e..a0fab42 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -143,7 +143,10 @@
 
     void refreshAlarmStatus(AlarmManager.AlarmClockInfo nextAlarm) {
         if (nextAlarm != null) {
-            mAlarmStatusView.setText(formatNextAlarm(mContext, nextAlarm));
+            String alarm = formatNextAlarm(mContext, nextAlarm);
+            mAlarmStatusView.setText(alarm);
+            mAlarmStatusView.setContentDescription(
+                    getResources().getString(R.string.keyguard_accessibility_next_alarm, alarm));
             mAlarmStatusView.setVisibility(View.VISIBLE);
         } else {
             mAlarmStatusView.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index c7198fe..d39f64e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -143,7 +143,7 @@
         mBackgroundColor = new ColorDrawable(0);
         // Copy the ripple drawable since we are going to be manipulating it
         mBackground = (RippleDrawable)
-                getResources().getDrawable(R.drawable.recents_task_view_header_bg);
+                getContext().getDrawable(R.drawable.recents_task_view_header_bg);
         mBackground = (RippleDrawable) mBackground.mutate().getConstantState().newDrawable();
         mBackground.setColor(ColorStateList.valueOf(0));
         mBackground.setDrawableByLayerId(mBackground.getId(0), mBackgroundColor);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index d53aa47..735fbfc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -158,8 +158,9 @@
                             picture = BitmapHelper.createCircularClip(
                                     picture, avatarSize, avatarSize);
                         }
-                        records.add(new UserRecord(info, picture, false /* isGuest */, isCurrent,
-                                false /* isAddUser */, false /* isRestricted */));
+                        int index = isCurrent ? 0 : records.size();
+                        records.add(index, new UserRecord(info, picture, false /* isGuest */,
+                                isCurrent, false /* isAddUser */, false /* isRestricted */));
                     }
                 }
 
@@ -182,7 +183,8 @@
                                     false /* isAddUser */, createIsRestricted));
                         }
                     } else {
-                        records.add(guestRecord);
+                        int index = guestRecord.isCurrent ? 0 : records.size();
+                        records.add(index, guestRecord);
                     }
                 }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 73358c8..9652ebd 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -267,6 +267,7 @@
     private Boolean mAllowExitTransitionOverlap;
     private Boolean mAllowEnterTransitionOverlap;
     private long mBackgroundFadeDurationMillis = -1;
+    private Boolean mSharedElementsUseOverlay;
 
     static class WindowManagerHolder {
         static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
@@ -3546,6 +3547,10 @@
                             R.styleable.Window_windowTransitionBackgroundFadeDuration,
                             DEFAULT_BACKGROUND_FADE_DURATION_MS);
                 }
+                if (mSharedElementsUseOverlay == null) {
+                    mSharedElementsUseOverlay = getWindowStyle().getBoolean(
+                            R.styleable.Window_windowSharedElementsUseOverlay, true);
+                }
             }
         }
     }
@@ -4024,6 +4029,16 @@
         mBackgroundFadeDurationMillis = fadeDurationMillis;
     }
 
+    @Override
+    public void setSharedElementsUseOverlay(boolean sharedElementsUseOverlay) {
+        mSharedElementsUseOverlay = sharedElementsUseOverlay;
+    }
+
+    @Override
+    public boolean getSharedElementsUseOverlay() {
+        return (mSharedElementsUseOverlay == null) ? true : mSharedElementsUseOverlay;
+    }
+
     private static final class DrawableFeatureState {
         DrawableFeatureState(int _featureId) {
             featureId = _featureId;
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index c6aa30b..f1e99fd 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -1539,7 +1539,7 @@
                 widget.views = views;
             }
 
-            scheduleNotifyUpdateAppWidgetLocked(widget);
+            scheduleNotifyUpdateAppWidgetLocked(widget, views);
         }
     }
 
@@ -1611,7 +1611,7 @@
         }
     }
 
-    private void scheduleNotifyUpdateAppWidgetLocked(Widget widget) {
+    private void scheduleNotifyUpdateAppWidgetLocked(Widget widget, RemoteViews updateViews) {
         if (widget == null || widget.provider == null || widget.provider.zombie
                 || widget.host.callbacks == null || widget.host.zombie) {
             return;
@@ -1620,7 +1620,7 @@
         SomeArgs args = SomeArgs.obtain();
         args.arg1 = widget.host;
         args.arg2 = widget.host.callbacks;
-        args.arg3 = widget.views;
+        args.arg3 = updateViews;
         args.argi1 = widget.appWidgetId;
 
         mCallbackHandler.obtainMessage(
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 54afe99..1005bd7 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4761,7 +4761,9 @@
             result.setType(networkType);
             return result;
         } else {
-           return new NetworkInfo(networkType, 0, "Unknown", "");
+            NetworkInfo result = new NetworkInfo(networkType);
+            result.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
+            return result;
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e8b1d03..f36f25f 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1841,6 +1841,7 @@
                         BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_START,
                         Integer.toString(msg.arg1), msg.arg1);
                 mSystemServiceManager.switchUser(msg.arg1);
+                mLockToAppRequest.clearPrompt();
                 break;
             }
             case ENTER_ANIMATION_COMPLETE_MSG: {
@@ -3505,7 +3506,8 @@
         try {
             int ret = mStackSupervisor.startActivityMayWait(null, targetUid, targetPackage, intent,
                     resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
-                    null, null, null, null, options, UserHandle.getUserId(targetUid), null);
+                    null, null, null, null, options, UserHandle.getUserId(sourceRecord.app.uid),
+                    null);
             return ret;
         } catch (SecurityException e) {
             // XXX need to figure out how to propagate to original app.
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 24b7cb3..fcbe71e 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -773,8 +773,8 @@
         if (newThumbnail != null) {
             if (ActivityManagerService.DEBUG_THUMBNAILS) Slog.i(ActivityManagerService.TAG,
                     "Setting thumbnail of " + this + " to " + newThumbnail);
-            task.setLastThumbnail(newThumbnail);
-            if (isPersistable()) {
+            boolean thumbnailUpdated = task.setLastThumbnail(newThumbnail);
+            if (thumbnailUpdated && isPersistable()) {
                 mStackSupervisor.mService.notifyTaskPersisterLocked(task, false);
             }
         }
diff --git a/services/core/java/com/android/server/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java
index 0ba62c5..098b0b6 100644
--- a/services/core/java/com/android/server/am/AppErrorDialog.java
+++ b/services/core/java/com/android/server/am/AppErrorDialog.java
@@ -94,6 +94,9 @@
             }
             mResult.set(msg.what);
 
+            // Make sure we don't have time timeout still hanging around.
+            removeMessages(FORCE_QUIT);
+
             // If this is a timeout we won't be automatically closed, so go
             // ahead and explicitly dismiss ourselves just in case.
             dismiss();
diff --git a/services/core/java/com/android/server/am/LockToAppRequestDialog.java b/services/core/java/com/android/server/am/LockToAppRequestDialog.java
index 5abf699..a1eb31e 100644
--- a/services/core/java/com/android/server/am/LockToAppRequestDialog.java
+++ b/services/core/java/com/android/server/am/LockToAppRequestDialog.java
@@ -74,11 +74,15 @@
         return 0;
     }
 
-    public void showLockTaskPrompt(TaskRecord task) {
+    public void clearPrompt() {
         if (mDialog != null) {
             mDialog.dismiss();
             mDialog = null;
         }
+    }
+
+    public void showLockTaskPrompt(TaskRecord task) {
+        clearPrompt();
         mRequestedTask = task;
         final int unlockStringId = getLockString(task.userId);
 
@@ -97,6 +101,8 @@
         mDialog = builder.create();
 
         mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+        mDialog.getWindow().getAttributes().privateFlags |=
+                WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
         mDialog.show();
 
         if (unlockStringId != 0) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 2a8c6fb..d35e09f 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -386,15 +386,23 @@
         setNextAffiliate(null);
     }
 
-    void setLastThumbnail(Bitmap thumbnail) {
-        mLastThumbnail = thumbnail;
-        if (thumbnail == null) {
-            if (mLastThumbnailFile != null) {
-                mLastThumbnailFile.delete();
+    /**
+     * Sets the last thumbnail.
+     * @return whether the thumbnail was set
+     */
+    boolean setLastThumbnail(Bitmap thumbnail) {
+        if (mLastThumbnail != thumbnail) {
+            mLastThumbnail = thumbnail;
+            if (thumbnail == null) {
+                if (mLastThumbnailFile != null) {
+                    mLastThumbnailFile.delete();
+                }
+            } else {
+                mService.mTaskPersister.saveImage(thumbnail, mFilename);
             }
-        } else {
-            mService.mTaskPersister.saveImage(thumbnail, mFilename);
+            return true;
         }
+        return false;
     }
 
     void getLastThumbnail(TaskThumbnail thumbs) {
@@ -403,7 +411,8 @@
         if (mLastThumbnail == null) {
             thumbs.mainThumbnail = mService.mTaskPersister.getThumbnail(mFilename);
         }
-        if (mLastThumbnailFile.exists()) {
+        // Only load the thumbnail file if we don't have a thumbnail
+        if (thumbs.mainThumbnail == null && mLastThumbnailFile.exists()) {
             try {
                 thumbs.thumbnailFileDescriptor = ParcelFileDescriptor.open(mLastThumbnailFile,
                         ParcelFileDescriptor.MODE_READ_ONLY);
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 14457ec..6771cce 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -162,6 +162,7 @@
         JobStatus jobStatus = new JobStatus(job, uId);
         cancelJob(uId, job.getId());
         startTrackingJob(jobStatus);
+        mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
         return JobScheduler.RESULT_SUCCESS;
     }
 
@@ -507,7 +508,9 @@
                 case MSG_JOB_EXPIRED:
                     synchronized (mJobs) {
                         JobStatus runNow = (JobStatus) message.obj;
-                        if (!mPendingJobs.contains(runNow)) {
+                        // runNow can be null, which is a controller's way of indicating that its
+                        // state is such that all ready jobs should be run immediately.
+                        if (runNow != null && !mPendingJobs.contains(runNow)) {
                             mPendingJobs.add(runNow);
                         }
                     }
diff --git a/services/core/java/com/android/server/job/StateChangedListener.java b/services/core/java/com/android/server/job/StateChangedListener.java
index 90c203a..97dfad3 100644
--- a/services/core/java/com/android/server/job/StateChangedListener.java
+++ b/services/core/java/com/android/server/job/StateChangedListener.java
@@ -33,7 +33,8 @@
     /**
      * Called by the controller to notify the JobManager that regardless of the state of the task,
      * it must be run immediately.
-     * @param jobStatus The state of the task which is to be run immediately.
+     * @param jobStatus The state of the task which is to be run immediately. <strong>null
+     *                  indicates to the scheduler that any ready jobs should be flushed.</strong>
      */
     public void onRunJobNow(JobStatus jobStatus);
 }
diff --git a/services/core/java/com/android/server/job/controllers/BatteryController.java b/services/core/java/com/android/server/job/controllers/BatteryController.java
index 538a252..309e034 100644
--- a/services/core/java/com/android/server/job/controllers/BatteryController.java
+++ b/services/core/java/com/android/server/job/controllers/BatteryController.java
@@ -84,15 +84,15 @@
 
     @Override
     public void maybeStartTrackingJob(JobStatus taskStatus) {
+        final boolean isOnStablePower = mChargeTracker.isOnStablePower();
         if (taskStatus.hasChargingConstraint()) {
-            final boolean isOnStablePower = mChargeTracker.isOnStablePower();
             synchronized (mTrackedTasks) {
                 mTrackedTasks.add(taskStatus);
                 taskStatus.chargingConstraintSatisfied.set(isOnStablePower);
             }
-            if (isOnStablePower) {
-                mStateChangedListener.onControllerStateChanged();
-            }
+        }
+        if (isOnStablePower) {
+            mChargeTracker.setStableChargingAlarm();
         }
     }
 
@@ -119,9 +119,15 @@
                 }
             }
         }
+        // Let the scheduler know that state has changed. This may or may not result in an
+        // execution.
         if (reportChange) {
             mStateChangedListener.onControllerStateChanged();
         }
+        // Also tell the scheduler that any ready jobs should be flushed.
+        if (stablePower) {
+            mStateChangedListener.onRunJobNow(null);
+        }
     }
 
     public class ChargingTracker extends BroadcastReceiver {
@@ -196,9 +202,7 @@
                 }
                 // Set up an alarm for ACTION_CHARGING_STABLE - we don't want to kick off tasks
                 // here if the user unplugs the phone immediately.
-                mAlarm.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                        SystemClock.elapsedRealtime() + STABLE_CHARGING_THRESHOLD_MILLIS,
-                        mStableChargingTriggerIntent);
+                setStableChargingAlarm();
                 mCharging = true;
             } else if (Intent.ACTION_POWER_DISCONNECTED.equals(action)) {
                 if (DEBUG) {
@@ -211,7 +215,7 @@
             }else if (ACTION_CHARGING_STABLE.equals(action)) {
                 // Here's where we actually do the notify for a task being ready.
                 if (DEBUG) {
-                    Slog.d(TAG, "Battery connected fired @ " + SystemClock.elapsedRealtime()
+                    Slog.d(TAG, "Stable charging fired @ " + SystemClock.elapsedRealtime()
                             + " charging: " + mCharging);
                 }
                 if (mCharging) {  // Should never receive this intent if mCharging is false.
@@ -219,6 +223,17 @@
                 }
             }
         }
+
+        void setStableChargingAlarm() {
+            final long alarmTriggerElapsed =
+                    SystemClock.elapsedRealtime() + STABLE_CHARGING_THRESHOLD_MILLIS;
+            if (DEBUG) {
+                Slog.d(TAG, "Setting stable alarm to go off in " +
+                        (STABLE_CHARGING_THRESHOLD_MILLIS / 1000) + "s");
+            }
+            mAlarm.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTriggerElapsed,
+                    mStableChargingTriggerIntent);
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b57a090..32f3707 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5801,6 +5801,29 @@
         SystemProperties.set(StrictMode.VISUAL_PROPERTY, value);
     }
 
+    private static void convertCropForSurfaceFlinger(Rect crop, int rot, int dw, int dh) {
+        if (rot == Surface.ROTATION_90) {
+            final int tmp = crop.top;
+            crop.top = dw - crop.right;
+            crop.right = crop.bottom;
+            crop.bottom = dw - crop.left;
+            crop.left = tmp;
+        } else if (rot == Surface.ROTATION_180) {
+            int tmp = crop.top;
+            crop.top = dh - crop.bottom;
+            crop.bottom = dh - tmp;
+            tmp = crop.right;
+            crop.right = dw - crop.left;
+            crop.left = dw - tmp;
+        } else if (rot == Surface.ROTATION_270) {
+            final int tmp = crop.top;
+            crop.top = crop.left;
+            crop.left = dh - crop.bottom;
+            crop.bottom = crop.right;
+            crop.right = dh - tmp;
+        }
+    }
+
     /**
      * Takes a snapshot of the screen.  In landscape mode this grabs the whole screen.
      * In portrait mode, it grabs the upper region of the screen based on the vertical dimension
@@ -5962,21 +5985,31 @@
 
                 // Constrain frame to the screen size.
                 frame.intersect(0, 0, dw, dh);
-                // Constrain thumbnail to smaller of screen width or height. Assumes aspect
-                // of thumbnail is the same as the screen (in landscape) or square.
-                scale = Math.max(width / (float) frame.width(), height / (float) frame.height());
-                dw = (int)(dw * scale);
-                dh = (int)(dh * scale);
+
+                // Tell surface flinger what part of the image to crop. Take the top
+                // right part of the application, and crop the larger dimension to fit.
+                Rect crop = new Rect(frame);
+                if (width / (float) frame.width() < height / (float) frame.height()) {
+                    int cropWidth = (int)((float)width / (float)height * frame.height());
+                    crop.right = crop.left + cropWidth;
+                } else {
+                    int cropHeight = (int)((float)height / (float)width * frame.width());
+                    crop.bottom = crop.top + cropHeight;
+                }
 
                 // The screenshot API does not apply the current screen rotation.
                 rot = getDefaultDisplayContentLocked().getDisplay().getRotation();
                 if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
-                    final int tmp = dw;
-                    dw = dh;
-                    dh = tmp;
+                    final int tmp = width;
+                    width = height;
+                    height = tmp;
                     rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
                 }
 
+                // Surfaceflinger is not aware of orientation, so convert our logical
+                // crop to surfaceflinger's portrait orientation.
+                convertCropForSurfaceFlinger(crop, rot, dw, dh);
+
                 if (DEBUG_SCREENSHOT) {
                     Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from " + minLayer + " to "
                             + maxLayer + " appToken=" + appToken);
@@ -5995,7 +6028,7 @@
                 if (DEBUG_SCREENSHOT && inRotation) Slog.v(TAG,
                         "Taking screenshot while rotating");
 
-                rawss = SurfaceControl.screenshot(new Rect(), dw, dh, minLayer, maxLayer,
+                rawss = SurfaceControl.screenshot(crop, width, height, minLayer, maxLayer,
                         inRotation);
                 if (rawss == null) {
                     Slog.w(TAG, "Screenshot failure taking screenshot for (" + dw + "x" + dh
@@ -6012,11 +6045,8 @@
         if (DEBUG_SCREENSHOT) {
             bm.eraseColor(0xFF000000);
         }
-        frame.scale(scale);
         Matrix matrix = new Matrix();
-        ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
-        // TODO: Test for RTL vs. LTR and use frame.right-width instead of -frame.left
-        matrix.postTranslate(-FloatMath.ceil(frame.left), -FloatMath.ceil(frame.top));
+        ScreenRotationAnimation.createRotationMatrix(rot, width, height, matrix);
         Canvas canvas = new Canvas(bm);
         canvas.drawBitmap(rawss, matrix, null);
         canvas.setBitmap(null);
@@ -6042,6 +6072,7 @@
         }
 
         rawss.recycle();
+
         return bm;
     }
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index 4b60c9f..5938819 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -267,6 +267,9 @@
             if (mDeviceOwner != null) {
                 out.startTag(null, TAG_DEVICE_OWNER);
                 out.attribute(null, ATTR_PACKAGE, mDeviceOwner.packageName);
+                if (mDeviceOwner.name != null) {
+                    out.attribute(null, ATTR_NAME, mDeviceOwner.name);
+                }
                 out.endTag(null, TAG_DEVICE_OWNER);
             }
 
diff --git a/telecomm/java/android/telecomm/Conference.java b/telecomm/java/android/telecomm/Conference.java
index 34b9dae..44accb7 100644
--- a/telecomm/java/android/telecomm/Conference.java
+++ b/telecomm/java/android/telecomm/Conference.java
@@ -163,6 +163,7 @@
      * @return True if the connection was successfully removed.
      */
     public void removeConnection(Connection connection) {
+        Log.d(this, "removing %s from %s", connection, mChildConnections);
         if (connection != null && mChildConnections.remove(connection)) {
             connection.resetConference();
             for (Listener l : mListeners) {
@@ -177,7 +178,7 @@
     public void destroy() {
         Log.d(this, "destroying conference : %s", this);
         // Tear down the children.
-        for (Connection connection : new ArrayList<>(mChildConnections)) {
+        for (Connection connection : mChildConnections) {
             Log.d(this, "removing connection %s", connection);
             removeConnection(connection);
         }
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
index c307a25..3aa4baf 100644
--- a/telecomm/java/android/telecomm/Connection.java
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -914,10 +914,11 @@
      */
     public final boolean setConference(Conference conference) {
         // We check to see if it is already part of another conference.
-        if (mConference == null && mConnectionService != null &&
-                mConnectionService.containsConference(conference)) {
+        if (mConference == null) {
             mConference = conference;
-            fireConferenceChanged();
+            if (mConnectionService != null && mConnectionService.containsConference(conference)) {
+                fireConferenceChanged();
+            }
             return true;
         }
         return false;
@@ -929,6 +930,7 @@
      */
     public final void resetConference() {
         if (mConference != null) {
+            Log.d(this, "Conference reset");
             mConference = null;
             fireConferenceChanged();
         }
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index c805978..b77bb18 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -84,6 +84,7 @@
     private final ConnectionServiceAdapter mAdapter = new ConnectionServiceAdapter();
 
     private boolean mAreAccountsInitialized = false;
+    private Conference sNullConference;
 
     private final IBinder mBinder = new IConnectionService.Stub() {
         @Override
@@ -561,17 +562,29 @@
 
     private void disconnect(String callId) {
         Log.d(this, "disconnect %s", callId);
-        findConnectionForAction(callId, "disconnect").onDisconnect();
+        if (mConnectionById.containsKey(callId)) {
+            findConnectionForAction(callId, "disconnect").onDisconnect();
+        } else {
+            findConferenceForAction(callId, "disconnect").onDisconnect();
+        }
     }
 
     private void hold(String callId) {
         Log.d(this, "hold %s", callId);
-        findConnectionForAction(callId, "hold").onHold();
+        if (mConnectionById.containsKey(callId)) {
+            findConnectionForAction(callId, "hold").onHold();
+        } else {
+            findConferenceForAction(callId, "hold").onHold();
+        }
     }
 
     private void unhold(String callId) {
         Log.d(this, "unhold %s", callId);
-        findConnectionForAction(callId, "unhold").onUnhold();
+        if (mConnectionById.containsKey(callId)) {
+            findConnectionForAction(callId, "unhold").onUnhold();
+        } else {
+            findConferenceForAction(callId, "unhold").onUnhold();
+        }
     }
 
     private void onAudioStateChanged(String callId, AudioState audioState) {
@@ -616,7 +629,10 @@
             return;
         }
 
-        // TODO: Find existing conference call and invoke split(connection).
+        Conference conference = connection.getConference();
+        if (conference != null) {
+            conference.onSeparate(connection);
+        }
     }
 
     private void onPostDialContinue(String callId, boolean proceed) {
@@ -885,4 +901,19 @@
         }
         return sNullConnection;
     }
+
+    private Conference findConferenceForAction(String conferenceId, String action) {
+        if (mConferenceById.containsKey(conferenceId)) {
+            return mConferenceById.get(conferenceId);
+        }
+        Log.w(this, "%s - Cannot find conference %s", action, conferenceId);
+        return getNullConference();
+    }
+
+    private Conference getNullConference() {
+        if (sNullConference == null) {
+            sNullConference = new Conference(null) {};
+        }
+        return sNullConference;
+    }
 }
diff --git a/telecomm/java/android/telecomm/ConnectionServiceAdapter.java b/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
index 41c6360..cb63646 100644
--- a/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
@@ -197,6 +197,7 @@
     void setIsConferenced(String callId, String conferenceCallId) {
         for (IConnectionServiceAdapter adapter : mAdapters) {
             try {
+                Log.d(this, "sending connection %s with conference %s", callId, conferenceCallId);
                 adapter.setIsConferenced(callId, conferenceCallId);
             } catch (RemoteException ignored) {
             }
diff --git a/telephony/java/com/android/ims/ImsCallProfile.java b/telephony/java/com/android/ims/ImsCallProfile.java
index dcd0b79..767ecf9 100644
--- a/telephony/java/com/android/ims/ImsCallProfile.java
+++ b/telephony/java/com/android/ims/ImsCallProfile.java
@@ -21,6 +21,8 @@
 import android.os.Parcelable;
 import android.telecomm.VideoProfile;
 
+import com.android.internal.telephony.PhoneConstants;
+
 /**
  * Parcelable object to handle IMS call profile.
  * It is created from GSMA IR.92/IR.94, 3GPP TS 24.229/TS 26.114/TS26.111.
@@ -337,6 +339,38 @@
     }
 
     /**
+     * Translate presentation value to OIR value
+     * @param presentation
+     * @return OIR valuse
+     */
+    public static int presentationToOIR(int presentation) {
+        switch (presentation) {
+            case PhoneConstants.PRESENTATION_RESTRICTED:
+                return ImsCallProfile.OIR_PRESENTATION_RESTRICTED;
+            case PhoneConstants.PRESENTATION_ALLOWED:
+                return ImsCallProfile.OIR_PRESENTATION_NOT_RESTRICTED;
+            default:
+                return ImsCallProfile.OIR_DEFAULT;
+        }
+    }
+
+    /**
+     * Translate OIR value to presentation value
+     * @param oir value
+     * @return presentation value
+     */
+    public static int OIRToPresentation(int oir) {
+        switch(oir) {
+            case ImsCallProfile.OIR_PRESENTATION_RESTRICTED:
+                return PhoneConstants.PRESENTATION_RESTRICTED;
+            case ImsCallProfile.OIR_PRESENTATION_NOT_RESTRICTED:
+                return PhoneConstants.PRESENTATION_ALLOWED;
+            default:
+                return PhoneConstants.PRESENTATION_UNKNOWN;
+        }
+    }
+
+    /**
      * Determines if a video state is set in a video state bit-mask.
      *
      * @param videoState The video state bit mask.
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
index 08d7667..d402699 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
@@ -54,7 +54,7 @@
         for (int i = 0; i < rowIndices.length; i++)
             rowIndices[i] = i * REGION_SIZE;
 
-        mScript = new ScriptC_errorCalculator(mRS, resources, R.raw.errorcalculator);
+        mScript = new ScriptC_errorCalculator(mRS);
         mScript.set_HEIGHT(height);
         mScript.set_WIDTH(width);
         mScript.set_REGION_SIZE(REGION_SIZE);
diff --git a/tests/RenderScriptTests/FountainFbo/Android.mk b/tests/RenderScriptTests/FountainFbo/Android.mk
index 4535eb1..c0f3323 100644
--- a/tests/RenderScriptTests/FountainFbo/Android.mk
+++ b/tests/RenderScriptTests/FountainFbo/Android.mk
@@ -25,5 +25,6 @@
 # LOCAL_SDK_VERSION := current
 
 LOCAL_PACKAGE_NAME := RsFountainFbo
+LOCAL_SDK_VERSION := 14
 
 include $(BUILD_PACKAGE)
diff --git a/tests/Split/Android.mk b/tests/Split/Android.mk
index 7884d4d..b068bef 100644
--- a/tests/Split/Android.mk
+++ b/tests/Split/Android.mk
@@ -20,8 +20,7 @@
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 LOCAL_PACKAGE_NAME := Split
 
-LOCAL_AAPT_FLAGS := --split fr,de
-LOCAL_AAPT_FLAGS += -v
+LOCAL_PACKAGE_SPLITS := mdpi-v4 hdpi-v4 xhdpi-v4 xxhdpi-v4
 
 LOCAL_MODULE_TAGS := tests
 
diff --git a/tests/Split/AndroidManifest.xml b/tests/Split/AndroidManifest.xml
index a4956a7..0de8344 100644
--- a/tests/Split/AndroidManifest.xml
+++ b/tests/Split/AndroidManifest.xml
@@ -16,7 +16,8 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.example.split">
-    <application android:label="@string/app_title">
+    <application android:label="@string/app_title"
+            android:icon="@mipmap/ic_app">
         <activity android:name="ActivityMain">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/tests/Split/res/drawable-hdpi/image.png b/tests/Split/res/drawable-hdpi/image.png
new file mode 100644
index 0000000..dcf4242
--- /dev/null
+++ b/tests/Split/res/drawable-hdpi/image.png
Binary files differ
diff --git a/tests/Split/res/drawable-mdpi/image.png b/tests/Split/res/drawable-mdpi/image.png
new file mode 100644
index 0000000..3437952
--- /dev/null
+++ b/tests/Split/res/drawable-mdpi/image.png
Binary files differ
diff --git a/tests/Split/res/drawable-xhdpi/image.png b/tests/Split/res/drawable-xhdpi/image.png
new file mode 100644
index 0000000..68b2f8e
--- /dev/null
+++ b/tests/Split/res/drawable-xhdpi/image.png
Binary files differ
diff --git a/tests/Split/res/drawable-xxhdpi/image.png b/tests/Split/res/drawable-xxhdpi/image.png
new file mode 100644
index 0000000..4bff9b9
--- /dev/null
+++ b/tests/Split/res/drawable-xxhdpi/image.png
Binary files differ
diff --git a/tests/Split/res/layout/main.xml b/tests/Split/res/layout/main.xml
index 36992a2..607cdb0 100644
--- a/tests/Split/res/layout/main.xml
+++ b/tests/Split/res/layout/main.xml
@@ -14,6 +14,12 @@
      limitations under the License.
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+    android:layout_height="match_parent">
+    <ImageView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerInParent="true"
+        android:src="@drawable/image"/>
+</RelativeLayout>
diff --git a/tests/Split/res/mipmap-hdpi/ic_app.png b/tests/Split/res/mipmap-hdpi/ic_app.png
new file mode 100644
index 0000000..ffcb9e5
--- /dev/null
+++ b/tests/Split/res/mipmap-hdpi/ic_app.png
Binary files differ
diff --git a/tests/Split/res/mipmap-mdpi/ic_app.png b/tests/Split/res/mipmap-mdpi/ic_app.png
new file mode 100644
index 0000000..35f5b45
--- /dev/null
+++ b/tests/Split/res/mipmap-mdpi/ic_app.png
Binary files differ
diff --git a/tests/Split/res/mipmap-xhdpi/ic_app.png b/tests/Split/res/mipmap-xhdpi/ic_app.png
new file mode 100644
index 0000000..bfe71fe
--- /dev/null
+++ b/tests/Split/res/mipmap-xhdpi/ic_app.png
Binary files differ
diff --git a/tests/Split/res/mipmap-xxhdpi/ic_app.png b/tests/Split/res/mipmap-xxhdpi/ic_app.png
new file mode 100644
index 0000000..b65532c
--- /dev/null
+++ b/tests/Split/res/mipmap-xxhdpi/ic_app.png
Binary files differ
diff --git a/tests/Split/res/mipmap-xxxhdpi/ic_app.png b/tests/Split/res/mipmap-xxxhdpi/ic_app.png
new file mode 100644
index 0000000..2679b49
--- /dev/null
+++ b/tests/Split/res/mipmap-xxxhdpi/ic_app.png
Binary files differ
diff --git a/tests/Split/src/java/com/android/example/split/ActivityMain.java b/tests/Split/src/java/com/android/example/split/ActivityMain.java
index a15fb3c..63963a2 100644
--- a/tests/Split/src/java/com/android/example/split/ActivityMain.java
+++ b/tests/Split/src/java/com/android/example/split/ActivityMain.java
@@ -24,8 +24,6 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        TextView text = new TextView(this);
-        text.setText(R.string.test);
-        setContentView(text);
+        setContentView(R.layout.main);
     }
 }
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index eead68c..b44e2d1 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -561,15 +561,17 @@
         return NO_ERROR;
     }
 
-#if 0
-    printf("Error adding file %s: group %s already exists in leaf=%s path=%s\n",
-            file->getSourceFile().string(),
-            file->getGroupEntry().toDirName(String8()).string(),
-            mLeaf.string(), mPath.string());
-#endif
+    // Check if the version is automatically applied. This is a common source of
+    // error.
+    ConfigDescription withoutVersion = file->getGroupEntry().toParams();
+    withoutVersion.version = 0;
+    AaptConfig::applyVersionForCompatibility(&withoutVersion);
 
-    SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
-                                               getPrintableSource().string());
+    const sp<AaptFile>& originalFile = mFiles.valueAt(index);
+    SourcePos(file->getSourceFile(), -1)
+            .error("Duplicate file.\n%s: Original is here. %s",
+                   originalFile->getPrintableSource().string(),
+                   (withoutVersion.version != 0) ? "The version qualifier may be implied." : "");
     return UNKNOWN_ERROR;
 }
 
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 869a6fc..1d93b89 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1399,7 +1399,8 @@
             sp<ApkSplit>& split = splits.editItemAt(i);
             sp<AaptFile> flattenedTable = new AaptFile(String8("resources.arsc"),
                     AaptGroupEntry(), String8());
-            err = table.flatten(bundle, split->getResourceFilter(), flattenedTable);
+            err = table.flatten(bundle, split->getResourceFilter(),
+                    flattenedTable, split->isBase());
             if (err != NO_ERROR) {
                 fprintf(stderr, "Failed to generate resource table for split '%s'\n",
                         split->getPrintableName().string());
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 49d8699..b3c364b 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -2074,10 +2074,11 @@
     return mNumLocal > 0;
 }
 
-sp<AaptFile> ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter)
+sp<AaptFile> ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
+        const bool isBase)
 {
     sp<AaptFile> data = new AaptFile(String8(), AaptGroupEntry(), String8());
-    status_t err = flatten(bundle, filter, data);
+    status_t err = flatten(bundle, filter, data, isBase);
     return err == NO_ERROR ? data : NULL;
 }
 
@@ -2699,7 +2700,9 @@
     return err;
 }
 
-status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter, const sp<AaptFile>& dest)
+status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
+        const sp<AaptFile>& dest,
+        const bool isBase)
 {
     const ConfigDescription nullConfig;
 
@@ -2768,6 +2771,13 @@
                 configTypeName = "2value";
             }
 
+            // mipmaps don't get filtered, so they will
+            // allways end up in the base. Make sure they
+            // don't end up in a split.
+            if (typeName == mipmap16 && !isBase) {
+                continue;
+            }
+
             const bool filterable = (typeName != mipmap16);
 
             const size_t N = t->getOrderedConfigs().size();
@@ -2871,10 +2881,12 @@
             return amt;
         }
 
-        status_t err = flattenLibraryTable(data, libraryPackages);
-        if (err != NO_ERROR) {
-            fprintf(stderr, "ERROR: failed to write library table\n");
-            return err;
+        if (isBase) {
+            status_t err = flattenLibraryTable(data, libraryPackages);
+            if (err != NO_ERROR) {
+                fprintf(stderr, "ERROR: failed to write library table\n");
+                return err;
+            }
         }
 
         // Build the type chunks inside of this package.
@@ -2890,6 +2902,7 @@
                 continue;
             }
             const bool filterable = (typeName != mipmap16);
+            const bool skipEntireType = (typeName == mipmap16 && !isBase);
 
             const size_t N = t != NULL ? t->getOrderedConfigs().size() : 0;
 
@@ -2927,6 +2940,11 @@
                     if (cl->getPublic()) {
                         typeSpecFlags[ei] |= htodl(ResTable_typeSpec::SPEC_PUBLIC);
                     }
+
+                    if (skipEntireType) {
+                        continue;
+                    }
+
                     const size_t CN = cl->getEntries().size();
                     for (size_t ci=0; ci<CN; ci++) {
                         if (filterable && !filter->match(cl->getEntries().keyAt(ci))) {
@@ -2943,6 +2961,10 @@
                 }
             }
             
+            if (skipEntireType) {
+                continue;
+            }
+
             // We need to write one type chunk for each configuration for
             // which we have entries in this type.
             const size_t NC = t->getUniqueConfigs().size();
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index d4f47ef..3721de4 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -165,7 +165,8 @@
     size_t numLocalResources() const;
     bool hasResources() const;
 
-    sp<AaptFile> flatten(Bundle* bundle, const sp<const ResourceFilter>& filter);
+    sp<AaptFile> flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
+            const bool isBase);
 
     static inline uint32_t makeResId(uint32_t packageId,
                                      uint32_t typeId,
@@ -206,7 +207,8 @@
     void addLocalization(const String16& name, const String8& locale, const SourcePos& src);
     status_t validateLocalizations(void);
 
-    status_t flatten(Bundle* bundle, const sp<const ResourceFilter>& filter, const sp<AaptFile>& dest);
+    status_t flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
+            const sp<AaptFile>& dest, const bool isBase);
     status_t flattenLibraryTable(const sp<AaptFile>& dest, const Vector<sp<Package> >& libs);
 
     void writePublicDefinitions(const String16& package, FILE* fp);
diff --git a/tools/aapt/tests/ResourceFilter_test.cpp b/tools/aapt/tests/ResourceFilter_test.cpp
index 30697bb..b55379e 100644
--- a/tools/aapt/tests/ResourceFilter_test.cpp
+++ b/tools/aapt/tests/ResourceFilter_test.cpp
@@ -126,3 +126,38 @@
     EXPECT_TRUE(filter.match(config));
 }
 
+TEST(StrongResourceFilterTest, MatchesDensities) {
+    ConfigDescription config;
+    config.density = 160;
+    config.version = 4;
+    std::set<ConfigDescription> configs;
+    configs.insert(config);
+
+    StrongResourceFilter filter(configs);
+
+    ConfigDescription expectedConfig;
+    expectedConfig.density = 160;
+    expectedConfig.version = 4;
+    ASSERT_TRUE(filter.match(expectedConfig));
+}
+
+TEST(StrongResourceFilterTest, MatchOnlyMdpiAndExcludeAllOthers) {
+    std::set<ConfigDescription> configsToMatch;
+    ConfigDescription config;
+    config.density = 160;
+    config.version = 4;
+    configsToMatch.insert(config);
+
+    std::set<ConfigDescription> configsToNotMatch;
+    config.density = 480;
+    configsToNotMatch.insert(config);
+
+    AndResourceFilter filter;
+    filter.addFilter(new InverseResourceFilter(new StrongResourceFilter(configsToNotMatch)));
+    filter.addFilter(new StrongResourceFilter(configsToMatch));
+
+    ConfigDescription expectedConfig;
+    expectedConfig.density = 160;
+    expectedConfig.version = 4;
+    ASSERT_TRUE(filter.match(expectedConfig));
+}