Merge "TM TaskServiceContext implementation"
diff --git a/api/current.txt b/api/current.txt
index 67f33f4..907c3b8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12308,12 +12308,16 @@
     field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MODE;
   }
 
+}
+
+package android.hardware.camera2.params {
+
   public final class ColorSpaceTransform {
-    ctor public ColorSpaceTransform(android.hardware.camera2.Rational[]);
+    ctor public ColorSpaceTransform(android.util.Rational[]);
     ctor public ColorSpaceTransform(int[]);
-    method public void copyElements(android.hardware.camera2.Rational[], int);
+    method public void copyElements(android.util.Rational[], int);
     method public void copyElements(int[], int);
-    method public android.hardware.camera2.Rational getElement(int, int);
+    method public android.util.Rational getElement(int, int);
   }
 
   public final class Face {
@@ -12333,7 +12337,7 @@
     method public int getColumnCount();
     method public float getGainFactor(int, int, int);
     method public int getGainFactorCount();
-    method public android.hardware.camera2.RggbChannelVector getGainFactorVector(int, int);
+    method public android.hardware.camera2.params.RggbChannelVector getGainFactorVector(int, int);
     method public int getRowCount();
     field public static final float MINIMUM_GAIN_FACTOR = 1.0f;
   }
@@ -12342,7 +12346,7 @@
     ctor public MeteringRectangle(int, int, int, int, int);
     ctor public MeteringRectangle(android.graphics.Point, android.util.Size, int);
     ctor public MeteringRectangle(android.graphics.Rect, int);
-    method public boolean equals(android.hardware.camera2.MeteringRectangle);
+    method public boolean equals(android.hardware.camera2.params.MeteringRectangle);
     method public int getHeight();
     method public int getMeteringWeight();
     method public android.graphics.Rect getRect();
@@ -12353,12 +12357,6 @@
     method public int getY();
   }
 
-  public final class Rational {
-    ctor public Rational(int, int);
-    method public int getDenominator();
-    method public int getNumerator();
-  }
-
   public final class RggbChannelVector {
     ctor public RggbChannelVector(float, float, float, float);
     method public void copyTo(float[], int);
@@ -12374,10 +12372,17 @@
     field public static final int RED = 0; // 0x0
   }
 
-  public final class Size {
-    ctor public Size(int, int);
-    method public final int getHeight();
-    method public final int getWidth();
+  public final class StreamConfigurationMap {
+    method public final int[] getOutputFormats();
+    method public long getOutputMinFrameDuration(int, android.util.Size);
+    method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
+    method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
+    method public android.util.Size[] getOutputSizes(int);
+    method public long getOutputStallDuration(int, android.util.Size);
+    method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
+    method public boolean isOutputSupportedFor(int);
+    method public static boolean isOutputSupportedFor(java.lang.Class<T>);
+    method public boolean isOutputSupportedFor(android.view.Surface);
   }
 
   public final class TonemapCurve {
@@ -12394,23 +12399,6 @@
 
 }
 
-package android.hardware.camera2.params {
-
-  public final class StreamConfigurationMap {
-    method public final int[] getOutputFormats();
-    method public long getOutputMinFrameDuration(int, android.util.Size);
-    method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
-    method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
-    method public android.util.Size[] getOutputSizes(int);
-    method public long getOutputStallDuration(int, android.util.Size);
-    method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
-    method public boolean isOutputSupportedFor(int);
-    method public static boolean isOutputSupportedFor(java.lang.Class<T>);
-    method public boolean isOutputSupportedFor(android.view.Surface);
-  }
-
-}
-
 package android.hardware.display {
 
   public final class DisplayManager {
@@ -27124,6 +27112,7 @@
     method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
     method public boolean isNetworkRoaming();
     method public void listen(android.telephony.PhoneStateListener, int);
+    method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
     field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
     field public static final int CALL_STATE_IDLE = 0; // 0x0
@@ -29996,6 +29985,12 @@
     method public T getUpper();
   }
 
+  public final class Rational {
+    ctor public Rational(int, int);
+    method public int getDenominator();
+    method public int getNumerator();
+  }
+
   public final class Size {
     ctor public Size(int, int);
     method public int getHeight();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index b4d8942..eeb5283 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1345,6 +1345,15 @@
     public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
             String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
             int initialCode, String initialData, Bundle initialExtras) {
+        sendOrderedBroadcastAsUser(intent, user, receiverPermission, AppOpsManager.OP_NONE,
+                resultReceiver, scheduler, initialCode, initialData, initialExtras);
+    }
+
+    @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+            Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
         IIntentReceiver rd = null;
         if (resultReceiver != null) {
             if (mPackageInfo != null) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9f01369..fd76b9c4 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1456,7 +1456,7 @@
         /**
          * Add a timestamp pertaining to the notification (usually the time the event occurred).
          * It will be shown in the notification content view by default; use
-         * {@link Builder#setShowWhen(boolean) setShowWhen} to control this.
+         * {@link #setShowWhen(boolean) setShowWhen} to control this.
          *
          * @see Notification#when
          */
@@ -1466,7 +1466,7 @@
         }
 
         /**
-         * Control whether the timestamp set with {@link Builder#setWhen(long) setWhen} is shown
+         * Control whether the timestamp set with {@link #setWhen(long) setWhen} is shown
          * in the content view.
          */
         public Builder setShowWhen(boolean show) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a059e48..a364e68 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1499,6 +1499,17 @@
             @Nullable  Bundle initialExtras);
 
     /**
+     * Similar to above but takes an appOp as well, to enforce restrictions.
+     * @see #sendOrderedBroadcastAsUser(Intent, UserHandle, String,
+     *       BroadcastReceiver, Handler, int, String, Bundle)
+     * @hide
+     */
+    public abstract void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            @Nullable String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+            @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
+            @Nullable  Bundle initialExtras);
+
+    /**
      * Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
      * Intent you are sending stays around after the broadcast is complete,
      * so that others can quickly retrieve that data through the return
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 93f6cdf..c66355b 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -418,6 +418,16 @@
                 scheduler, initialCode, initialData, initialExtras);
     }
 
+    /** @hide */
+    @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+            Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
+        mBase.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp, resultReceiver,
+                scheduler, initialCode, initialData, initialExtras);
+    }
+
     @Override
     public void sendStickyBroadcast(Intent intent) {
         mBase.sendStickyBroadcast(intent);
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index b1c1005..1127fe5 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -17,6 +17,7 @@
 package android.hardware.camera2;
 
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.util.Rational;
 
 import java.util.Collections;
 import java.util.List;
@@ -316,8 +317,8 @@
      * <li>All non (0, 0) sizes will have non-zero widths and heights.</li>
      * </ul>
      */
-    public static final Key<android.hardware.camera2.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES =
-            new Key<android.hardware.camera2.Size[]>("android.jpeg.availableThumbnailSizes", android.hardware.camera2.Size[].class);
+    public static final Key<android.util.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES =
+            new Key<android.util.Size[]>("android.jpeg.availableThumbnailSizes", android.util.Size[].class);
 
     /**
      * <p>List of supported aperture
@@ -393,8 +394,8 @@
      * <p>The map should be on the order of 30-40 rows and columns, and
      * must be smaller than 64x64.</p>
      */
-    public static final Key<android.hardware.camera2.Size> LENS_INFO_SHADING_MAP_SIZE =
-            new Key<android.hardware.camera2.Size>("android.lens.info.shadingMapSize", android.hardware.camera2.Size.class);
+    public static final Key<android.util.Size> LENS_INFO_SHADING_MAP_SIZE =
+            new Key<android.util.Size>("android.lens.info.shadingMapSize", android.util.Size.class);
 
     /**
      * <p>The lens focus distance calibration quality.</p>
@@ -658,8 +659,8 @@
      * @hide
      */
     @Deprecated
-    public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_JPEG_SIZES =
-            new Key<android.hardware.camera2.Size[]>("android.scaler.availableJpegSizes", android.hardware.camera2.Size[].class);
+    public static final Key<android.util.Size[]> SCALER_AVAILABLE_JPEG_SIZES =
+            new Key<android.util.Size[]>("android.scaler.availableJpegSizes", android.util.Size[].class);
 
     /**
      * <p>The maximum ratio between active area width
@@ -704,8 +705,8 @@
      * @hide
      */
     @Deprecated
-    public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_PROCESSED_SIZES =
-            new Key<android.hardware.camera2.Size[]>("android.scaler.availableProcessedSizes", android.hardware.camera2.Size[].class);
+    public static final Key<android.util.Size[]> SCALER_AVAILABLE_PROCESSED_SIZES =
+            new Key<android.util.Size[]>("android.scaler.availableProcessedSizes", android.util.Size[].class);
 
     /**
      * <p>The mapping of image formats that are supported by this
@@ -961,9 +962,6 @@
      * can provide.</p>
      * <p>Please reference the documentation for the image data destination to
      * check if it limits the maximum size for image data.</p>
-     * <p>Not all output formats may be supported in a configuration with
-     * an input stream of a particular format. For more details, see
-     * android.scaler.availableInputOutputFormatsMap.</p>
      * <p>The following table describes the minimum required output stream
      * configurations based on the hardware level
      * ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel}):</p>
@@ -1106,8 +1104,8 @@
      * match this in
      * android.scaler.availableStreamConfigurations.</p>
      */
-    public static final Key<android.hardware.camera2.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE =
-            new Key<android.hardware.camera2.Size>("android.sensor.info.pixelArraySize", android.hardware.camera2.Size.class);
+    public static final Key<android.util.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE =
+            new Key<android.util.Size>("android.sensor.info.pixelArraySize", android.util.Size.class);
 
     /**
      * <p>Maximum raw value output by sensor.</p>
@@ -1515,13 +1513,4 @@
     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * End generated code
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
-
-
-
-
-
-
-
-
-
 }
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 8ae21f3..a70aa3b 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -19,6 +19,7 @@
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Rational;
 import android.view.Surface;
 
 import java.util.HashSet;
@@ -169,7 +170,7 @@
      * @param in The parcel from which the object should be read
      * @hide
      */
-    public void readFromParcel(Parcel in) {
+    private void readFromParcel(Parcel in) {
         mSettings.readFromParcel(in);
 
         mSurfaceSet.clear();
@@ -965,8 +966,8 @@
      * <p>When a jpeg image capture is issued, the thumbnail size selected should have
      * the same aspect ratio as the jpeg image.</p>
      */
-    public static final Key<android.hardware.camera2.Size> JPEG_THUMBNAIL_SIZE =
-            new Key<android.hardware.camera2.Size>("android.jpeg.thumbnailSize", android.hardware.camera2.Size.class);
+    public static final Key<android.util.Size> JPEG_THUMBNAIL_SIZE =
+            new Key<android.util.Size>("android.jpeg.thumbnailSize", android.util.Size.class);
 
     /**
      * <p>The ratio of lens focal length to the effective
@@ -1518,12 +1519,4 @@
     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * End generated code
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
-
-
-
-
-
-
-
-
 }
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 0160622..d79f4b0 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -17,6 +17,8 @@
 package android.hardware.camera2;
 
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.params.Face;
+import android.util.Rational;
 
 /**
  * <p>The results of a single image capture from the image sensor.</p>
@@ -1512,8 +1514,8 @@
      * <p>When a jpeg image capture is issued, the thumbnail size selected should have
      * the same aspect ratio as the jpeg image.</p>
      */
-    public static final Key<android.hardware.camera2.Size> JPEG_THUMBNAIL_SIZE =
-            new Key<android.hardware.camera2.Size>("android.jpeg.thumbnailSize", android.hardware.camera2.Size.class);
+    public static final Key<android.util.Size> JPEG_THUMBNAIL_SIZE =
+            new Key<android.util.Size>("android.jpeg.thumbnailSize", android.util.Size.class);
 
     /**
      * <p>The ratio of lens focal length to the effective
@@ -2060,6 +2062,16 @@
             new Key<byte[]>("android.statistics.faceScores", byte[].class);
 
     /**
+     * <p>List of the faces detected through camera face detection
+     * in this result.</p>
+     * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} <code>!=</code> OFF.</p>
+     *
+     * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
+     */
+    public static final Key<android.hardware.camera2.params.Face[]> STATISTICS_FACES =
+            new Key<android.hardware.camera2.params.Face[]>("android.statistics.faces", android.hardware.camera2.params.Face[].class);
+
+    /**
      * <p>The shading map is a low-resolution floating-point map
      * that lists the coefficients used to correct for vignetting, for each
      * Bayer color channel.</p>
@@ -2425,27 +2437,4 @@
     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * End generated code
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
-
-
-
-
-
-
-
-
-
-    /**
-     * <p>
-     * List of the {@link Face Faces} detected through camera face detection
-     * in this result.
-     * </p>
-     * <p>
-     * Only available if {@link #STATISTICS_FACE_DETECT_MODE} {@code !=}
-     * {@link CameraMetadata#STATISTICS_FACE_DETECT_MODE_OFF OFF}.
-     * </p>
-     *
-     * @see Face
-     */
-    public static final Key<Face[]> STATISTICS_FACES =
-            new Key<Face[]>("android.statistics.faces", Face[].class);
 }
diff --git a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index a14d38b..caabed3 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -17,7 +17,7 @@
 package android.hardware.camera2;
 
 import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.CaptureResultExtras;
+import android.hardware.camera2.impl.CaptureResultExtras;
 
 /** @hide */
 interface ICameraDeviceCallbacks
diff --git a/core/java/android/hardware/camera2/Size.java b/core/java/android/hardware/camera2/Size.java
deleted file mode 100644
index 9328a003..0000000
--- a/core/java/android/hardware/camera2/Size.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2;
-
-// TODO: Delete this class, since it was moved to android.util as public API
-
-/**
- * Immutable class for describing width and height dimensions in pixels.
- *
- * @hide
- */
-public final class Size {
-    /**
-     * Create a new immutable Size instance.
-     *
-     * @param width The width of the size, in pixels
-     * @param height The height of the size, in pixels
-     */
-    public Size(final int width, final int height) {
-        mWidth = width;
-        mHeight = height;
-    }
-
-    /**
-     * Get the width of the size (in pixels).
-     * @return width
-     */
-    public final int getWidth() {
-        return mWidth;
-    }
-
-    /**
-     * Get the height of the size (in pixels).
-     * @return height
-     */
-    public final int getHeight() {
-        return mHeight;
-    }
-
-    /**
-     * Check if this size is equal to another size.
-     * <p>
-     * Two sizes are equal if and only if both their widths and heights are
-     * equal.
-     * </p>
-     * <p>
-     * A size object is never equal to any other type of object.
-     * </p>
-     *
-     * @return {@code true} if the objects were equal, {@code false} otherwise
-     */
-    @Override
-    public boolean equals(final Object obj) {
-        if (obj == null) {
-            return false;
-        }
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof Size) {
-            final Size other = (Size) obj;
-            return mWidth == other.mWidth && mHeight == other.mHeight;
-        }
-        return false;
-    }
-
-    /**
-     * Return the size represented as a string with the format {@code "WxH"}
-     *
-     * @return string representation of the size
-     */
-    @Override
-    public String toString() {
-        return mWidth + "x" + mHeight;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int hashCode() {
-        // assuming most sizes are <2^16, doing a rotate will give us perfect hashing
-        return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2)));
-    }
-
-    private final int mWidth;
-    private final int mHeight;
-};
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index 628d1c3..dba24a1 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -21,7 +21,6 @@
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.CaptureResultExtras;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.utils.CameraBinderDecorator;
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index d28f7bd..db7486d 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -22,7 +22,6 @@
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.Face;
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.MarshalQueryable;
 import android.hardware.camera2.marshal.MarshalRegistry;
@@ -43,6 +42,7 @@
 import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration;
 import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration;
 import android.hardware.camera2.marshal.impl.MarshalQueryableString;
+import android.hardware.camera2.params.Face;
 import android.hardware.camera2.params.StreamConfiguration;
 import android.hardware.camera2.params.StreamConfigurationDuration;
 import android.hardware.camera2.params.StreamConfigurationMap;
diff --git a/core/java/android/hardware/camera2/CaptureResultExtras.aidl b/core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl
similarity index 94%
rename from core/java/android/hardware/camera2/CaptureResultExtras.aidl
rename to core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl
index 6587f02..ebc812a 100644
--- a/core/java/android/hardware/camera2/CaptureResultExtras.aidl
+++ b/core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.camera2;
+package android.hardware.camera2.impl;
 
 /** @hide */
 parcelable CaptureResultExtras;
diff --git a/core/java/android/hardware/camera2/CaptureResultExtras.java b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java
similarity index 98%
rename from core/java/android/hardware/camera2/CaptureResultExtras.java
rename to core/java/android/hardware/camera2/impl/CaptureResultExtras.java
index e5c2c1c..b3a9559 100644
--- a/core/java/android/hardware/camera2/CaptureResultExtras.java
+++ b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.hardware.camera2;
+package android.hardware.camera2.impl;
 
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/hardware/camera2/marshal/MarshalHelpers.java b/core/java/android/hardware/camera2/marshal/MarshalHelpers.java
index fd72ee2..35ecc2a 100644
--- a/core/java/android/hardware/camera2/marshal/MarshalHelpers.java
+++ b/core/java/android/hardware/camera2/marshal/MarshalHelpers.java
@@ -18,8 +18,8 @@
 import static android.hardware.camera2.impl.CameraMetadataNative.*;
 import static com.android.internal.util.Preconditions.*;
 
-import android.hardware.camera2.Rational;
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.util.Rational;
 
 /**
  * Static functions in order to help implementing various marshaler functionality.
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java
index d3796db..47f79bf 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java
@@ -15,9 +15,9 @@
  */
 package android.hardware.camera2.marshal.impl;
 
-import android.hardware.camera2.ColorSpaceTransform;
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.ColorSpaceTransform;
 import android.hardware.camera2.utils.TypeReference;
 
 import java.nio.ByteBuffer;
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java
index c8b9bd8..01780db 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java
@@ -15,9 +15,9 @@
  */
 package android.hardware.camera2.marshal.impl;
 
-import android.hardware.camera2.MeteringRectangle;
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.MeteringRectangle;
 import android.hardware.camera2.utils.TypeReference;
 
 import java.nio.ByteBuffer;
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java
index 708da70..189b597 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java
@@ -15,11 +15,11 @@
  */
 package android.hardware.camera2.marshal.impl;
 
-import android.hardware.camera2.Rational;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.MarshalQueryable;
 import android.hardware.camera2.utils.TypeReference;
+import android.util.Rational;
 
 import static android.hardware.camera2.impl.CameraMetadataNative.*;
 import static android.hardware.camera2.marshal.MarshalHelpers.*;
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java
index 93c0e92..4253a0a 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java
@@ -15,9 +15,9 @@
  */
 package android.hardware.camera2.marshal.impl;
 
-import android.hardware.camera2.RggbChannelVector;
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.RggbChannelVector;
 import android.hardware.camera2.utils.TypeReference;
 
 import java.nio.ByteBuffer;
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java
index 6a73bee..721644e 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java
@@ -15,7 +15,7 @@
  */
 package android.hardware.camera2.marshal.impl;
 
-import android.hardware.camera2.Size;
+import android.util.Size;
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.MarshalQueryable;
 import android.hardware.camera2.utils.TypeReference;
diff --git a/core/java/android/hardware/camera2/ColorSpaceTransform.java b/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
similarity index 98%
rename from core/java/android/hardware/camera2/ColorSpaceTransform.java
rename to core/java/android/hardware/camera2/params/ColorSpaceTransform.java
index 5e4c0a2..fa8c8ea 100644
--- a/core/java/android/hardware/camera2/ColorSpaceTransform.java
+++ b/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
@@ -14,11 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.camera2;
+package android.hardware.camera2.params;
 
 import static com.android.internal.util.Preconditions.*;
 
+import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.utils.HashCodeHelpers;
+import android.util.Rational;
 
 import java.util.Arrays;
 
diff --git a/core/java/android/hardware/camera2/Face.java b/core/java/android/hardware/camera2/params/Face.java
similarity index 97%
rename from core/java/android/hardware/camera2/Face.java
rename to core/java/android/hardware/camera2/params/Face.java
index ded8839d..2cd83a3 100644
--- a/core/java/android/hardware/camera2/Face.java
+++ b/core/java/android/hardware/camera2/params/Face.java
@@ -15,10 +15,13 @@
  */
 
 
-package android.hardware.camera2;
+package android.hardware.camera2.params;
 
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureResult;
 
 /**
  * Describes a face detected in an image.
diff --git a/core/java/android/hardware/camera2/LensShadingMap.java b/core/java/android/hardware/camera2/params/LensShadingMap.java
similarity index 97%
rename from core/java/android/hardware/camera2/LensShadingMap.java
rename to core/java/android/hardware/camera2/params/LensShadingMap.java
index 2b0108c..b328f578 100644
--- a/core/java/android/hardware/camera2/LensShadingMap.java
+++ b/core/java/android/hardware/camera2/params/LensShadingMap.java
@@ -14,11 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.camera2;
+package android.hardware.camera2.params;
 
 import static com.android.internal.util.Preconditions.*;
-import static android.hardware.camera2.RggbChannelVector.*;
+import static android.hardware.camera2.params.RggbChannelVector.*;
 
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.utils.HashCodeHelpers;
 
 import java.util.Arrays;
diff --git a/core/java/android/hardware/camera2/MeteringRectangle.java b/core/java/android/hardware/camera2/params/MeteringRectangle.java
similarity index 97%
rename from core/java/android/hardware/camera2/MeteringRectangle.java
rename to core/java/android/hardware/camera2/params/MeteringRectangle.java
index bb8e5b1..a26c57d 100644
--- a/core/java/android/hardware/camera2/MeteringRectangle.java
+++ b/core/java/android/hardware/camera2/params/MeteringRectangle.java
@@ -13,13 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.hardware.camera2;
+package android.hardware.camera2.params;
 
 import android.util.Size;
 import static com.android.internal.util.Preconditions.*;
 
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.utils.HashCodeHelpers;
 
 /**
diff --git a/core/java/android/hardware/camera2/RggbChannelVector.java b/core/java/android/hardware/camera2/params/RggbChannelVector.java
similarity index 99%
rename from core/java/android/hardware/camera2/RggbChannelVector.java
rename to core/java/android/hardware/camera2/params/RggbChannelVector.java
index 80167c6..30591f6 100644
--- a/core/java/android/hardware/camera2/RggbChannelVector.java
+++ b/core/java/android/hardware/camera2/params/RggbChannelVector.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.camera2;
+package android.hardware.camera2.params;
 
 import static com.android.internal.util.Preconditions.*;
 
diff --git a/core/java/android/hardware/camera2/TonemapCurve.java b/core/java/android/hardware/camera2/params/TonemapCurve.java
similarity index 97%
rename from core/java/android/hardware/camera2/TonemapCurve.java
rename to core/java/android/hardware/camera2/params/TonemapCurve.java
index 2958ebf..0fcffac 100644
--- a/core/java/android/hardware/camera2/TonemapCurve.java
+++ b/core/java/android/hardware/camera2/params/TonemapCurve.java
@@ -14,11 +14,15 @@
  * limitations under the License.
  */
 
-package android.hardware.camera2;
+package android.hardware.camera2.params;
 
 import static com.android.internal.util.Preconditions.*;
 
 import android.graphics.PointF;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.utils.HashCodeHelpers;
 
 import java.util.Arrays;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index cf0caed..af45fa0 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -531,7 +531,8 @@
 
     public final static class HistoryItem implements Parcelable {
         public HistoryItem next;
-        
+
+        // The time of this event in milliseconds, as per SystemClock.elapsedRealtime().
         public long time;
 
         public static final byte CMD_UPDATE = 0;        // These can be written as deltas
@@ -645,7 +646,7 @@
         public int eventCode;
         public HistoryTag eventTag;
 
-        // Only set for CMD_CURRENT_TIME.
+        // Only set for CMD_CURRENT_TIME or CMD_RESET, as per System.currentTimeMillis().
         public long currentTime;
 
         // Meta-data when reading.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d09bb88..d063168 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2900,6 +2900,7 @@
             MOVED_TO_GLOBAL.add(Settings.Global.SET_GLOBAL_HTTP_PROXY);
             MOVED_TO_GLOBAL.add(Settings.Global.DEFAULT_DNS_SERVER);
             MOVED_TO_GLOBAL.add(Settings.Global.PREFERRED_NETWORK_MODE);
+            MOVED_TO_GLOBAL.add(Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY);
         }
 
         /** @hide */
@@ -5330,6 +5331,13 @@
         */
        public static final String USE_GOOGLE_MAIL = "use_google_mail";
 
+        /**
+         * Webview Data reduction proxy key.
+         * @hide
+         */
+        public static final String WEBVIEW_DATA_REDUCTION_PROXY_KEY =
+                "webview_data_reduction_proxy_key";
+
        /**
         * Whether Wifi display is enabled/disabled
         * 0=disabled. 1=enabled.
diff --git a/core/java/android/hardware/camera2/Rational.java b/core/java/android/util/Rational.java
similarity index 92%
rename from core/java/android/hardware/camera2/Rational.java
rename to core/java/android/util/Rational.java
index 693ee2b..8d4c67f 100644
--- a/core/java/android/hardware/camera2/Rational.java
+++ b/core/java/android/util/Rational.java
@@ -13,11 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.hardware.camera2;
+package android.util;
 
 /**
- * The rational data type used by CameraMetadata keys. Contains a pair of ints representing the
- * numerator and denominator of a Rational number. This type is immutable.
+ * <p>An immutable data type representation a rational number.</p>
+ *
+ * <p>Contains a pair of {@code int}s representing the numerator and denominator of a
+ * Rational number. </p>
  */
 public final class Rational {
     private final int mNumerator;
@@ -30,7 +32,9 @@
      * is always positive.</p>
      *
      * <p>A rational value with a 0-denominator may be constructed, but will have similar semantics
-     * as float NaN and INF values. The int getter functions return 0 in this case.</p>
+     * as float {@code NaN} and {@code INF} values. For {@code NaN},
+     * both {@link #getNumerator} and {@link #getDenominator} functions will return 0. For
+     * positive or negative {@code INF}, only the {@link #getDenominator} will return 0.</p>
      *
      * @param numerator the numerator of the rational
      * @param denominator the denominator of the rational
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index 7b49006..9601a8d 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -1220,10 +1220,6 @@
     }
 
     private RenderNode buildDisplayList(View view, HardwareCanvas canvas) {
-        if (mDrawDelta <= 0) {
-            return view.mRenderNode;
-        }
-
         view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
                 == View.PFLAG_INVALIDATED;
         view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index f14e73f..c1a4fee 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.animation.Animator;
 import android.animation.TimeInterpolator;
 import android.graphics.Canvas;
 import android.graphics.CanvasProperty;
@@ -28,12 +29,12 @@
 import com.android.internal.view.animation.NativeInterpolatorFactory;
 
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 
 /**
  * @hide
  */
-public final class RenderNodeAnimator {
-
+public final class RenderNodeAnimator extends Animator {
     // Keep in sync with enum RenderProperty in Animator.h
     public static final int TRANSLATION_X = 0;
     public static final int TRANSLATION_Y = 1;
@@ -50,6 +51,11 @@
 
     // Keep in sync with enum PaintFields in Animator.h
     public static final int PAINT_STROKE_WIDTH = 0;
+
+    /**
+     * Field for the Paint alpha channel, which should be specified as a value
+     * between 0 and 255.
+     */
     public static final int PAINT_ALPHA = 1;
 
     // ViewPropertyAnimator uses a mask for its values, we need to remap them
@@ -74,8 +80,11 @@
     private VirtualRefBasePtr mNativePtr;
 
     private RenderNode mTarget;
+    private View mViewTarget;
     private TimeInterpolator mInterpolator;
+
     private boolean mStarted = false;
+    private boolean mFinished = false;
 
     public int mapViewPropertyToRenderProperty(int viewProperty) {
         return sViewPropertyAnimatorMap.get(viewProperty);
@@ -92,6 +101,14 @@
                 property.getNativeContainer(), finalValue));
     }
 
+    /**
+     * Creates a new render node animator for a field on a Paint property.
+     *
+     * @param property The paint property to target
+     * @param paintField Paint field to animate, one of {@link #PAINT_ALPHA} or
+     *            {@link #PAINT_STROKE_WIDTH}
+     * @param finalValue The target value for the property
+     */
     public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField, float finalValue) {
         init(nCreateCanvasPropertyPaintAnimator(
                 new WeakReference<RenderNodeAnimator>(this),
@@ -115,56 +132,139 @@
         if (mInterpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class)) {
             ni = ((NativeInterpolatorFactory)mInterpolator).createNativeInterpolator();
         } else {
-            int duration = nGetDuration(mNativePtr.get());
+            long duration = nGetDuration(mNativePtr.get());
             ni = FallbackLUTInterpolator.createNativeInterpolator(mInterpolator, duration);
         }
         nSetInterpolator(mNativePtr.get(), ni);
     }
 
-    private void start(RenderNode node) {
+    @Override
+    public void start() {
+        if (mTarget == null) {
+            throw new IllegalStateException("Missing target!");
+        }
+
         if (mStarted) {
             throw new IllegalStateException("Already started!");
         }
+
         mStarted = true;
         applyInterpolator();
-        mTarget = node;
         mTarget.addAnimator(this);
+
+        final ArrayList<AnimatorListener> listeners = getListeners();
+        final int numListeners = listeners == null ? 0 : listeners.size();
+        for (int i = 0; i < numListeners; i++) {
+            listeners.get(i).onAnimationStart(this);
+        }
+
+        if (mViewTarget != null) {
+            // Kick off a frame to start the process
+            mViewTarget.invalidateViewProperty(true, false);
+        }
     }
 
-    public void start(View target) {
-        start(target.mRenderNode);
-        // Kick off a frame to start the process
-        target.invalidateViewProperty(true, false);
+    @Override
+    public void cancel() {
+        mTarget.removeAnimator(this);
+
+        final ArrayList<AnimatorListener> listeners = getListeners();
+        final int numListeners = listeners == null ? 0 : listeners.size();
+        for (int i = 0; i < numListeners; i++) {
+            listeners.get(i).onAnimationCancel(this);
+        }
     }
 
-    public void start(Canvas canvas) {
+    @Override
+    public void end() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void pause() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void resume() {
+        throw new UnsupportedOperationException();
+    }
+
+    public void setTarget(View view) {
+        mViewTarget = view;
+        mTarget = view.mRenderNode;
+    }
+
+    public void setTarget(Canvas canvas) {
         if (!(canvas instanceof GLES20RecordingCanvas)) {
             throw new IllegalArgumentException("Not a GLES20RecordingCanvas");
         }
-        GLES20RecordingCanvas recordingCanvas = (GLES20RecordingCanvas) canvas;
-        start(recordingCanvas.mNode);
+
+        final GLES20RecordingCanvas recordingCanvas = (GLES20RecordingCanvas) canvas;
+        setTarget(recordingCanvas.mNode);
     }
 
-    public void cancel() {
-        mTarget.removeAnimator(this);
+    public void setTarget(RenderNode node) {
+        mViewTarget = null;
+        mTarget = node;
     }
 
-    public void setDuration(int duration) {
+    public RenderNode getTarget() {
+        return mTarget;
+    }
+
+    @Override
+    public void setStartDelay(long startDelay) {
+        checkMutable();
+        nSetStartDelay(mNativePtr.get(), startDelay);
+    }
+
+    @Override
+    public long getStartDelay() {
+        return nGetStartDelay(mNativePtr.get());
+    }
+
+    @Override
+    public RenderNodeAnimator setDuration(long duration) {
         checkMutable();
         nSetDuration(mNativePtr.get(), duration);
+        return this;
     }
 
+    @Override
+    public long getDuration() {
+        return nGetDuration(mNativePtr.get());
+    }
+
+    @Override
+    public boolean isRunning() {
+        return mStarted && !mFinished;
+    }
+
+    @Override
     public void setInterpolator(TimeInterpolator interpolator) {
         checkMutable();
         mInterpolator = interpolator;
     }
 
-    long getNativeAnimator() {
-        return mNativePtr.get();
+    @Override
+    public TimeInterpolator getInterpolator() {
+        return mInterpolator;
     }
 
     private void onFinished() {
+        mFinished = true;
         mTarget.removeAnimator(this);
+
+        final ArrayList<AnimatorListener> listeners = getListeners();
+        final int numListeners = listeners == null ? 0 : listeners.size();
+        for (int i = 0; i < numListeners; i++) {
+            listeners.get(i).onAnimationEnd(this);
+        }
+    }
+
+    long getNativeAnimator() {
+        return mNativePtr.get();
     }
 
     // Called by native
@@ -181,7 +281,9 @@
             long canvasProperty, float deltaValue);
     private static native long nCreateCanvasPropertyPaintAnimator(WeakReference<RenderNodeAnimator> weakThis,
             long canvasProperty, int paintField, float deltaValue);
-    private static native void nSetDuration(long nativePtr, int duration);
-    private static native int nGetDuration(long nativePtr);
+    private static native void nSetDuration(long nativePtr, long duration);
+    private static native long nGetDuration(long nativePtr);
+    private static native void nSetStartDelay(long nativePtr, long startDelay);
+    private static native long nGetStartDelay(long nativePtr);
     private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5141877..fb7d57d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4774,8 +4774,8 @@
                 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this);
             }
 
-            manageFocusHotspot(true, oldFocus);
             onFocusChanged(true, direction, previouslyFocusedRect);
+            manageFocusHotspot(true, oldFocus);
             refreshDrawableState();
         }
     }
@@ -6752,6 +6752,24 @@
     }
 
     /**
+     * Sets the pressed state for this view and provides a touch coordinate for
+     * animation hinting.
+     *
+     * @param pressed Pass true to set the View's internal state to "pressed",
+     *            or false to reverts the View's internal state from a
+     *            previously set "pressed" state.
+     * @param x The x coordinate of the touch that caused the press
+     * @param y The y coordinate of the touch that caused the press
+     */
+    private void setPressed(boolean pressed, float x, float y) {
+        if (pressed) {
+            setHotspot(R.attr.state_pressed, x, y);
+        }
+
+        setPressed(pressed);
+    }
+
+    /**
      * Sets the pressed state for this view.
      *
      * @see #isClickable()
@@ -6769,6 +6787,10 @@
             mPrivateFlags &= ~PFLAG_PRESSED;
         }
 
+        if (!pressed) {
+            clearHotspot(R.attr.state_pressed);
+        }
+
         if (needsRefresh) {
             refreshDrawableState();
         }
@@ -8993,7 +9015,6 @@
 
         if ((viewFlags & ENABLED_MASK) == DISABLED) {
             if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
-                clearHotspot(R.attr.state_pressed);
                 setPressed(false);
             }
             // A disabled view that is clickable still consumes the touch
@@ -9026,8 +9047,7 @@
                             // showed it as pressed.  Make it show the pressed
                             // state now (before scheduling the click) to ensure
                             // the user sees it.
-                            setHotspot(R.attr.state_pressed, x, y);
-                            setPressed(true);
+                            setPressed(true, x, y);
                        }
 
                         if (!mHasPerformedLongPress) {
@@ -9061,8 +9081,6 @@
                         }
 
                         removeTapCallback();
-                    } else {
-                        clearHotspot(R.attr.state_pressed);
                     }
                     break;
 
@@ -9175,7 +9193,6 @@
      */
     private void removeUnsetPressCallback() {
         if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) {
-            clearHotspot(R.attr.state_pressed);
             setPressed(false);
             removeCallbacks(mUnsetPressedState);
         }
@@ -19234,8 +19251,7 @@
         @Override
         public void run() {
             mPrivateFlags &= ~PFLAG_PREPRESSED;
-            setHotspot(R.attr.state_pressed, x, y);
-            setPressed(true);
+            setPressed(true, x, y);
             checkForLongClick(ViewConfiguration.getTapTimeout());
         }
     }
@@ -19516,7 +19532,6 @@
     private final class UnsetPressedState implements Runnable {
         @Override
         public void run() {
-            clearHotspot(R.attr.state_pressed);
             setPressed(false);
         }
     }
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 438e164..74a3eec 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -666,6 +666,8 @@
             case MotionEvent.ACTION_CANCEL: {
                 if (mTouchMode == TOUCH_MODE_DRAGGING) {
                     stopDrag(ev);
+                    // Allow super class to handle pressed state, etc.
+                    super.onTouchEvent(ev);
                     return true;
                 }
                 mTouchMode = TOUCH_MODE_IDLE;
@@ -801,7 +803,7 @@
     }
 
     @Override
-    protected void onDraw(Canvas canvas) {
+    public void draw(Canvas c) {
         final Rect tempRect = mTempRect;
         final Drawable trackDrawable = mTrackDrawable;
         final Drawable thumbDrawable = mThumbDrawable;
@@ -815,9 +817,6 @@
         trackDrawable.getPadding(tempRect);
 
         final int switchInnerLeft = switchLeft + tempRect.left;
-        final int switchInnerTop = switchTop + tempRect.top;
-        final int switchInnerRight = switchRight - tempRect.right;
-        final int switchInnerBottom = switchBottom - tempRect.bottom;
 
         // Relies on mTempRect, MUST be called first!
         final int thumbPos = getThumbOffset();
@@ -833,8 +832,26 @@
             background.setHotspotBounds(thumbLeft, switchTop, thumbRight, switchBottom);
         }
 
+        // Draw the background.
+        super.draw(c);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
 
+        final Rect tempRect = mTempRect;
+        final Drawable trackDrawable = mTrackDrawable;
+        final Drawable thumbDrawable = mThumbDrawable;
+        trackDrawable.getPadding(tempRect);
+
+        final int switchTop = mSwitchTop;
+        final int switchBottom = mSwitchBottom;
+        final int switchInnerLeft = mSwitchLeft + tempRect.left;
+        final int switchInnerTop = switchTop + tempRect.top;
+        final int switchInnerRight = mSwitchRight - tempRect.right;
+        final int switchInnerBottom = switchBottom - tempRect.bottom;
+
         if (mSplitTrack) {
             final Insets insets = thumbDrawable.getOpticalInsets();
             thumbDrawable.copyBounds(tempRect);
@@ -861,7 +878,8 @@
             }
             mTextPaint.drawableState = drawableState;
 
-            final int left = (thumbLeft + thumbRight) / 2 - switchText.getWidth() / 2;
+            final Rect thumbBounds = thumbDrawable.getBounds();
+            final int left = (thumbBounds.left + thumbBounds.right) / 2 - switchText.getWidth() / 2;
             final int top = (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2;
             canvas.translate(left, top);
             switchText.draw(canvas);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 956c86d..8428f66 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -235,7 +235,8 @@
 
     int mWakeLockNesting;
     boolean mWakeLockImportant;
-    public boolean mRecordAllWakeLocks;
+    boolean mRecordAllWakeLocks;
+    boolean mNoAutoReset;
 
     int mScreenState = Display.STATE_UNKNOWN;
     StopwatchTimer mScreenOnTimer;
@@ -2314,9 +2315,6 @@
         }
     }
 
-    private String mInitialAcquireWakeName;
-    private int mInitialAcquireWakeUid = -1;
-
     public void setRecordAllWakeLocksLocked(boolean enabled) {
         mRecordAllWakeLocks = enabled;
         if (!enabled) {
@@ -2325,6 +2323,13 @@
         }
     }
 
+    public void setNoAutoReset(boolean enabled) {
+        mNoAutoReset = enabled;
+    }
+
+    private String mInitialAcquireWakeName;
+    private int mInitialAcquireWakeUid = -1;
+
     public void noteStartWakeLocked(int uid, int pid, String name, String historyName, int type,
             boolean unimportantForLogging, long elapsedRealtime, long uptime) {
         uid = mapUid(uid);
@@ -2355,6 +2360,7 @@
             } else if (mRecordAllWakeLocks) {
                 if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName,
                         uid, 0)) {
+                    mWakeLockNesting++;
                     return;
                 }
                 addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_WAKE_LOCK_START,
@@ -5942,9 +5948,9 @@
             // we have gone through a significant charge (from a very low
             // level to a now very high level).
             boolean reset = false;
-            if (oldStatus == BatteryManager.BATTERY_STATUS_FULL
+            if (!mNoAutoReset && (oldStatus == BatteryManager.BATTERY_STATUS_FULL
                     || level >= 90
-                    || (mDischargeCurrentLevel < 20 && level >= 80)) {
+                    || (mDischargeCurrentLevel < 20 && level >= 80))) {
                 doWrite = true;
                 resetAllStatsLocked();
                 mDischargeStartLevel = level;
diff --git a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
index aec2b7e..1feb943 100644
--- a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
+++ b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
@@ -34,11 +34,11 @@
      * Used to cache the float[] LUT for use across multiple native
      * interpolator creation
      */
-    public FallbackLUTInterpolator(TimeInterpolator interpolator, int duration) {
+    public FallbackLUTInterpolator(TimeInterpolator interpolator, long duration) {
         mLut = createLUT(interpolator, duration);
     }
 
-    private static float[] createLUT(TimeInterpolator interpolator, int duration) {
+    private static float[] createLUT(TimeInterpolator interpolator, long duration) {
         long frameIntervalNanos = Choreographer.getInstance().getFrameIntervalNanos();
         int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS);
         int numAnimFrames = (int) Math.ceil(duration / animIntervalMs);
@@ -59,7 +59,7 @@
     /**
      * Used to create a one-shot float[] LUT & native interpolator
      */
-    public static long createNativeInterpolator(TimeInterpolator interpolator, int duration) {
+    public static long createNativeInterpolator(TimeInterpolator interpolator, long duration) {
         float[] lut = createLUT(interpolator, duration);
         return NativeInterpolatorFactoryHelper.createLutInterpolator(lut);
     }
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index bf58918..9279758 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -367,7 +367,6 @@
         bool forceLTR = false;
         bool forceRTL = false;
 
-        ALOGD("computeValues dirFlags=%d", dirFlags);
         switch (dirFlags & kBidi_Mask) {
             case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
             case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp
index ea2f96e..e19ce36 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -116,15 +116,26 @@
     return reinterpret_cast<jlong>( animator );
 }
 
-static void setDuration(JNIEnv* env, jobject clazz, jlong animatorPtr, jint duration) {
+static void setDuration(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong duration) {
     LOG_ALWAYS_FATAL_IF(duration < 0, "Duration cannot be negative");
     BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
     animator->setDuration(duration);
 }
 
-static jint getDuration(JNIEnv* env, jobject clazz, jlong animatorPtr) {
+static jlong getDuration(JNIEnv* env, jobject clazz, jlong animatorPtr) {
     BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
-    return static_cast<jint>(animator->duration());
+    return static_cast<jlong>(animator->duration());
+}
+
+static void setStartDelay(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong startDelay) {
+    LOG_ALWAYS_FATAL_IF(startDelay < 0, "Start delay cannot be negative");
+    BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
+    animator->setStartDelay(startDelay);
+}
+
+static jlong getStartDelay(JNIEnv* env, jobject clazz, jlong animatorPtr) {
+    BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
+    return static_cast<jlong>(animator->startDelay());
 }
 
 static void setInterpolator(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong interpolatorPtr) {
@@ -146,8 +157,10 @@
     { "nCreateAnimator", "(Ljava/lang/ref/WeakReference;IF)J", (void*) createAnimator },
     { "nCreateCanvasPropertyFloatAnimator", "(Ljava/lang/ref/WeakReference;JF)J", (void*) createCanvasPropertyFloatAnimator },
     { "nCreateCanvasPropertyPaintAnimator", "(Ljava/lang/ref/WeakReference;JIF)J", (void*) createCanvasPropertyPaintAnimator },
-    { "nSetDuration", "(JI)V", (void*) setDuration },
-    { "nGetDuration", "(J)I", (void*) getDuration },
+    { "nSetDuration", "(JJ)V", (void*) setDuration },
+    { "nGetDuration", "(J)J", (void*) getDuration },
+    { "nSetStartDelay", "(JJ)V", (void*) setStartDelay },
+    { "nGetStartDelay", "(J)J", (void*) getStartDelay },
     { "nSetInterpolator", "(JJ)V", (void*) setInterpolator },
 #endif
 };
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index a49b89a..d04bddf 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -427,7 +427,10 @@
         <item name="paddingEnd">8dp</item>
     </style>
 
-    <style name="Widget.Quantum.CheckedTextView" parent="Widget.CheckedTextView"/>
+    <style name="Widget.Quantum.CheckedTextView" parent="Widget.CheckedTextView">
+        <item name="drawablePadding">4dip</item>
+    </style>
+
     <style name="Widget.Quantum.TextSelectHandle" parent="Widget.TextSelectHandle"/>
     <style name="Widget.Quantum.TextSuggestionsPopupWindow" parent="Widget.TextSuggestionsPopupWindow"/>
     <style name="Widget.Quantum.AbsListView" parent="Widget.AbsListView"/>
@@ -441,10 +444,12 @@
 
     <style name="Widget.Quantum.CompoundButton.CheckBox" parent="Widget.CompoundButton.CheckBox">
         <item name="background">?attr/selectableItemBackground</item>
+        <item name="drawablePadding">4dip</item>
     </style>
 
     <style name="Widget.Quantum.CompoundButton.RadioButton" parent="Widget.CompoundButton.RadioButton">
         <item name="background">?attr/selectableItemBackground</item>
+        <item name="drawablePadding">4dip</item>
     </style>
 
     <style name="Widget.Quantum.CompoundButton.Star" parent="Widget.CompoundButton.Star">
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 218a057..24e8de6 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -17,227 +17,220 @@
 package android.graphics.drawable;
 
 import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
 import android.graphics.Paint;
 import android.graphics.Paint.Style;
 import android.graphics.Rect;
-import android.view.animation.DecelerateInterpolator;
+import android.view.HardwareCanvas;
+import android.view.RenderNodeAnimator;
+import android.view.animation.AccelerateInterpolator;
+
+import java.util.ArrayList;
 
 /**
  * Draws a Quantum Paper ripple.
  */
 class Ripple {
-    private static final TimeInterpolator INTERPOLATOR = new DecelerateInterpolator();
+    private static final TimeInterpolator INTERPOLATOR = new AccelerateInterpolator();
 
-    /** Starting radius for a ripple. */
-    private static final int STARTING_RADIUS_DP = 16;
+    private static final float GLOBAL_SPEED = 1.0f;
+    private static final float WAVE_TOUCH_DOWN_ACCELERATION = 512.0f * GLOBAL_SPEED;
+    private static final float WAVE_TOUCH_UP_ACCELERATION = 1024.0f * GLOBAL_SPEED;
+    private static final float WAVE_OPACITY_DECAY_VELOCITY = 1.6f / GLOBAL_SPEED;
+    private static final float WAVE_OUTER_OPACITY_VELOCITY = 1.2f * GLOBAL_SPEED;
 
-    /** Radius when finger is outside view bounds. */
-    private static final int OUTSIDE_RADIUS_DP = 16;
-
-    /** Radius when finger is inside view bounds. */
-    private static final int INSIDE_RADIUS_DP = 96;
-
-    /** Margin when constraining outside touches (fraction of outer radius). */
-    private static final float OUTSIDE_MARGIN = 0.8f;
-
-    /** Resistance factor when constraining outside touches. */
-    private static final float OUTSIDE_RESISTANCE = 0.7f;
-
-    /** Minimum alpha value during a pulse animation. */
-    private static final float PULSE_MIN_ALPHA = 0.5f;
-
-    /** Duration for animating the trailing edge of the ripple. */
-    private static final int EXIT_DURATION = 600;
-
-    /** Duration for animating the leading edge of the ripple. */
-    private static final int ENTER_DURATION = 400;
-
-    /** Duration for animating the ripple alpha in and out. */
-    private static final int FADE_DURATION = 50;
-
-    /** Minimum elapsed time between start of enter and exit animations. */
-    private static final int EXIT_MIN_DELAY = 200;
-
-    /** Duration for animating between inside and outside touch. */
-    private static final int OUTSIDE_DURATION = 300;
-
-    /** Duration for animating pulses. */
-    private static final int PULSE_DURATION = 400;
-
-    /** Interval between pulses while inside and fully entered. */
-    private static final int PULSE_INTERVAL = 400;
-
-    /** Delay before pulses start. */
-    private static final int PULSE_DELAY = 500;
+    // Hardware animators.
+    private final ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<>();
+    private final ArrayList<RenderNodeAnimator> mPendingAnimations = new ArrayList<>();
 
     private final Drawable mOwner;
 
-    /** Bounds used for computing max radius and containment. */
+    /** Bounds used for computing max radius. */
     private final Rect mBounds;
 
-    /** Configured maximum ripple radius when the center is outside the bounds. */
-    private final int mMaxOutsideRadius;
-
-    /** Configured maximum ripple radius. */
-    private final int mMaxInsideRadius;
-
-    private ObjectAnimator mOuter;
-    private ObjectAnimator mInner;
-    private ObjectAnimator mAlpha;
+    /** Full-opacity color for drawing this ripple. */
+    private final int mColor;
 
     /** Maximum ripple radius. */
-    private int mMaxRadius;
-
     private float mOuterRadius;
-    private float mInnerRadius;
-    private float mAlphaMultiplier;
 
-    /** Center x-coordinate. */
+    // Hardware rendering properties.
+    private CanvasProperty<Paint> mPropPaint;
+    private CanvasProperty<Float> mPropRadius;
+    private CanvasProperty<Float> mPropX;
+    private CanvasProperty<Float> mPropY;
+    private CanvasProperty<Paint> mPropOuterPaint;
+    private CanvasProperty<Float> mPropOuterRadius;
+    private CanvasProperty<Float> mPropOuterX;
+    private CanvasProperty<Float> mPropOuterY;
+
+    // Software animators.
+    private ObjectAnimator mAnimRadius;
+    private ObjectAnimator mAnimOpacity;
+    private ObjectAnimator mAnimOuterOpacity;
+    private ObjectAnimator mAnimX;
+    private ObjectAnimator mAnimY;
+
+    // Software rendering properties.
+    private float mOuterOpacity = 0;
+    private float mOpacity = 1;
+    private float mRadius = 0;
+    private float mOuterX;
+    private float mOuterY;
     private float mX;
-
-    /** Center y-coordinate. */
     private float mY;
 
-    /** Whether the center is within the parent bounds. */
-    private boolean mInsideBounds;
+    private boolean mFinished;
 
-    /** Whether to pulse this ripple. */
-    private boolean mPulseEnabled;
+    /** Whether we should be drawing hardware animations. */
+    private boolean mHardwareAnimating;
 
-    /** Temporary hack since we can't check finished state of animator. */
-    private boolean mExitFinished;
-
-    /** Whether this ripple has ever moved. */
-    private boolean mHasMoved;
+    /** Whether we can use hardware acceleration for the exit animation. */
+    private boolean mCanUseHardware;
 
     /**
      * Creates a new ripple.
      */
-    public Ripple(Drawable owner, Rect bounds, float density, boolean pulseEnabled) {
+    public Ripple(Drawable owner, Rect bounds, int color) {
         mOwner = owner;
         mBounds = bounds;
-        mPulseEnabled = pulseEnabled;
+        mColor = color | 0xFF000000;
 
-        mOuterRadius = (int) (density * STARTING_RADIUS_DP + 0.5f);
-        mMaxOutsideRadius = (int) (density * OUTSIDE_RADIUS_DP + 0.5f);
-        mMaxInsideRadius = (int) (density * INSIDE_RADIUS_DP + 0.5f);
-        mMaxRadius = Math.min(mMaxInsideRadius, Math.max(bounds.width(), bounds.height()));
+        final float halfWidth = bounds.width() / 2.0f;
+        final float halfHeight = bounds.height() / 2.0f;
+        mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
+        mOuterX = 0;
+        mOuterY = 0;
     }
 
-    public void setOuterRadius(float r) {
-        mOuterRadius = r;
+    public void setRadius(float r) {
+        mRadius = r;
         invalidateSelf();
     }
 
-    public float getOuterRadius() {
-        return mOuterRadius;
+    public float getRadius() {
+        return mRadius;
     }
 
-    public void setInnerRadius(float r) {
-        mInnerRadius = r;
+    public void setOpacity(float a) {
+        mOpacity = a;
         invalidateSelf();
     }
 
-    public float getInnerRadius() {
-        return mInnerRadius;
+    public float getOpacity() {
+        return mOpacity;
     }
 
-    public void setAlphaMultiplier(float a) {
-        mAlphaMultiplier = a;
+    public void setOuterOpacity(float a) {
+        mOuterOpacity = a;
         invalidateSelf();
     }
 
-    public float getAlphaMultiplier() {
-        return mAlphaMultiplier;
+    public float getOuterOpacity() {
+        return mOuterOpacity;
+    }
+
+    public void setX(float x) {
+        mX = x;
+        invalidateSelf();
+    }
+
+    public float getX() {
+        return mX;
+    }
+
+    public void setY(float y) {
+        mY = y;
+        invalidateSelf();
+    }
+
+    public float getY() {
+        return mY;
     }
 
     /**
      * Returns whether this ripple has finished exiting.
      */
     public boolean isFinished() {
-        return mExitFinished;
+        return mFinished;
     }
 
     /**
-     * Called when the bounds change.
-     */
-    public void onBoundsChanged() {
-        mMaxRadius = Math.min(mMaxInsideRadius, Math.max(mBounds.width(), mBounds.height()));
-
-        updateInsideBounds();
-    }
-
-    private void updateInsideBounds() {
-        final boolean insideBounds = mBounds.contains((int) (mX + 0.5f), (int) (mY + 0.5f));
-        if (mInsideBounds != insideBounds || !mHasMoved) {
-            mInsideBounds = insideBounds;
-            mHasMoved = true;
-
-            if (insideBounds) {
-                enter();
-            } else {
-                outside();
-            }
-        }
-    }
-
-    /**
-     * Draws the ripple using the specified paint.
+     * Draws the ripple centered at (0,0) using the specified paint.
      */
     public boolean draw(Canvas c, Paint p) {
-        final Rect bounds = mBounds;
-        final float outerRadius = mOuterRadius;
-        final float innerRadius = mInnerRadius;
-        final float alphaMultiplier = mAlphaMultiplier;
+        final boolean canUseHardware = c.isHardwareAccelerated();
+        if (mCanUseHardware != canUseHardware && mCanUseHardware) {
+            // We've switched from hardware to non-hardware mode. Panic.
+            cancelHardwareAnimations();
+        }
+        mCanUseHardware = canUseHardware;
+
+        final boolean hasContent;
+        if (canUseHardware && mHardwareAnimating) {
+            hasContent = drawHardware((HardwareCanvas) c);
+        } else {
+            hasContent = drawSoftware(c, p);
+        }
+
+        return hasContent;
+    }
+
+    private boolean drawHardware(HardwareCanvas c) {
+        // If we have any pending hardware animations, cancel any running
+        // animations and start those now.
+        final ArrayList<RenderNodeAnimator> pendingAnimations = mPendingAnimations;
+        final int N = pendingAnimations == null ? 0 : pendingAnimations.size();
+        if (N > 0) {
+            cancelHardwareAnimations();
+
+            for (int i = 0; i < N; i++) {
+                pendingAnimations.get(i).setTarget(c);
+                pendingAnimations.get(i).start();
+            }
+
+            mRunningAnimations.addAll(pendingAnimations);
+            pendingAnimations.clear();
+        }
+
+        c.drawCircle(mPropOuterX, mPropOuterY, mPropOuterRadius, mPropOuterPaint);
+        c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint);
+
+        return true;
+    }
+
+    private boolean drawSoftware(Canvas c, Paint p) {
+        final float radius = mRadius;
+        final float opacity = mOpacity;
+        final float outerOpacity = mOuterOpacity;
 
         // Cache the paint alpha so we can restore it later.
         final int paintAlpha = p.getAlpha();
-        final int alpha = (int) (paintAlpha * alphaMultiplier + 0.5f);
+        final int alpha = (int) (255 * opacity + 0.5f);
+        final int outerAlpha = (int) (255 * outerOpacity + 0.5f);
 
-        // Apply resistance effect when outside bounds.
-        final float x;
-        final float y;
-        if (mInsideBounds) {
-            x = mX;
-            y = mY;
-        } else {
-            // TODO: We need to do this outside of draw() so that our dirty
-            // bounds accurately reflect resistance.
-            x = looseConstrain(mX, bounds.left, bounds.right,
-                    mOuterRadius * OUTSIDE_MARGIN, OUTSIDE_RESISTANCE);
-            y = looseConstrain(mY, bounds.top, bounds.bottom,
-                    mOuterRadius * OUTSIDE_MARGIN, OUTSIDE_RESISTANCE);
+        boolean hasContent = false;
+
+        if (outerAlpha > 0 && alpha > 0) {
+            p.setAlpha(Math.min(alpha, outerAlpha));
+            p.setStyle(Style.FILL);
+            c.drawCircle(mOuterX, mOuterY, mOuterRadius, p);
+            hasContent = true;
         }
 
-        final boolean hasContent;
-        if (alphaMultiplier <= 0 || innerRadius >= outerRadius) {
-            // Nothing to draw.
-            hasContent = false;
-        } else if (innerRadius > 0) {
-            // Draw a ring.
-            final float strokeWidth = outerRadius - innerRadius;
-            final float strokeRadius = innerRadius + strokeWidth / 2.0f;
-            p.setAlpha(alpha);
-            p.setStyle(Style.STROKE);
-            p.setStrokeWidth(strokeWidth);
-            c.drawCircle(x, y, strokeRadius, p);
-            hasContent = true;
-        } else if (outerRadius > 0) {
-            // Draw a circle.
+        if (opacity > 0 && radius > 0) {
             p.setAlpha(alpha);
             p.setStyle(Style.FILL);
-            c.drawCircle(x, y, outerRadius, p);
+            c.drawCircle(mX, mY, radius, p);
             hasContent = true;
-        } else {
-            hasContent = false;
         }
 
         p.setAlpha(paintAlpha);
+
         return hasContent;
     }
 
@@ -245,156 +238,279 @@
      * Returns the maximum bounds for this ripple.
      */
     public void getBounds(Rect bounds) {
+        final int outerX = (int) mOuterX;
+        final int outerY = (int) mOuterY;
+        final int r = (int) mOuterRadius;
+        bounds.set(outerX - r, outerY - r, outerX + r, outerY + r);
+
         final int x = (int) mX;
         final int y = (int) mY;
-        final int maxRadius = mMaxRadius;
-        bounds.set(x - maxRadius, y - maxRadius, x + maxRadius, y + maxRadius);
+        bounds.union(x - r, y - r, x + r, y + r);
     }
 
     /**
-     * Updates the center coordinates.
+     * Starts the enter animation at the specified absolute coordinates.
      */
-    public void move(float x, float y) {
-        mX = x;
-        mY = y;
+    public void enter(float x, float y) {
+        mX = x - mBounds.exactCenterX();
+        mY = y - mBounds.exactCenterY();
 
-        updateInsideBounds();
+        final int radiusDuration = (int)
+                (1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION) + 0.5);
+        final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_VELOCITY);
+
+        final ObjectAnimator radius = ObjectAnimator.ofFloat(this, "radius", 0, mOuterRadius);
+        radius.setAutoCancel(true);
+        radius.setDuration(radiusDuration);
+
+        final ObjectAnimator cX = ObjectAnimator.ofFloat(this, "x", mOuterX);
+        cX.setAutoCancel(true);
+        cX.setDuration(radiusDuration);
+
+        final ObjectAnimator cY = ObjectAnimator.ofFloat(this, "y", mOuterY);
+        cY.setAutoCancel(true);
+        cY.setDuration(radiusDuration);
+
+        final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1);
+        outer.setAutoCancel(true);
+        outer.setDuration(outerDuration);
+
+        mAnimRadius = radius;
+        mAnimOuterOpacity = outer;
+        mAnimX = cX;
+        mAnimY = cY;
+
+        // Enter animations always run on the UI thread, since it's unlikely
+        // that anything interesting is happening until the user lifts their
+        // finger.
+        radius.start();
+        outer.start();
+        cX.start();
+        cY.start();
+    }
+
+    /**
+     * Starts the exit animation.
+     */
+    public void exit() {
+        cancelSoftwareAnimations();
+
+        final float remaining;
+        if (mAnimRadius != null && mAnimRadius.isRunning()) {
+            remaining = mOuterRadius - mRadius;
+        } else {
+            remaining = mOuterRadius;
+        }
+
+        final int radiusDuration = (int) (1000 * Math.sqrt(remaining / (WAVE_TOUCH_UP_ACCELERATION
+                + WAVE_TOUCH_DOWN_ACCELERATION)) + 0.5);
+        final int opacityDuration = (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f);
+
+        // Determine at what time the inner and outer opacity intersect.
+        // inner(t) = mOpacity - t * WAVE_OPACITY_DECAY_VELOCITY / 1000
+        // outer(t) = mOuterOpacity + t * WAVE_OUTER_OPACITY_VELOCITY / 1000
+        final int outerInflection = Math.max(0, (int) (1000 * (mOpacity - mOuterOpacity)
+                / (WAVE_OPACITY_DECAY_VELOCITY + WAVE_OUTER_OPACITY_VELOCITY) + 0.5f));
+        final int inflectionOpacity = (int) (255 * (mOuterOpacity + outerInflection
+                * WAVE_OUTER_OPACITY_VELOCITY / 1000) + 0.5f);
+
+        if (mCanUseHardware) {
+            exitHardware(radiusDuration, opacityDuration, outerInflection, inflectionOpacity);
+        } else {
+            exitSoftware(radiusDuration, opacityDuration, outerInflection, inflectionOpacity);
+        }
+    }
+
+    private void exitHardware(int radiusDuration, int opacityDuration, int outerInflection,
+            int inflectionOpacity) {
+        mPendingAnimations.clear();
+
+        final Paint outerPaint = new Paint();
+        outerPaint.setAntiAlias(true);
+        outerPaint.setColor(mColor);
+        outerPaint.setAlpha((int) (255 * mOuterOpacity + 0.5f));
+        outerPaint.setStyle(Style.FILL);
+        mPropOuterPaint = CanvasProperty.createPaint(outerPaint);
+        mPropOuterRadius = CanvasProperty.createFloat(mOuterRadius);
+        mPropOuterX = CanvasProperty.createFloat(mOuterX);
+        mPropOuterY = CanvasProperty.createFloat(mOuterY);
+
+        final Paint paint = new Paint();
+        paint.setAntiAlias(true);
+        paint.setColor(mColor);
+        paint.setAlpha((int) (255 * mOpacity + 0.5f));
+        paint.setStyle(Style.FILL);
+        mPropPaint = CanvasProperty.createPaint(paint);
+        mPropRadius = CanvasProperty.createFloat(mRadius);
+        mPropX = CanvasProperty.createFloat(mX);
+        mPropY = CanvasProperty.createFloat(mY);
+
+        final RenderNodeAnimator radius = new RenderNodeAnimator(mPropRadius, mOuterRadius);
+        radius.setDuration(radiusDuration);
+
+        final RenderNodeAnimator x = new RenderNodeAnimator(mPropX, mOuterX);
+        x.setDuration(radiusDuration);
+
+        final RenderNodeAnimator y = new RenderNodeAnimator(mPropY, mOuterY);
+        y.setDuration(radiusDuration);
+
+        final RenderNodeAnimator opacity = new RenderNodeAnimator(mPropPaint,
+                RenderNodeAnimator.PAINT_ALPHA, 0);
+        opacity.setDuration(opacityDuration);
+        opacity.addListener(mAnimationListener);
+
+        final RenderNodeAnimator outerOpacity;
+        if (outerInflection > 0) {
+            // Outer opacity continues to increase for a bit.
+            outerOpacity = new RenderNodeAnimator(
+                    mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, inflectionOpacity);
+            outerOpacity.setDuration(outerInflection);
+
+            // Chain the outer opacity exit animation.
+            final int outerDuration = opacityDuration - outerInflection;
+            if (outerDuration > 0) {
+                final RenderNodeAnimator outerFadeOut = new RenderNodeAnimator(
+                        mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
+                outerFadeOut.setDuration(outerDuration);
+                outerFadeOut.setStartDelay(outerInflection);
+
+                mPendingAnimations.add(outerFadeOut);
+            }
+        } else {
+            outerOpacity = new RenderNodeAnimator(
+                    mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
+            outerOpacity.setDuration(opacityDuration);
+        }
+
+        mPendingAnimations.add(radius);
+        mPendingAnimations.add(opacity);
+        mPendingAnimations.add(outerOpacity);
+        mPendingAnimations.add(x);
+        mPendingAnimations.add(y);
+
+        mHardwareAnimating = true;
+
         invalidateSelf();
     }
 
-    /**
-     * Starts the exit animation. If {@link #enter()} was called recently, the
-     * animation may be postponed.
-     */
-    public void exit() {
-        mExitFinished = false;
+    private void exitSoftware(int radiusDuration, int opacityDuration, int outerInflection,
+            float inflectionOpacity) {
+        final ObjectAnimator radius = ObjectAnimator.ofFloat(this, "radius", mOuterRadius);
+        radius.setAutoCancel(true);
+        radius.setDuration(radiusDuration);
 
-        final ObjectAnimator inner = ObjectAnimator.ofFloat(this, "innerRadius", 0, mMaxRadius);
-        inner.setAutoCancel(true);
-        inner.setDuration(EXIT_DURATION);
-        inner.setInterpolator(INTERPOLATOR);
-        inner.addListener(mAnimationListener);
+        final ObjectAnimator x = ObjectAnimator.ofFloat(this, "x", mOuterX);
+        x.setAutoCancel(true);
+        x.setDuration(radiusDuration);
 
-        if (mOuter != null && mOuter.isStarted()) {
-            // If we haven't been running the enter animation for long enough,
-            // delay the exit animator.
-            final int elapsed = (int) (mOuter.getAnimatedFraction() * mOuter.getDuration());
-            final int delay = Math.max(0, EXIT_MIN_DELAY - elapsed);
-            inner.setStartDelay(delay);
+        final ObjectAnimator y = ObjectAnimator.ofFloat(this, "y", mOuterY);
+        y.setAutoCancel(true);
+        y.setDuration(radiusDuration);
+
+        final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, "opacity", 0);
+        opacity.setAutoCancel(true);
+        opacity.setDuration(opacityDuration);
+        opacity.addListener(mAnimationListener);
+
+        final ObjectAnimator outerOpacity;
+        if (outerInflection > 0) {
+            // Outer opacity continues to increase for a bit.
+            outerOpacity = ObjectAnimator.ofFloat(this, "outerOpacity", inflectionOpacity);
+            outerOpacity.setDuration(outerInflection);
+
+            // Chain the outer opacity exit animation.
+            final int outerDuration = opacityDuration - outerInflection;
+            outerOpacity.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    final ObjectAnimator outerFadeOut = ObjectAnimator.ofFloat(Ripple.this,
+                            "outerOpacity", 0);
+                    outerFadeOut.setDuration(outerDuration);
+
+                    mAnimOuterOpacity = outerFadeOut;
+
+                    outerFadeOut.start();
+                }
+
+                @Override
+                public void onAnimationCancel(Animator animation) {
+                    animation.removeListener(this);
+                }
+            });
+        } else {
+            outerOpacity = ObjectAnimator.ofFloat(this, "outerOpacity", 0);
+            outerOpacity.setDuration(opacityDuration);
         }
 
-        inner.start();
+        mAnimRadius = radius;
+        mAnimOpacity = opacity;
+        mAnimOuterOpacity = outerOpacity;
+        mAnimX = opacity;
+        mAnimY = opacity;
 
-        final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 0);
-        alpha.setAutoCancel(true);
-        alpha.setDuration(EXIT_DURATION);
-        alpha.start();
-
-        mInner = inner;
-        mAlpha = alpha;
+        radius.start();
+        opacity.start();
+        outerOpacity.start();
+        x.start();
+        y.start();
     }
 
     /**
      * Cancel all animations.
      */
     public void cancel() {
-        if (mInner != null) {
-            mInner.cancel();
+        cancelSoftwareAnimations();
+        cancelHardwareAnimations();
+    }
+
+    private void cancelSoftwareAnimations() {
+        if (mAnimRadius != null) {
+            mAnimRadius.cancel();
         }
 
-        if (mOuter != null) {
-            mOuter.cancel();
+        if (mAnimOpacity != null) {
+            mAnimOpacity.cancel();
         }
 
-        if (mAlpha != null) {
-            mAlpha.cancel();
+        if (mAnimOuterOpacity != null) {
+            mAnimOuterOpacity.cancel();
         }
+
+        if (mAnimX != null) {
+            mAnimX.cancel();
+        }
+
+        if (mAnimY != null) {
+            mAnimY.cancel();
+        }
+    }
+
+    /**
+     * Cancels any running hardware animations.
+     */
+    private void cancelHardwareAnimations() {
+        final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
+        final int N = runningAnimations == null ? 0 : runningAnimations.size();
+        for (int i = 0; i < N; i++) {
+            runningAnimations.get(i).cancel();
+        }
+
+        runningAnimations.clear();
     }
 
     private void invalidateSelf() {
         mOwner.invalidateSelf();
     }
 
-    /**
-     * Starts the enter animation.
-     */
-    private void enter() {
-        final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerRadius", mMaxRadius);
-        outer.setAutoCancel(true);
-        outer.setDuration(ENTER_DURATION);
-        outer.setInterpolator(INTERPOLATOR);
-        outer.start();
-
-        final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 1);
-        if (mPulseEnabled) {
-            alpha.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    final ObjectAnimator pulse = ObjectAnimator.ofFloat(
-                            this, "alphaMultiplier", 1, PULSE_MIN_ALPHA);
-                    pulse.setAutoCancel(true);
-                    pulse.setDuration(PULSE_DURATION + PULSE_INTERVAL);
-                    pulse.setRepeatCount(ObjectAnimator.INFINITE);
-                    pulse.setRepeatMode(ObjectAnimator.REVERSE);
-                    pulse.setStartDelay(PULSE_DELAY);
-                    pulse.start();
-
-                    mAlpha = pulse;
-                }
-            });
-        }
-        alpha.setAutoCancel(true);
-        alpha.setDuration(FADE_DURATION);
-        alpha.start();
-
-        mOuter = outer;
-        mAlpha = alpha;
-    }
-
-    /**
-     * Starts the outside transition animation.
-     */
-    private void outside() {
-        final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerRadius", mMaxOutsideRadius);
-        outer.setAutoCancel(true);
-        outer.setDuration(OUTSIDE_DURATION);
-        outer.setInterpolator(INTERPOLATOR);
-        outer.start();
-
-        final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 1);
-        alpha.setAutoCancel(true);
-        alpha.setDuration(FADE_DURATION);
-        alpha.start();
-
-        mOuter = outer;
-        mAlpha = alpha;
-    }
-
-    /**
-     * Constrains a value within a specified asymptotic margin outside a minimum
-     * and maximum.
-     */
-    private static float looseConstrain(float value, float min, float max, float margin,
-            float factor) {
-        // TODO: Can we use actual spring physics here?
-        if (value < min) {
-            return min - Math.min(margin, (float) Math.pow(min - value, factor));
-        } else if (value > max) {
-            return max + Math.min(margin, (float) Math.pow(value - max, factor));
-        } else {
-            return value;
-        }
-    }
-
-    private final AnimatorListener mAnimationListener = new AnimatorListenerAdapter() {
+    private final AnimatorListenerAdapter mAnimationListener = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
-            if (animation == mInner) {
-                mExitFinished = true;
-                mOuterRadius = 0;
-                mInnerRadius = 0;
-                mAlphaMultiplier = 1;
-            }
+            mFinished = true;
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mFinished = true;
         }
     };
 }
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
index 8128b5f..a55a4b2 100644
--- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -24,6 +24,7 @@
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.PointF;
 import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
@@ -33,6 +34,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.R;
+import com.android.org.bouncycastle.util.Arrays;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -40,11 +42,36 @@
 import java.io.IOException;
 
 /**
- * Documentation pending.
+ * Drawable that shows a ripple effect in response to state changes. The
+ * anchoring position of the ripple for a given state may be specified by
+ * calling {@link #setHotspot(int, float, float)} with the corresponding state
+ * attribute identifier.
+ * <p>
+ * A touch feedback drawable may contain multiple child layers, including a
+ * special mask layer that is not drawn to the screen. A single layer may be set
+ * as the mask by specifying its android:id value as {@link android.R.id#mask}.
+ * <p>
+ * If a mask layer is set, the ripple effect will be masked against that layer
+ * before it is blended onto the composite of the remaining child layers.
+ * <p>
+ * If no mask layer is set, the ripple effect is simply blended onto the
+ * composite of the child layers using the specified
+ * {@link android.R.styleable#TouchFeedbackDrawable_tintMode}.
+ * <p>
+ * If no child layers or mask is specified and the ripple is set as a View
+ * background, the ripple will be blended onto the first available parent
+ * background within the View's hierarchy using the specified
+ * {@link android.R.styleable#TouchFeedbackDrawable_tintMode}. In this case, the
+ * drawing region may extend outside of the Drawable bounds.
+ *
+ * @attr ref android.R.styleable#DrawableStates_state_focused
+ * @attr ref android.R.styleable#DrawableStates_state_pressed
  */
 public class TouchFeedbackDrawable extends LayerDrawable {
     private static final String LOG_TAG = TouchFeedbackDrawable.class.getSimpleName();
     private static final PorterDuffXfermode DST_IN = new PorterDuffXfermode(Mode.DST_IN);
+    private static final PorterDuffXfermode DST_ATOP = new PorterDuffXfermode(Mode.DST_ATOP);
+    private static final PorterDuffXfermode SRC_ATOP = new PorterDuffXfermode(Mode.SRC_ATOP);
     private static final PorterDuffXfermode SRC_OVER = new PorterDuffXfermode(Mode.SRC_OVER);
 
     /** The maximum number of ripples supported. */
@@ -63,10 +90,22 @@
 
     private final TouchFeedbackState mState;
 
-    /** Lazily-created map of touch hotspot IDs to ripples. */
-    private SparseArray<Ripple> mRipples;
+    /**
+     * Lazily-created map of pending hotspot locations. These may be modified by
+     * calls to {@link #setHotspot(int, float, float)}.
+     */
+    private SparseArray<PointF> mPendingHotspots;
 
-    /** Lazily-created array of actively animating ripples. */
+    /**
+     * Lazily-created map of active hotspot locations. These may be modified by
+     * calls to {@link #setHotspot(int, float, float)}.
+     */
+    private SparseArray<Ripple> mActiveHotspots;
+
+    /**
+     * Lazily-created array of actively animating ripples. Inactive ripples are
+     * pruned during draw(). The locations of these will not change.
+     */
     private Ripple[] mAnimatingRipples;
     private int mAnimatingRipplesCount = 0;
 
@@ -96,24 +135,18 @@
     protected boolean onStateChange(int[] stateSet) {
         super.onStateChange(stateSet);
 
-        // TODO: Implicitly tie states to ripple IDs. For now, just clear
-        // focused and pressed if they aren't in the state set.
-        boolean hasFocused = false;
-        boolean hasPressed = false;
-        for (int i = 0; i < stateSet.length; i++) {
-            if (stateSet[i] == R.attr.state_pressed) {
-                hasPressed = true;
-            } else if (stateSet[i] == R.attr.state_focused) {
-                hasFocused = true;
-            }
-        }
-
-        if (!hasPressed) {
+        final boolean pressed = Arrays.contains(stateSet, R.attr.state_pressed);
+        if (!pressed) {
             removeHotspot(R.attr.state_pressed);
+        } else {
+            activateHotspot(R.attr.state_pressed);
         }
 
-        if (!hasFocused) {
+        final boolean focused = Arrays.contains(stateSet, R.attr.state_focused);
+        if (!focused) {
             removeHotspot(R.attr.state_focused);
+        } else {
+            activateHotspot(R.attr.state_focused);
         }
 
         if (mRipplePaint != null && mState.mTint != null) {
@@ -138,19 +171,7 @@
             mHotspotBounds.set(bounds);
         }
 
-        onHotspotBoundsChange();
-    }
-
-    private void onHotspotBoundsChange() {
-        final int x = mHotspotBounds.centerX();
-        final int y = mHotspotBounds.centerY();
-        final int N = mAnimatingRipplesCount;
-        for (int i = 0; i < N; i++) {
-            if (mState.mPinned) {
-                mAnimatingRipples[i].move(x, y);
-            }
-            mAnimatingRipples[i].onBoundsChanged();
-        }
+        invalidateSelf();
     }
 
     @Override
@@ -172,7 +193,7 @@
 
     @Override
     public boolean isStateful() {
-        return super.isStateful() || mState.mTint != null && mState.mTint.isStateful();
+        return true;
     }
 
     /**
@@ -213,7 +234,7 @@
             throws XmlPullParserException, IOException {
         final TypedArray a = obtainAttributes(
                 r, theme, attrs, R.styleable.TouchFeedbackDrawable);
-        inflateStateFromTypedArray(a);
+        updateStateFromTypedArray(a);
         a.recycle();
 
         super.inflate(r, parser, attrs, theme);
@@ -245,25 +266,23 @@
     /**
      * Initializes the constant state from the values in the typed array.
      */
-    private void inflateStateFromTypedArray(TypedArray a) {
+    private void updateStateFromTypedArray(TypedArray a) {
         final TouchFeedbackState state = mState;
 
         // Extract the theme attributes, if any.
-        final int[] themeAttrs = a.extractThemeAttrs();
-        state.mTouchThemeAttrs = themeAttrs;
+        state.mTouchThemeAttrs = a.extractThemeAttrs();
 
-        if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_tint] == 0) {
-            mState.mTint = a.getColorStateList(R.styleable.TouchFeedbackDrawable_tint);
+        final ColorStateList tint = a.getColorStateList(R.styleable.TouchFeedbackDrawable_tint);
+        if (tint != null) {
+            mState.mTint = tint;
         }
 
-        if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_tintMode] == 0) {
-            mState.setTintMode(Drawable.parseTintMode(
-                    a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP));
+        final int tintMode = a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1);
+        if (tintMode != -1) {
+            mState.setTintMode(Drawable.parseTintMode(tintMode, Mode.SRC_ATOP));
         }
 
-        if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_pinned] == 0) {
-            mState.mPinned = a.getBoolean(R.styleable.TouchFeedbackDrawable_pinned, false);
-        }
+        mState.mPinned = a.getBoolean(R.styleable.TouchFeedbackDrawable_pinned, mState.mPinned);
     }
 
     /**
@@ -283,38 +302,14 @@
         super.applyTheme(t);
 
         final TouchFeedbackState state = mState;
-        if (state == null) {
-            throw new RuntimeException(
-                    "Can't apply theme to <touch-feedback> with no constant state");
+        if (state == null || state.mTouchThemeAttrs == null) {
+            return;
         }
 
-        final int[] themeAttrs = state.mTouchThemeAttrs;
-        if (themeAttrs != null) {
-            final TypedArray a = t.resolveAttributes(
-                    themeAttrs, R.styleable.TouchFeedbackDrawable);
-            updateStateFromTypedArray(a);
-            a.recycle();
-        }
-    }
-
-    /**
-     * Updates the constant state from the values in the typed array.
-     */
-    private void updateStateFromTypedArray(TypedArray a) {
-        final TouchFeedbackState state = mState;
-
-        if (a.hasValue(R.styleable.TouchFeedbackDrawable_tint)) {
-            state.mTint = a.getColorStateList(R.styleable.TouchFeedbackDrawable_tint);
-        }
-
-        if (a.hasValue(R.styleable.TouchFeedbackDrawable_tintMode)) {
-            mState.setTintMode(Drawable.parseTintMode(
-                    a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP));
-        }
-
-        if (a.hasValue(R.styleable.TouchFeedbackDrawable_pinned)) {
-            mState.mPinned = a.getBoolean(R.styleable.TouchFeedbackDrawable_pinned, false);
-        }
+        final TypedArray a = t.resolveAttributes(state.mTouchThemeAttrs,
+                R.styleable.TouchFeedbackDrawable);
+        updateStateFromTypedArray(a);
+        a.recycle();
     }
 
     @Override
@@ -329,59 +324,123 @@
 
     @Override
     public void setHotspot(int id, float x, float y) {
-        if (mRipples == null) {
-            mRipples = new SparseArray<Ripple>();
-            mAnimatingRipples = new Ripple[MAX_RIPPLES];
+        if (mState.mPinned && !circleContains(mHotspotBounds, x, y)) {
+            x = mHotspotBounds.exactCenterX();
+            y = mHotspotBounds.exactCenterY();
         }
 
-        if (mAnimatingRipplesCount >= MAX_RIPPLES) {
-            Log.e(LOG_TAG, "Max ripple count exceeded", new RuntimeException());
+        final int[] stateSet = getState();
+        if (!Arrays.contains(stateSet, id)) {
+            // The hotspot is not active, so just modify the pending location.
+            getOrCreatePendingHotspot(id).set(x, y);
             return;
         }
 
-        final Ripple ripple = mRipples.get(id);
-        if (ripple == null) {
-            final Rect bounds = mHotspotBounds;
-            if (mState.mPinned) {
-                x = bounds.exactCenterX();
-                y = bounds.exactCenterY();
-            }
-
-            // TODO: Clean this up in the API.
-            final boolean pulse = (id != R.attr.state_focused);
-            final Ripple newRipple = new Ripple(this, bounds, mDensity, pulse);
-            newRipple.move(x, y);
-
-            mAnimatingRipples[mAnimatingRipplesCount++] = newRipple;
-            mRipples.put(id, newRipple);
-        } else if (mState.mPinned) {
-            final Rect bounds = mHotspotBounds;
-            x = bounds.exactCenterX();
-            y = bounds.exactCenterY();
-            ripple.move(x, y);
-        } else {
-            ripple.move(x, y);
+        if (mAnimatingRipplesCount >= MAX_RIPPLES) {
+            // This should never happen unless the user is tapping like a maniac
+            // or there is a bug that's preventing ripples from being removed.
+            Log.d(LOG_TAG, "Max ripple count exceeded", new RuntimeException());
+            return;
         }
+
+        if (mActiveHotspots == null) {
+            mActiveHotspots = new SparseArray<Ripple>();
+            mAnimatingRipples = new Ripple[MAX_RIPPLES];
+        }
+
+        final Ripple ripple = mActiveHotspots.get(id);
+        if (ripple != null) {
+            // The hotspot is active, but we can't move it because it's probably
+            // busy animating the center position.
+            return;
+        }
+
+        // The hotspot needs to be made active.
+        createActiveHotspot(id, x, y);
+    }
+
+    private boolean circleContains(Rect bounds, float x, float y) {
+        final float pX = bounds.exactCenterX() - x;
+        final float pY = bounds.exactCenterY() - y;
+        final double pointRadius = Math.sqrt(pX * pX + pY * pY);
+
+        final float bX = bounds.width() / 2.0f;
+        final float bY = bounds.height() / 2.0f;
+        final double boundsRadius = Math.sqrt(bX * bX + bY * bY);
+
+        return pointRadius < boundsRadius;
+    }
+
+    private PointF getOrCreatePendingHotspot(int id) {
+        final PointF p;
+        if (mPendingHotspots == null) {
+            mPendingHotspots = new SparseArray<>(2);
+            p = null;
+        } else {
+            p = mPendingHotspots.get(id);
+        }
+
+        if (p == null) {
+            final PointF newPoint = new PointF();
+            mPendingHotspots.put(id, newPoint);
+            return newPoint;
+        } else {
+            return p;
+        }
+    }
+
+    /**
+     * Moves a hotspot from pending to active.
+     */
+    private void activateHotspot(int id) {
+        final SparseArray<PointF> pendingHotspots = mPendingHotspots;
+        if (pendingHotspots != null) {
+            final int index = pendingHotspots.indexOfKey(id);
+            if (index >= 0) {
+                final PointF hotspot = pendingHotspots.valueAt(index);
+                pendingHotspots.removeAt(index);
+                createActiveHotspot(id, hotspot.x, hotspot.y);
+            }
+        }
+    }
+
+    /**
+     * Creates an active hotspot at the specified location.
+     */
+    private void createActiveHotspot(int id, float x, float y) {
+        final int color = mState.mTint.getColorForState(getState(), Color.TRANSPARENT);
+        final Ripple newRipple = new Ripple(this, mHotspotBounds, color);
+        newRipple.enter(x, y);
+
+        if (mAnimatingRipples == null) {
+            mAnimatingRipples = new Ripple[MAX_RIPPLES];
+        }
+        mAnimatingRipples[mAnimatingRipplesCount++] = newRipple;
+
+        if (mActiveHotspots == null) {
+            mActiveHotspots = new SparseArray<Ripple>();
+        }
+        mActiveHotspots.put(id, newRipple);
     }
 
     @Override
     public void removeHotspot(int id) {
-        if (mRipples == null) {
+        if (mActiveHotspots == null) {
             return;
         }
 
-        final Ripple ripple = mRipples.get(id);
+        final Ripple ripple = mActiveHotspots.get(id);
         if (ripple != null) {
             ripple.exit();
 
-            mRipples.remove(id);
+            mActiveHotspots.remove(id);
         }
     }
 
     @Override
     public void clearHotspots() {
-        if (mRipples != null) {
-            mRipples.clear();
+        if (mActiveHotspots != null) {
+            mActiveHotspots.clear();
         }
 
         final int count = mAnimatingRipplesCount;
@@ -402,7 +461,6 @@
     public void setHotspotBounds(int left, int top, int right, int bottom) {
         mOverrideBounds = true;
         mHotspotBounds.set(left, top, right, bottom);
-        onHotspotBoundsChange();
     }
 
     @Override
@@ -412,9 +470,9 @@
         final ChildDrawable[] array = mLayerState.mChildren;
         final boolean maskOnly = mState.mMask != null && N == 1;
 
-        int restoreToCount = drawRippleLayer(canvas, bounds, maskOnly);
+        int restoreToCount = drawRippleLayer(canvas, maskOnly);
 
-        if (restoreToCount >= 0) { 
+        if (restoreToCount >= 0) {
             // We have a ripple layer that contains ripples. If we also have an
             // explicit mask drawable, apply it now using DST_IN blending.
             if (mState.mMask != null) {
@@ -450,7 +508,7 @@
         }
     }
 
-    private int drawRippleLayer(Canvas canvas, Rect bounds, boolean maskOnly) {
+    private int drawRippleLayer(Canvas canvas, boolean maskOnly) {
         final int count = mAnimatingRipplesCount;
         if (count == 0) {
             return -1;
@@ -458,7 +516,7 @@
 
         final Ripple[] ripples = mAnimatingRipples;
         final boolean projected = isProjected();
-        final Rect layerBounds = projected ? getDirtyBounds() : bounds;
+        final Rect layerBounds = projected ? getDirtyBounds() : getBounds();
 
         // Separate the ripple color and alpha channel. The alpha will be
         // applied when we merge the ripples down to the canvas.
@@ -479,6 +537,7 @@
 
         boolean drewRipples = false;
         int restoreToCount = -1;
+        int restoreTranslate = -1;
         int animatingCount = 0;
 
         // Draw ripples and update the animating ripples array.
@@ -509,6 +568,10 @@
                 restoreToCount = canvas.saveLayer(layerBounds.left, layerBounds.top,
                         layerBounds.right, layerBounds.bottom, layerPaint);
                 layerPaint.setAlpha(255);
+
+                restoreTranslate = canvas.save();
+                // Translate the canvas to the current hotspot bounds.
+                canvas.translate(mHotspotBounds.exactCenterX(), mHotspotBounds.exactCenterY());
             }
 
             drewRipples |= ripple.draw(canvas, ripplePaint);
@@ -519,6 +582,11 @@
 
         mAnimatingRipplesCount = animatingCount;
 
+        // Always restore the translation.
+        if (restoreTranslate >= 0) {
+            canvas.restoreToCount(restoreTranslate);
+        }
+
         // If we created a layer with no content, merge it immediately.
         if (restoreToCount >= 0 && !drewRipples) {
             canvas.restoreToCount(restoreToCount);
@@ -543,11 +611,14 @@
         dirtyBounds.set(drawingBounds);
         drawingBounds.setEmpty();
 
+        final int cX = (int) mHotspotBounds.exactCenterX();
+        final int cY = (int) mHotspotBounds.exactCenterY();
         final Rect rippleBounds = mTempRect;
         final Ripple[] activeRipples = mAnimatingRipples;
         final int N = mAnimatingRipplesCount;
         for (int i = 0; i < N; i++) {
             activeRipples[i].getBounds(rippleBounds);
+            rippleBounds.offset(cX, cY);
             drawingBounds.union(rippleBounds);
         }
 
@@ -563,11 +634,11 @@
 
     static class TouchFeedbackState extends LayerState {
         int[] mTouchThemeAttrs;
-        ColorStateList mTint;
-        PorterDuffXfermode mTintXfermode;
-        PorterDuffXfermode mTintXfermodeInverse;
+        ColorStateList mTint = null;
+        PorterDuffXfermode mTintXfermode = SRC_ATOP;
+        PorterDuffXfermode mTintXfermodeInverse = DST_ATOP;
         Drawable mMask;
-        boolean mPinned;
+        boolean mPinned = false;
 
         public TouchFeedbackState(
                 TouchFeedbackState orig, TouchFeedbackDrawable owner, Resources res) {
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index 83eedfb..b80f7e9 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -37,7 +37,10 @@
         , mInterpolator(0)
         , mPlayState(NEEDS_START)
         , mStartTime(0)
-        , mDuration(300){
+        , mDelayUntil(0)
+        , mDuration(300)
+        , mStartDelay(0) {
+
 }
 
 BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
@@ -49,10 +52,6 @@
     mInterpolator = interpolator;
 }
 
-void BaseRenderNodeAnimator::setDuration(nsecs_t duration) {
-    mDuration = duration;
-}
-
 void BaseRenderNodeAnimator::setStartValue(float value) {
     LOG_ALWAYS_FATAL_IF(mPlayState != NEEDS_START,
             "Cannot set the start value after the animator has started!");
@@ -68,7 +67,24 @@
     }
 }
 
+void BaseRenderNodeAnimator::setDuration(nsecs_t duration) {
+    mDuration = duration;
+}
+
+void BaseRenderNodeAnimator::setStartDelay(nsecs_t startDelay) {
+    mStartDelay = startDelay;
+}
+
 bool BaseRenderNodeAnimator::animate(RenderNode* target, TreeInfo& info) {
+    if (mPlayState == PENDING && mStartDelay > 0 && mDelayUntil == 0) {
+        mDelayUntil = info.frameTimeMs + mStartDelay;
+        return false;
+    }
+
+    if (mDelayUntil > info.frameTimeMs) {
+        return false;
+    }
+
     if (mPlayState == PENDING) {
         mPlayState = RUNNING;
         mStartTime = info.frameTimeMs;
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index fe88cbf..7741617 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -44,6 +44,8 @@
     ANDROID_API void setInterpolator(Interpolator* interpolator);
     ANDROID_API void setDuration(nsecs_t durationInMs);
     ANDROID_API nsecs_t duration() { return mDuration; }
+    ANDROID_API void setStartDelay(nsecs_t startDelayInMs);
+    ANDROID_API nsecs_t startDelay() { return mStartDelay; }
     ANDROID_API void setListener(AnimationListener* listener) {
         mListener = listener;
     }
@@ -82,10 +84,12 @@
 
     Interpolator* mInterpolator;
     PlayState mPlayState;
-    long mStartTime;
-    long mDuration;
+    nsecs_t mStartTime;
+    nsecs_t mDelayUntil;
+    nsecs_t mDuration;
+    nsecs_t mStartDelay;
 
-   sp<AnimationListener> mListener;
+    sp<AnimationListener> mListener;
 };
 
 class RenderPropertyAnimator : public BaseRenderNodeAnimator {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index 89886ef..8a7e642 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -23,10 +23,10 @@
 import android.hardware.IProCameraCallbacks;
 import android.hardware.IProCameraUser;
 import android.hardware.camera2.CameraMetadata;
-import android.hardware.camera2.CaptureResultExtras;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.utils.BinderHolder;
 import android.hardware.camera2.utils.CameraBinderDecorator;
 import android.os.Binder;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 74ce997..7b2e7dd 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -21,10 +21,10 @@
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.CaptureResultExtras;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.utils.BinderHolder;
 import android.media.Image;
 import android.media.ImageReader;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index 5ab586f..a77b647 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -18,6 +18,7 @@
 
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Range;
+import android.util.Rational;
 import android.util.SizeF;
 import android.graphics.ImageFormat;
 import android.graphics.Point;
@@ -26,15 +27,14 @@
 import android.graphics.SurfaceTexture;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.ColorSpaceTransform;
-import android.hardware.camera2.Face;
-import android.hardware.camera2.MeteringRectangle;
-import android.hardware.camera2.Rational;
-import android.hardware.camera2.RggbChannelVector;
-import android.hardware.camera2.Size;
+import android.util.Size;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
+import android.hardware.camera2.params.ColorSpaceTransform;
+import android.hardware.camera2.params.Face;
+import android.hardware.camera2.params.MeteringRectangle;
 import android.hardware.camera2.params.ReprocessFormatsMap;
+import android.hardware.camera2.params.RggbChannelVector;
 import android.hardware.camera2.params.StreamConfiguration;
 import android.hardware.camera2.params.StreamConfigurationDuration;
 import android.hardware.camera2.params.StreamConfigurationMap;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
index 9621f92..18c0d3e 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
@@ -17,7 +17,7 @@
 package com.android.mediaframeworktest.unit;
 
 import android.test.suitebuilder.annotation.SmallTest;
-import android.hardware.camera2.Rational;
+import android.util.Rational;
 
 /**
  * <pre>
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 908bfbd..249422b 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -623,8 +623,8 @@
         pw.println("  --charged: only output data since last charged.");
         pw.println("  --reset: reset the stats, clearing all current data.");
         pw.println("  --write: force write current collected stats to disk.");
-        pw.println("  --enable: enable an option: full-wake-history.");
-        pw.println("  --disable: disable an option: full-wake-history.");
+        pw.println("  --enable: enable an option: full-wake-history, no-auto-reset.");
+        pw.println("  --disable: disable an option: full-wake-history, no-auto-reset.");
         pw.println("  -h: print this help text.");
         pw.println("  <package.name>: optional name of package to filter output by.");
     }
@@ -640,6 +640,10 @@
             synchronized (mStats) {
                 mStats.setRecordAllWakeLocksLocked(enable);
             }
+        } else if ("no-auto-reset".equals(args[i])) {
+            synchronized (mStats) {
+                mStats.setNoAutoReset(enable);
+            }
         } else {
             pw.println("Unknown enable/disable option: " + args[i]);
             dumpHelp(pw);
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index a39c116..c1b9a33 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -24,11 +24,14 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.Manifest;
+import android.app.admin.DevicePolicyManager;
 import android.app.trust.ITrustListener;
 import android.app.trust.ITrustManager;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
@@ -46,6 +49,7 @@
 import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.Slog;
+import android.util.SparseBooleanArray;
 import android.util.Xml;
 
 import java.io.IOException;
@@ -81,6 +85,8 @@
 
     private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<AgentInfo>();
     private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<ITrustListener>();
+    private final DevicePolicyReceiver mDevicePolicyReceiver = new DevicePolicyReceiver();
+    private final SparseBooleanArray mUserHasAuthenticatedSinceBoot = new SparseBooleanArray();
     private final Context mContext;
 
     private UserManager mUserManager;
@@ -105,8 +111,8 @@
     @Override
     public void onBootPhase(int phase) {
         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY && !isSafeMode()) {
-            // Listen for package changes
             mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
+            mDevicePolicyReceiver.register(mContext);
             refreshAgentList();
         }
     }
@@ -158,8 +164,13 @@
         mObsoleteAgents.addAll(mActiveAgents);
 
         for (UserInfo userInfo : userInfos) {
+            int disabledFeatures = lockPatternUtils.getDevicePolicyManager()
+                    .getKeyguardDisabledFeatures(null, userInfo.id);
+            boolean disableTrustAgents =
+                    (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
+
             List<ComponentName> enabledAgents = lockPatternUtils.getEnabledTrustAgents(userInfo.id);
-            if (enabledAgents == null) {
+            if (disableTrustAgents || enabledAgents == null) {
                 continue;
             }
             List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(TRUST_AGENT_INTENT,
@@ -259,6 +270,9 @@
     // Agent dispatch and aggregation
 
     private boolean aggregateIsTrusted(int userId) {
+        if (!mUserHasAuthenticatedSinceBoot.get(userId)) {
+            return false;
+        }
         for (int i = 0; i < mActiveAgents.size(); i++) {
             AgentInfo info = mActiveAgents.valueAt(i);
             if (info.userId == userId) {
@@ -277,6 +291,11 @@
                 info.agent.onUnlockAttempt(successful);
             }
         }
+
+        if (successful && !mUserHasAuthenticatedSinceBoot.get(userId)) {
+            mUserHasAuthenticatedSinceBoot.put(userId, true);
+            updateTrust(userId);
+        }
     }
 
     // Listeners
@@ -384,4 +403,24 @@
             return true;
         }
     };
+
+    private class DevicePolicyReceiver extends BroadcastReceiver {
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(
+                    intent.getAction())) {
+                refreshAgentList();
+            }
+        }
+
+        public void register(Context context) {
+            context.registerReceiverAsUser(this,
+                    UserHandle.ALL,
+                    new IntentFilter(
+                            DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+                    null /* permission */,
+                    null /* scheduler */);
+        }
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index a0c59cc..edbbc9f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1214,18 +1214,20 @@
         }
         mAppOpsService = IAppOpsService.Stub.asInterface(
                 ServiceManager.getService(Context.APP_OPS_SERVICE));
-        if (mDeviceOwner.hasDeviceOwner()) {
-            try {
-                mAppOpsService.setDeviceOwner(mDeviceOwner.getDeviceOwnerPackageName());
-            } catch (RemoteException e) {
-                Log.w(LOG_TAG, "Unable to notify AppOpsService of DeviceOwner", e);
+        if (mDeviceOwner != null) {
+            if (mDeviceOwner.hasDeviceOwner()) {
+                try {
+                    mAppOpsService.setDeviceOwner(mDeviceOwner.getDeviceOwnerPackageName());
+                } catch (RemoteException e) {
+                    Log.w(LOG_TAG, "Unable to notify AppOpsService of DeviceOwner", e);
+                }
             }
-        }
-        for (Integer i : mDeviceOwner.getProfileOwnerKeys()) {
-            try {
-                mAppOpsService.setProfileOwner(mDeviceOwner.getProfileOwnerName(i), i);
-            } catch (RemoteException e) {
-                Log.w(LOG_TAG, "Unable to notify AppOpsService of ProfileOwner", e);
+            for (Integer i : mDeviceOwner.getProfileOwnerKeys()) {
+                try {
+                    mAppOpsService.setProfileOwner(mDeviceOwner.getProfileOwnerName(i), i);
+                } catch (RemoteException e) {
+                    Log.w(LOG_TAG, "Unable to notify AppOpsService of ProfileOwner", e);
+                }
             }
         }
     }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7002744..2bf9ef1 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1773,12 +1773,15 @@
      *
      * Input parameters equivalent to TS 27.007 AT+CCHO command.
      *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#SIM_COMMUNICATION SIM_COMMUNICATION}
+     *
      * @param AID Application id. See ETSI 102.221 and 101.220.
      * @return The logical channel id which is negative on error.
      */
     public int iccOpenLogicalChannel(String AID) {
         try {
-          return getITelephony().iccOpenLogicalChannel(AID);
+            return getITelephony().iccOpenLogicalChannel(AID);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -1790,13 +1793,16 @@
      *
      * Input parameters equivalent to TS 27.007 AT+CCHC command.
      *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#SIM_COMMUNICATION SIM_COMMUNICATION}
+     *
      * @param channel is the channel id to be closed as retruned by a successful
      *            iccOpenLogicalChannel.
      * @return true if the channel was closed successfully.
      */
     public boolean iccCloseLogicalChannel(int channel) {
         try {
-          return getITelephony().iccCloseLogicalChannel(channel);
+            return getITelephony().iccCloseLogicalChannel(channel);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -1808,6 +1814,9 @@
      *
      * Input parameters equivalent to TS 27.007 AT+CGLA command.
      *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#SIM_COMMUNICATION SIM_COMMUNICATION}
+     *
      * @param channel is the channel id to be closed as returned by a successful
      *            iccOpenLogicalChannel.
      * @param cla Class of the APDU command.
@@ -1823,8 +1832,30 @@
     public String iccTransmitApduLogicalChannel(int channel, int cla,
             int instruction, int p1, int p2, int p3, String data) {
         try {
-          return getITelephony().iccTransmitApduLogicalChannel(channel, cla,
-                  instruction, p1, p2, p3, data);
+            return getITelephony().iccTransmitApduLogicalChannel(channel, cla,
+                    instruction, p1, p2, p3, data);
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+        return "";
+    }
+
+    /**
+     * Send ENVELOPE to the SIM and return the response.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#SIM_COMMUNICATION SIM_COMMUNICATION}
+     *
+     * @param content String containing SAT/USAT response in hexadecimal
+     *                format starting with command tag. See TS 102 223 for
+     *                details.
+     * @return The APDU response from the ICC card, with the last 4 bytes
+     *         being the status word. If the command fails, returns an empty
+     *         string.
+     */
+    public String sendEnvelopeWithStatus(String content) {
+        try {
+            return getITelephony().sendEnvelopeWithStatus(content);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 72398ad..8b80bfa 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -373,6 +373,18 @@
             int p1, int p2, int p3, String data);
 
     /**
+     * Send ENVELOPE to the SIM and returns the response.
+     *
+     * @param contents  String containing SAT/USAT response in hexadecimal
+     *                  format starting with command tag. See TS 102 223 for
+     *                  details.
+     * @return The APDU response from the ICC card, with the last 4 bytes
+     *         being the status word. If the command fails, returns an empty
+     *         string.
+     */
+    String sendEnvelopeWithStatus(String content);
+
+    /**
      * Read one of the NV items defined in {@link RadioNVItems} / {@code ril_nv_items.h}.
      * Used for device configuration by some CDMA operators.
      *
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 0d9cd18..c162bf28 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -350,7 +350,17 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
     @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+            Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+
     public void sendStickyBroadcast(Intent intent) {
         throw new UnsupportedOperationException();
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 08e9d99..d31239b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -567,7 +567,7 @@
         StyleResourceValue customStyleValues = null;
         if (customStyle != null) {
             ResourceValue item = mRenderResources.findResValue(customStyle,
-                    false /*forceFrameworkOnly*/);
+                    isPlatformFile /*forceFrameworkOnly*/);
 
             // resolve it in case it links to something else
             item = mRenderResources.resolveResValue(item);
@@ -1284,6 +1284,14 @@
     }
 
     @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+            Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
+        // pass
+    }
+
+    @Override
     public void sendStickyBroadcast(Intent arg0) {
         // pass
 
diff --git a/tools/layoutlib/rename_font/README b/tools/layoutlib/rename_font/README
new file mode 100644
index 0000000..600b756
--- /dev/null
+++ b/tools/layoutlib/rename_font/README
@@ -0,0 +1,9 @@
+This tool is used to rename the PS name encoded inside the ttf font that we ship
+with the SDK. There is bug in Java that returns incorrect results for
+java.awt.Font#layoutGlyphVector() if two fonts with same name but differnt
+versions are loaded. As a workaround, we rename all the fonts that we ship with
+the SDK by appending the font version to its name.
+
+
+The build_font.py copies all files from input_dir to output_dir while renaming
+the font files (*.ttf) in the process.
diff --git a/tools/layoutlib/rename_font/Roboto-Regular.ttf b/tools/layoutlib/rename_font/Roboto-Regular.ttf
new file mode 100644
index 0000000..7469063
--- /dev/null
+++ b/tools/layoutlib/rename_font/Roboto-Regular.ttf
Binary files differ
diff --git a/tools/layoutlib/rename_font/build_font.py b/tools/layoutlib/rename_font/build_font.py
new file mode 100755
index 0000000..ea3dccc
--- /dev/null
+++ b/tools/layoutlib/rename_font/build_font.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+
+# 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.
+
+"""
+Rename the PS name of all fonts in the input directory and copy them to the
+output directory.
+
+Usage: build_font.py /path/to/input_fonts/ /path/to/output_fonts/
+
+"""
+
+import sys
+# fontTools is available at platform/external/fonttools
+from fontTools import ttx
+import re
+import os
+from lxml import etree
+import shutil
+import glob
+
+def main(argv):
+  if len(argv) != 2:
+    print "Usage: build_font.py /path/to/input_fonts/ /path/to/out/dir/"
+    sys.exit(1)
+  if not os.path.isdir(argv[0]):
+    print argv[0] + "is not a valid directory"
+    sys.exit(1)
+  if not os.path.isdir(argv[1]):
+    print argv[1] + "is not a valid directory"
+    sys.exit(1)
+  cwd = os.getcwd()
+  os.chdir(argv[1])
+  files = glob.glob('*')
+  for filename in files:
+    os.remove(filename)
+  os.chdir(cwd)
+  for filename in os.listdir(argv[0]):
+    if not os.path.splitext(filename)[1].lower() == ".ttf":
+      shutil.copy(os.path.join(argv[0], filename), argv[1])
+      continue
+    print os.path.join(argv[0], filename)
+    old_ttf_path = os.path.join(argv[0], filename)
+    # run ttx to generate an xml file in the output folder which represents all
+    # its info
+    ttx_args = ["-d", argv[1], old_ttf_path]
+    ttx.main(ttx_args)
+    # the path to the output file. The file name is the fontfilename.ttx
+    ttx_path = os.path.join(argv[1], filename)
+    ttx_path = ttx_path[:-1] + "x"
+    # now parse the xml file to change its PS name.
+    tree = etree.parse(ttx_path)
+    encoding = tree.docinfo.encoding
+    root = tree.getroot()
+    for name in root.iter('name'):
+      [old_ps_name, version] = get_font_info(name)
+      new_ps_name = old_ps_name + version
+      update_name(name, new_ps_name)
+    tree.write(ttx_path, xml_declaration=True, encoding=encoding )
+    # generate the udpated font now.
+    ttx_args = ["-d", argv[1], ttx_path]
+    ttx.main(ttx_args)
+    # delete the temp ttx file.
+    os.remove(ttx_path)
+
+def get_font_info(tag):
+  ps_name = None
+  ps_version = None
+  for namerecord in tag.iter('namerecord'):
+    if 'nameID' in namerecord.attrib:
+      # if the tag has nameID=6, it is the postscript name of the font.
+      # see: http://scripts.sil.org/cms/scripts/page.php?item_id=IWS-Chapter08#3054f18b
+      if namerecord.attrib['nameID'] == '6':
+        if ps_name is not None:
+          if not sanitize(namerecord.text) == ps_name:
+            sys.exit('found multiple possibilities of the font name')
+        else:
+          ps_name = sanitize(namerecord.text)
+      # nameID=5 means the font version
+      if namerecord.attrib['nameID'] == '5':
+        if ps_version is not None:
+          if not ps_version == get_version(namerecord.text):
+            sys.exit('found multiple possibilities of the font version')
+        else:
+          ps_version = get_version(namerecord.text)
+  if ps_name is not None and ps_version is not None:
+    return [ps_name, ps_version]
+  sys.exit('didn\'t find the font name or version')
+
+
+def update_name(tag, name):
+  for namerecord in tag.iter('namerecord'):
+    if 'nameID' in namerecord.attrib:
+      if namerecord.attrib['nameID'] == '6':
+        namerecord.text = name
+
+def sanitize(string):
+  return re.sub(r'[^\w-]+', '', string)
+
+def get_version(string):
+  # The string must begin with "Version n.nn "
+  # to extract n.nn, we return the second entry in the split strings.
+  string = string.strip()
+  if not string.startswith("Version "):
+    sys.exit('mal-formed font version')
+  return sanitize(string.split()[1])
+
+if __name__ == '__main__':
+  main(sys.argv[1:])
diff --git a/tools/layoutlib/rename_font/test.py b/tools/layoutlib/rename_font/test.py
new file mode 100755
index 0000000..d4c86cb
--- /dev/null
+++ b/tools/layoutlib/rename_font/test.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+"""Tests build_font.py by renaming a font.
+
+The test copies Roboto-Regular.ttf to a tmp directory and ask build_font.py to rename it and put in another dir.
+We then use ttx to dump the new font to its xml and check if rename was successful
+
+To test locally, use:
+PYTHONPATH="$PYTHONPATH:/path/to/android/checkout/external/fonttools/Lib" ./test.py
+"""
+
+import unittest
+import build_font
+
+from fontTools import ttx
+import os
+from lxml import etree
+import shutil
+import tempfile
+
+class MyTest(unittest.TestCase):
+  def test(self):
+    font_name = "Roboto-Regular.ttf"
+    srcdir = tempfile.mkdtemp()
+    print "srcdir: " + srcdir
+    shutil.copy(font_name, srcdir)
+    destdir = tempfile.mkdtemp()
+    print "destdir: " + destdir
+    self.assertTrue(build_font.main([srcdir, destdir]) is None)
+    out_path = os.path.join(destdir, font_name)
+    ttx.main([out_path])
+    ttx_path = out_path[:-1] + "x"
+    tree = etree.parse(ttx_path)
+    root = tree.getroot()
+    name_tag = root.find('name')
+    [f_name, f_version] = build_font.get_font_info(name_tag)
+    shutil.rmtree(srcdir)
+    shutil.rmtree(destdir)
+    self.assertEqual(f_name, "Roboto-Regular1200310")
+
+
+
+if __name__ == '__main__':
+  unittest.main()