Merge "AudioSystem JNI: Add audio policy custom mixes registration" into lmp-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index 25b36b6..3b30bb0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -33331,6 +33331,7 @@
     method public void dispatchDisplayHint(int);
     method public boolean dispatchDragEvent(android.view.DragEvent);
     method protected void dispatchDraw(android.graphics.Canvas);
+    method public void dispatchDrawableHotspotChanged(float, float);
     method protected boolean dispatchGenericFocusedEvent(android.view.MotionEvent);
     method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
     method protected boolean dispatchGenericPointerEvent(android.view.MotionEvent);
diff --git a/core/java/android/hardware/camera2/legacy/GLThreadManager.java b/core/java/android/hardware/camera2/legacy/GLThreadManager.java
index 64c532b..b160d2a 100644
--- a/core/java/android/hardware/camera2/legacy/GLThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/GLThreadManager.java
@@ -22,6 +22,8 @@
 import android.os.Handler;
 import android.os.Message;
 import android.util.Log;
+import android.util.Pair;
+import android.util.Size;
 import android.view.Surface;
 
 import java.util.Collection;
@@ -57,11 +59,11 @@
      */
     private static class ConfigureHolder {
         public final ConditionVariable condition;
-        public final Collection<Surface> surfaces;
+        public final Collection<Pair<Surface, Size>> surfaces;
         public final CaptureCollector collector;
 
-        public ConfigureHolder(ConditionVariable condition, Collection<Surface> surfaces,
-                               CaptureCollector collector) {
+        public ConfigureHolder(ConditionVariable condition, Collection<Pair<Surface,
+                Size>> surfaces, CaptureCollector collector) {
             this.condition = condition;
             this.surfaces = surfaces;
             this.collector = collector;
@@ -202,10 +204,12 @@
      * Configure the GL renderer for the given set of output surfaces, and block until
      * this configuration has been applied.
      *
-     * @param surfaces a collection of {@link android.view.Surface}s to configure.
+     * @param surfaces a collection of pairs of {@link android.view.Surface}s and their
+     *                 corresponding sizes to configure.
      * @param collector a {@link CaptureCollector} to retrieve requests from.
      */
-    public void setConfigurationAndWait(Collection<Surface> surfaces, CaptureCollector collector) {
+    public void setConfigurationAndWait(Collection<Pair<Surface, Size>> surfaces,
+                                        CaptureCollector collector) {
         checkNotNull(collector, "collector must not be null");
         Handler handler = mGLHandlerThread.getHandler();
 
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index 3a976ba..3043d13 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -24,7 +24,6 @@
 import android.hardware.camera2.impl.CameraDeviceImpl;
 import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.ICameraDeviceCallbacks;
-import android.hardware.camera2.params.StreamConfiguration;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.utils.ArrayUtils;
 import android.hardware.camera2.utils.CameraBinderDecorator;
@@ -36,6 +35,7 @@
 import android.os.HandlerThread;
 import android.os.RemoteException;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Size;
 import android.view.Surface;
 
@@ -78,6 +78,15 @@
     private final Handler mResultHandler;
     private static final int ILLEGAL_VALUE = -1;
 
+    // Keep up to date with values in hardware/libhardware/include/hardware/gralloc.h
+    private static final int GRALLOC_USAGE_RENDERSCRIPT = 0x00100000;
+    private static final int GRALLOC_USAGE_SW_READ_OFTEN = 0x00000003;
+    private static final int GRALLOC_USAGE_HW_TEXTURE = 0x00000100;
+    private static final int GRALLOC_USAGE_HW_COMPOSER = 0x00000800;
+    private static final int GRALLOC_USAGE_HW_VIDEO_ENCODER = 0x00010000;
+
+    private static final int MAX_DIMEN_FOR_ROUNDING = 1080; // maximum allowed width for rounding
+
     private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) {
         if (holder == null) {
             return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE,
@@ -276,6 +285,7 @@
      *          on success.
      */
     public int configureOutputs(List<Surface> outputs) {
+        List<Pair<Surface, Size>> sizedSurfaces = new ArrayList<>();
         if (outputs != null) {
             for (Surface output : outputs) {
                 if (output == null) {
@@ -289,16 +299,25 @@
                 try {
                     Size s = getSurfaceSize(output);
                     int surfaceType = detectSurfaceType(output);
-                    Size[] sizes = streamConfigurations.getOutputSizes(surfaceType);
+                    int usageFlags = detectSurfaceUsageFlags(output);
 
+                    // Keep up to date with allowed consumer types in
+                    // frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+                    int disallowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_RENDERSCRIPT;
+                    int allowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_OFTEN |
+                            GRALLOC_USAGE_HW_COMPOSER;
+                    boolean flexibleConsumer = ((usageFlags & disallowedFlags) == 0 &&
+                            (usageFlags & allowedFlags) != 0);
+
+                    Size[] sizes = streamConfigurations.getOutputSizes(surfaceType);
                     if (sizes == null) {
                         // WAR: Override default format to IMPLEMENTATION_DEFINED for b/9487482
                         if ((surfaceType >= LegacyMetadataMapper.HAL_PIXEL_FORMAT_RGBA_8888 &&
                             surfaceType <= LegacyMetadataMapper.HAL_PIXEL_FORMAT_BGRA_8888)) {
 
-                            // YUV_420_888 is always present in LEGACY for all IMPLEMENTATION_DEFINED
-                            // output sizes, and is publicly visible in the API (i.e.
-                            // {@code #getOutputSizes} works here).
+                            // YUV_420_888 is always present in LEGACY for all
+                            // IMPLEMENTATION_DEFINED output sizes, and is publicly visible in the
+                            // API (i.e. {@code #getOutputSizes} works here).
                             sizes = streamConfigurations.getOutputSizes(ImageFormat.YUV_420_888);
                         } else if (surfaceType == LegacyMetadataMapper.HAL_PIXEL_FORMAT_BLOB) {
                             sizes = streamConfigurations.getOutputSizes(ImageFormat.JPEG);
@@ -306,12 +325,18 @@
                     }
 
                     if (!ArrayUtils.contains(sizes, s)) {
-                        String reason = (sizes == null) ? "format is invalid." :
-                                ("size not in valid set: " + Arrays.toString(sizes));
-                        Log.e(TAG, String.format("Surface with size (w=%d, h=%d) and format 0x%x is"
-                                + " not valid, %s", s.getWidth(), s.getHeight(), surfaceType,
-                                reason));
-                        return BAD_VALUE;
+                        if (flexibleConsumer && (s = findClosestSize(s, sizes)) != null) {
+                            sizedSurfaces.add(new Pair<>(output, s));
+                        } else {
+                            String reason = (sizes == null) ? "format is invalid." :
+                                    ("size not in valid set: " + Arrays.toString(sizes));
+                            Log.e(TAG, String.format("Surface with size (w=%d, h=%d) and format " +
+                                    "0x%x is not valid, %s", s.getWidth(), s.getHeight(),
+                                    surfaceType, reason));
+                            return BAD_VALUE;
+                        }
+                    } else {
+                        sizedSurfaces.add(new Pair<>(output, s));
                     }
                 } catch (BufferQueueAbandonedException e) {
                     Log.e(TAG, "Surface bufferqueue is abandoned, cannot configure as output: ", e);
@@ -323,7 +348,7 @@
 
         boolean success = false;
         if (mDeviceState.setConfiguring()) {
-            mRequestThreadManager.configure(outputs);
+            mRequestThreadManager.configure(sizedSurfaces);
             success = mDeviceState.setIdle();
         }
 
@@ -473,6 +498,31 @@
         }
     }
 
+    static long findEuclidDistSquare(Size a, Size b) {
+        long d0 = a.getWidth() - b.getWidth();
+        long d1 = a.getHeight() - b.getHeight();
+        return d0 * d0 + d1 * d1;
+    }
+
+    // Keep up to date with rounding behavior in
+    // frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+    static Size findClosestSize(Size size, Size[] supportedSizes) {
+        if (size == null || supportedSizes == null) {
+            return null;
+        }
+        Size bestSize = null;
+        for (Size s : supportedSizes) {
+            if (s.equals(size)) {
+                return size;
+            } else if (s.getWidth() <= MAX_DIMEN_FOR_ROUNDING && (bestSize == null ||
+                    LegacyCameraDevice.findEuclidDistSquare(size, s) <
+                    LegacyCameraDevice.findEuclidDistSquare(bestSize, s))) {
+                bestSize = s;
+            }
+        }
+        return bestSize;
+    }
+
     /**
      * Query the surface for its currently configured default buffer size.
      * @param surface a non-{@code null} {@code Surface}
@@ -490,6 +540,11 @@
         return new Size(dimens[0], dimens[1]);
     }
 
+    static int detectSurfaceUsageFlags(Surface surface) {
+        checkNotNull(surface);
+        return nativeDetectSurfaceUsageFlags(surface);
+    }
+
     static int detectSurfaceType(Surface surface) throws BufferQueueAbandonedException {
         checkNotNull(surface);
         return LegacyExceptionUtils.throwOnError(nativeDetectSurfaceType(surface));
@@ -608,5 +663,7 @@
 
     private static native int nativeSetNextTimestamp(Surface surface, long timestamp);
 
+    private static native int nativeDetectSurfaceUsageFlags(Surface surface);
+
     static native int nativeGetJpegFooterSize();
 }
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index 35deb71..6535a4e 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -41,6 +41,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
@@ -116,9 +117,10 @@
      */
     private static class ConfigureHolder {
         public final ConditionVariable condition;
-        public final Collection<Surface> surfaces;
+        public final Collection<Pair<Surface, Size>> surfaces;
 
-        public ConfigureHolder(ConditionVariable condition, Collection<Surface> surfaces) {
+        public ConfigureHolder(ConditionVariable condition, Collection<Pair<Surface,
+                Size>> surfaces) {
             this.condition = condition;
             this.surfaces = surfaces;
         }
@@ -317,7 +319,7 @@
         startPreview();
     }
 
-    private void configureOutputs(Collection<Surface> outputs) {
+    private void configureOutputs(Collection<Pair<Surface, Size>> outputs) {
         if (DEBUG) {
             String outputsStr = outputs == null ? "null" : (outputs.size() + " surfaces");
             Log.d(TAG, "configureOutputs with " + outputsStr);
@@ -346,10 +348,15 @@
         mJpegSurfaceIds.clear();
         mPreviewTexture = null;
 
+        List<Size> previewOutputSizes = new ArrayList<>();
+        List<Size> callbackOutputSizes = new ArrayList<>();
+
         int facing = mCharacteristics.get(CameraCharacteristics.LENS_FACING);
         int orientation = mCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
         if (outputs != null) {
-            for (Surface s : outputs) {
+            for (Pair<Surface, Size> outPair : outputs) {
+                Surface s = outPair.first;
+                Size outSize = outPair.second;
                 try {
                     int format = LegacyCameraDevice.detectSurfaceType(s);
                     LegacyCameraDevice.setSurfaceOrientation(s, facing, orientation);
@@ -362,9 +369,11 @@
                             }
                             mJpegSurfaceIds.add(LegacyCameraDevice.getSurfaceId(s));
                             mCallbackOutputs.add(s);
+                            callbackOutputSizes.add(outSize);
                             break;
                         default:
                             mPreviewOutputs.add(s);
+                            previewOutputSizes.add(outSize);
                             break;
                     }
                 } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
@@ -391,18 +400,9 @@
         mParams.setPreviewFpsRange(bestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
                 bestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
 
-        if (mPreviewOutputs.size() > 0) {
-            List<Size> outputSizes = new ArrayList<>(outputs.size());
-            for (Surface s : mPreviewOutputs) {
-                try {
-                    Size size = LegacyCameraDevice.getSurfaceSize(s);
-                    outputSizes.add(size);
-                } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
-                    Log.w(TAG, "Surface abandoned, skipping...", e);
-                }
-            }
+        if (previewOutputSizes.size() > 0) {
 
-            Size largestOutput = SizeAreaComparator.findLargestByArea(outputSizes);
+            Size largestOutput = SizeAreaComparator.findLargestByArea(previewOutputSizes);
 
             // Find largest jpeg dimension - assume to have the same aspect ratio as sensor.
             Size largestJpegDimen = ParameterUtils.getLargestSupportedJpegSizeByArea(mParams);
@@ -439,7 +439,8 @@
             }
         }
 
-        Size smallestSupportedJpegSize = calculatePictureSize(mCallbackOutputs, mParams);
+        Size smallestSupportedJpegSize = calculatePictureSize(mCallbackOutputs,
+                callbackOutputSizes, mParams);
         if (smallestSupportedJpegSize != null) {
             /*
              * Set takePicture size to the smallest supported JPEG size large enough
@@ -457,7 +458,12 @@
             mGLThreadManager.start();
         }
         mGLThreadManager.waitUntilStarted();
-        mGLThreadManager.setConfigurationAndWait(mPreviewOutputs, mCaptureCollector);
+        List<Pair<Surface, Size>> previews = new ArrayList<>();
+        Iterator<Size> previewSizeIter = previewOutputSizes.iterator();
+        for (Surface p : mPreviewOutputs) {
+            previews.add(new Pair<>(p, previewSizeIter.next()));
+        }
+        mGLThreadManager.setConfigurationAndWait(previews, mCaptureCollector);
         mGLThreadManager.allowNewFrames();
         mPreviewTexture = mGLThreadManager.getCurrentSurfaceTexture();
         if (mPreviewTexture != null) {
@@ -499,26 +505,25 @@
      *          {@code null} if the {@code callbackOutputs} did not have any {@code JPEG}
      *          surfaces.
      */
-    private Size calculatePictureSize(
-            Collection<Surface> callbackOutputs, Camera.Parameters params) {
+    private Size calculatePictureSize( List<Surface> callbackOutputs,
+                                       List<Size> callbackSizes, Camera.Parameters params) {
         /*
          * Find the largest JPEG size (if any), from the configured outputs:
          * - the api1 picture size should be set to the smallest legal size that's at least as large
          *   as the largest configured JPEG size
          */
-        List<Size> configuredJpegSizes = new ArrayList<Size>();
+        if (callbackOutputs.size() != callbackSizes.size()) {
+            throw new IllegalStateException("Input collections must be same length");
+        }
+        List<Size> configuredJpegSizes = new ArrayList<>();
+        Iterator<Size> sizeIterator = callbackSizes.iterator();
         for (Surface callbackSurface : callbackOutputs) {
-            try {
-
+            Size jpegSize = sizeIterator.next();
                 if (!LegacyCameraDevice.containsSurfaceId(callbackSurface, mJpegSurfaceIds)) {
                     continue; // Ignore non-JPEG callback formats
                 }
 
-                Size jpegSize = LegacyCameraDevice.getSurfaceSize(callbackSurface);
                 configuredJpegSizes.add(jpegSize);
-            } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
-                Log.w(TAG, "Surface abandoned, skipping...", e);
-            }
         }
         if (!configuredJpegSizes.isEmpty()) {
             /*
@@ -994,7 +999,7 @@
      *
      * @param outputs a {@link java.util.Collection} of outputs to configure.
      */
-    public void configure(Collection<Surface> outputs) {
+    public void configure(Collection<Pair<Surface, Size>> outputs) {
         Handler handler = mRequestThread.waitAndGetHandler();
         final ConditionVariable condition = new ConditionVariable(/*closed*/false);
         ConfigureHolder holder = new ConfigureHolder(condition, outputs);
diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
index c0d1d5e..4853b81 100644
--- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
+++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
@@ -397,16 +397,9 @@
                 EGL14.EGL_NONE
         };
         for (EGLSurfaceHolder holder : surfaces) {
-            try {
-                Size size = LegacyCameraDevice.getSurfaceSize(holder.surface);
-                holder.width = size.getWidth();
-                holder.height = size.getHeight();
-                holder.eglSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mConfigs,
-                        holder.surface, surfaceAttribs, /*offset*/ 0);
-                checkEglError("eglCreateWindowSurface");
-            } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
-                Log.w(TAG, "Surface abandoned, skipping...", e);
-            }
+            holder.eglSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mConfigs,
+                    holder.surface, surfaceAttribs, /*offset*/ 0);
+            checkEglError("eglCreateWindowSurface");
         }
     }
 
@@ -417,24 +410,17 @@
 
         int maxLength = 0;
         for (EGLSurfaceHolder holder : surfaces) {
-            try {
-                Size size = LegacyCameraDevice.getSurfaceSize(holder.surface);
-                int length = size.getWidth() * size.getHeight();
-                // Find max surface size, ensure PBuffer can hold this many pixels
-                maxLength = (length > maxLength) ? length : maxLength;
-                int[] surfaceAttribs = {
-                        EGL14.EGL_WIDTH, size.getWidth(),
-                        EGL14.EGL_HEIGHT, size.getHeight(),
-                        EGL14.EGL_NONE
-                };
-                holder.width = size.getWidth();
-                holder.height = size.getHeight();
-                holder.eglSurface =
-                        EGL14.eglCreatePbufferSurface(mEGLDisplay, mConfigs, surfaceAttribs, 0);
-                checkEglError("eglCreatePbufferSurface");
-            } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
-                Log.w(TAG, "Surface abandoned, skipping...", e);
-            }
+            int length = holder.width * holder.height;
+            // Find max surface size, ensure PBuffer can hold this many pixels
+            maxLength = (length > maxLength) ? length : maxLength;
+            int[] surfaceAttribs = {
+                    EGL14.EGL_WIDTH, holder.width,
+                    EGL14.EGL_HEIGHT, holder.height,
+                    EGL14.EGL_NONE
+            };
+            holder.eglSurface =
+                    EGL14.eglCreatePbufferSurface(mEGLDisplay, mConfigs, surfaceAttribs, 0);
+            checkEglError("eglCreatePbufferSurface");
         }
         mPBufferPixels = ByteBuffer.allocateDirect(maxLength * PBUFFER_PIXEL_BYTES)
                 .order(ByteOrder.nativeOrder());
@@ -569,7 +555,7 @@
      *
      * @param surfaces a {@link Collection} of surfaces.
      */
-    public void configureSurfaces(Collection<Surface> surfaces) {
+    public void configureSurfaces(Collection<Pair<Surface, Size>> surfaces) {
         releaseEGLContext();
 
         if (surfaces == null || surfaces.size() == 0) {
@@ -577,18 +563,20 @@
             return;
         }
 
-        for (Surface s : surfaces) {
+        for (Pair<Surface, Size> p : surfaces) {
+            Surface s = p.first;
+            Size surfaceSize = p.second;
             // If pixel conversions aren't handled by egl, use a pbuffer
             try {
+                EGLSurfaceHolder holder = new EGLSurfaceHolder();
+                holder.surface = s;
+                holder.width = surfaceSize.getWidth();
+                holder.height = surfaceSize.getHeight();
                 if (LegacyCameraDevice.needsConversion(s)) {
                     // Always override to YV12 output for YUV surface formats.
                     LegacyCameraDevice.setSurfaceFormat(s, ImageFormat.YV12);
-                    EGLSurfaceHolder holder = new EGLSurfaceHolder();
-                    holder.surface = s;
                     mConversionSurfaces.add(holder);
                 } else {
-                    EGLSurfaceHolder holder = new EGLSurfaceHolder();
-                    holder.surface = s;
                     mSurfaces.add(holder);
                 }
             } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
@@ -672,10 +660,11 @@
         List<Long> targetSurfaceIds = LegacyCameraDevice.getSurfaceIds(targetSurfaces);
         for (EGLSurfaceHolder holder : mSurfaces) {
             if (LegacyCameraDevice.containsSurfaceId(holder.surface, targetSurfaceIds)) {
-                makeCurrent(holder.eglSurface);
-                try {
+                try{
                     LegacyCameraDevice.setSurfaceDimens(holder.surface, holder.width,
                             holder.height);
+                    makeCurrent(holder.eglSurface);
+
                     LegacyCameraDevice.setNextTimestamp(holder.surface, captureHolder.second);
                     drawFrame(mSurfaceTexture, holder.width, holder.height);
                     swapBuffers(holder.eglSurface);
@@ -695,10 +684,11 @@
 
                 try {
                     int format = LegacyCameraDevice.detectSurfaceType(holder.surface);
+                    LegacyCameraDevice.setSurfaceDimens(holder.surface, holder.width,
+                            holder.height);
                     LegacyCameraDevice.setNextTimestamp(holder.surface, captureHolder.second);
                     LegacyCameraDevice.produceFrame(holder.surface, mPBufferPixels.array(),
                             holder.width, holder.height, format);
-                    swapBuffers(holder.eglSurface);
                 } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
                     Log.w(TAG, "Surface abandoned, dropping frame. ", e);
                 }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 4215f20..fa87c80 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -37,6 +37,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.provider.Settings;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -1295,9 +1296,15 @@
         if (b != null) {
             try {
                 ITelephony it = ITelephony.Stub.asInterface(b);
-                return it.getDataEnabled();
+                int subId = SubscriptionManager.getDefaultDataSubId();
+                Log.d("ConnectivityManager", "getMobileDataEnabled()+ subId=" + subId);
+                boolean retVal = it.getDataEnabled(subId);
+                Log.d("ConnectivityManager", "getMobileDataEnabled()- subId=" + subId
+                        + " retVal=" + retVal);
+                return retVal;
             } catch (RemoteException e) { }
         }
+        Log.d("ConnectivityManager", "getMobileDataEnabled()- remote exception retVal=false");
         return false;
     }
 
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 8021210..d9921a6 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -68,9 +68,6 @@
 
     boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress);
 
-    /** Policy control over specific {@link NetworkStateTracker}. */
-    void setPolicyDataEnable(int networkType, boolean enabled);
-
     int tether(String iface);
 
     int untether(String iface);
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index b7b8731..2c3881c 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -40,8 +40,12 @@
 
     /** Mark given UID as being in foreground for stats purposes. */
     void setUidForeground(int uid, boolean uidForeground);
+
+    /** Force update of ifaces. */
+    void forceUpdateIfaces();
     /** Force update of statistics. */
     void forceUpdate();
+
     /** Advise persistance threshold; may be overridden internally. */
     void advisePersistThreshold(long thresholdBytes);
 
diff --git a/core/java/android/net/LocalServerSocket.java b/core/java/android/net/LocalServerSocket.java
index a36203b..9464222 100644
--- a/core/java/android/net/LocalServerSocket.java
+++ b/core/java/android/net/LocalServerSocket.java
@@ -20,12 +20,8 @@
 import java.io.FileDescriptor;
 
 /**
- * non-standard class for creating inbound UNIX-domain socket
- * on the Android platform, this is created in the Linux non-filesystem
- * namespace.
- *
- * On simulator platforms, this may be created in a temporary directory on
- * the filesystem
+ * Non-standard class for creating an inbound UNIX-domain socket
+ * in the Linux abstract namespace.
  */
 public class LocalServerSocket {
     private final LocalSocketImpl impl;
@@ -35,7 +31,7 @@
     private static final int LISTEN_BACKLOG = 50;
 
     /**
-     * Crewates a new server socket listening at specified name.
+     * Creates a new server socket listening at specified name.
      * On the Android platform, the name is created in the Linux
      * abstract namespace (instead of on the filesystem).
      * 
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index d36707e..a9de23e 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -25,6 +25,7 @@
 import android.net.wifi.WifiManager;
 import android.os.Build;
 import android.telephony.TelephonyManager;
+import android.util.Slog;
 
 import java.util.Objects;
 
@@ -35,10 +36,16 @@
  * @hide
  */
 public class NetworkIdentity implements Comparable<NetworkIdentity> {
+    private static final String TAG = "NetworkIdentity";
+
     /**
      * When enabled, combine all {@link #mSubType} together under
      * {@link #SUBTYPE_COMBINED}.
+     *
+     * @deprecated we no longer offer to collect statistics on a per-subtype
+     *             basis; this is always disabled.
      */
+    @Deprecated
     public static final boolean COMBINE_SUBTYPE_ENABLED = true;
 
     public static final int SUBTYPE_COMBINED = -1;
@@ -133,6 +140,18 @@
     }
 
     /**
+     * Scrub given IMSI on production builds.
+     */
+    public static String[] scrubSubscriberId(String[] subscriberId) {
+        if (subscriberId == null) return null;
+        final String[] res = new String[subscriberId.length];
+        for (int i = 0; i < res.length; i++) {
+            res[i] = NetworkIdentity.scrubSubscriberId(subscriberId[i]);
+        }
+        return res;
+    }
+
+    /**
      * Build a {@link NetworkIdentity} from the given {@link NetworkState},
      * assuming that any mobile networks are using the current IMSI.
      */
@@ -140,23 +159,18 @@
         final int type = state.networkInfo.getType();
         final int subType = state.networkInfo.getSubtype();
 
-        // TODO: consider moving subscriberId over to LinkCapabilities, so it
-        // comes from an authoritative source.
-
         String subscriberId = null;
         String networkId = null;
         boolean roaming = false;
 
         if (isNetworkTypeMobile(type)) {
-            final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
-                    Context.TELEPHONY_SERVICE);
-            roaming = telephony.isNetworkRoaming();
-            if (state.subscriberId != null) {
-                subscriberId = state.subscriberId;
-            } else {
-                subscriberId = telephony.getSubscriberId();
+            if (state.subscriberId == null) {
+                Slog.w(TAG, "Active mobile network without subscriber!");
             }
 
+            subscriberId = state.subscriberId;
+            roaming = state.networkInfo.isRoaming();
+
         } else if (type == TYPE_WIFI) {
             if (state.networkId != null) {
                 networkId = state.networkId;
diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java
index 5d2a43d..b92c9e3 100644
--- a/core/java/android/net/NetworkMisc.java
+++ b/core/java/android/net/NetworkMisc.java
@@ -20,15 +20,18 @@
 import android.os.Parcelable;
 
 /**
- * A grab-bag of information (metadata, policies, properties, etc) about a {@link Network}.
+ * A grab-bag of information (metadata, policies, properties, etc) about a
+ * {@link Network}. Since this contains PII, it should not be sent outside the
+ * system.
  *
  * @hide
  */
 public class NetworkMisc implements Parcelable {
 
     /**
-     * If the {@link Network} is a VPN, whether apps are allowed to bypass the VPN. This is set by
-     * a {@link VpnService} and used by {@link ConnectivityService} when creating a VPN.
+     * If the {@link Network} is a VPN, whether apps are allowed to bypass the
+     * VPN. This is set by a {@link VpnService} and used by
+     * {@link ConnectivityManager} when creating a VPN.
      */
     public boolean allowBypass;
 
@@ -41,6 +44,11 @@
      */
     public boolean explicitlySelected;
 
+    /**
+     * For mobile networks, this is the subscriber ID (such as IMSI).
+     */
+    public String subscriberId;
+
     public NetworkMisc() {
     }
 
@@ -48,6 +56,7 @@
         if (nm != null) {
             allowBypass = nm.allowBypass;
             explicitlySelected = nm.explicitlySelected;
+            subscriberId = nm.subscriberId;
         }
     }
 
@@ -60,6 +69,7 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(allowBypass ? 1 : 0);
         out.writeInt(explicitlySelected ? 1 : 0);
+        out.writeString(subscriberId);
     }
 
     public static final Creator<NetworkMisc> CREATOR = new Creator<NetworkMisc>() {
@@ -68,6 +78,7 @@
             NetworkMisc networkMisc = new NetworkMisc();
             networkMisc.allowBypass = in.readInt() != 0;
             networkMisc.explicitlySelected = in.readInt() != 0;
+            networkMisc.subscriberId = in.readString();
             return networkMisc;
         }
 
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index 10c686b..e88bc26 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -35,7 +35,7 @@
     public static final long LIMIT_DISABLED = -1;
     public static final long SNOOZE_NEVER = -1;
 
-    public final NetworkTemplate template;
+    public NetworkTemplate template;
     public int cycleDay;
     public String cycleTimezone;
     public long warningBytes;
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index d26c70d..933287f 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -30,16 +30,10 @@
     public final LinkProperties linkProperties;
     public final NetworkCapabilities networkCapabilities;
     public final Network network;
-    /** Currently only used by testing. */
     public final String subscriberId;
     public final String networkId;
 
     public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties,
-            NetworkCapabilities networkCapabilities, Network network) {
-        this(networkInfo, linkProperties, networkCapabilities, network, null, null);
-    }
-
-    public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties,
             NetworkCapabilities networkCapabilities, Network network, String subscriberId,
             String networkId) {
         this.networkInfo = networkInfo;
@@ -85,5 +79,4 @@
             return new NetworkState[size];
         }
     };
-
 }
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index b839e0a..57eef83 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -22,7 +22,6 @@
 import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
 import static android.net.ConnectivityManager.TYPE_WIMAX;
 import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED;
-import static android.net.NetworkIdentity.scrubSubscriberId;
 import static android.net.wifi.WifiInfo.removeDoubleQuotes;
 import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
 import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
@@ -36,7 +35,9 @@
 import android.os.Parcelable;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 
+import java.util.Arrays;
 import java.util.Objects;
 
 /**
@@ -48,7 +49,9 @@
 public class NetworkTemplate implements Parcelable {
 
     public static final int MATCH_MOBILE_ALL = 1;
+    @Deprecated
     public static final int MATCH_MOBILE_3G_LOWER = 2;
+    @Deprecated
     public static final int MATCH_MOBILE_4G = 3;
     public static final int MATCH_WIFI = 4;
     public static final int MATCH_ETHERNET = 5;
@@ -146,17 +149,35 @@
 
     private final int mMatchRule;
     private final String mSubscriberId;
+
+    /**
+     * Ugh, templates are designed to target a single subscriber, but we might
+     * need to match several "merged" subscribers. These are the subscribers
+     * that should be considered to match this template.
+     * <p>
+     * Since the merge set is dynamic, it should <em>not</em> be persisted or
+     * used for determining equality.
+     */
+    private final String[] mMatchSubscriberIds;
+
     private final String mNetworkId;
 
     public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
+        this(matchRule, subscriberId, new String[] { subscriberId }, networkId);
+    }
+
+    public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
+            String networkId) {
         mMatchRule = matchRule;
         mSubscriberId = subscriberId;
+        mMatchSubscriberIds = matchSubscriberIds;
         mNetworkId = networkId;
     }
 
     private NetworkTemplate(Parcel in) {
         mMatchRule = in.readInt();
         mSubscriberId = in.readString();
+        mMatchSubscriberIds = in.createStringArray();
         mNetworkId = in.readString();
     }
 
@@ -164,6 +185,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mMatchRule);
         dest.writeString(mSubscriberId);
+        dest.writeStringArray(mMatchSubscriberIds);
         dest.writeString(mNetworkId);
     }
 
@@ -177,7 +199,12 @@
         final StringBuilder builder = new StringBuilder("NetworkTemplate: ");
         builder.append("matchRule=").append(getMatchRuleName(mMatchRule));
         if (mSubscriberId != null) {
-            builder.append(", subscriberId=").append(scrubSubscriberId(mSubscriberId));
+            builder.append(", subscriberId=").append(
+                    NetworkIdentity.scrubSubscriberId(mSubscriberId));
+        }
+        if (mMatchSubscriberIds != null) {
+            builder.append(", matchSubscriberIds=").append(
+                    Arrays.toString(NetworkIdentity.scrubSubscriberId(mMatchSubscriberIds)));
         }
         if (mNetworkId != null) {
             builder.append(", networkId=").append(mNetworkId);
@@ -201,6 +228,18 @@
         return false;
     }
 
+    public boolean isMatchRuleMobile() {
+        switch (mMatchRule) {
+            case MATCH_MOBILE_3G_LOWER:
+            case MATCH_MOBILE_4G:
+            case MATCH_MOBILE_ALL:
+            case MATCH_MOBILE_WILDCARD:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     public int getMatchRule() {
         return mMatchRule;
     }
@@ -247,14 +286,16 @@
             // TODO: consider matching against WiMAX subscriber identity
             return true;
         } else {
-            return ((sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType))
-                    && Objects.equals(mSubscriberId, ident.mSubscriberId));
+            final boolean matchesType = (sForceAllNetworkTypes
+                    || contains(DATA_USAGE_NETWORK_TYPES, ident.mType));
+            return matchesType && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
         }
     }
 
     /**
      * Check if mobile network classified 3G or lower with matching IMSI.
      */
+    @Deprecated
     private boolean matchesMobile3gLower(NetworkIdentity ident) {
         ensureSubtypeAvailable();
         if (ident.mType == TYPE_WIMAX) {
@@ -273,6 +314,7 @@
     /**
      * Check if mobile network classified 4G with matching IMSI.
      */
+    @Deprecated
     private boolean matchesMobile4g(NetworkIdentity ident) {
         ensureSubtypeAvailable();
         if (ident.mType == TYPE_WIMAX) {
@@ -368,6 +410,27 @@
         }
     }
 
+    /**
+     * Examine the given template and normalize if it refers to a "merged"
+     * mobile subscriber. We pick the "lowest" merged subscriber as the primary
+     * for key purposes, and expand the template to match all other merged
+     * subscribers.
+     * <p>
+     * For example, given an incoming template matching B, and the currently
+     * active merge set [A,B], we'd return a new template that primarily matches
+     * A, but also matches B.
+     */
+    public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) {
+        if (template.isMatchRuleMobile() && ArrayUtils.contains(merged, template.mSubscriberId)) {
+            // Requested template subscriber is part of the merge group; return
+            // a template that matches all merged subscribers.
+            return new NetworkTemplate(template.mMatchRule, merged[0], merged,
+                    template.mNetworkId);
+        } else {
+            return template;
+        }
+    }
+
     public static final Creator<NetworkTemplate> CREATOR = new Creator<NetworkTemplate>() {
         @Override
         public NetworkTemplate createFromParcel(Parcel in) {
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 3f42d25..a9deaf3 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -168,7 +168,7 @@
         public static final int NUM_OTHER_STATS = 17;
 
         /** @hide */
-        public static final int NUM_DVK_STATS = 5;
+        public static final int NUM_DVK_STATS = 8;
 
         /** @hide */
         public static final int NUM_CATEGORIES = 7;
@@ -314,6 +314,9 @@
                 case 19: return ".LinearAlloc";
                 case 20: return ".GC";
                 case 21: return ".JITCache";
+                case 22: return ".Zygote";
+                case 23: return ".NonMoving";
+                case 24: return ".IndirectRef";
                 default: return "????";
             }
         }
@@ -1071,9 +1074,10 @@
     /**
      * Retrieves the PSS memory used by the process as given by the
      * smaps.  Optionally supply a long array of 1 entry to also
-     * receive the uss of the process.  @hide
+     * receive the uss of the process, and another array to also
+     * retrieve the separate memtrack size.  @hide
      */
-    public static native long getPss(int pid, long[] outUss);
+    public static native long getPss(int pid, long[] outUss, long[] outMemtrack);
 
     /** @hide */
     public static final int MEMINFO_TOTAL = 0;
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 67f632f..9496b53 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -691,8 +691,8 @@
                     if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
                             + ", frame=" + mWinFrame);
                     
-                    int w = mWinFrame.width() + mOverscanInsets.left + mOverscanInsets.right;
-                    int h = mWinFrame.height() + mOverscanInsets.top + mOverscanInsets.bottom;
+                    int w = mWinFrame.width();
+                    int h = mWinFrame.height();
 
                     if (!fixedSize) {
                         final Rect padding = mIWallpaperEngine.mDisplayPadding;
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index 7feca30..7b35a3b 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -148,6 +148,10 @@
         if (mState != STATE_PREPARE) {
             throw new IllegalStateException("Animator has already started, cannot change it now!");
         }
+        if (mNativePtr == null) {
+            throw new IllegalStateException("Animator's target has been destroyed "
+                    + "(trying to modify an animation after activity destroy?)");
+        }
     }
 
     static boolean isNativeInterpolator(TimeInterpolator interpolator) {
@@ -180,7 +184,10 @@
         mState = STATE_DELAYED;
         applyInterpolator();
 
-        if (mStartDelay <= 0 || !mUiThreadHandlesDelay) {
+        if (mNativePtr == null) {
+            // It's dead, immediately cancel
+            cancel();
+        } else if (mStartDelay <= 0 || !mUiThreadHandlesDelay) {
             nSetStartDelay(mNativePtr.get(), mStartDelay);
             doStart();
         } else {
@@ -208,7 +215,9 @@
 
     private void moveToRunningState() {
         mState = STATE_RUNNING;
-        nStart(mNativePtr.get(), this);
+        if (mNativePtr != null) {
+            nStart(mNativePtr.get());
+        }
         notifyStartListeners();
     }
 
@@ -227,7 +236,6 @@
                 getHelper().removeDelayedAnimation(this);
                 moveToRunningState();
             }
-            nEnd(mNativePtr.get());
 
             final ArrayList<AnimatorListener> listeners = cloneListeners();
             final int numListeners = listeners == null ? 0 : listeners.size();
@@ -235,10 +243,7 @@
                 listeners.get(i).onAnimationCancel(this);
             }
 
-            if (mViewTarget != null) {
-                // Kick off a frame to flush the state change
-                mViewTarget.invalidateViewProperty(true, false);
-            }
+            end();
         }
     }
 
@@ -249,10 +254,15 @@
                 getHelper().removeDelayedAnimation(this);
                 doStart();
             }
-            nEnd(mNativePtr.get());
-            if (mViewTarget != null) {
-                // Kick off a frame to flush the state change
-                mViewTarget.invalidateViewProperty(true, false);
+            if (mNativePtr != null) {
+                nEnd(mNativePtr.get());
+                if (mViewTarget != null) {
+                    // Kick off a frame to flush the state change
+                    mViewTarget.invalidateViewProperty(true, false);
+                }
+            } else {
+                // It's already dead, jump to onFinish
+                onFinished();
             }
         }
     }
@@ -281,9 +291,11 @@
     }
 
     private void setTarget(RenderNode node) {
+        checkMutable();
         if (mTarget != null) {
             throw new IllegalStateException("Target already set!");
         }
+        nSetListener(mNativePtr.get(), this);
         mTarget = node;
         mTarget.addAnimator(this);
     }
@@ -346,6 +358,12 @@
     }
 
     protected void onFinished() {
+        if (mState == STATE_PREPARE) {
+            // Unlikely but possible, the native side has been destroyed
+            // before we have started.
+            releaseNativePtr();
+            return;
+        }
         if (mState == STATE_DELAYED) {
             getHelper().removeDelayedAnimation(this);
             notifyStartListeners();
@@ -361,8 +379,14 @@
         // Release the native object, as it has a global reference to us. This
         // breaks the cyclic reference chain, and allows this object to be
         // GC'd
-        mNativePtr.release();
-        mNativePtr = null;
+        releaseNativePtr();
+    }
+
+    private void releaseNativePtr() {
+        if (mNativePtr != null) {
+            mNativePtr.release();
+            mNativePtr = null;
+        }
     }
 
     @SuppressWarnings("unchecked")
@@ -484,7 +508,8 @@
     private static native void nSetStartDelay(long nativePtr, long startDelay);
     private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
     private static native void nSetAllowRunningAsync(long animPtr, boolean mayRunAsync);
+    private static native void nSetListener(long animPtr, RenderNodeAnimator listener);
 
-    private static native void nStart(long animPtr, RenderNodeAnimator finishListener);
+    private static native void nStart(long animPtr);
     private static native void nEnd(long animPtr);
 }
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 14b950f..ad4a048 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -37,6 +37,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.HashSet;
 
 /**
@@ -465,11 +466,13 @@
             final LongSparseArray<Drawable.ConstantState> drawables = resources.getPreloadedDrawables();
 
             final int count = drawables.size();
+            ArrayList<Bitmap> tmpList = new ArrayList<Bitmap>();
             for (int i = 0; i < count; i++) {
-                final Bitmap bitmap = drawables.valueAt(i).getBitmap();
-                if (bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888) {
-                    preloadedPointers.add(bitmap.mNativeBitmap);
+                drawables.valueAt(i).addAtlasableBitmaps(tmpList);
+                for (int j = 0; j < tmpList.size(); j++) {
+                    preloadedPointers.add(tmpList.get(j).mNativeBitmap);
                 }
+                tmpList.clear();
             }
 
             for (int i = 0; i < map.length; i += 4) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index b54d462..2bb1ebc 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5938,9 +5938,12 @@
      * layer.
      *
      * @param outRects List to which to add clickable areas.
+     *
+     * @hide
      */
-    void addClickableRectsForAccessibility(List<RectF> outRects) {
-        if (isClickable() || isLongClickable()) {
+    public void addClickableRectsForAccessibility(List<RectF> outRects) {
+        if (isClickable() || isLongClickable()
+                || (mListenerInfo != null && mListenerInfo.mOnTouchListener != null)) {
             RectF bounds = new RectF();
             bounds.set(0, 0, getWidth(), getHeight());
             outRects.add(bounds);
@@ -16059,7 +16062,10 @@
 
     /**
      * This function is called whenever the view hotspot changes and needs to
-     * be propagated to drawables managed by the view.
+     * be propagated to drawables or child views managed by the view.
+     * <p>
+     * Dispatching to child views is handled by
+     * {@link #dispatchDrawableHotspotChanged(float, float)}.
      * <p>
      * Be sure to call through to the superclass when overriding this function.
      *
@@ -16070,6 +16076,18 @@
         if (mBackground != null) {
             mBackground.setHotspot(x, y);
         }
+
+        dispatchDrawableHotspotChanged(x, y);
+    }
+
+    /**
+     * Dispatches drawableHotspotChanged to all of this View's children.
+     *
+     * @param x hotspot x coordinate
+     * @param y hotspot y coordinate
+     * @see #drawableHotspotChanged(float, float)
+     */
+    public void dispatchDrawableHotspotChanged(float x, float y) {
     }
 
     /**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 1551504..25a70eb 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -161,6 +161,9 @@
     // Used during drag dispatch
     private PointF mLocalPoint;
 
+    // Lazily-created holder for point computations.
+    private float[] mTempPoint;
+
     // Layout animation
     private LayoutAnimationController mLayoutAnimationController;
     private Animation.AnimationListener mAnimationListener;
@@ -880,8 +883,11 @@
         return true;
     }
 
+    /**
+     * @hide
+     */
     @Override
-    void addClickableRectsForAccessibility(List<RectF> outRects) {
+    public void addClickableRectsForAccessibility(List<RectF> outRects) {
         int sizeBefore = outRects.size();
 
         super.addClickableRectsForAccessibility(outRects);
@@ -2442,6 +2448,13 @@
                 || child.getAnimation() != null;
     }
 
+    private float[] getTempPoint() {
+        if (mTempPoint == null) {
+            mTempPoint = new float[2];
+        }
+        return mTempPoint;
+    }
+
     /**
      * Returns true if a child view contains the specified point when transformed
      * into its coordinate space.
@@ -2450,24 +2463,30 @@
      */
     protected boolean isTransformedTouchPointInView(float x, float y, View child,
             PointF outLocalPoint) {
-        float localX = x + mScrollX - child.mLeft;
-        float localY = y + mScrollY - child.mTop;
-        if (! child.hasIdentityMatrix() && mAttachInfo != null) {
-            final float[] localXY = mAttachInfo.mTmpTransformLocation;
-            localXY[0] = localX;
-            localXY[1] = localY;
-            child.getInverseMatrix().mapPoints(localXY);
-            localX = localXY[0];
-            localY = localXY[1];
-        }
-        final boolean isInView = child.pointInView(localX, localY);
+        final float[] point = getTempPoint();
+        point[0] = x;
+        point[1] = y;
+        transformPointToViewLocal(point, child);
+        final boolean isInView = child.pointInView(point[0], point[1]);
         if (isInView && outLocalPoint != null) {
-            outLocalPoint.set(localX, localY);
+            outLocalPoint.set(point[0], point[1]);
         }
         return isInView;
     }
 
     /**
+     * @hide
+     */
+    public void transformPointToViewLocal(float[] point, View child) {
+        point[0] += mScrollX - child.mLeft;
+        point[1] += mScrollY - child.mTop;
+
+        if (!child.hasIdentityMatrix()) {
+            child.getInverseMatrix().mapPoints(point);
+        }
+    }
+
+    /**
      * Transforms a motion event into the coordinate space of a particular child view,
      * filters out irrelevant pointer ids, and overrides its action if necessary.
      * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
@@ -3606,6 +3625,44 @@
         }
     }
 
+    /**
+     * Dispatches drawable hotspot changes to child views that meet at least
+     * one of the following criteria:
+     * <ul>
+     *     <li>Returns {@code false} from both {@link View#isClickable()} and
+     *     {@link View#isLongClickable()}</li>
+     *     <li>Requests duplication of parent state via
+     *     {@link View#setDuplicateParentStateEnabled(boolean)}</li>
+     * </ul>
+     *
+     * @param x hotspot x coordinate
+     * @param y hotspot y coordinate
+     * @see #drawableHotspotChanged(float, float)
+     */
+    @Override
+    public void dispatchDrawableHotspotChanged(float x, float y) {
+        final int count = mChildrenCount;
+        if (count == 0) {
+            return;
+        }
+
+        final View[] children = mChildren;
+        for (int i = 0; i < count; i++) {
+            final View child = children[i];
+            // Children that are clickable on their own should not
+            // receive hotspots when their parent view does.
+            final boolean nonActionable = !child.isClickable() && !child.isLongClickable();
+            final boolean duplicatesState = (child.mViewFlags & DUPLICATE_PARENT_STATE) != 0;
+            if (nonActionable || duplicatesState) {
+                final float[] point = getTempPoint();
+                point[0] = x;
+                point[1] = y;
+                transformPointToViewLocal(point, child);
+                child.drawableHotspotChanged(point[0], point[1]);
+            }
+        }
+    }
+
     @Override
     void dispatchCancelPendingInputEvents() {
         super.dispatchCancelPendingInputEvents();
@@ -5961,28 +6018,6 @@
     }
 
     @Override
-    public void drawableHotspotChanged(float x, float y) {
-        super.drawableHotspotChanged(x, y);
-
-        if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
-            if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
-                throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
-                        + " child has duplicateParentState set to true");
-            }
-
-            final View[] children = mChildren;
-            final int count = mChildrenCount;
-
-            for (int i = 0; i < count; i++) {
-                final View child = children[i];
-                if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
-                    child.drawableHotspotChanged(x, y);
-                }
-            }
-        }
-    }
-
-    @Override
     protected int[] onCreateDrawableState(int extraSpace) {
         if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
             return super.onCreateDrawableState(extraSpace);
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index a218e4d..52912b1 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -78,6 +78,7 @@
                 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED:
                 case AccessibilityEvent.TYPE_VIEW_SELECTED:
                 case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
+                case AccessibilityEvent.TYPE_VIEW_CLICKED:
                 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: {
                     refreshCachedNodeLocked(event.getWindowId(), event.getSourceNodeId());
                 } break;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 6927660..d80ad6a 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.TransitionDrawable;
@@ -611,6 +612,8 @@
     private final int[] mScrollOffset = new int[2];
     private final int[] mScrollConsumed = new int[2];
 
+    private final float[] mTmpPoint = new float[2];
+
     // Used for offsetting MotionEvents that we feed to the VelocityTracker.
     // In the future it would be nice to be able to give this to the VelocityTracker
     // directly, or alternatively put a VT into absolute-positioning mode that only
@@ -2509,38 +2512,29 @@
      * Positions the selector in a way that mimics touch.
      */
     void positionSelectorLikeTouch(int position, View sel, float x, float y) {
-        positionSelectorLikeFocus(position, sel);
-
-        if (mSelector != null && position != INVALID_POSITION) {
-            mSelector.setHotspot(x, y);
-        }
+        positionSelector(position, sel, true, x, y);
     }
 
     /**
      * Positions the selector in a way that mimics keyboard focus.
      */
     void positionSelectorLikeFocus(int position, View sel) {
-        // If we're changing position, update the visibility since the selector
-        // is technically being detached from the previous selection.
-        final Drawable selector = mSelector;
-        final boolean manageState = selector != null && mSelectorPosition != position
-                && position != INVALID_POSITION;
-        if (manageState) {
-            selector.setVisible(false, false);
-        }
-
-        positionSelector(position, sel);
-
-        if (manageState) {
+        if (mSelector != null && mSelectorPosition != position && position != INVALID_POSITION) {
             final Rect bounds = mSelectorRect;
             final float x = bounds.exactCenterX();
             final float y = bounds.exactCenterY();
-            selector.setVisible(getVisibility() == VISIBLE, false);
-            selector.setHotspot(x, y);
+            positionSelector(position, sel, true, x, y);
+        } else {
+            positionSelector(position, sel);
         }
     }
 
     void positionSelector(int position, View sel) {
+        positionSelector(position, sel, false, -1, -1);
+    }
+
+    private void positionSelector(int position, View sel, boolean manageHotspot, float x, float y) {
+        final boolean positionChanged = position != mSelectorPosition;
         if (position != INVALID_POSITION) {
             mSelectorPosition = position;
         }
@@ -2560,7 +2554,22 @@
         // Update the selector drawable.
         final Drawable selector = mSelector;
         if (selector != null) {
+            if (positionChanged) {
+                // Wipe out the current selector state so that we can start
+                // over in the new position with a fresh state.
+                selector.setVisible(false, false);
+                selector.setState(StateSet.NOTHING);
+            }
             selector.setBounds(selectorRect);
+            if (positionChanged) {
+                if (getVisibility() == VISIBLE) {
+                    selector.setVisible(true, false);
+                }
+                selector.setState(getDrawableState());
+            }
+            if (manageHotspot) {
+                selector.setHotspot(x, y);
+            }
         }
 
         final boolean isChildViewEnabled = mIsChildViewEnabled;
@@ -3198,6 +3207,12 @@
         // get the selector in the right state, but we don't want to press each child.
     }
 
+    @Override
+    public void dispatchDrawableHotspotChanged(float x, float y) {
+        // Don't dispatch hotspot changes to children. We'll manually handle
+        // calling drawableHotspotChanged on the correct child.
+    }
+
     /**
      * Maps a point to a position in the list.
      *
@@ -3256,6 +3271,11 @@
                     mLayoutMode = LAYOUT_NORMAL;
 
                     if (!mDataChanged) {
+                        final float[] point = mTmpPoint;
+                        point[0] = x;
+                        point[1] = y;
+                        transformPointToViewLocal(point, child);
+                        child.drawableHotspotChanged(point[0], point[1]);
                         child.setPressed(true);
                         setPressed(true);
                         layoutChildren();
@@ -3756,10 +3776,10 @@
                 }
                 // Otherwise, check containment within list bounds. If we're
                 // outside bounds, cancel any active presses.
+                final View motionView = getChildAt(mMotionPosition - mFirstPosition);
                 final float x = ev.getX(pointerIndex);
                 if (!pointInView(x, y, mTouchSlop)) {
                     setPressed(false);
-                    final View motionView = getChildAt(mMotionPosition - mFirstPosition);
                     if (motionView != null) {
                         motionView.setPressed(false);
                     }
@@ -3767,6 +3787,13 @@
                             mPendingCheckForTap : mPendingCheckForLongPress);
                     mTouchMode = TOUCH_MODE_DONE_WAITING;
                     updateSelectorState();
+                } else if (motionView != null) {
+                    // Still within bounds, update the hotspot.
+                    final float[] point = mTmpPoint;
+                    point[0] = x;
+                    point[1] = y;
+                    transformPointToViewLocal(point, motionView);
+                    motionView.drawableHotspotChanged(point[0], point[1]);
                 }
                 break;
             case TOUCH_MODE_SCROLL:
@@ -6416,6 +6443,8 @@
                     // Note:  We do place AdapterView.ITEM_VIEW_TYPE_IGNORE in active views.
                     //        However, we will NOT place them into scrap views.
                     activeViews[i] = child;
+                    // Remember the position so that setupChild() doesn't reset state.
+                    lp.scrappedFromPosition = firstActivePosition + i;
                 }
             }
         }
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 0c65c50..371b480 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -20,6 +20,7 @@
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -757,10 +758,22 @@
         } else {
             super.scrollTo(scrollX, scrollY);
         }
-        
+
         awakenScrollBars();
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public void addClickableRectsForAccessibility(List<RectF> outRects) {
+        // This class always consumes touch events, therefore if it
+        // covers a view we do not want to send a click over it.
+        RectF bounds = new RectF();
+        bounds.set(0, 0, getWidth(), getHeight());
+        outRects.add(bounds);
+    }
+
     @Override
     public boolean performAccessibilityAction(int action, Bundle arguments) {
         if (super.performAccessibilityAction(action, arguments)) {
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index a31d37e..fe8b08b 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -1385,7 +1385,9 @@
             clearCallbacks();
 
             final View src = mSrc;
-            if (!src.isEnabled()) {
+            if (!src.isEnabled() || src.isLongClickable()) {
+                // Ignore long-press if the view is disabled or has its own
+                // handler.
                 return;
             }
 
@@ -1394,12 +1396,12 @@
             }
 
             // Don't let the parent intercept our events.
-            mSrc.getParent().requestDisallowInterceptTouchEvent(true);
+            src.getParent().requestDisallowInterceptTouchEvent(true);
 
             // Make sure we cancel any ongoing source event stream.
             final long now = SystemClock.uptimeMillis();
             final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0);
-            mSrc.onTouchEvent(e);
+            src.onTouchEvent(e);
             e.recycle();
 
             mForwarding = true;
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index 04b5616..75c6184 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -1246,37 +1246,40 @@
         }
 
         final int[] selectionDegrees = mSelectionDegrees;
-        int type = -1;
-        int newValue = -1;
+        final int type;
+        final int newValue;
+        final boolean valueChanged;
 
         if (mShowHours) {
             final int snapDegrees = snapOnly30s(degrees, 0) % 360;
-            if (forceSelection
-                    || selectionDegrees[HOURS] != snapDegrees
+            valueChanged = selectionDegrees[HOURS] != snapDegrees
                     || selectionDegrees[HOURS_INNER] != snapDegrees
-                    || wasOnInnerCircle != mIsOnInnerCircle) {
-                selectionDegrees[HOURS] = snapDegrees;
-                selectionDegrees[HOURS_INNER] = snapDegrees;
+                    || wasOnInnerCircle != mIsOnInnerCircle;
 
-                type = HOURS;
-                newValue = getCurrentHour();
-            }
+            selectionDegrees[HOURS] = snapDegrees;
+            selectionDegrees[HOURS_INNER] = snapDegrees;
+            type = HOURS;
+            newValue = getCurrentHour();
         } else {
             final int snapDegrees = snapPrefer30s(degrees) % 360;
-            if (forceSelection || selectionDegrees[MINUTES] != snapDegrees) {
-                selectionDegrees[MINUTES] = snapDegrees;
+            valueChanged = selectionDegrees[MINUTES] != snapDegrees;
 
-                type = MINUTES;
-                newValue = getCurrentMinute();
-            }
+            selectionDegrees[MINUTES] = snapDegrees;
+            type = MINUTES;
+            newValue = getCurrentMinute();
         }
 
-        if (newValue != -1) {
+        if (valueChanged || forceSelection || autoAdvance) {
+            // Fire the listener even if we just need to auto-advance.
             if (mListener != null) {
                 mListener.onValueSelected(type, newValue, autoAdvance);
             }
-            performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
-            invalidate();
+
+            // Only provide feedback if the value actually changed.
+            if (valueChanged || forceSelection) {
+                performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
+                invalidate();
+            }
             return true;
         }
 
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 4c8aa51..7a22224 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -689,6 +689,10 @@
      * @return true if (x, y) is within the target area of the switch thumb
      */
     private boolean hitThumb(float x, float y) {
+        if (mThumbDrawable == null) {
+            return false;
+        }
+
         // Relies on mTempRect, MUST be called first!
         final int thumbOffset = getThumbOffset();
 
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 8e786da..f908fcb 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -128,6 +128,20 @@
     }
 
     /**
+     * Checks if given array is null or has zero elements.
+     */
+    public static boolean isEmpty(int[] array) {
+        return array == null || array.length == 0;
+    }
+
+    /**
+     * Checks if given array is null or has zero elements.
+     */
+    public static boolean isEmpty(long[] array) {
+        return array == null || array.length == 0;
+    }
+
+    /**
      * Checks that value is present as at least one of the elements of the array.
      * @param array the array to check in
      * @param value the value to check for
@@ -157,6 +171,7 @@
      * Test if all {@code check} items are contained in {@code array}.
      */
     public static <T> boolean containsAll(T[] array, T[] check) {
+        if (check == null) return true;
         for (T checkItem : check) {
             if (!contains(array, checkItem)) {
                 return false;
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index 8440a0e..b44c829 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -470,6 +470,26 @@
     return NO_ERROR;
 }
 
+static jint LegacyCameraDevice_nativeDetectSurfaceUsageFlags(JNIEnv* env, jobject thiz,
+          jobject surface) {
+    ALOGV("nativeDetectSurfaceUsageFlags");
+
+    sp<ANativeWindow> anw;
+    if ((anw = getNativeWindow(env, surface)) == NULL) {
+        jniThrowException(env, "Ljava/lang/UnsupportedOperationException;",
+            "Could not retrieve native window from surface.");
+        return BAD_VALUE;
+    }
+    int32_t usage = 0;
+    status_t err = anw->query(anw.get(), NATIVE_WINDOW_CONSUMER_USAGE_BITS, &usage);
+    if(err != NO_ERROR) {
+        jniThrowException(env, "Ljava/lang/UnsupportedOperationException;",
+            "Error while querying surface usage bits");
+        return err;
+    }
+    return usage;
+}
+
 static jint LegacyCameraDevice_nativeDetectTextureDimens(JNIEnv* env, jobject thiz,
         jobject surfaceTexture, jintArray dimens) {
     ALOGV("nativeDetectTextureDimens");
@@ -713,6 +733,9 @@
     { "nativeGetJpegFooterSize",
     "()I",
     (void *)LegacyCameraDevice_nativeGetJpegFooterSize },
+    { "nativeDetectSurfaceUsageFlags",
+    "(Landroid/view/Surface;)I",
+    (void *)LegacyCameraDevice_nativeDetectSurfaceUsageFlags },
 };
 
 // Get all the required offsets in java class and register native functions
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index e572d22..5a32718 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -70,6 +70,9 @@
     HEAP_DALVIK_LINEARALLOC,
     HEAP_DALVIK_ACCOUNTING,
     HEAP_DALVIK_CODE_CACHE,
+    HEAP_DALVIK_ZYGOTE,
+    HEAP_DALVIK_NON_MOVING,
+    HEAP_DALVIK_INDIRECT_REFERENCE_TABLE,
 
     _NUM_HEAP,
     _NUM_EXCLUSIVE_HEAP = HEAP_OTHER_MEMTRACK+1,
@@ -274,15 +277,21 @@
                     if (strstr(name, "/dev/ashmem/dalvik-LinearAlloc") == name) {
                         subHeap = HEAP_DALVIK_LINEARALLOC;
                     } else if ((strstr(name, "/dev/ashmem/dalvik-alloc space") == name) ||
-                               (strstr(name, "/dev/ashmem/dalvik-main space") == name) ||
-                               (strstr(name, "/dev/ashmem/dalvik-zygote space") == name) ||
-                               (strstr(name, "/dev/ashmem/dalvik-non moving space") == name)) {
+                               (strstr(name, "/dev/ashmem/dalvik-main space") == name)) {
                         // This is the regular Dalvik heap.
                         whichHeap = HEAP_DALVIK;
                         subHeap = HEAP_DALVIK_NORMAL;
                     } else if (strstr(name, "/dev/ashmem/dalvik-large object space") == name) {
                         whichHeap = HEAP_DALVIK;
                         subHeap = HEAP_DALVIK_LARGE;
+                    } else if (strstr(name, "/dev/ashmem/dalvik-non moving space") == name) {
+                        whichHeap = HEAP_DALVIK;
+                        subHeap = HEAP_DALVIK_NON_MOVING;
+                    } else if (strstr(name, "/dev/ashmem/dalvik-zygote space") == name) {
+                        whichHeap = HEAP_DALVIK;
+                        subHeap = HEAP_DALVIK_ZYGOTE;
+                    } else if (strstr(name, "/dev/ashmem/dalvik-indirect ref") == name) {
+                        subHeap = HEAP_DALVIK_INDIRECT_REFERENCE_TABLE;
                     } else if (strstr(name, "/dev/ashmem/dalvik-jit-code-cache") == name) {
                         subHeap = HEAP_DALVIK_CODE_CACHE;
                     } else {
@@ -486,11 +495,13 @@
     android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object);
 }
 
-static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid, jlongArray outUss)
+static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid, jlongArray outUss,
+        jlongArray outMemtrack)
 {
     char line[1024];
     jlong pss = 0;
     jlong uss = 0;
+    jlong memtrack = 0;
     unsigned temp;
 
     char tmp[128];
@@ -498,7 +509,7 @@
 
     struct graphics_memory_pss graphics_mem;
     if (read_memtrack_memory(pid, &graphics_mem) == 0) {
-        pss = uss = graphics_mem.graphics + graphics_mem.gl + graphics_mem.other;
+        pss = uss = memtrack = graphics_mem.graphics + graphics_mem.gl + graphics_mem.other;
     }
 
     sprintf(tmp, "/proc/%d/smaps", pid);
@@ -541,12 +552,22 @@
         }
     }
 
+    if (outMemtrack != NULL) {
+        if (env->GetArrayLength(outMemtrack) >= 1) {
+            jlong* outMemtrackArray = env->GetLongArrayElements(outMemtrack, 0);
+            if (outMemtrackArray != NULL) {
+                outMemtrackArray[0] = memtrack;
+            }
+            env->ReleaseLongArrayElements(outMemtrack, outMemtrackArray, 0);
+        }
+    }
+
     return pss;
 }
 
 static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz)
 {
-    return android_os_Debug_getPssPid(env, clazz, getpid(), NULL);
+    return android_os_Debug_getPssPid(env, clazz, getpid(), NULL, NULL);
 }
 
 enum {
@@ -954,7 +975,7 @@
             (void*) android_os_Debug_getDirtyPagesPid },
     { "getPss",                 "()J",
             (void*) android_os_Debug_getPss },
-    { "getPss",                 "(I[J)J",
+    { "getPss",                 "(I[J[J)J",
             (void*) android_os_Debug_getPssPid },
     { "getMemInfo",             "([J)V",
             (void*) android_os_Debug_getMemInfo },
diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp
index 311882d..eb56639 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -177,9 +177,13 @@
     animator->setAllowRunningAsync(mayRunAsync);
 }
 
-static void start(JNIEnv* env, jobject clazz, jlong animatorPtr, jobject finishListener) {
+static void setListener(JNIEnv* env, jobject clazz, jlong animatorPtr, jobject finishListener) {
     BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
     animator->setListener(new AnimationListenerBridge(env, finishListener));
+}
+
+static void start(JNIEnv* env, jobject clazz, jlong animatorPtr) {
+    BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
     animator->start();
 }
 
@@ -208,7 +212,8 @@
     { "nSetStartDelay", "(JJ)V", (void*) setStartDelay },
     { "nSetInterpolator", "(JJ)V", (void*) setInterpolator },
     { "nSetAllowRunningAsync", "(JZ)V", (void*) setAllowRunningAsync },
-    { "nStart", "(JLandroid/view/RenderNodeAnimator;)V", (void*) start },
+    { "nSetListener", "(JLandroid/view/RenderNodeAnimator;)V", (void*) setListener},
+    { "nStart", "(J)V", (void*) start},
     { "nEnd", "(J)V", (void*) end },
 #endif
 };
diff --git a/core/res/res/drawable-hdpi/textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/textfield_activated_mtrl_alpha.9.png
index b9a81be..9501e7c 100644
--- a/core/res/res/drawable-hdpi/textfield_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-hdpi/textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/textfield_default_mtrl_alpha.9.png
index 3682629..de5572d 100644
--- a/core/res/res/drawable-hdpi/textfield_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-hdpi/textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ab_solid_shadow_mtrl.9.png b/core/res/res/drawable-ldpi/ab_solid_shadow_mtrl.9.png
deleted file mode 100644
index 098a315..0000000
--- a/core/res/res/drawable-ldpi/ab_solid_shadow_mtrl.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ab_transparent_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/ab_transparent_mtrl_alpha.9.png
deleted file mode 100644
index 4d4cb4f..0000000
--- a/core/res/res/drawable-ldpi/ab_transparent_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/btn_check_off_mtrl_alpha.png b/core/res/res/drawable-ldpi/btn_check_off_mtrl_alpha.png
deleted file mode 100644
index fbe176f..0000000
--- a/core/res/res/drawable-ldpi/btn_check_off_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/btn_check_on_mtrl_alpha.png b/core/res/res/drawable-ldpi/btn_check_on_mtrl_alpha.png
deleted file mode 100644
index 5fd18e5..0000000
--- a/core/res/res/drawable-ldpi/btn_check_on_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/btn_radio_off_mtrl_alpha.png b/core/res/res/drawable-ldpi/btn_radio_off_mtrl_alpha.png
deleted file mode 100644
index d17081f..0000000
--- a/core/res/res/drawable-ldpi/btn_radio_off_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/btn_radio_off_pressed_mtrl_alpha.png b/core/res/res/drawable-ldpi/btn_radio_off_pressed_mtrl_alpha.png
deleted file mode 100644
index ac27576..0000000
--- a/core/res/res/drawable-ldpi/btn_radio_off_pressed_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/btn_radio_on_mtrl_alpha.png b/core/res/res/drawable-ldpi/btn_radio_on_mtrl_alpha.png
deleted file mode 100644
index f31d37f..0000000
--- a/core/res/res/drawable-ldpi/btn_radio_on_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/btn_radio_on_pressed_mtrl_alpha.png b/core/res/res/drawable-ldpi/btn_radio_on_pressed_mtrl_alpha.png
deleted file mode 100644
index 458abaf..0000000
--- a/core/res/res/drawable-ldpi/btn_radio_on_pressed_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/btn_star_mtrl_alpha.png b/core/res/res/drawable-ldpi/btn_star_mtrl_alpha.png
deleted file mode 100644
index ae665fd..0000000
--- a/core/res/res/drawable-ldpi/btn_star_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/expander_close_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/expander_close_mtrl_alpha.9.png
deleted file mode 100644
index 19ac6f5..0000000
--- a/core/res/res/drawable-ldpi/expander_close_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/expander_open_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/expander_open_mtrl_alpha.9.png
deleted file mode 100644
index e51f018..0000000
--- a/core/res/res/drawable-ldpi/expander_open_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_cab_done_mtrl_alpha.png b/core/res/res/drawable-ldpi/ic_cab_done_mtrl_alpha.png
deleted file mode 100644
index 8ee0546..0000000
--- a/core/res/res/drawable-ldpi/ic_cab_done_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_find_next_mtrl_alpha.png b/core/res/res/drawable-ldpi/ic_find_next_mtrl_alpha.png
deleted file mode 100644
index dd6fe20..0000000
--- a/core/res/res/drawable-ldpi/ic_find_next_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_find_previous_mtrl_alpha.png b/core/res/res/drawable-ldpi/ic_find_previous_mtrl_alpha.png
deleted file mode 100644
index d4598ba..0000000
--- a/core/res/res/drawable-ldpi/ic_find_previous_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_menu_find_mtrl_alpha.png b/core/res/res/drawable-ldpi/ic_menu_find_mtrl_alpha.png
deleted file mode 100644
index c828577..0000000
--- a/core/res/res/drawable-ldpi/ic_menu_find_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_menu_search_mtrl_alpha.png b/core/res/res/drawable-ldpi/ic_menu_search_mtrl_alpha.png
deleted file mode 100644
index ec759fb..0000000
--- a/core/res/res/drawable-ldpi/ic_menu_search_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/list_divider_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/list_divider_mtrl_alpha.9.png
deleted file mode 100644
index 941d0d7..0000000
--- a/core/res/res/drawable-ldpi/list_divider_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/list_section_divider_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/list_section_divider_mtrl_alpha.9.png
deleted file mode 100644
index f1a0362..0000000
--- a/core/res/res/drawable-ldpi/list_section_divider_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/progress_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/progress_mtrl_alpha.9.png
deleted file mode 100644
index cd39bb4..0000000
--- a/core/res/res/drawable-ldpi/progress_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/scrubber_control_off_mtrl_alpha.png b/core/res/res/drawable-ldpi/scrubber_control_off_mtrl_alpha.png
deleted file mode 100644
index bf6ce6c..0000000
--- a/core/res/res/drawable-ldpi/scrubber_control_off_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/scrubber_control_off_pressed_mtrl_alpha.png b/core/res/res/drawable-ldpi/scrubber_control_off_pressed_mtrl_alpha.png
deleted file mode 100644
index df88c4e..0000000
--- a/core/res/res/drawable-ldpi/scrubber_control_off_pressed_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/scrubber_control_on_mtrl_alpha.png b/core/res/res/drawable-ldpi/scrubber_control_on_mtrl_alpha.png
deleted file mode 100644
index 85a06b9..0000000
--- a/core/res/res/drawable-ldpi/scrubber_control_on_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/scrubber_control_on_pressed_mtrl_alpha.png b/core/res/res/drawable-ldpi/scrubber_control_on_pressed_mtrl_alpha.png
deleted file mode 100644
index 458abaf..0000000
--- a/core/res/res/drawable-ldpi/scrubber_control_on_pressed_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/scrubber_primary_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/scrubber_primary_mtrl_alpha.9.png
deleted file mode 100644
index 6f99790..0000000
--- a/core/res/res/drawable-ldpi/scrubber_primary_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/spinner_mtrl_am_alpha.9.png b/core/res/res/drawable-ldpi/spinner_mtrl_am_alpha.9.png
deleted file mode 100644
index 368a9b0..0000000
--- a/core/res/res/drawable-ldpi/spinner_mtrl_am_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/switch_off_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/switch_off_mtrl_alpha.9.png
deleted file mode 100644
index 9cd2df3..0000000
--- a/core/res/res/drawable-ldpi/switch_off_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/switch_on_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/switch_on_mtrl_alpha.9.png
deleted file mode 100644
index f9b287a..0000000
--- a/core/res/res/drawable-ldpi/switch_on_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/text_cursor_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/text_cursor_mtrl_alpha.9.png
deleted file mode 100644
index 4aaa79f..0000000
--- a/core/res/res/drawable-ldpi/text_cursor_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/textfield_activated_mtrl_alpha.9.png
deleted file mode 100644
index d12ec06..0000000
--- a/core/res/res/drawable-ldpi/textfield_activated_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/textfield_default_mtrl_alpha.9.png
deleted file mode 100644
index 6f0c57f..0000000
--- a/core/res/res/drawable-ldpi/textfield_default_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/textfield_activated_mtrl_alpha.9.png
index f3d06fe..45db6f7 100644
--- a/core/res/res/drawable-mdpi/textfield_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-mdpi/textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/textfield_default_mtrl_alpha.9.png
index f0e7db8..8111fcb 100644
--- a/core/res/res/drawable-mdpi/textfield_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-mdpi/textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/textfield_activated_mtrl_alpha.9.png
index 7174b67..8c617fd 100644
--- a/core/res/res/drawable-xhdpi/textfield_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xhdpi/textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/textfield_default_mtrl_alpha.9.png
index 46dad22..240ef7b 100644
--- a/core/res/res/drawable-xhdpi/textfield_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xhdpi/textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/textfield_activated_mtrl_alpha.9.png
index 661d5f0..778670a 100644
--- a/core/res/res/drawable-xxhdpi/textfield_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/textfield_default_mtrl_alpha.9.png
index d7696c3..6dd5d4f 100644
--- a/core/res/res/drawable-xxhdpi/textfield_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable/spinner_background_material.xml b/core/res/res/drawable/spinner_background_material.xml
index 02ea11b..d99e367 100644
--- a/core/res/res/drawable/spinner_background_material.xml
+++ b/core/res/res/drawable/spinner_background_material.xml
@@ -16,16 +16,17 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android"
     android:autoMirrored="true">
-    <item android:state_checked="true">
+    <item android:state_enabled="false">
         <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
-            android:tint="?attr/colorControlActivated" />
+            android:tint="?attr/colorControlNormal"
+            android:alpha="?attr/disabledAlpha" />
     </item>
-    <item android:state_pressed="true">
+    <item android:state_pressed="false" android:state_focused="false">
         <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
-            android:tint="?attr/colorControlActivated" />
+            android:tint="?attr/colorControlNormal" />
     </item>
     <item>
         <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
-            android:tint="?attr/colorControlNormal" />
+            android:tint="?attr/colorControlActivated" />
     </item>
 </selector>
diff --git a/core/res/res/drawable/spinner_textfield_background_material.xml b/core/res/res/drawable/spinner_textfield_background_material.xml
index 2732d53..fab3dc9 100644
--- a/core/res/res/drawable/spinner_textfield_background_material.xml
+++ b/core/res/res/drawable/spinner_textfield_background_material.xml
@@ -17,7 +17,21 @@
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
        android:inset="@dimen/control_inset_material">
     <selector android:autoMirrored="true">
-        <item android:state_checked="false" android:state_pressed="false">
+        <item android:state_enabled="false">
+            <layer-list android:paddingMode="stack">
+                <item>
+                    <nine-patch android:src="@drawable/textfield_activated_mtrl_alpha"
+                        android:tint="?attr/colorControlActivated"
+                        android:alpha="?attr/disabledAlpha" />
+                </item>
+                <item>
+                    <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
+                        android:tint="?attr/colorControlActivated"
+                        android:alpha="?attr/disabledAlpha" />
+                </item>
+            </layer-list>
+        </item>
+        <item android:state_pressed="false" android:state_focused="false">
             <layer-list android:paddingMode="stack">
                 <item>
                     <nine-patch android:src="@drawable/textfield_default_mtrl_alpha"
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index a8fd8d4..8dad63e 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -26,8 +26,8 @@
     <color name="primary_dark_material_dark">#ff000000</color>
     <color name="primary_dark_material_light">#ff757575</color>
 
-    <color name="ripple_material_dark">#40ffffff</color>
-    <color name="ripple_material_light">#40000000</color>
+    <color name="ripple_material_dark">#4dffffff</color>
+    <color name="ripple_material_light">#1f000000</color>
 
     <color name="accent_material_light">@color/material_deep_teal_500</color>
     <color name="accent_material_dark">@color/material_deep_teal_200</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d0c612d..6769c85 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1830,6 +1830,9 @@
          provisioning, availability etc -->
     <bool name="config_carrier_volte_available">false</bool>
 
+    <!-- Flag specifying whether VoLTE availability is based on provisioning -->
+    <bool name="config_carrier_volte_provisioned">false</bool>
+
     <!-- Flag specifying whether VT is available on device -->
     <bool name="config_device_vt_available">false</bool>
 
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index 8cc2a8a..bdb0324 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -105,8 +105,8 @@
     <dimen name="control_corner_material">2dp</dimen>
 
     <dimen name="edit_text_inset_horizontal_material">4dp</dimen>
-    <dimen name="edit_text_inset_top_material">4dp</dimen>
-    <dimen name="edit_text_inset_bottom_material">8dp</dimen>
+    <dimen name="edit_text_inset_top_material">10dp</dimen>
+    <dimen name="edit_text_inset_bottom_material">7dp</dimen>
 
     <dimen name="dialog_padding_material">24dp</dimen>
     <dimen name="dialog_padding_top_material">18dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9845096..4f2ed22 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2079,6 +2079,7 @@
   <java-symbol type="bool" name="imsServiceAllowTurnOff" />
   <java-symbol type="bool" name="config_device_volte_available" />
   <java-symbol type="bool" name="config_carrier_volte_available" />
+  <java-symbol type="bool" name="config_carrier_volte_provisioned" />
   <java-symbol type="bool" name="config_device_vt_available" />
   <java-symbol type="bool" name="config_carrier_vt_available" />
   <java-symbol type="bool" name="useImsAlwaysForEmergencyCall" />
diff --git a/docs/html/design/material/index.jd b/docs/html/design/material/index.jd
index db18a83..4d9a1a7 100644
--- a/docs/html/design/material/index.jd
+++ b/docs/html/design/material/index.jd
@@ -5,6 +5,40 @@
 
 @jd:body
 
+<!-- developer docs box -->
+<a class="notice-developers right" href="{@docRoot}training/material/index.html">
+  <div>
+    <h3>Developer Docs</h3>
+    <p>Creating Apps with Material Design</p>
+  </div>
+</a>
+
+<!-- video box -->
+<a class="notice-developers-video" href="https://www.youtube.com/watch?v=p4gmvHyuZzw">
+<div>
+    <h3>Video</h3>
+    <p>Introduction to Material Design</p>
+</div>
+</a>
+
+<!-- video box -->
+<a class="notice-developers-video" href="https://www.youtube.com/watch?v=YaG_ljfzeUw">
+<div>
+    <h3>Video</h3>
+    <p>Paper and Ink: The Materials that Matter</p>
+</div>
+</a>
+
+<!-- video box -->
+<a class="notice-developers-video" href="https://www.youtube.com/watch?v=XOcCOBe8PTc">
+<div>
+    <h3>Video</h3>
+    <p>Material Design in the Google I/O App</p>
+</div>
+</a>
+
+
+
 <p itemprop="description">Material design is a comprehensive guide for visual, motion, and
 interaction design across platforms and devices. Android now includes support for
 material design apps. To use material design in your Android apps, follow the guidelines defined
diff --git a/docs/html/images/tools/projectview01.png b/docs/html/images/tools/projectview01.png
index 90589fb..2deb752 100644
--- a/docs/html/images/tools/projectview01.png
+++ b/docs/html/images/tools/projectview01.png
Binary files differ
diff --git a/docs/html/images/tools/studio-cloudmodule.png b/docs/html/images/tools/studio-cloudmodule.png
index b7c4fb7..cffa2d5 100644
--- a/docs/html/images/tools/studio-cloudmodule.png
+++ b/docs/html/images/tools/studio-cloudmodule.png
Binary files differ
diff --git a/docs/html/images/tools/studio-helloworld-design.png b/docs/html/images/tools/studio-helloworld-design.png
index ff90c6b..a355e7a 100644
--- a/docs/html/images/tools/studio-helloworld-design.png
+++ b/docs/html/images/tools/studio-helloworld-design.png
Binary files differ
diff --git a/docs/html/images/tools/studio-helloworld-text.png b/docs/html/images/tools/studio-helloworld-text.png
index 5dde675..28e39fe 100644
--- a/docs/html/images/tools/studio-helloworld-text.png
+++ b/docs/html/images/tools/studio-helloworld-text.png
Binary files differ
diff --git a/docs/html/images/tools/studio-projectview_scripts.png b/docs/html/images/tools/studio-projectview_scripts.png
index 3e7b9cd..a0565c5 100644
--- a/docs/html/images/tools/studio-projectview_scripts.png
+++ b/docs/html/images/tools/studio-projectview_scripts.png
Binary files differ
diff --git a/docs/html/images/tools/studio-samples-githubaccess.png b/docs/html/images/tools/studio-samples-githubaccess.png
index 991bf69..3980361 100644
--- a/docs/html/images/tools/studio-samples-githubaccess.png
+++ b/docs/html/images/tools/studio-samples-githubaccess.png
Binary files differ
diff --git a/docs/html/images/tools/studio-setup-wizard.png b/docs/html/images/tools/studio-setup-wizard.png
index f84660a..ccd92d3 100644
--- a/docs/html/images/tools/studio-setup-wizard.png
+++ b/docs/html/images/tools/studio-setup-wizard.png
Binary files differ
diff --git a/docs/html/images/tools/studio-tvwearsupport.png b/docs/html/images/tools/studio-tvwearsupport.png
index 02bf484..88343a6 100644
--- a/docs/html/images/tools/studio-tvwearsupport.png
+++ b/docs/html/images/tools/studio-tvwearsupport.png
Binary files differ
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 8412609..dc7a6ca 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -281,7 +281,7 @@
 
 <img src="{@docRoot}images/tools/studio-hero.png"
 srcset="{@docRoot}images/tools/studio-hero_2x.png 2x, {@docRoot}images/tools/studio-hero.png 1x"
-width="760" height="400" alt="" style="margin-bottom:60px" />
+width="760" height="400" alt="" style="margin-bottom:80px" />
 
 <div style="color: #fff; width:226px; height:0; overflow:visible; position:absolute; top:40px; left:25px">
 
@@ -311,6 +311,8 @@
   <li><a href="#Requirements">System Requirements</a></li>
   <li><a href="#Other">Other Download Options</a></li>
   <li><a href="{@docRoot}sdk/installing/migrate.html">Migrating to Android Studio</a></li>
+  <li><a href="https://docs.google.com/a/google.com/forms/d/1mjsyfzv3HAnDY-_Kfj-3QJKdpuksyMFs9e73CRwmT6Q/viewform"
+target="_blank">Take a Survey</a></li>
 </ul>
 
 </div>
@@ -427,8 +429,9 @@
 </div>
 
 
-<p>If you've been using Eclipse with ADT, be aware that the ADT plugin is no longer in active
-development, so you should migrate to Android Studio as soon as possible. For help moving projects,
+<p>If you have been using Eclipse with ADT, be aware that Android Studio is now the official IDE
+for Android, so you should migrate to Android Studio to receive all the
+latest IDE updates. For help moving projects,
 see <a href="{@docRoot}sdk/installing/migrate.html">Migrating to Android
 Studio</a>.</p>
 
diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd
index 744ce15..14d274f 100644
--- a/docs/html/sdk/installing/index.jd
+++ b/docs/html/sdk/installing/index.jd
@@ -28,9 +28,8 @@
 <!-- ################    STUDIO    ##################### -->
 <div id="studio" heading="Installing Android Studio" style="display:none">
 
-<p>Android Studio provides the tools you need to start developing apps, including
-the Android Studio IDE (powered by IntelliJ) and guides you to install
-the Android SDK tools to streamline your Android app development.</p>
+<p>Android Studio provides everything you need to start developing apps for Android, including
+the Android Studio IDE and the Android SDK tools.</p>
 
 <p>If you didn't download Android Studio, go <a href="{@docRoot}sdk/index.html"
 ><b>download Android Studio now</b></a>, or switch to the
@@ -39,7 +38,8 @@
 
 
 <p>Before you set up Android Studio, be sure you have installed
-JDK 6 or greater (the JRE alone is not sufficient). To check if you
+JDK 6 or higher (the JRE alone is not sufficient)&mdash;JDK 7 is required when
+developing for Android 5.0 and higher. To check if you
 have JDK installed (and which version), open a terminal and type <code>javac -version</code>.
 If the JDK is not available or the version is lower than 6,
 <a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html" class="external-link"
@@ -57,7 +57,7 @@
 <p><b>To set up Android Studio on Windows:</b></p>
   <ol>
     <li>Launch the <code>.exe</code> file you just downloaded.</li>
-    <li>Follow the setup wizard to install Android Studio and the SDK Tools.
+    <li>Follow the setup wizard to install Android Studio and any necessary SDK tools.
 
     <p>On some Windows systems, the launcher script does not find where Java is installed.
       If you encounter this problem,
@@ -88,7 +88,7 @@
   <ol>
     <li>Launch the {@code .dmg} file you just downloaded.</li>
     <li>Drag and drop Android Studio into the Applications folder.
-    <li>Open Android Studio and follow the instructions to set up the SDK.
+    <li>Open Android Studio and follow the setup wizard to install any necessary SDK tools.
       <p>
       Depending on your security settings, when you attempt to open Android Studio, you might
       see a warning that says the package is damaged and should be moved to the trash. If this
@@ -118,7 +118,7 @@
       <p>You may want to add {@code android-studio/bin/} to your PATH environmental
       variable so that you can start Android Studio from any directory.</p>
     </li>
-    <li>Follow the links to install the SDK tools outside of the Android Studio directories.</li>
+    <li>Follow the setup wizard to install any necessary SDK tools.</li>
   </ol>
 
 </div><!-- end linux -->
@@ -226,8 +226,7 @@
       <li><a href="https://help.ubuntu.com/community/Java">https://help.ubuntu.com/community/JavaInstallation</a></li>
     </ul>
   </li>
-  <li>Here are the steps to install Java and Eclipse, prior to installing
-  the Android SDK and ADT Plugin.
+  <li>Here are the steps to install Java:
     <ol>
       <li><p>If you are running a 64-bit distribution on your development
       machine, you need to install additional packages first. For Ubuntu 13.10 (Saucy Salamander)
@@ -241,13 +240,6 @@
       <pre class="no-pretty-print">apt-get install ia32-libs</pre>
       </li>
       <li>Next, install Java: <pre class="no-pretty-print">apt-get install sun-java6-jdk</pre></li>
-      <li>The Ubuntu package manager does not currently offer an Eclipse 3.7
-      version for download, so we recommend that you download Eclipse from
-      eclipse.org (<a
-      href="http://www.eclipse.org/downloads/">http://www.eclipse.org/downloads/</a>).
-      A Java or RCP version of Eclipse is recommended.</li>
-      <li>Follow the steps given in previous sections to install the SDK
-      and the ADT plugin. </li>
     </ol>
   </li>
 </ul>
@@ -272,47 +264,6 @@
 
 
 
-<!-- ###################    ADT BUNDLE     ####################### -->
-<div id="adt" heading="Installing the Eclipse ADT Bundle" style="display:none">
-
-
-<p>The Eclipse ADT Bundle provides everything you need to start developing apps, including
-the Android SDK tools and a version of the Eclipse IDE with built-in ADT
-(Android Developer Tools) to streamline your Android app development.</p>
-
-<p>If you didn't download the Eclipse ADT bundle, go <a href="{@docRoot}tools/eclipse/index.html"
-><b>download the Eclipse ADT bundle now</b></a>, or switch to the
-<a href="{@docRoot}sdk/installing/index.html?pkg=studio">Android Studio
-install</a> or <a href="{@docRoot}sdk/installing/index.html?pkg=tools">stand-alone SDK Tools
-install</a> instructions</i>.</p>
-
-<div class="procedure-box">
-<p><b>To set up the ADT Bundle:</b></p>
-<ol>
-<li>Unpack the ZIP file
-(named {@code adt-bundle-&lt;os_platform>.zip}) and save it to an appropriate location,
-such as a "Development" directory in your home directory.</li>
-<li>Open the {@code adt-bundle-&lt;os_platform>/eclipse/} directory and launch
-<strong>Eclipse</strong>.</li>
-</ol>
-
-<p class="caution"><strong>Caution:</strong> Do not move any of the files or directories
-from the {@code adt-bundle-&lt;os_platform>} directory. If you move the {@code eclipse/}
-or {@code sdk/} directory, ADT will not be able to locate the SDK and you'll
-need to manually update the ADT preferences.</p>
-</div>
-
-<p>Eclipse with ADT is now ready and loaded with the Android developer tools, but there are still
-a couple packages you should add to make your Android SDK complete.</p>
-
-<p class="paging-links">
-<a href="{@docRoot}sdk/installing/adding-packages.html" class="next-page-link">
-Continue: Adding SDK Packages</a></p>
-
-
-</div>
-<!-- ################    END ADT BUNDLE    ##################### -->
-
 
 
 
@@ -368,10 +319,6 @@
   // Show the SDK Tools (other IDE) instructions
   $("h1").text($("#tools").attr('heading'));
   $("#tools").show();
-} else if (package == "adt") {
-  // Show the ADT instructions
-  $("h1").text($("#adt").attr('heading'));
-  $("#adt").show();
 } else if (package == "studio") {
   // Show the Android Studio instructions
   $("h1").text($("#studio").attr('heading'));
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index c8200aa..0114848 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -15,12 +15,18 @@
 UI, debug your app, and export signed (or unsigned) app packages (APKs) for distribution.
 </p>
 
-<p class="note"><strong>Note:</strong> You should install the ADT plugin
-only if you already have an Eclipse installation that you want to continue using. If you do not
-have Eclipse installed, you should instead <b><a href="{@docRoot}sdk/index.html">install
-the complete Android SDK</a></b>, which includes the latest IDE for Android developers.</p>
+<p class="note"><strong>Note:</strong>
+If you have been using Eclipse with ADT, be aware that <a
+href="{@docRoot}tools/studio/index.html">Android Studio</a> is now the official IDE
+for Android, so you should migrate to Android Studio to receive all the
+latest IDE updates. For help moving projects,
+see <a href="/sdk/installing/migrate.html">Migrating to Android
+Studio</a>.</p>
 
-<p>Your existing Eclipse installation must meet these requirements:</p>
+
+<p>You should install the ADT plugin
+only if you already have an Eclipse installation that you want to continue using.
+Your existing Eclipse installation must meet these requirements:</p>
     <ul>
       <li><a href="http://eclipse.org/mobile/">Eclipse</a> 3.7.2 (Indigo) or greater
 <p class="note"><strong>Note:</strong> Eclipse 3.6 (Helios) is no longer
diff --git a/docs/html/sdk/installing/migrate.jd b/docs/html/sdk/installing/migrate.jd
index 06b9e3f..3c04cb4 100644
--- a/docs/html/sdk/installing/migrate.jd
+++ b/docs/html/sdk/installing/migrate.jd
@@ -6,7 +6,8 @@
 <div id="qv">
 <h2>See also</h2>
 <ul>
-  <li><a href="http://confluence.jetbrains.com/display/IntelliJIDEA/FAQ+on+Migrating+to+IntelliJ+IDEA">IntelliJ FAQ on migrating to IntelliJ IDEA</a></li>
+  <li><a href="http://confluence.jetbrains.com/display/IntelliJIDEA/FAQ+on+Migrating+to+IntelliJ+IDEA"
+  class="external-link">IntelliJ FAQ on migrating to IntelliJ IDEA</a></li>
  <li><a href="http://confluence.jetbrains.com/display/IntelliJIDEA/Working+in+Eclipse+Compatibility+Mode" class="external-link"
  >Eclipse Compatibility Mode</a></li>
  <li><a href="http://confluence.jetbrains.com/display/IntelliJIDEA/FAQ+on+Migrating+to+IntelliJ+IDEA" class="external-link"
@@ -15,25 +16,12 @@
 </div>
 </div>
 
-<p>If you're currently using Eclipse with ADT, we recommend you migrate to
-<a href="{@docRoot}tools/studio/index.html">Android Studio</a> as soon as possible, because
-the ADT plugin for Eclipse is no longer in active development.</p>
 
+<p>If you have been using <a href="{@docRoot}tools/help/adt.html">Eclipse with ADT</a>, be aware
+that <a href="{@docRoot}tools/studio/index.html">Android Studio</a> is now the official IDE for
+Android, so you should migrate to Android Studio to receive all the latest IDE updates.</p>
 
-<p>To migrate existing Android projects from Eclipse,
-you should export your projects from Eclipse in order to generate
-Gradle build files:</p>
-
-<ol>
-  <li>In Eclipse, select <strong>File &gt; Export</strong>.</li>
-  <li>Select <strong>Generate Gradle build files</strong> inside the Android folder, then click
-  <strong>Next</strong>.</li>
-  <li>Click <strong>Browse</strong> to find your project to export.</li>
-  <li>Select your project from the list, click <strong>OK</strong>, then <strong>Finish</strong>.</li>
-</ol>
-
-
-<p>You can then import the project into Android Studio:</p>
+<p>To migrate existing Android projects, simply import them using Android Studio:</p>
 
 <ol>
   <li>In Android Studio, close any projects currently open. You should see the
@@ -45,11 +33,10 @@
   <strong>OK</strong>. (You do not need to specify the Gradle home.)</li>
 </ol>
 
-<p>It's possible to import an existing Android project to Android Studio even if you
-don't generate a Gradle build file from Eclipse&mdash;Android Studio will successfully build and
-run projects using an existing Ant build file. However, in order to take advantage of build
-variants and other advanced features in the future,
-you should generate a Gradle build file using
-the ADT plugin or write your own Gradle build file for use with Android Studio.</p>
+<p>Android Studio properly updates the project structure and creates the appropriate
+Gradle build file.</p>
 
-<p><a href="{@docRoot}tools/studio/index.html">Learn more about Android Studio</a>.</p>
+<p>For more help getting started with Android Studio and the IntelliJ user experience,
+<a href="{@docRoot}tools/studio/index.html">learn more about Android Studio</a> and
+read <a href="http://confluence.jetbrains.com/display/IntelliJIDEA/FAQ+on+Migrating+to+IntelliJ+IDEA"
+  class="external-link">FAQ on Migrating to IntelliJ IDEA</a>.</p>
diff --git a/docs/html/sdk/installing/studio-build.jd b/docs/html/sdk/installing/studio-build.jd
index c80368f..4fe9071 100644
--- a/docs/html/sdk/installing/studio-build.jd
+++ b/docs/html/sdk/installing/studio-build.jd
@@ -13,7 +13,7 @@
    <li><a href="{@docRoot}sdk/installing/studio.html">
    Getting Started with Android Studio</a></li>
    <li><a href="{@docRoot}tools/studio/index.html">Android Studio Basics</a></li>
-   <li><a href="{@docRoot}tools/eclipse/migrate-adt.html">Migrating from Eclipse</a></li>
+   <li><a href="{@docRoot}sdk/installing/migrate.html">Migrating from Eclipse</a></li>
 </div>
 </div>
 
diff --git a/docs/html/sdk/installing/studio-tips.jd b/docs/html/sdk/installing/studio-tips.jd
index fba7a70..8e7e345 100644
--- a/docs/html/sdk/installing/studio-tips.jd
+++ b/docs/html/sdk/installing/studio-tips.jd
@@ -40,25 +40,19 @@
 add all missing attributs</em>. Clicking the message adds the missing attributes to the layout.</p>
 
 
-<h2>Output window message filtering</h2>
-<p>When checking build results, you can filter messages by <em>message type</em> to quickly
-locate messages of interest.</p>
-<img src="{@docRoot}images/tools/studio-outputwindowmsgfiltering.png" style="width:200px"style="width:200px" />
-<p class="img-caption"><strong>Figure 14.</strong> Filter Build Messages</p>
-
 <h3> Bitmap rendering in the debugger</h3>
 <p>While debugging, you can now right-click on bitmap variables in your app and invoke
 <em>View Bitmap</em>. This fetches the associated data from the debugged process and renders
 the bitmap in the debugger. </p>
 <p><img src="{@docRoot}images/tools/studio-bitmap-rendering.png" style="width:350px"/></p>
-<p class="img-caption"><strong>Figure 2.</strong> Bitmap Rendering</p>
+<p class="img-caption"><strong>Figure 1.</strong> Bitmap Rendering</p>
 
 
 <h3>Output window message filtering</h3>
 <p>When checking build results, you can filter messages by <em>message type</em> to quickly
 locate messages of interest.</p>
 <img src="{@docRoot}images/tools/studio-outputwindowmsgfiltering.png" style="width:200px"style="width:200px" />
-<p class="img-caption"><strong>Figure 3.</strong> Filter Build Messages</p>
+<p class="img-caption"><strong>Figure 2.</strong> Filter Build Messages</p>
 
 
 <h3>Hierarchical parent setting</h3>
@@ -79,7 +73,7 @@
 multiple devices simultaneously, select <strong>Preview All Screen Sizes</strong> from the
 device drop-down.</p>
 <p><img src="{@docRoot}images/tools/studio-previewall.png" style="width:350px"/></p>
-<p class="img-caption"><strong>Figure 4.</strong> Preview All Screens</p>
+<p class="img-caption"><strong>Figure 3.</strong> Preview All Screens</p>
 
 <p>You can switch to the graphical editor by clicking <strong>Design</strong> at the
 bottom of the window. While editing in the Design view, you can show and hide the
@@ -166,7 +160,7 @@
 </strong> <code>F1</code>, see the theme inheritance hierarchy, and resolved values for the
 various attributes.</p>
 <img src="{@docRoot}images/tools/studio-allocationtracker.png" style="width:300px" />
-<p class="img-caption"><strong>Figure 1.</strong> Allocation Tracker</p>
+<p class="img-caption"><strong>Figure 4.</strong> Allocation Tracker</p>
 
 
 <h3 id="key-commands">Keyboard Commands</h3>
diff --git a/docs/html/tools/eclipse/index.jd b/docs/html/tools/eclipse/index.jd
deleted file mode 100644
index c8a998b..0000000
--- a/docs/html/tools/eclipse/index.jd
+++ /dev/null
@@ -1,37 +0,0 @@
-page.title=Eclipse ADT
-@jd:body
-
-
-<div id="qv-wrapper">
-<div id="qv">
-  <h2>See also</h2>
-  <ol>
-    <li><a href="{@docRoot}tools/sdk/index.html">Downloading Android Studio</a></li>
-    <li><a href="{@docRoot}tools/studio/index.html">Android Studio</a></li>
-    <li><a href="{@docRoot}tools/eclipse/migrate-adt.html">Migrating to Android Studio</a></li>
-  </ol>
-</div>
-</div>
-
-
-<p>The Android Developer Tools (ADT) plugin for Eclipse provides a professional-grade development
-environment for building Android apps. It's a full Java IDE with advanced features to help you build,
-test, debug, and package your Android apps. </p>
-
-<p>Android developers are encouraged to <a href="{@docRoot}tools/eclipse/migrate-adt.html">migrate
-to Android Studio</a> as the Eclipse ADT is no longer in active development.
-</p>
-
-<p>The Android Studio build system replaces the Apache Ant build software used with Eclipse ADT
-with an Android plugin for <em>Gradle</em>. <a href="http://www.gradle.org/">Gradle</a> is an
-advanced build toolkit that manages dependencies and allows you to define custom build logic. Android
-Studio also adds support for Maven-based build dependencies, build variants, advanced code
-completion and refactoring. For more details about Android Studio, see the
-<a href="{@docRoot}tools/studio/index.html">Android Studio</a> guide.
-
-<p>If you still wish to get started with the ADT plugin,
-<a href="{@docRoot}tools/eclipse/installing-adt.html">download and install the Eclipse ADT plugin.</a>
-</p>
-
-</div>
-</div>
diff --git a/docs/html/tools/help/adt.jd b/docs/html/tools/help/adt.jd
index 1bb3015..0130524 100644
--- a/docs/html/tools/help/adt.jd
+++ b/docs/html/tools/help/adt.jd
@@ -24,63 +24,30 @@
         </li>
 
         <li><a href="#refactoring">Layout Factoring Support</a></li>
-        <li><a href="#Updating">Updating the ADT Plugin</h2>
+        <li><a href="#Updating">Updating the ADT Plugin</a></li>
 
       </ol>
-
-      <h2>Related videos</h2>
-
-      <ol>
-        <li><a href="{@docRoot}videos/index.html#v=Oq05KqjXTvs">Android Developer Tools
-            Google I/O Session</a>
-        </li>
-      </ol>
-
-      <h2>See also</h2>
-
-      <ol>
-        <li><a href="http://tools.android.com/recent">Android Tools change blog</a></li>
-      </ol>
     </div>
   </div>
 
   <p>ADT (Android Developer Tools) is a plugin for Eclipse that provides a suite of
   tools that are integrated with the Eclipse IDE. It offers you access to many features that help
-  you develop Android applications quickly. ADT
+  you develop Android applications. ADT
   provides GUI access to many of the command line SDK tools as well as a UI design tool for rapid
   prototyping, designing, and building of your application's user interface.</p>
 
-  <p>Because ADT is a plugin for Eclipse, you get the functionality of a well-established IDE,
-  along with Android-specific features that are bundled with ADT. The following
-  describes important features of Eclipse and ADT:</p>
+<p class="note"><strong>Note:</strong>
+If you have been using Eclipse with ADT, be aware that <a
+href="{@docRoot}tools/studio/index.html">Android Studio</a> is now the official IDE
+for Android, so you should migrate to Android Studio to receive all the
+latest IDE updates. For help moving projects,
+see <a href="/sdk/installing/migrate.html">Migrating to Android
+Studio</a>.</p>
 
-  <dl>
-    <dt><strong>Integrated Android project creation, building, packaging, installation, and
-    debugging</strong></dt>
+<p>If you still wish to use the ADT plugin for Eclipse, see
+<a href="{@docRoot}sdk/installing/installing-adt.html">Installing Eclipse Plugin.</a>
+</p>
 
-    <dd>ADT integrates many development workflow tasks into Eclipse, making it easy for you to
-    rapidly develop and test your Android applications.</dd>
-
-    <dt><strong>SDK Tools integration</strong></dt>
-
-    <dd>Many of the <a href="#tools">SDK tools</a> are integrated into Eclipse's menus,
-    perspectives, or as a part of background processes ran by ADT.</dd>
-
-    <dt><strong>Java programming language and XML editors</strong></dt>
-
-    <dd>The Java programming language editor contains common IDE features such as compile time
-    syntax checking, auto-completion, and integrated documentation for the Android framework APIs.
-    ADT also provides custom XML editors that let you
-    edit Android-specific XML files in a form-based UI. A graphical layout editor lets you design
-    user interfaces with a drag and drop interface.</dd>
-
-    <dt><strong>Integrated documentation for Android framework APIs</strong></dt>
-    <dd>You can access documentation by hovering over classes, methods, or variables.</dd>
-  </dl>
-
-  <p>You can find the most up-to-date and more detailed information about changes and new features
-on the <a  href="http://tools.android.com/recent">Recent Changes</a> page at the Android  Tools
-Project site.</p>
 
   <h2 id="tools">SDK Tools Integration</h2>
 
@@ -568,5 +535,6 @@
 
 
 <p>If you encounter problems during the update, remove the existing ADT plugin from Eclipse, then
-perform a fresh installation, using the instructions for <a href="#installing">Installing the ADT
+perform a fresh installation, using the instructions for <a
+href="{@docRoot}sdk/installing/installing-adt.html">Installing the ADT
 Plugin</a>.</p>
diff --git a/docs/html/tools/revisions/build-tools.jd b/docs/html/tools/revisions/build-tools.jd
index 4afdf13..593770a 100644
--- a/docs/html/tools/revisions/build-tools.jd
+++ b/docs/html/tools/revisions/build-tools.jd
@@ -1,4 +1,5 @@
-page.title=Build Tools
+page.title=SDK Build Tools Release Notes
+
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/tools/revisions/platforms.jd b/docs/html/tools/revisions/platforms.jd
index ef8575a..75b3cef 100644
--- a/docs/html/tools/revisions/platforms.jd
+++ b/docs/html/tools/revisions/platforms.jd
@@ -1,4 +1,5 @@
-page.title=Platforms
+page.title=SDK Platforms Release Notes
+
 @jd:body
 
 <div id="qv-wrapper">
@@ -20,10 +21,16 @@
 
 
 
-<p>This document provides information about Android platform releases. In order to compile your
-application against a particular platform release, you must download and install the SDK Platform
-for that release. If you want to test your application on an emulator, you must also download at
-least one system image for that platform release.</p>
+<p>This document provides release information about the SDK Platform packages required
+for app development. If you want details about the features and APIs added in each Android
+version, instead read the highlights in the <a href="{@docRoot}about/index.html">About</a>
+section.</p>
+
+<p>In order to compile your application against a particular version of Android, you must use the
+<a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a> to download and install the SDK
+Platform for that release. If you want to test your application on an emulator, you must also
+download at least one System Image for that Android version.</p>
+
 
 <p>Each platform release includes system images that support a specific processor architecture,
 such as ARM EABI, Intel x86 or MIPS. Platform releases also include a system image that contains
@@ -44,7 +51,7 @@
 <p class="caution"><strong>Important:</strong> To download the most recent Android
 system components from the Android SDK Manager, you must first update the SDK Tools to the
 most recent release and restart the SDK Manager. If you do not, the latest Android system
-components will not be available for download.</p>
+packages may not be available for download.</p>
 
 
 <h2 id="5.0">Android 5.0</h2>
@@ -58,6 +65,8 @@
   <div class="toggle-content-toggleme">
 
     <p>Initial release for Android 5.0 (API level 21).</p>
+    <p>Also see the
+    <a href="{@docRoot}about/versions/android-5.0.html">Android 5.0 APIs overview</a>.</p>
     <p>Dependencies:</p>
     <ul>
       <li>Android SDK Platform-tools r21 or higher is required.</li>
@@ -82,7 +91,7 @@
 
 <div class="toggle-content open">
   <p><a href="#" onclick="return toggleContent(this)">
-    <img src="{@docRoot}assets/images/triangle-open.png"
+    <img src="{@docRoot}assets/images/triangle-closed.png"
 class="toggle-content-img" alt="" />Revision 2</a> <em>(October 2014)</em>
   </p>
 
@@ -135,6 +144,8 @@
   <div class="toggle-content-toggleme">
 
     <p>Maintenance release. The system version is 4.4.2.</p>
+    <p>Also see the
+    <a href="{@docRoot}about/versions/android-4.4.html">Android 4.4 APIs overview</a>.</p>
     <dl>
       <dt>Dependencies:</dt>
       <dd>Android SDK Platform-tools r19 or higher is required.</dd>
@@ -153,6 +164,8 @@
   <div class="toggle-content-toggleme">
 
     <p>Initial release. The system version is 4.4.</p>
+    <p>Also see the
+    <a href="{@docRoot}about/versions/android-4.4.html">Android 4.4 APIs overview</a>.</p>
     <dl>
       <dt>Dependencies:</dt>
       <dd>Android SDK Platform-tools r19 or higher is required.</dd>
diff --git a/docs/html/tools/revisions/studio.jd b/docs/html/tools/revisions/studio.jd
index fe3b99b..422beaa 100644
--- a/docs/html/tools/revisions/studio.jd
+++ b/docs/html/tools/revisions/studio.jd
@@ -1,4 +1,4 @@
-page.title=Android Studio Revisions
+page.title=Android Studio Release Notes
 
 @jd:body
 
@@ -26,8 +26,8 @@
 <li>A version of the Android system image for the emulator</li>
 </ul>
 
-<p>For an introduction to Android Studio, make sure to read
-<a href="{@docRoot}tools/studio/basics.html">Android Studio Basics</a>.</p>
+<p>For an introduction to Android Studio, read the
+<a href="{@docRoot}tools/studio/index.html">Android Studio</a> guide.</p>
 
 <p>Periodic updates are pushed to Android Studio without requiring you to update from here. To
 manually check for updates, select <strong>Help > Check for updates</strong> (on Mac, select
@@ -39,10 +39,21 @@
 <p>The sections below provide notes about successive releases of
 Android Studio, as denoted by revision number. </p>
 
-
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Android Studio v1.0</a> <em>(December 2014)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+    <p>Initial release of Android Studio.</p>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Android Studio v0.8.14</a> <em>(October 2014)</em>
   </p>
 
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index deafed5..c3a4dea 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -1,4 +1,4 @@
-page.title=ADT Plugin
+page.title=ADT Plugin Release Notes
 
 @jd:body
 
@@ -15,29 +15,25 @@
 </div>
 
 <p>Android Development Tools (ADT) is a plugin for the Eclipse IDE
-that is designed to give you a powerful, integrated environment in which
-to build Android applications.</p>
-
-<p>ADT extends the capabilities of Eclipse to let you quickly set up new Android
+that extends the capabilities of Eclipse to let you quickly set up new Android
 projects, create an application UI, add packages based on the Android
 Framework API, debug your applications using the Android SDK tools, and even
 export signed (or unsigned) {@code .apk} files in order to distribute your application.</p>
 
-<p>Developing in Eclipse with ADT is highly recommended and is the fastest way
-to get started. With the guided project setup it provides, as well as tools
-integration, custom XML editors, and debug output pane, ADT gives you an
-incredible boost in developing Android applications. </p>
+<p class="note"><strong>Note:</strong>
+If you have been using Eclipse with ADT, be aware that <a
+href="{@docRoot}tools/studio/index.html">Android Studio</a> is now the official IDE
+for Android, so you should migrate to Android Studio to receive all the
+latest IDE updates. For help moving projects,
+see <a href="/sdk/installing/migrate.html">Migrating to Android
+Studio</a>.</p>
 
-<p>This document provides step-by-step instructions on how to download the ADT
-plugin and install it into your Eclipse development environment. Note that
+<p>Note that
 before you can install or use ADT, you must have compatible versions of both the
 Eclipse IDE and the Android SDK installed. For details, make sure to read <a
 href="{@docRoot}sdk/installing/installing-adt.html">Installing the Eclipse
 Plugin</a>. </p>
 
-<p>If you are already using ADT, this document also provides instructions on
-how to update ADT to the latest version or how to uninstall it, if necessary.
-</p>
 
 <p>For information about the features provided by the ADT plugin, such as code
 editor features, SDK tool integration, and the graphical layout editor (for drag-and-drop layout
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index 3e3cb4b..80edb4f 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -1,19 +1,15 @@
-page.title=SDK Tools
+page.title=SDK Tools Release Notes
 excludeFromSuggestions=true
 @jd:body
 
 <p>SDK Tools is a downloadable component for the Android SDK. It includes the
-complete set of development and debugging tools for the Android SDK.</p>
-
-<p>If you are new to the Android SDK, the <a
-href="{@docRoot}sdk/index.html">SDK starter package</a> installs the
-latest revision of the SDK Tools in the <code>&lt;sdk&gt;/tools</code> directory.</p>
+complete set of development and debugging tools for the Android SDK. It is included
+with <a href="{@docRoot}tools/studio/index.html">Android Studio</a>.</p>
 
 <p>If you are already using the SDK and you want to update to the latest version
-of the SDK Tools, use the <em>Android SDK Manager</em> to get the
-update, rather than downloading a new SDK starter package. For more information
-about how to update, see <a
-href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>.</p>
+of the SDK Tools, use the <a
+href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a> to get the
+update.</p>
 
 
 <h2 id="notes">Revisions</h2>
@@ -29,6 +25,33 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>SDK Tools, Revision 24.0.0</a> <em>(December 2014)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <dl>
+    <dt>Dependencies:</dt>
+
+    <dd>
+      <ul>
+        <li>Android SDK Platform-tools revision 19 or later.</li>
+      </ul>
+    </dd>
+
+    <dt>General Notes:</dt>
+    <dd>
+      <ul>
+        <li>Added support for Andriod Studio 1.0 and emulator enhancements.</li>
+      </ul>
+    </dd>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>SDK Tools, Revision 23.0.5</a> <em>(October 2014)</em>
   </p>
 
diff --git a/docs/html/tools/studio/index.jd b/docs/html/tools/studio/index.jd
index 1b9dd18..20c41e0 100644
--- a/docs/html/tools/studio/index.jd
+++ b/docs/html/tools/studio/index.jd
@@ -44,7 +44,7 @@
   <li>And much more</li>
 </ul>
 
-<p><b><a href="{@docRoot}tools/sdk/index.html">Download Android Studio now</a></b>. </p>
+<p><b><a href="{@docRoot}sdk/index.html">Download Android Studio now</a></b>. </p>
 
 <p>If you're new to Android Studio or the IntelliJ IDEA interface, this
 page provides an introduction to some key Android
@@ -102,9 +102,8 @@
 
 
 <h3>New Project and Directory Structure</h3>
-<p>When you use the <em>Project</em> view of a new project in Android Studio or
-(<a href="{@docRoot}tools/eclipse/migrate-adt.html"> a project migrated from Eclipse</a>), you
-should notice that the project structure appears different than you may be used to. Each
+<p>When you use the <em>Project</em> view of a new project in Android Studio, you
+should notice that the project structure appears different than you may be used to in Eclipse. Each
 instance of Android Studio contains a project with one or more application modules. Each
 application module folder contains the complete source sets for that module, including
 {@code src/main} and {@code src/androidTest} directories, resources, build
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index a8c588a..cb6a1de 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -159,13 +159,6 @@
 class="en">Tools Help</span></a></div>
     <ul>
       <li><a href="<?cs var:toroot ?>tools/help/adb.html">adb</a></li>
-      <li class="nav-section">
-        <div class="nav-section-header"><a href="<?cs var:toroot ?>tools/help/adt.html">ADT</a></div>
-        <ul>
-          <li><a href="<?cs var:toroot ?>sdk/installing/installing-adt.html">
-              <span class="en">Installing the Eclipse Plugin</span></a></li>
-        </ul>
-      </li>
       <li><a href="<?cs var:toroot ?>tools/help/android.html">android</a></li>
       <li><a href="<?cs var:toroot ?>tools/help/avd-manager.html">AVD Manager</a></li>
       <li><a href="<?cs var:toroot ?>tools/help/bmgr.html">bmgr</a>
@@ -262,10 +255,10 @@
         <span class="en">SDK Tools</span>
       </a></li>
       <li><a href="<?cs var:toroot ?>tools/revisions/build-tools.html">
-        <span class="en">Build Tools</span>
+        <span class="en">SDK Build Tools</span>
       </a></li>
       <li><a href="<?cs var:toroot ?>tools/revisions/platforms.html">
-        <span class="en">Platforms</span></a></li>
+        <span class="en">SDK Platforms</span></a></li>
       <li><a href="<?cs var:toroot ?>tools/sdk/eclipse-adt.html">
         <span class="en">ADT Plugin</span></a></li>
     </ul>
@@ -293,11 +286,13 @@
 
   <li class="nav-section">
     <div class="nav-section-header">
-    <a href="<?cs var:toroot ?>tools/eclipse/index.html">
+    <a href="<?cs var:toroot ?>tools/help/adt.html">
       <span class="en">Eclipse with ADT</span></a>
     </div>
     <ul>
     <li><a href="<?cs var:toroot ?>sdk/installing/migrate.html">Migrating to Android Studio</a></li>
+    <li><a href="<?cs var:toroot ?>sdk/installing/installing-adt.html">
+        <span class="en">Installing the Eclipse Plugin</span></a></li>
     <li><a href="<?cs var:toroot ?>tools/projects/projects-eclipse.html">Managing Projects</a></li>
     <li><a href="<?cs var:toroot ?>tools/building/building-eclipse.html">Building and Running</a></li>
     <li><a href="<?cs var:toroot ?>tools/building/building-cmdline-ant.html">Building with Ant</a></li>
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 9eb0251..74ff1b0 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -375,7 +375,7 @@
                 mOneShot = orig.mOneShot;
             } else {
                 mDurations = new int[getCapacity()];
-                mOneShot = true;
+                mOneShot = false;
             }
         }
 
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 79ac651..9be296a 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -48,6 +48,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.util.Collection;
 
 /**
  * A Drawable that wraps a bitmap and can be tiled, stretched, or aligned. You can create a
@@ -913,8 +914,11 @@
         }
 
         @Override
-        public Bitmap getBitmap() {
-            return mBitmap;
+        public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
+            if (isAtlasable(mBitmap) && atlasList.add(mBitmap)) {
+                return mBitmap.getWidth() * mBitmap.getHeight();
+            }
+            return 0;
         }
 
         @Override
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 1fac5b6..0e38cc0 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -51,6 +51,7 @@
 import java.io.InputStream;
 import java.lang.ref.WeakReference;
 import java.util.Arrays;
+import java.util.Collection;
 
 /**
  * A Drawable is a general abstraction for "something that can be drawn."  Most
@@ -1244,10 +1245,16 @@
         public abstract int getChangingConfigurations();
 
         /**
+         * @return Total pixel count
          * @hide
          */
-        public Bitmap getBitmap() {
-            return null;
+        public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
+            return 0;
+        }
+
+        /** @hide */
+        protected final boolean isAtlasable(Bitmap bitmap) {
+            return bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888;
         }
 
         /**
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 2748030..1e360d3 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -20,6 +20,7 @@
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
+import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.Insets;
@@ -31,6 +32,8 @@
 import android.util.LayoutDirection;
 import android.util.SparseArray;
 
+import java.util.Collection;
+
 /**
  * A helper class that contains several {@link Drawable}s and selects which one to use.
  *
@@ -1062,6 +1065,20 @@
             return true;
         }
 
+        /** @hide */
+        @Override
+        public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
+            final int N = mNumChildren;
+            int pixelCount = 0;
+            for (int i = 0; i < N; i++) {
+                final ConstantState state = getChild(i).getConstantState();
+                if (state != null) {
+                    pixelCount += state.addAtlasableBitmaps(atlasList);
+                }
+            }
+            return pixelCount;
+        }
+
         /**
          * Class capable of cloning a Drawable from another Drawable's
          * ConstantState.
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index acfd427..8b70a08 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -19,6 +19,7 @@
 import com.android.internal.R;
 
 import android.annotation.NonNull;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -26,16 +27,19 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.Resources.Theme;
+import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.Insets;
 import android.graphics.Outline;
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff.Mode;
+import android.graphics.drawable.Drawable.ConstantState;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 
 import java.io.IOException;
+import java.util.Collection;
 
 /**
  * A Drawable that insets another Drawable by a specified distance.
@@ -472,6 +476,15 @@
 
             return mCanConstantState;
         }
+
+        @Override
+        public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
+            final ConstantState state = mDrawable.getConstantState();
+            if (state != null) {
+                return state.addAtlasableBitmaps(atlasList);
+            }
+            return 0;
+        }
     }
 
     private InsetDrawable(InsetState state, Resources res) {
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 689d225..4aa5f59 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -21,6 +21,7 @@
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
+import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.Outline;
@@ -36,6 +37,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.util.Collection;
 
 /**
  * A Drawable that manages an array of other Drawables. These are drawn in array
@@ -1105,6 +1107,20 @@
             mHaveOpacity = false;
             mHaveIsStateful = false;
         }
+
+        @Override
+        public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
+            final ChildDrawable[] array = mChildren;
+            final int N = mNum;
+            int pixelCount = 0;
+            for (int i = 0; i < N; i++) {
+                final ConstantState state = array[i].mDrawable.getConstantState();
+                if (state != null) {
+                    pixelCount += state.addAtlasableBitmaps(atlasList);
+                }
+            }
+            return pixelCount;
+        }
     }
 }
 
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index d821224..b87ae92 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -48,6 +48,7 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Collection;
 
 /**
  *
@@ -289,7 +290,7 @@
         if (bounds.isEmpty()) return;
 
         if (mNinePatchState != null) {
-            NinePatch.InsetStruct insets = mNinePatchState.getBitmap().getNinePatchInsets();
+            NinePatch.InsetStruct insets = mNinePatchState.mNinePatch.getBitmap().getNinePatchInsets();
             if (insets != null) {
                 final Rect outlineInsets = insets.outlineRect;
                 outline.setRoundRect(bounds.left + outlineInsets.left,
@@ -648,8 +649,12 @@
         }
 
         @Override
-        public Bitmap getBitmap() {
-            return mNinePatch.getBitmap();
+        public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
+            final Bitmap bitmap = mNinePatch.getBitmap();
+            if (isAtlasable(bitmap) && atlasList.add(bitmap)) {
+                return bitmap.getWidth() * bitmap.getHeight();
+            }
+            return 0;
         }
 
         @Override
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 13e3d54..9809606 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -556,11 +556,13 @@
         if (mRipple != null) {
             mRipple.cancel();
             mRipple = null;
+            mRippleActive = false;
         }
 
         if (mBackground != null) {
             mBackground.cancel();
             mBackground = null;
+            mBackgroundActive = false;
         }
 
         cancelExitingRipples();
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index d6d4cb8..da722f3 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -31,6 +31,7 @@
 import android.util.AttributeSet;
 
 import java.io.IOException;
+import java.util.Collection;
 
 /**
  * A Drawable that changes the size of another Drawable based on its current
@@ -413,6 +414,15 @@
 
             return mCanConstantState;
         }
+
+        @Override
+        public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
+            final ConstantState state = mDrawable.getConstantState();
+            if (state != null) {
+                return state.addAtlasableBitmaps(atlasList);
+            }
+            return 0;
+        }
     }
 
     private ScaleDrawable(ScaleState state, Resources res) {
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index d78c1cb..96e76d0 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -720,7 +720,8 @@
     }
 
     virtual void output(int level, uint32_t logFlags) const {
-        OP_LOG("Draw bitmap %p at %f %f", mBitmap, mLocalBounds.left, mLocalBounds.top);
+        OP_LOG("Draw bitmap %p at %f %f%s", mBitmap, mLocalBounds.left, mLocalBounds.top,
+                mEntry ? " using AssetAtlas" : "");
     }
 
     virtual const char* name() { return "DrawBitmap"; }
@@ -954,7 +955,8 @@
     }
 
     virtual void output(int level, uint32_t logFlags) const {
-        OP_LOG("Draw patch " RECT_STRING, RECT_ARGS(mLocalBounds));
+        OP_LOG("Draw patch " RECT_STRING "%s", RECT_ARGS(mLocalBounds),
+                mEntry ? " with AssetAtlas" : "");
     }
 
     virtual const char* name() { return "DrawPatch"; }
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index 717ce9a..31bd637 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -68,8 +68,6 @@
 }
 
 void ResourceCache::incrementRefcount(const SkBitmap* bitmapResource) {
-    bitmapResource->pixelRef()->globalRef();
-    SkSafeRef(bitmapResource->getColorTable());
     incrementRefcount((void*) bitmapResource, kBitmap);
 }
 
@@ -92,8 +90,6 @@
 }
 
 void ResourceCache::incrementRefcountLocked(const SkBitmap* bitmapResource) {
-    bitmapResource->pixelRef()->globalRef();
-    SkSafeRef(bitmapResource->getColorTable());
     incrementRefcountLocked((void*) bitmapResource, kBitmap);
 }
 
@@ -111,8 +107,6 @@
 }
 
 void ResourceCache::decrementRefcount(const SkBitmap* bitmapResource) {
-    bitmapResource->pixelRef()->globalUnref();
-    SkSafeUnref(bitmapResource->getColorTable());
     decrementRefcount((void*) bitmapResource);
 }
 
@@ -138,8 +132,6 @@
 }
 
 void ResourceCache::decrementRefcountLocked(const SkBitmap* bitmapResource) {
-    bitmapResource->pixelRef()->globalUnref();
-    SkSafeUnref(bitmapResource->getColorTable());
     decrementRefcountLocked((void*) bitmapResource);
 }
 
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index ebb7380..ea9e703 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -3110,11 +3110,12 @@
                 break;
             }
             if ((direction == AudioManager.ADJUST_LOWER)) {
-                if (VOLUME_SETS_RINGER_MODE_SILENT
-                        && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
-                    ringerMode = RINGER_MODE_SILENT;
-                } else {
-                    result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
+                if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
+                    if (VOLUME_SETS_RINGER_MODE_SILENT) {
+                        ringerMode = RINGER_MODE_SILENT;
+                    } else {
+                        result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
+                    }
                 }
             } else if (direction == AudioManager.ADJUST_RAISE) {
                 ringerMode = RINGER_MODE_NORMAL;
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 400c082..8d6a588 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -578,7 +578,11 @@
         @Override
         public int getWidth() {
             if (mIsImageValid) {
-                return ImageReader.this.mWidth;
+                if (mWidth == -1) {
+                    mWidth = (getFormat() == ImageFormat.JPEG) ? ImageReader.this.getWidth() :
+                            nativeGetWidth();
+                }
+                return mWidth;
             } else {
                 throw new IllegalStateException("Image is already released");
             }
@@ -587,7 +591,11 @@
         @Override
         public int getHeight() {
             if (mIsImageValid) {
-                return ImageReader.this.mHeight;
+                if (mHeight == -1) {
+                    mHeight = (getFormat() == ImageFormat.JPEG) ? ImageReader.this.getHeight() :
+                            nativeGetHeight();
+                }
+                return mHeight;
             } else {
                 throw new IllegalStateException("Image is already released");
             }
@@ -721,9 +729,13 @@
 
         private SurfacePlane[] mPlanes;
         private boolean mIsImageValid;
+        private int mHeight = -1;
+        private int mWidth = -1;
 
         private synchronized native ByteBuffer nativeImageGetBuffer(int idx, int readerFormat);
         private synchronized native SurfacePlane nativeCreatePlane(int idx, int readerFormat);
+        private synchronized native int nativeGetWidth();
+        private synchronized native int nativeGetHeight();
     }
 
     private synchronized native void nativeInit(Object weakSelf, int w, int h,
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index acf1b43..615dac2 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -61,6 +61,7 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -979,6 +980,9 @@
             // Redirect ringtones to go directly to underlying provider
             uri = RingtoneManager.getActualDefaultRingtoneUri(context,
                     RingtoneManager.getDefaultType(uri));
+            if (uri == null) {
+                throw new FileNotFoundException("Failed to resolve default ringtone");
+            }
         }
 
         AssetFileDescriptor fd = null;
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 7d075ba..8441541 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -51,6 +51,12 @@
 
     private final Context mContext;
     private final AudioManager mAudioManager;
+
+    /**
+     * Flag indicating if we're allowed to fall back to remote playback using
+     * {@link #mRemotePlayer}. Typically this is false when we're the remote
+     * player and there is nobody else to delegate to.
+     */
     private final boolean mAllowRemote;
     private final IRingtonePlayer mRemotePlayer;
     private final Binder mRemoteToken;
@@ -211,12 +217,7 @@
             mLocalPlayer.setAudioAttributes(mAudioAttributes);
             mLocalPlayer.prepare();
 
-        } catch (SecurityException e) {
-            destroyLocalPlayer();
-            if (!mAllowRemote) {
-                Log.w(TAG, "Remote playback not allowed: " + e);
-            }
-        } catch (IOException e) {
+        } catch (SecurityException | IOException e) {
             destroyLocalPlayer();
             if (!mAllowRemote) {
                 Log.w(TAG, "Remote playback not allowed: " + e);
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index e13f008..df4bc78 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -412,7 +412,9 @@
      * @param metadata The new metadata
      */
     public void setMetadata(@Nullable MediaMetadata metadata) {
-        metadata = (new MediaMetadata.Builder(metadata, mMaxBitmapSize)).build();
+        if (metadata != null ) {
+            metadata = (new MediaMetadata.Builder(metadata, mMaxBitmapSize)).build();
+        }
         try {
             mBinder.setMetadata(metadata);
         } catch (RemoteException e) {
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 7830c80..3f4736d 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -615,6 +615,24 @@
     return rowStride;
 }
 
+static int Image_getBufferWidth(CpuConsumer::LockedBuffer* buffer) {
+    if (buffer == NULL) return -1;
+
+    if (!buffer->crop.isEmpty()) {
+        return buffer->crop.getWidth();
+    }
+    return buffer->width;
+}
+
+static int Image_getBufferHeight(CpuConsumer::LockedBuffer* buffer) {
+    if (buffer == NULL) return -1;
+
+    if (!buffer->crop.isEmpty()) {
+        return buffer->crop.getHeight();
+    }
+    return buffer->height;
+}
+
 // ----------------------------------------------------------------------------
 
 static void ImageReader_classInit(JNIEnv* env, jclass clazz)
@@ -795,33 +813,16 @@
     }
 
     // Check if the producer buffer configurations match what ImageReader configured.
-    // We want to fail for the very first image because this case is too bad.
-    int outputWidth = buffer->width;
-    int outputHeight = buffer->height;
-
-    // Correct width/height when crop is set.
-    if (!buffer->crop.isEmpty()) {
-        outputWidth = buffer->crop.getWidth();
-        outputHeight = buffer->crop.getHeight();
-    }
+    int outputWidth = Image_getBufferWidth(buffer);
+    int outputHeight = Image_getBufferHeight(buffer);
 
     int imgReaderFmt = ctx->getBufferFormat();
     int imageReaderWidth = ctx->getBufferWidth();
     int imageReaderHeight = ctx->getBufferHeight();
     if ((buffer->format != HAL_PIXEL_FORMAT_BLOB) && (imgReaderFmt != HAL_PIXEL_FORMAT_BLOB) &&
-            (imageReaderWidth != outputWidth || imageReaderHeight > outputHeight)) {
-        /**
-         * For video decoder, the buffer height is actually the vertical stride,
-         * which is always >= actual image height. For future, decoder need provide
-         * right crop rectangle to CpuConsumer to indicate the actual image height,
-         * see bug 9563986. After this bug is fixed, we can enforce the height equal
-         * check. Right now, only make sure buffer height is no less than ImageReader
-         * height.
-         */
-        jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
-                "Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d",
-                outputWidth, outputHeight, imageReaderWidth, imageReaderHeight);
-        return -1;
+            (imageReaderWidth != outputWidth || imageReaderHeight != outputHeight)) {
+        ALOGV("%s: Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d",
+                __FUNCTION__, outputWidth, outputHeight, imageReaderWidth, imageReaderHeight);
     }
 
     int bufFmt = buffer->format;
@@ -934,6 +935,19 @@
     return byteBuffer;
 }
 
+static jint Image_getWidth(JNIEnv* env, jobject thiz)
+{
+    CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
+    return Image_getBufferWidth(buffer);
+}
+
+static jint Image_getHeight(JNIEnv* env, jobject thiz)
+{
+    CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
+    return Image_getBufferHeight(buffer);
+}
+
+
 } // extern "C"
 
 // ----------------------------------------------------------------------------
@@ -943,14 +957,16 @@
     {"nativeInit",             "(Ljava/lang/Object;IIII)V",  (void*)ImageReader_init },
     {"nativeClose",            "()V",                        (void*)ImageReader_close },
     {"nativeReleaseImage",     "(Landroid/media/Image;)V",   (void*)ImageReader_imageRelease },
-    {"nativeImageSetup",       "(Landroid/media/Image;)I",    (void*)ImageReader_imageSetup },
+    {"nativeImageSetup",       "(Landroid/media/Image;)I",   (void*)ImageReader_imageSetup },
     {"nativeGetSurface",       "()Landroid/view/Surface;",   (void*)ImageReader_getSurface },
 };
 
 static JNINativeMethod gImageMethods[] = {
     {"nativeImageGetBuffer",   "(II)Ljava/nio/ByteBuffer;",   (void*)Image_getByteBuffer },
     {"nativeCreatePlane",      "(II)Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
-                                                             (void*)Image_createSurfacePlane },
+                                                              (void*)Image_createSurfacePlane },
+    {"nativeGetWidth",         "()I",                         (void*)Image_getWidth },
+    {"nativeGetHeight",        "()I",                         (void*)Image_getHeight },
 };
 
 int register_android_media_ImageReader(JNIEnv *env) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
index bca0305..7c56e84 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -17,7 +17,11 @@
 package com.android.keyguard;
 
 import android.content.Context;
+import android.database.ContentObserver;
 import android.graphics.Rect;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
 import android.view.View;
@@ -28,19 +32,39 @@
 public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
         implements View.OnKeyListener {
 
+    private final android.database.ContentObserver mSpeakPasswordObserver
+            = new ContentObserver(new Handler()) {
+        @Override
+        public void onChange(boolean selfChange) {
+            super.onChange(selfChange);
+            // Ensure that it's not called too early
+            if (mButton0 != null) {
+                mButton0.updateContentDescription();
+                mButton1.updateContentDescription();
+                mButton2.updateContentDescription();
+                mButton3.updateContentDescription();
+                mButton4.updateContentDescription();
+                mButton5.updateContentDescription();
+                mButton6.updateContentDescription();
+                mButton7.updateContentDescription();
+                mButton8.updateContentDescription();
+                mButton9.updateContentDescription();
+            }
+        }
+    };
     protected PasswordTextView mPasswordEntry;
     private View mOkButton;
     private View mDeleteButton;
-    private View mButton0;
-    private View mButton1;
-    private View mButton2;
-    private View mButton3;
-    private View mButton4;
-    private View mButton5;
-    private View mButton6;
-    private View mButton7;
-    private View mButton8;
-    private View mButton9;
+    private NumPadKey mButton0;
+    private NumPadKey mButton1;
+    private NumPadKey mButton2;
+    private NumPadKey mButton3;
+    private NumPadKey mButton4;
+    private NumPadKey mButton5;
+    private NumPadKey mButton6;
+    private NumPadKey mButton7;
+    private NumPadKey mButton8;
+    private NumPadKey mButton9;
 
     public KeyguardPinBasedInputView(Context context) {
         this(context, null);
@@ -48,6 +72,9 @@
 
     public KeyguardPinBasedInputView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        context.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD), true,
+                mSpeakPasswordObserver, UserHandle.USER_ALL);
     }
 
     @Override
@@ -188,16 +215,16 @@
             }
         });
 
-        mButton0 = findViewById(R.id.key0);
-        mButton1 = findViewById(R.id.key1);
-        mButton2 = findViewById(R.id.key2);
-        mButton3 = findViewById(R.id.key3);
-        mButton4 = findViewById(R.id.key4);
-        mButton5 = findViewById(R.id.key5);
-        mButton6 = findViewById(R.id.key6);
-        mButton7 = findViewById(R.id.key7);
-        mButton8 = findViewById(R.id.key8);
-        mButton9 = findViewById(R.id.key9);
+        mButton0 = (NumPadKey) findViewById(R.id.key0);
+        mButton1 = (NumPadKey) findViewById(R.id.key1);
+        mButton2 = (NumPadKey) findViewById(R.id.key2);
+        mButton3 = (NumPadKey) findViewById(R.id.key3);
+        mButton4 = (NumPadKey) findViewById(R.id.key4);
+        mButton5 = (NumPadKey) findViewById(R.id.key5);
+        mButton6 = (NumPadKey) findViewById(R.id.key6);
+        mButton7 = (NumPadKey) findViewById(R.id.key7);
+        mButton8 = (NumPadKey) findViewById(R.id.key8);
+        mButton9 = (NumPadKey) findViewById(R.id.key9);
 
         mPasswordEntry.requestFocus();
         super.onFinishInflate();
diff --git a/packages/Keyguard/src/com/android/keyguard/NumPadKey.java b/packages/Keyguard/src/com/android/keyguard/NumPadKey.java
index d539856..70a4108 100644
--- a/packages/Keyguard/src/com/android/keyguard/NumPadKey.java
+++ b/packages/Keyguard/src/com/android/keyguard/NumPadKey.java
@@ -22,6 +22,8 @@
 import android.os.Debug;
 import android.os.PowerManager;
 import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.AttributeSet;
 import android.view.HapticFeedbackConstants;
 import android.view.KeyEvent;
@@ -118,7 +120,17 @@
         }
 
         setBackground(mContext.getDrawable(R.drawable.ripple_drawable));
-        setContentDescription(mDigitText.getText().toString() + mKlondikeText.getText().toString());
+        updateContentDescription();
+    }
+
+    public void updateContentDescription() {
+        if (shouldSpeakPasswordsForAccessibility()) {
+            setContentDescription(
+                    mDigitText.getText().toString() + mKlondikeText.getText().toString());
+        } else {
+            setContentDescription(getContext().getString(
+                    com.android.internal.R.string.keyboard_password_character_no_headset));
+        }
     }
 
     @Override
@@ -152,6 +164,15 @@
         mKlondikeText.layout(left, top, left + mKlondikeText.getMeasuredWidth(), bottom);
     }
 
+    /**
+     * @return true if the user has explicitly allowed accessibility services
+     * to speak passwords.
+     */
+    private boolean shouldSpeakPasswordsForAccessibility() {
+        return (Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0, UserHandle.USER_CURRENT) == 1);
+    }
+
     @Override
     public boolean hasOverlappingRendering() {
         return false;
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index ca07c87..4cf4f52d 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -29,6 +29,7 @@
         android:layout_height="wrap_content"
         android:layout_marginBottom="@dimen/keyguard_indication_margin_bottom"
         android:layout_gravity="bottom|center_horizontal"
+        android:gravity="center_horizontal"
         android:textStyle="italic"
         android:textColor="#ffffff"
         android:textAppearance="?android:attr/textAppearanceSmall" />
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 4f0700e..f1bf66d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -61,15 +61,8 @@
 /** A proxy implementation for the recents component */
 public class AlternateRecentsComponent implements ActivityOptions.OnAnimationStartedListener {
 
-    final public static String EXTRA_FROM_HOME = "recents.triggeredOverHome";
-    final public static String EXTRA_FROM_SEARCH_HOME = "recents.triggeredOverSearchHome";
-    final public static String EXTRA_FROM_APP_THUMBNAIL = "recents.animatingWithThumbnail";
-    final public static String EXTRA_FROM_TASK_ID = "recents.activeTaskId";
     final public static String EXTRA_TRIGGERED_FROM_ALT_TAB = "recents.triggeredFromAltTab";
     final public static String EXTRA_TRIGGERED_FROM_HOME_KEY = "recents.triggeredFromHomeKey";
-    final public static String EXTRA_REUSE_TASK_STACK_VIEWS = "recents.reuseTaskStackViews";
-    final public static String EXTRA_NUM_VISIBLE_TASKS = "recents.numVisibleTasks";
-    final public static String EXTRA_NUM_VISIBLE_THUMBNAILS = "recents.numVisibleThumbnails";
 
     final public static String ACTION_START_ENTER_ANIMATION = "action_start_enter_animation";
     final public static String ACTION_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity";
@@ -550,7 +543,8 @@
             ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack,
                     mDummyStackView);
             if (opts != null) {
-                startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_APP_THUMBNAIL, stackVr);
+                startAlternateRecentsActivity(topTask, opts, false /* fromHome */,
+                        false /* fromSearchHome */, true /* fromThumbnail */, stackVr);
             } else {
                 // Fall through below to the non-thumbnail transition
                 useThumbnailTransition = false;
@@ -583,12 +577,13 @@
                 }
 
                 ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome);
-                startAlternateRecentsActivity(topTask, opts,
-                        fromSearchHome ? EXTRA_FROM_SEARCH_HOME : EXTRA_FROM_HOME, stackVr);
+                startAlternateRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome,
+                        false /* fromThumbnail */, stackVr);
             } else {
                 // Otherwise we do the normal fade from an unknown source
                 ActivityOptions opts = getUnknownTransitionActivityOptions();
-                startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_HOME, stackVr);
+                startAlternateRecentsActivity(topTask, opts, true /* fromHome */,
+                        false /* fromSearchHome */, false /* fromThumbnail */, stackVr);
             }
         }
         mLastToggleTime = SystemClock.elapsedRealtime();
@@ -596,21 +591,24 @@
 
     /** Starts the recents activity */
     void startAlternateRecentsActivity(ActivityManager.RunningTaskInfo topTask,
-            ActivityOptions opts, String extraFlag,
+            ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
             TaskStackViewLayoutAlgorithm.VisibilityReport vr) {
+        // Update the configuration based on the launch options
+        mConfig.launchedFromHome = fromSearchHome || fromHome;
+        mConfig.launchedFromSearchHome = fromSearchHome;
+        mConfig.launchedFromAppWithThumbnail = fromThumbnail;
+        mConfig.launchedToTaskId = (topTask != null) ? topTask.id : -1;
+        mConfig.launchedWithAltTab = mTriggeredFromAltTab;
+        mConfig.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
+        mConfig.launchedNumVisibleTasks = vr.numVisibleTasks;
+        mConfig.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
+        mConfig.launchedHasConfigurationChanged = false;
+
         Intent intent = new Intent(sToggleRecentsAction);
         intent.setClassName(sRecentsPackage, sRecentsActivity);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
                 | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
-        if (extraFlag != null) {
-            intent.putExtra(extraFlag, true);
-        }
-        intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, mTriggeredFromAltTab);
-        intent.putExtra(EXTRA_FROM_TASK_ID, (topTask != null) ? topTask.id : -1);
-        intent.putExtra(EXTRA_REUSE_TASK_STACK_VIEWS, mCanReuseTaskStackViews);
-        intent.putExtra(EXTRA_NUM_VISIBLE_TASKS, vr.numVisibleTasks);
-        intent.putExtra(EXTRA_NUM_VISIBLE_THUMBNAILS, vr.numVisibleThumbnails);
         if (opts != null) {
             mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index a37bc54..6baff96 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -108,8 +108,6 @@
 
         @Override
         public void run() {
-            // Mark Recents as no longer visible
-            onRecentsActivityVisibilityChanged(false);
             // Finish Recents
             if (mLaunchIntent != null) {
                 if (mLaunchOpts != null) {
@@ -133,8 +131,6 @@
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
             if (action.equals(AlternateRecentsComponent.ACTION_HIDE_RECENTS_ACTIVITY)) {
-                // Mark Recents as no longer visible
-                AlternateRecentsComponent.notifyVisibilityChanged(false);
                 if (intent.getBooleanExtra(AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false)) {
                     // If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app
                     dismissRecentsToFocusedTaskOrHome(false);
@@ -186,24 +182,6 @@
 
     /** Updates the set of recent tasks */
     void updateRecentsTasks(Intent launchIntent) {
-        // Update the configuration based on the launch intent
-        boolean fromSearchHome = launchIntent.getBooleanExtra(
-                AlternateRecentsComponent.EXTRA_FROM_SEARCH_HOME, false);
-        int numVisibleTasks = launchIntent.getIntExtra(
-                AlternateRecentsComponent.EXTRA_NUM_VISIBLE_TASKS, 0);
-        int numVisibleThumbnails = launchIntent.getIntExtra(
-                AlternateRecentsComponent.EXTRA_NUM_VISIBLE_THUMBNAILS, 0);
-        mConfig.launchedFromHome = fromSearchHome || launchIntent.getBooleanExtra(
-                AlternateRecentsComponent.EXTRA_FROM_HOME, false);
-        mConfig.launchedFromAppWithThumbnail = launchIntent.getBooleanExtra(
-                AlternateRecentsComponent.EXTRA_FROM_APP_THUMBNAIL, false);
-        mConfig.launchedToTaskId = launchIntent.getIntExtra(
-                AlternateRecentsComponent.EXTRA_FROM_TASK_ID, -1);
-        mConfig.launchedWithAltTab = launchIntent.getBooleanExtra(
-                AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false);
-        mConfig.launchedReuseTaskStackViews = launchIntent.getBooleanExtra(
-                AlternateRecentsComponent.EXTRA_REUSE_TASK_STACK_VIEWS, false);
-
         // If AlternateRecentsComponent has preloaded a load plan, then use that to prevent
         // reconstructing the task stack
         RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
@@ -218,8 +196,8 @@
         }
         RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
         loadOpts.runningTaskId = mConfig.launchedToTaskId;
-        loadOpts.numVisibleTasks = numVisibleTasks;
-        loadOpts.numVisibleTaskThumbnails = numVisibleThumbnails;
+        loadOpts.numVisibleTasks = mConfig.launchedNumVisibleTasks;
+        loadOpts.numVisibleTaskThumbnails = mConfig.launchedNumVisibleThumbnails;
         loader.loadTasks(this, plan, loadOpts);
 
         SpaceNode root = plan.getSpaceNode();
@@ -237,9 +215,9 @@
                 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
         mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent,
             ActivityOptions.makeCustomAnimation(this,
-                fromSearchHome ? R.anim.recents_to_search_launcher_enter :
+                mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_enter :
                         R.anim.recents_to_launcher_enter,
-                fromSearchHome ? R.anim.recents_to_search_launcher_exit :
+                    mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_exit :
                         R.anim.recents_to_launcher_exit));
 
         // Mark the task that is the launch target
@@ -403,12 +381,12 @@
         mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub);
         mDebugOverlayStub = (ViewStub) findViewById(R.id.debug_overlay_stub);
         mScrimViews = new SystemBarScrimViews(this, mConfig);
+        mStatusBar = ((SystemUIApplication) getApplication())
+                .getComponent(PhoneStatusBar.class);
         inflateDebugOverlay();
 
         // Bind the search app widget when we first start up
         bindSearchBarAppWidget();
-        // Update the recent tasks
-        updateRecentsTasks(getIntent());
 
         // Register the broadcast receiver to handle messages when the screen is turned off
         IntentFilter filter = new IntentFilter();
@@ -424,17 +402,6 @@
         } catch (InvocationTargetException e) {
             e.printStackTrace();
         }
-
-        // Update if we are getting a configuration change
-        if (savedInstanceState != null) {
-            // Update RecentsConfiguration
-            mConfig.updateOnConfigurationChange();
-            // Trigger the enter animation
-            onEnterAnimationTriggered();
-        }
-
-        mStatusBar = ((SystemUIApplication) getApplication())
-                .getComponent(PhoneStatusBar.class);
     }
 
     /** Inflates the debug overlay if debug mode is enabled. */
@@ -449,14 +416,6 @@
         }
     }
 
-    /** Handles changes to the activity visibility. */
-    void onRecentsActivityVisibilityChanged(boolean visible) {
-        if (!visible) {
-            AlternateRecentsComponent.notifyVisibilityChanged(visible);
-        }
-        mVisible = visible;
-    }
-
     @Override
     protected void onNewIntent(Intent intent) {
         super.onNewIntent(intent);
@@ -469,14 +428,13 @@
         if (mDebugOverlay != null) {
             mDebugOverlay.clear();
         }
-
-        // Update the recent tasks
-        updateRecentsTasks(intent);
     }
 
     @Override
     protected void onStart() {
         super.onStart();
+        mVisible = true;
+        AlternateRecentsComponent.notifyVisibilityChanged(true);
 
         // Register the broadcast receiver to handle messages from our service
         IntentFilter filter = new IntentFilter();
@@ -487,19 +445,16 @@
 
         // Register any broadcast receivers for the task loader
         RecentsTaskLoader.getInstance().registerReceivers(this, mRecentsView);
-    }
 
-    @Override
-    protected void onResume() {
-        super.onResume();
-
-        // Mark Recents as visible
-        onRecentsActivityVisibilityChanged(true);
+        // Update the recent tasks
+        updateRecentsTasks(getIntent());
     }
 
     @Override
     protected void onStop() {
         super.onStop();
+        mVisible = false;
+        AlternateRecentsComponent.notifyVisibilityChanged(false);
 
         // Notify the views that we are no longer visible
         mRecentsView.onRecentsHidden();
@@ -641,8 +596,6 @@
 
     @Override
     public void onTaskViewClicked() {
-        // Mark recents as no longer visible
-        onRecentsActivityVisibilityChanged(false);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 2b33d14..52e7e7f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -124,8 +124,12 @@
     public boolean launchedWithNoRecentTasks;
     public boolean launchedFromAppWithThumbnail;
     public boolean launchedFromHome;
+    public boolean launchedFromSearchHome;
     public boolean launchedReuseTaskStackViews;
+    public boolean launchedHasConfigurationChanged;
     public int launchedToTaskId;
+    public int launchedNumVisibleTasks;
+    public int launchedNumVisibleThumbnails;
 
     /** Misc **/
     public boolean useHardwareLayers;
@@ -308,12 +312,10 @@
     /** Called when the configuration has changed, and we want to reset any configuration specific
      * members. */
     public void updateOnConfigurationChange() {
-        launchedWithAltTab = false;
-        launchedWithNoRecentTasks = false;
-        launchedFromAppWithThumbnail = false;
-        launchedFromHome = false;
+        // Reset this flag on configuration change to ensure that we recreate new task views
         launchedReuseTaskStackViews = false;
-        launchedToTaskId = -1;
+        // Set this flag to indicate that the configuration has changed since Recents last launched
+        launchedHasConfigurationChanged = true;
     }
 
     /** Returns whether the search bar app widget exists. */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 33a36f6..169683f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -715,14 +715,20 @@
             mStartEnterAnimationContext = null;
         }
 
-        // When Alt-Tabbing, we scroll to and focus the previous task
+        // When Alt-Tabbing, focus the previous task (but leave the animation until we finish the
+        // enter animation).
         if (mConfig.launchedWithAltTab) {
-            if (mConfig.launchedFromHome) {
-                focusTask(Math.max(0, mStack.getTaskCount() - 1), false, true);
+            if (mConfig.launchedFromAppWithThumbnail) {
+                focusTask(Math.max(0, mStack.getTaskCount() - 2), false,
+                        mConfig.launchedHasConfigurationChanged);
             } else {
-                focusTask(Math.max(0, mStack.getTaskCount() - 2), false, true);
+                focusTask(Math.max(0, mStack.getTaskCount() - 1), false,
+                        mConfig.launchedHasConfigurationChanged);
             }
         }
+
+        // Start dozing
+        mUIDozeTrigger.startDozing();
     }
 
     /** Requests this task stacks to start it's enter-recents animation */
@@ -767,16 +773,27 @@
                 @Override
                 public void run() {
                     mStartEnterAnimationCompleted = true;
-                    // Start dozing
-                    mUIDozeTrigger.startDozing();
-                    // Focus the first view if accessibility is enabled
+                    // Poke the dozer to restart the trigger after the animation completes
+                    mUIDozeTrigger.poke();
+
                     RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
                     SystemServicesProxy ssp = loader.getSystemServicesProxy();
                     int childCount = getChildCount();
-                    if (childCount > 0 && ssp.isTouchExplorationEnabled()) {
-                        TaskView tv = ((TaskView) getChildAt(childCount - 1));
-                        tv.requestAccessibilityFocus();
-                        mPrevAccessibilityFocusedIndex = mStack.indexOfTask(tv.getTask());
+                    if (childCount > 0) {
+                        // Focus the first view if accessibility is enabled
+                        if (ssp.isTouchExplorationEnabled()) {
+                            TaskView tv = ((TaskView) getChildAt(childCount - 1));
+                            tv.requestAccessibilityFocus();
+                            mPrevAccessibilityFocusedIndex = mStack.indexOfTask(tv.getTask());
+                        }
+                    }
+
+                    // Start the focus animation when alt-tabbing
+                    if (mConfig.launchedWithAltTab && !mConfig.launchedHasConfigurationChanged) {
+                        View tv = getChildAt(mFocusedTaskIndex);
+                        if (tv != null) {
+                            ((TaskView) tv).setFocusedTask(true);
+                        }
                     }
                 }
             });
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
index 26fbbf4..49b9129 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
@@ -135,7 +135,6 @@
         // Update the task offsets
         float pAtBackMostCardTop = 0.5f;
         float pAtFrontMostCardTop = pAtBackMostCardTop;
-        float pAtSecondFrontMostCardTop = pAtBackMostCardTop;
         int taskCount = tasks.size();
         for (int i = 0; i < taskCount; i++) {
             Task task = tasks.get(i);
@@ -145,25 +144,19 @@
                 // Increment the peek height
                 float pPeek = task.group.isFrontMostTask(task) ?
                         pBetweenAffiliateOffset : pWithinAffiliateOffset;
-                pAtSecondFrontMostCardTop = pAtFrontMostCardTop;
                 pAtFrontMostCardTop += pPeek;
             }
         }
 
         mMaxScrollP = pAtFrontMostCardTop - ((1f - pTaskHeightOffset - pNavBarOffset));
         mMinScrollP = tasks.size() == 1 ? Math.max(mMaxScrollP, 0f) : 0f;
-        if (launchedWithAltTab) {
-            if (launchedFromHome) {
-                // Center the top most task, since that will be focused first
-                mInitialScrollP = pAtSecondFrontMostCardTop - 0.5f;
-            } else {
-                // Center the second top most task, since that will be focused first
-                mInitialScrollP = pAtSecondFrontMostCardTop - 0.5f;
-            }
+        if (launchedWithAltTab && launchedFromHome) {
+            // Center the top most task, since that will be focused first
+            mInitialScrollP = mMaxScrollP;
         } else {
             mInitialScrollP = pAtFrontMostCardTop - 0.825f;
         }
-        mInitialScrollP = Math.max(0, mInitialScrollP);
+        mInitialScrollP = Math.min(mMaxScrollP, Math.max(0, mInitialScrollP));
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index de5974f..faa728d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -235,7 +235,9 @@
     void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask,
                                              boolean occludesLaunchTarget, int offscreenY) {
         int initialDim = getDim();
-        if (mConfig.launchedFromAppWithThumbnail) {
+        if (mConfig.launchedHasConfigurationChanged) {
+            // Just load the views as-is
+        } else if (mConfig.launchedFromAppWithThumbnail) {
             if (isTaskViewLaunchTargetTask) {
                 // Set the dim to 0 so we can animate it in
                 initialDim = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 464d007..05f6f40 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -237,15 +237,17 @@
 
     /** Animates this task bar if the user does not interact with the stack after a certain time. */
     void startNoUserInteractionAnimation() {
-        mDismissButton.setVisibility(View.VISIBLE);
-        mDismissButton.setAlpha(0f);
-        mDismissButton.animate()
-                .alpha(1f)
-                .setStartDelay(0)
-                .setInterpolator(mConfig.fastOutLinearInInterpolator)
-                .setDuration(mConfig.taskViewEnterFromAppDuration)
-                .withLayer()
-                .start();
+        if (mDismissButton.getVisibility() != View.VISIBLE) {
+            mDismissButton.setVisibility(View.VISIBLE);
+            mDismissButton.setAlpha(0f);
+            mDismissButton.animate()
+                    .alpha(1f)
+                    .setStartDelay(0)
+                    .setInterpolator(mConfig.fastOutLinearInInterpolator)
+                    .setDuration(mConfig.taskViewEnterFromAppDuration)
+                    .withLayer()
+                    .start();
+        }
     }
 
     /** Mark this task view that the user does has not interacted with the stack after a certain time. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 0faad21..914b3d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -124,6 +124,7 @@
         mContractedChild = child;
         mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child);
         selectLayout(false /* animate */, true /* force */);
+        mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */);
     }
 
     public void setExpandedChild(View child) {
@@ -245,6 +246,7 @@
     public void notifyContentUpdated() {
         selectLayout(false /* animate */, true /* force */);
         if (mContractedChild != null) {
+            mContractedWrapper.notifyContentUpdated();
             mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
index 5b6e1cd..fbcba0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
@@ -26,6 +26,7 @@
 import android.graphics.ColorMatrixColorFilter;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
 import android.view.View;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
@@ -40,17 +41,18 @@
  */
 public class NotificationTemplateViewWrapper extends NotificationViewWrapper {
 
-    private final ViewInvertHelper mInvertHelper;
-    private final ImageView mIcon;
-    protected final ImageView mPicture;
     private final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix();
     private final PorterDuffColorFilter mIconColorFilter = new PorterDuffColorFilter(
             0, PorterDuff.Mode.SRC_ATOP);
     private final int mIconDarkAlpha;
-    private final int mIconBackgroundColor;
     private final int mIconBackgroundDarkColor;
     private final Interpolator mLinearOutSlowInInterpolator;
 
+    private int mIconBackgroundColor;
+    private ViewInvertHelper mInvertHelper;
+    private ImageView mIcon;
+    protected ImageView mPicture;
+
     protected NotificationTemplateViewWrapper(Context ctx, View view) {
         super(view);
         mIconDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha);
@@ -58,12 +60,16 @@
                 ctx.getResources().getColor(R.color.doze_small_icon_background_color);
         mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(ctx,
                 android.R.interpolator.linear_out_slow_in);
-        View mainColumn = view.findViewById(com.android.internal.R.id.notification_main_column);
+        resolveViews();
+    }
+
+    private void resolveViews() {
+        View mainColumn = mView.findViewById(com.android.internal.R.id.notification_main_column);
         mInvertHelper = mainColumn != null
                 ? new ViewInvertHelper(mainColumn, NotificationPanelView.DOZE_ANIMATION_DURATION)
                 : null;
-        ImageView largeIcon = (ImageView) view.findViewById(com.android.internal.R.id.icon);
-        ImageView rightIcon = (ImageView) view.findViewById(com.android.internal.R.id.right_icon);
+        ImageView largeIcon = (ImageView) mView.findViewById(com.android.internal.R.id.icon);
+        ImageView rightIcon = (ImageView) mView.findViewById(com.android.internal.R.id.right_icon);
         mIcon = resolveIcon(largeIcon, rightIcon);
         mPicture = resolvePicture(largeIcon);
         mIconBackgroundColor = resolveBackgroundColor(mIcon);
@@ -92,6 +98,14 @@
     }
 
     @Override
+    public void notifyContentUpdated() {
+        super.notifyContentUpdated();
+
+        // Reinspect the notification.
+        resolveViews();
+    }
+
+    @Override
     public void setDark(boolean dark, boolean fade, long delay) {
         if (mInvertHelper != null) {
             if (fade) {
@@ -180,7 +194,13 @@
     private void updateIconColorFilter(ImageView target, float intensity) {
         int color = interpolateColor(mIconBackgroundColor, mIconBackgroundDarkColor, intensity);
         mIconColorFilter.setColor(color);
-        target.getBackground().mutate().setColorFilter(mIconColorFilter);
+        Drawable background = target.getBackground();
+
+        // The notification might have been modified during the animation, so background might be
+        // null here.
+        if (background != null) {
+            background.mutate().setColorFilter(mIconColorFilter);
+        }
     }
 
     private void updateIconAlpha(ImageView target, boolean dark) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
index 0a02573..78b9739 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
@@ -53,4 +53,9 @@
      * @param delay if fading, the delay of the animation
      */
     public abstract void setDark(boolean dark, boolean fade, long delay);
+
+    /**
+     * Notifies this wrapper that the content of the view might have changed.
+     */
+    public void notifyContentUpdated() {}
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 8e50abe..8e35ee9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -277,9 +277,13 @@
                     mWifiStrengthId));
 
         boolean anyMobileVisible = false;
+        int firstMobileTypeId = 0;
         for (PhoneState state : mPhoneStates) {
             if (state.apply(anyMobileVisible)) {
-                anyMobileVisible = true;
+                if (!anyMobileVisible) {
+                    firstMobileTypeId = state.mMobileTypeId;
+                    anyMobileVisible = true;
+                }
             }
         }
 
@@ -298,7 +302,7 @@
             mWifiAirplaneSpacer.setVisibility(View.GONE);
         }
 
-        if ((anyMobileVisible || mNoSimsVisible) && mWifiVisible) {
+        if (((anyMobileVisible && firstMobileTypeId != 0) || mNoSimsVisible) && mWifiVisible) {
             mWifiSignalSpacer.setVisibility(View.VISIBLE);
         } else {
             mWifiSignalSpacer.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java
index 30da9cb..af51266 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java
@@ -196,6 +196,7 @@
     }
 
     public void setMobileDataEnabled(boolean enabled) {
+        Log.d(TAG, "setMobileDataEnabled: enabled=" + enabled);
         mTelephonyManager.setDataEnabled(enabled);
         if (mCallback != null) {
             mCallback.onMobileDataEnabled(enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 6431ab5..3397a38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -272,7 +272,7 @@
         if (mMobileSignalControllers.containsKey(dataSubId)) {
             return mMobileSignalControllers.get(dataSubId);
         }
-        Log.e(TAG, "Cannot find controller for data sub: " + dataSubId);
+        if (DEBUG) Log.e(TAG, "Cannot find controller for data sub: " + dataSubId);
         return mDefaultSignalController;
     }
 
@@ -293,7 +293,7 @@
         if (mMobileSignalControllers.containsKey(voiceSubId)) {
             return mMobileSignalControllers.get(voiceSubId).isEmergencyOnly();
         }
-        Log.e(TAG, "Cannot find controller for voice sub: " + voiceSubId);
+        if (DEBUG) Log.e(TAG, "Cannot find controller for voice sub: " + voiceSubId);
         // Something is wrong, better assume we can't make calls...
         return true;
     }
@@ -483,6 +483,10 @@
                 cachedControllers.get(key).unregisterListener();
             }
         }
+        // There may be new MobileSignalControllers around, make sure they get the current
+        // inet condition and airplane mode.
+        pushConnectivityToSignals();
+        updateAirplaneMode(true /* force */);
     }
 
     private boolean hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions) {
@@ -577,6 +581,13 @@
         mBluetoothTethered = mConnectedTransports.get(TRANSPORT_BLUETOOTH);
         mEthernetConnected = mConnectedTransports.get(TRANSPORT_ETHERNET);
 
+        pushConnectivityToSignals();
+    }
+
+    /**
+     * Pushes the current connectivity state to all SignalControllers.
+     */
+    private void pushConnectivityToSignals() {
         // We want to update all the icons, all at once, for any condition change
         for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
             mobileSignalController.setInetCondition(
diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java
index fc4838c..bc31450 100644
--- a/services/core/java/com/android/server/AssetAtlasService.java
+++ b/services/core/java/com/android/server/AssetAtlasService.java
@@ -46,8 +46,11 @@
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashSet;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -66,7 +69,7 @@
      */
     public static final String ASSET_ATLAS_SERVICE = "assetatlas";
 
-    private static final String LOG_TAG = "Atlas";
+    private static final String LOG_TAG = "AssetAtlas";
 
     // Turns debug logs on/off. Debug logs are kept to a minimum and should
     // remain on to diagnose issues
@@ -131,7 +134,7 @@
         mContext = context;
         mVersionName = queryVersionName(context);
 
-        ArrayList<Bitmap> bitmaps = new ArrayList<Bitmap>(300);
+        Collection<Bitmap> bitmaps = new HashSet<Bitmap>(300);
         int totalPixelCount = 0;
 
         // We only care about drawables that hold bitmaps
@@ -140,16 +143,18 @@
 
         final int count = drawables.size();
         for (int i = 0; i < count; i++) {
-            final Bitmap bitmap = drawables.valueAt(i).getBitmap();
-            if (bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888) {
-                bitmaps.add(bitmap);
-                totalPixelCount += bitmap.getWidth() * bitmap.getHeight();
+            try {
+                totalPixelCount += drawables.valueAt(i).addAtlasableBitmaps(bitmaps);
+            } catch (Throwable t) {
+                Log.e("AssetAtlas", "Failed to fetch preloaded drawable state", t);
+                throw t;
             }
         }
 
+        ArrayList<Bitmap> sortedBitmaps = new ArrayList<Bitmap>(bitmaps);
         // Our algorithms perform better when the bitmaps are first sorted
         // The comparator will sort the bitmap by width first, then by height
-        Collections.sort(bitmaps, new Comparator<Bitmap>() {
+        Collections.sort(sortedBitmaps, new Comparator<Bitmap>() {
             @Override
             public int compare(Bitmap b1, Bitmap b2) {
                 if (b1.getWidth() == b2.getWidth()) {
@@ -160,7 +165,7 @@
         });
 
         // Kick off the packing work on a worker thread
-        new Thread(new Renderer(bitmaps, totalPixelCount)).start();
+        new Thread(new Renderer(sortedBitmaps, totalPixelCount)).start();
     }
 
     /**
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 9c0e486..a86d564 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -20,22 +20,8 @@
 import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
-import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
-import static android.net.ConnectivityManager.TYPE_DUMMY;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_MOBILE_CBS;
-import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
-import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
-import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
-import static android.net.ConnectivityManager.TYPE_MOBILE_IA;
-import static android.net.ConnectivityManager.TYPE_MOBILE_IMS;
-import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
-import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
 import static android.net.ConnectivityManager.TYPE_NONE;
-import static android.net.ConnectivityManager.TYPE_PROXY;
 import static android.net.ConnectivityManager.TYPE_VPN;
-import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.ConnectivityManager.TYPE_WIMAX;
 import static android.net.ConnectivityManager.getNetworkTypeName;
 import static android.net.ConnectivityManager.isNetworkTypeValid;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
@@ -45,11 +31,9 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
-import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
@@ -62,7 +46,6 @@
 import android.net.INetworkPolicyListener;
 import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
-import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.LinkProperties.CompareResult;
 import android.net.MobileDataStateTracker;
@@ -72,7 +55,6 @@
 import android.net.NetworkConfig;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkFactory;
 import android.net.NetworkMisc;
 import android.net.NetworkQuotaInfo;
 import android.net.NetworkRequest;
@@ -80,16 +62,12 @@
 import android.net.NetworkStateTracker;
 import android.net.NetworkUtils;
 import android.net.Proxy;
-import android.net.ProxyDataTracker;
 import android.net.ProxyInfo;
 import android.net.RouteInfo;
 import android.net.SamplingDataTracker;
 import android.net.UidRange;
 import android.net.Uri;
-import android.net.wimax.WimaxManagerConstants;
-import android.os.AsyncTask;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -103,7 +81,6 @@
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -126,9 +103,6 @@
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnProfile;
 import com.android.internal.telephony.DctConstants;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.XmlUtils;
@@ -146,8 +120,6 @@
 import com.google.android.collect.Lists;
 import com.google.android.collect.Sets;
 
-import dalvik.system.DexClassLoader;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -157,31 +129,20 @@
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.lang.reflect.Constructor;
-import java.net.HttpURLConnection;
 import java.net.Inet4Address;
-import java.net.Inet6Address;
 import java.net.InetAddress;
-import java.net.URL;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.GregorianCalendar;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Random;
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLSession;
-
 /**
  * @hide
  */
@@ -270,6 +231,7 @@
     private static ConnectivityService sServiceInstance;
 
     private INetworkManagementService mNetd;
+    private INetworkStatsService mStatsService;
     private INetworkPolicyManager mPolicyManager;
 
     private String mCurrentTcpBufferSizes;
@@ -328,12 +290,6 @@
     private static final int EVENT_SEND_STICKY_BROADCAST_INTENT = 11;
 
     /**
-     * Used internally to
-     * {@link NetworkStateTracker#setPolicyDataEnable(boolean)}.
-     */
-    private static final int EVENT_SET_POLICY_DATA_ENABLE = 12;
-
-    /**
      * Used internally to disable fail fast of mobile data
      */
     private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 14;
@@ -675,6 +631,7 @@
 
         mContext = checkNotNull(context, "missing Context");
         mNetd = checkNotNull(netManager, "missing INetworkManagementService");
+        mStatsService = checkNotNull(statsService, "missing INetworkStatsService");
         mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
         mKeyStore = KeyStore.getInstance();
         mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
@@ -850,6 +807,7 @@
         LinkProperties lp = null;
         NetworkCapabilities nc = null;
         Network network = null;
+        String subscriberId = null;
 
         if (mLegacyTypeTracker.isTypeSupported(networkType)) {
             NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
@@ -859,6 +817,7 @@
                     lp = new LinkProperties(nai.linkProperties);
                     nc = new NetworkCapabilities(nai.networkCapabilities);
                     network = new Network(nai.network);
+                    subscriberId = (nai.networkMisc != null) ? nai.networkMisc.subscriberId : null;
                 }
                 info.setType(networkType);
             } else {
@@ -872,7 +831,7 @@
             info = getFilteredNetworkInfo(info, lp, uid);
         }
 
-        return new NetworkState(info, lp, nc, network);
+        return new NetworkState(info, lp, nc, network, subscriberId, null);
     }
 
     private NetworkAgentInfo getNetworkAgentInfoForNetwork(Network network) {
@@ -889,6 +848,7 @@
         LinkProperties lp = null;
         NetworkCapabilities nc = null;
         Network network = null;
+        String subscriberId = null;
 
         NetworkAgentInfo nai = mNetworkForRequestId.get(mDefaultRequest.requestId);
 
@@ -920,10 +880,11 @@
                 lp = new LinkProperties(nai.linkProperties);
                 nc = new NetworkCapabilities(nai.networkCapabilities);
                 network = new Network(nai.network);
+                subscriberId = (nai.networkMisc != null) ? nai.networkMisc.subscriberId : null;
             }
         }
 
-        return new NetworkState(info, lp, nc, network);
+        return new NetworkState(info, lp, nc, network, subscriberId, null);
     }
 
     /**
@@ -1220,14 +1181,19 @@
 
     @Override
     public NetworkState[] getAllNetworkState() {
-        enforceAccessPermission();
-        final int uid = Binder.getCallingUid();
+        // Require internal since we're handing out IMSI details
+        enforceConnectivityInternalPermission();
+
         final ArrayList<NetworkState> result = Lists.newArrayList();
-        for (int networkType = 0; networkType <= ConnectivityManager.MAX_NETWORK_TYPE;
-                networkType++) {
-            NetworkState state = getFilteredNetworkState(networkType, uid);
-            if (state.networkInfo != null) {
-                result.add(state);
+        for (Network network : getAllNetworks()) {
+            final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+            if (nai != null) {
+                synchronized (nai) {
+                    final String subscriberId = (nai.networkMisc != null)
+                            ? nai.networkMisc.subscriberId : null;
+                    result.add(new NetworkState(nai.networkInfo, nai.linkProperties,
+                            nai.networkCapabilities, network, subscriberId, null));
+                }
             }
         }
         return result.toArray(new NetworkState[result.size()]);
@@ -1452,25 +1418,6 @@
         }
     };
 
-    @Override
-    public void setPolicyDataEnable(int networkType, boolean enabled) {
-        // only someone like NPMS should only be calling us
-        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-
-        mHandler.sendMessage(mHandler.obtainMessage(
-                EVENT_SET_POLICY_DATA_ENABLE, networkType, (enabled ? ENABLED : DISABLED)));
-    }
-
-    private void handleSetPolicyDataEnable(int networkType, boolean enabled) {
-   // TODO - handle this passing to factories
-//        if (isNetworkTypeValid(networkType)) {
-//            final NetworkStateTracker tracker = mNetTrackers[networkType];
-//            if (tracker != null) {
-//                tracker.setPolicyDataEnable(enabled);
-//            }
-//        }
-    }
-
     private void enforceInternetPermission() {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.INTERNET,
@@ -2221,6 +2168,7 @@
             if (isDefaultNetwork(nai)) {
                 mDefaultInetConditionPublished = 0;
             }
+            notifyIfacesChanged();
             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
             nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
             mNetworkAgentInfos.remove(msg.replyTo);
@@ -2457,12 +2405,6 @@
                     sendStickyBroadcast(intent);
                     break;
                 }
-                case EVENT_SET_POLICY_DATA_ENABLE: {
-                    final int networkType = msg.arg1;
-                    final boolean enabled = msg.arg2 == ENABLED;
-                    handleSetPolicyDataEnable(networkType, enabled);
-                    break;
-                }
                 case EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: {
                     int tag = mEnableFailFastMobileDataTag.get();
                     if (msg.arg1 == tag) {
@@ -3721,6 +3663,7 @@
         if (isDefaultNetwork(networkAgent)) handleApplyDefaultProxy(newLp.getHttpProxy());
         // TODO - move this check to cover the whole function
         if (!Objects.equals(newLp, oldLp)) {
+            notifyIfacesChanged();
             notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
         }
     }
@@ -3858,7 +3801,6 @@
         mNumDnsEntries = last;
     }
 
-
     private void updateCapabilities(NetworkAgentInfo networkAgent,
             NetworkCapabilities networkCapabilities) {
         if (!Objects.equals(networkAgent.networkCapabilities, networkCapabilities)) {
@@ -4312,6 +4254,7 @@
             }
             networkAgent.created = true;
             updateLinkProperties(networkAgent, null);
+            notifyIfacesChanged();
             notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK);
             networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
             if (networkAgent.isVPN()) {
@@ -4455,6 +4398,16 @@
         return "UNKNOWN";
     }
 
+    /**
+     * Notify other system services that set of active ifaces has changed.
+     */
+    private void notifyIfacesChanged() {
+        try {
+            mStatsService.forceUpdateIfaces();
+        } catch (Exception ignored) {
+        }
+    }
+
     @Override
     public boolean addVpnAddress(String address, int prefixLength) {
         throwIfLockdownEnabled();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4eadff9..1227148 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1075,6 +1075,13 @@
      */
     boolean mSafeMode;
 
+    /**
+     * If true, we are running under a test environment so will sample PSS from processes
+     * much more rapidly to try to collect better data when the tests are rapidly
+     * running through apps.
+     */
+    boolean mTestPssMode = false;
+
     String mDebugApp = null;
     boolean mWaitForDebugger = false;
     boolean mDebugTransient = false;
@@ -1091,6 +1098,8 @@
     int mProfileType = 0;
     String mOpenGlTraceApp = null;
 
+    final long[] mTmpLong = new long[1];
+
     static class ProcessChangeItem {
         static final int CHANGE_ACTIVITIES = 1<<0;
         static final int CHANGE_PROCESS_STATE = 1<<1;
@@ -1802,7 +1811,7 @@
                                     continue;
                                 }
                             }
-                            nativeTotalPss += Debug.getPss(st.pid, null);
+                            nativeTotalPss += Debug.getPss(st.pid, null, null);
                         }
                     }
                     memInfo.readMemInfo();
@@ -1815,48 +1824,38 @@
                     }
                 }
 
-                int i = 0;
                 int num = 0;
                 long[] tmp = new long[1];
                 do {
                     ProcessRecord proc;
                     int procState;
                     int pid;
+                    long lastPssTime;
                     synchronized (ActivityManagerService.this) {
-                        if (i >= mPendingPssProcesses.size()) {
-                            if (DEBUG_PSS) Slog.d(TAG, "Collected PSS of " + num + " of " + i
+                        if (mPendingPssProcesses.size() <= 0) {
+                            if (mTestPssMode || DEBUG_PSS) Slog.d(TAG, "Collected PSS of " + num
                                     + " processes in " + (SystemClock.uptimeMillis()-start) + "ms");
                             mPendingPssProcesses.clear();
                             return;
                         }
-                        proc = mPendingPssProcesses.get(i);
+                        proc = mPendingPssProcesses.remove(0);
                         procState = proc.pssProcState;
+                        lastPssTime = proc.lastPssTime;
                         if (proc.thread != null && procState == proc.setProcState) {
                             pid = proc.pid;
                         } else {
                             proc = null;
                             pid = 0;
                         }
-                        i++;
                     }
                     if (proc != null) {
-                        long pss = Debug.getPss(pid, tmp);
+                        long pss = Debug.getPss(pid, tmp, null);
                         synchronized (ActivityManagerService.this) {
-                            if (proc.thread != null && proc.setProcState == procState
-                                    && proc.pid == pid) {
+                            if (pss != 0 && proc.thread != null && proc.setProcState == procState
+                                    && proc.pid == pid && proc.lastPssTime == lastPssTime) {
                                 num++;
-                                proc.lastPssTime = SystemClock.uptimeMillis();
-                                proc.baseProcessTracker.addPss(pss, tmp[0], true, proc.pkgList);
-                                if (DEBUG_PSS) Slog.d(TAG, "PSS of " + proc.toShortString()
-                                        + ": " + pss + " lastPss=" + proc.lastPss
-                                        + " state=" + ProcessList.makeProcStateString(procState));
-                                if (proc.initialIdlePss == 0) {
-                                    proc.initialIdlePss = pss;
-                                }
-                                proc.lastPss = pss;
-                                if (procState >= ActivityManager.PROCESS_STATE_HOME) {
-                                    proc.lastCachedPss = pss;
-                                }
+                                recordPssSample(proc, procState, pss, tmp[0],
+                                        SystemClock.uptimeMillis());
                             }
                         }
                     }
@@ -5420,7 +5419,7 @@
                 }
             }
             long[] tmpUss = new long[1];
-            pss[i] = Debug.getPss(pids[i], tmpUss);
+            pss[i] = Debug.getPss(pids[i], tmpUss, null);
             if (proc != null) {
                 synchronized (this) {
                     if (proc.thread != null && proc.setAdj == oomAdj) {
@@ -10949,7 +10948,7 @@
                     proc.notCachedSinceIdle = true;
                     proc.initialIdlePss = 0;
                     proc.nextPssTime = ProcessList.computeNextPssTime(proc.curProcState, true,
-                            isSleeping(), now);
+                            mTestPssMode, isSleeping(), now);
                 }
             }
 
@@ -12919,7 +12918,8 @@
                     + PowerManagerInternal.wakefulnessToString(mWakefulness));
             pw.println("  mSleeping=" + mSleeping + " mLockScreenShown="
                     + lockScreenShownToString());
-            pw.println("  mShuttingDown=" + mShuttingDown + " mRunningVoice=" + mRunningVoice);
+            pw.println("  mShuttingDown=" + mShuttingDown + " mRunningVoice=" + mRunningVoice
+                    + " mTestPssMode=" + mTestPssMode);
         }
         if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
                 || mOrigWaitForDebugger) {
@@ -14014,7 +14014,7 @@
                         if (dumpDetails || (!brief && !oomOnly)) {
                             Debug.getMemoryInfo(pid, mi);
                         } else {
-                            mi.dalvikPss = (int)Debug.getPss(pid, tmpLong);
+                            mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null);
                             mi.dalvikPrivateDirty = (int)tmpLong[0];
                         }
                         ActivityThread.dumpMemInfoTable(pw, mi, isCheckinRequest, dumpFullDetails,
@@ -14076,7 +14076,7 @@
                 if (dumpDetails || (!brief && !oomOnly)) {
                     Debug.getMemoryInfo(pid, mi);
                 } else {
-                    mi.dalvikPss = (int)Debug.getPss(pid, tmpLong);
+                    mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null);
                     mi.dalvikPrivateDirty = (int)tmpLong[0];
                 }
                 if (dumpDetails) {
@@ -14152,6 +14152,7 @@
             // If we are showing aggregations, also look for native processes to
             // include so that our aggregations are more accurate.
             updateCpuStatsNow();
+            mi = null;
             synchronized (mProcessCpuTracker) {
                 final int N = mProcessCpuTracker.countStats();
                 for (int i=0; i<N; i++) {
@@ -14163,7 +14164,7 @@
                         if (!brief && !oomOnly) {
                             Debug.getMemoryInfo(st.pid, mi);
                         } else {
-                            mi.nativePss = (int)Debug.getPss(st.pid, tmpLong);
+                            mi.nativePss = (int)Debug.getPss(st.pid, tmpLong, null);
                             mi.nativePrivateDirty = (int)tmpLong[0];
                         }
 
@@ -14354,7 +14355,7 @@
     }
 
     private void appendBasicMemEntry(StringBuilder sb, int oomAdj, int procState, long pss,
-            String name) {
+            long memtrack, String name) {
         sb.append("  ");
         sb.append(ProcessList.makeOomAdjString(oomAdj));
         sb.append(' ');
@@ -14363,11 +14364,16 @@
         ProcessList.appendRamKb(sb, pss);
         sb.append(" kB: ");
         sb.append(name);
+        if (memtrack > 0) {
+            sb.append(" (");
+            sb.append(memtrack);
+            sb.append(" kB memtrack)");
+        }
     }
 
     private void appendMemInfo(StringBuilder sb, ProcessMemInfo mi) {
-        appendBasicMemEntry(sb, mi.oomAdj, mi.procState, mi.pss, mi.name);
-        sb.append(" (");
+        appendBasicMemEntry(sb, mi.oomAdj, mi.procState, mi.pss, mi.memtrack, mi.name);
+        sb.append(" (pid ");
         sb.append(mi.pid);
         sb.append(") ");
         sb.append(mi.adjType);
@@ -14386,17 +14392,19 @@
             infoMap.put(mi.pid, mi);
         }
         updateCpuStatsNow();
+        long[] memtrackTmp = new long[1];
         synchronized (mProcessCpuTracker) {
             final int N = mProcessCpuTracker.countStats();
             for (int i=0; i<N; i++) {
                 ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
                 if (st.vsize > 0) {
-                    long pss = Debug.getPss(st.pid, null);
+                    long pss = Debug.getPss(st.pid, null, memtrackTmp);
                     if (pss > 0) {
                         if (infoMap.indexOfKey(st.pid) < 0) {
                             ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
                                     ProcessList.NATIVE_ADJ, -1, "native", null);
                             mi.pss = pss;
+                            mi.memtrack = memtrackTmp[0];
                             memInfos.add(mi);
                         }
                     }
@@ -14405,12 +14413,15 @@
         }
 
         long totalPss = 0;
+        long totalMemtrack = 0;
         for (int i=0, N=memInfos.size(); i<N; i++) {
             ProcessMemInfo mi = memInfos.get(i);
             if (mi.pss == 0) {
-                mi.pss = Debug.getPss(mi.pid, null);
+                mi.pss = Debug.getPss(mi.pid, null, memtrackTmp);
+                mi.memtrack = memtrackTmp[0];
             }
             totalPss += mi.pss;
+            totalMemtrack += mi.memtrack;
         }
         Collections.sort(memInfos, new Comparator<ProcessMemInfo>() {
             @Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) {
@@ -14437,6 +14448,7 @@
         boolean firstLine = true;
         int lastOomAdj = Integer.MIN_VALUE;
         long extraNativeRam = 0;
+        long extraNativeMemtrack = 0;
         long cachedPss = 0;
         for (int i=0, N=memInfos.size(); i<N; i++) {
             ProcessMemInfo mi = memInfos.get(i);
@@ -14487,18 +14499,19 @@
 
             appendMemInfo(fullNativeBuilder, mi);
             if (mi.oomAdj == ProcessList.NATIVE_ADJ) {
-                // The short form only has native processes that are >= 1MB.
-                if (mi.pss >= 1000) {
+                // The short form only has native processes that are >= 512K.
+                if (mi.pss >= 512) {
                     appendMemInfo(shortNativeBuilder, mi);
                 } else {
                     extraNativeRam += mi.pss;
+                    extraNativeMemtrack += mi.memtrack;
                 }
             } else {
                 // Short form has all other details, but if we have collected RAM
                 // from smaller native processes let's dump a summary of that.
                 if (extraNativeRam > 0) {
                     appendBasicMemEntry(shortNativeBuilder, ProcessList.NATIVE_ADJ,
-                            -1, extraNativeRam, "(Other native)");
+                            -1, extraNativeRam, extraNativeMemtrack, "(Other native)");
                     shortNativeBuilder.append('\n');
                     extraNativeRam = 0;
                 }
@@ -14508,7 +14521,14 @@
 
         fullJavaBuilder.append("           ");
         ProcessList.appendRamKb(fullJavaBuilder, totalPss);
-        fullJavaBuilder.append(" kB: TOTAL\n");
+        fullJavaBuilder.append(" kB: TOTAL");
+        if (totalMemtrack > 0) {
+            fullJavaBuilder.append(" (");
+            fullJavaBuilder.append(totalMemtrack);
+            fullJavaBuilder.append(" kB memtrack)");
+        } else {
+        }
+        fullJavaBuilder.append("\n");
 
         MemInfoReader memInfo = new MemInfoReader();
         memInfo.readMemInfo();
@@ -15680,11 +15700,13 @@
                 true, ALLOW_NON_FULL, "broadcast", callerPackage);
 
         // Make sure that the user who is receiving this broadcast is running.
-        // If not, we will just skip it.
+        // If not, we will just skip it. Make an exception for shutdown broadcasts
+        // and upgrade steps.
 
         if (userId != UserHandle.USER_ALL && !isUserRunningLocked(userId, false)) {
-            if (callingUid != Process.SYSTEM_UID || (intent.getFlags()
-                    & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
+            if ((callingUid != Process.SYSTEM_UID
+                    || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
+                    && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
                 Slog.w(TAG, "Skipping broadcast of " + intent
                         + ": user " + userId + " is stopped");
                 return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
@@ -17336,6 +17358,24 @@
     }
 
     /**
+     * Record new PSS sample for a process.
+     */
+    void recordPssSample(ProcessRecord proc, int procState, long pss, long uss, long now) {
+        proc.lastPssTime = now;
+        proc.baseProcessTracker.addPss(pss, uss, true, proc.pkgList);
+        if (DEBUG_PSS) Slog.d(TAG, "PSS of " + proc.toShortString()
+                + ": " + pss + " lastPss=" + proc.lastPss
+                + " state=" + ProcessList.makeProcStateString(procState));
+        if (proc.initialIdlePss == 0) {
+            proc.initialIdlePss = pss;
+        }
+        proc.lastPss = pss;
+        if (procState >= ActivityManager.PROCESS_STATE_HOME) {
+            proc.lastCachedPss = pss;
+        }
+    }
+
+    /**
      * Schedule PSS collection of a process.
      */
     void requestPssLocked(ProcessRecord proc, int procState) {
@@ -17370,13 +17410,24 @@
             if (memLowered || now > (app.lastStateTime+ProcessList.PSS_ALL_INTERVAL)) {
                 app.pssProcState = app.setProcState;
                 app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
-                        isSleeping(), now);
+                        mTestPssMode, isSleeping(), now);
                 mPendingPssProcesses.add(app);
             }
         }
         mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
     }
 
+    public void setTestPssMode(boolean enabled) {
+        synchronized (this) {
+            mTestPssMode = enabled;
+            if (enabled) {
+                // Whenever we enable the mode, we want to take a snapshot all of current
+                // process mem use.
+                requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, true);
+            }
+        }
+    }
+
     /**
      * Ask a given process to GC right now.
      */
@@ -17673,9 +17724,22 @@
         }
         if (app.setProcState < 0 || ProcessList.procStatesDifferForMem(app.curProcState,
                 app.setProcState)) {
+            if (false && mTestPssMode && app.setProcState >= 0 && app.lastStateTime <= (now-200)) {
+                // Experimental code to more aggressively collect pss while
+                // running test...  the problem is that this tends to collect
+                // the data right when a process is transitioning between process
+                // states, which well tend to give noisy data.
+                long start = SystemClock.uptimeMillis();
+                long pss = Debug.getPss(app.pid, mTmpLong, null);
+                recordPssSample(app, app.curProcState, pss, mTmpLong[0], now);
+                mPendingPssProcesses.remove(app);
+                Slog.i(TAG, "Recorded pss for " + app + " state " + app.setProcState
+                        + " to " + app.curProcState + ": "
+                        + (SystemClock.uptimeMillis()-start) + "ms");
+            }
             app.lastStateTime = now;
             app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
-                    isSleeping(), now);
+                    mTestPssMode, isSleeping(), now);
             if (DEBUG_PSS) Slog.d(TAG, "Process state change from "
                     + ProcessList.makeProcStateString(app.setProcState) + " to "
                     + ProcessList.makeProcStateString(app.curProcState) + " next pss in "
@@ -17685,7 +17749,7 @@
                     && now > (app.lastStateTime+ProcessList.PSS_MIN_TIME_FROM_STATE_CHANGE))) {
                 requestPssLocked(app, app.setProcState);
                 app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, false,
-                        isSleeping(), now);
+                        mTestPssMode, isSleeping(), now);
             } else if (false && DEBUG_PSS) {
                 Slog.d(TAG, "Not requesting PSS of " + app + ": next=" + (app.nextPssTime-now));
             }
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index d98f03c..efed0b9 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -222,13 +222,6 @@
     long mLaunchStartTime = 0;
     long mFullyDrawnStartTime = 0;
 
-    /**
-     * Save the most recent screenshot for reuse. This keeps Recents from taking two identical
-     * screenshots, one for the Recents thumbnail and one for the pauseActivity thumbnail.
-     */
-    private ActivityRecord mLastScreenshotActivity = null;
-    private Bitmap mLastScreenshotBitmap = null;
-
     int mCurrentUser;
 
     final int mStackId;
@@ -741,18 +734,6 @@
         }
     }
 
-    /**
-     * This resets the saved state from the last screenshot, forcing a new screenshot to be taken
-     * again when requested.
-     */
-    private void invalidateLastScreenshot() {
-        mLastScreenshotActivity = null;
-        if (mLastScreenshotBitmap != null) {
-            mLastScreenshotBitmap.recycle();
-        }
-        mLastScreenshotBitmap = null;
-    }
-
     public final Bitmap screenshotActivities(ActivityRecord who) {
         if (DEBUG_SCREENSHOTS) Slog.d(TAG, "screenshotActivities: " + who);
         if (who.noDisplay) {
@@ -762,30 +743,17 @@
 
         if (isHomeStack()) {
             // This is an optimization -- since we never show Home or Recents within Recents itself,
-            // we can just go ahead and skip taking the screenshot if this is the home stack.  In
-            // the case where the most recent task is not the task that was supplied, then the stack
-            // has changed, so invalidate the last screenshot().
-            invalidateLastScreenshot();
-            if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tIs Home stack? " + isHomeStack());
+            // we can just go ahead and skip taking the screenshot if this is the home stack.
+            if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tHome stack");
             return null;
         }
 
         int w = mService.mThumbnailWidth;
         int h = mService.mThumbnailHeight;
         if (w > 0) {
-            if (who != mLastScreenshotActivity || mLastScreenshotBitmap == null
-                    || mLastScreenshotActivity.state == ActivityState.RESUMED
-                    || mLastScreenshotBitmap.getWidth() != w
-                    || mLastScreenshotBitmap.getHeight() != h) {
-                if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tUpdating screenshot");
-                mLastScreenshotActivity = who;
-                mLastScreenshotBitmap = mWindowManager.screenshotApplications(
-                        who.appToken, Display.DEFAULT_DISPLAY, w, h, SCREENSHOT_FORCE_565);
-            }
-            if (mLastScreenshotBitmap != null) {
-                if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tReusing last screenshot");
-                return mLastScreenshotBitmap.copy(mLastScreenshotBitmap.getConfig(), true);
-            }
+            if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tTaking screenshot");
+            return mWindowManager.screenshotApplications(who.appToken, Display.DEFAULT_DISPLAY,
+                    w, h, SCREENSHOT_FORCE_565);
         }
         Slog.e(TAG, "Invalid thumbnail dimensions: " + w + "x" + h);
         return null;
@@ -1103,11 +1071,6 @@
             next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
         }
 
-        // If we are resuming the activity that we had last screenshotted, then we know it will be
-        // updated, so invalidate the last screenshot to ensure we take a fresh one when requested
-        if (next == mLastScreenshotActivity) {
-            invalidateLastScreenshot();
-        }
         next.returningOptions = null;
 
         if (mActivityContainer.mActivityDisplay.mVisibleBehindActivity == next) {
@@ -1824,9 +1787,6 @@
                     // Do over!
                     mStackSupervisor.scheduleResumeTopActivities();
                 }
-                if (next == mLastScreenshotActivity) {
-                    invalidateLastScreenshot();
-                }
                 if (mStackSupervisor.reportResumedActivityLocked(next)) {
                     mNoAnimActivities.clear();
                     if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index cdc5134..aa86786 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -441,6 +441,18 @@
     // The amount of time until PSS when a cached process stays in the same state.
     private static final int PSS_SAME_CACHED_INTERVAL = 30*60*1000;
 
+    // The amount of time during testing until PSS when a process first becomes top.
+    private static final int PSS_TEST_FIRST_TOP_INTERVAL = 3*1000;
+
+    // The amount of time during testing until PSS when a process first goes into the background.
+    private static final int PSS_TEST_FIRST_BACKGROUND_INTERVAL = 5*1000;
+
+    // The amount of time during testing until PSS when an important process stays in same state.
+    private static final int PSS_TEST_SAME_IMPORTANT_INTERVAL = 10*1000;
+
+    // The amount of time during testing until PSS when a background process stays in same state.
+    private static final int PSS_TEST_SAME_BACKGROUND_INTERVAL = 15*1000;
+
     public static final int PROC_MEM_PERSISTENT = 0;
     public static final int PROC_MEM_TOP = 1;
     public static final int PROC_MEM_IMPORTANT = 2;
@@ -498,16 +510,50 @@
         PSS_SAME_CACHED_INTERVAL,       // ActivityManager.PROCESS_STATE_CACHED_EMPTY
     };
 
+    private static final long[] sTestFirstAwakePssTimes = new long[] {
+        PSS_TEST_FIRST_TOP_INTERVAL,        // ActivityManager.PROCESS_STATE_PERSISTENT
+        PSS_TEST_FIRST_TOP_INTERVAL,        // ActivityManager.PROCESS_STATE_PERSISTENT_UI
+        PSS_TEST_FIRST_TOP_INTERVAL,        // ActivityManager.PROCESS_STATE_TOP
+        PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+        PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+        PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_BACKUP
+        PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
+        PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_SERVICE
+        PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_RECEIVER
+        PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_HOME
+        PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
+        PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
+        PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+        PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
+    };
+
+    private static final long[] sTestSameAwakePssTimes = new long[] {
+        PSS_TEST_SAME_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_PERSISTENT
+        PSS_TEST_SAME_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_PERSISTENT_UI
+        PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_TOP
+        PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+        PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+        PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_BACKUP
+        PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
+        PSS_TEST_SAME_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_SERVICE
+        PSS_TEST_SAME_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_RECEIVER
+        PSS_TEST_SAME_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_HOME
+        PSS_TEST_SAME_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
+        PSS_TEST_SAME_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
+        PSS_TEST_SAME_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+        PSS_TEST_SAME_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_CACHED_EMPTY
+    };
+
     public static boolean procStatesDifferForMem(int procState1, int procState2) {
         return sProcStateToProcMem[procState1] != sProcStateToProcMem[procState2];
     }
 
-    public static long computeNextPssTime(int procState, boolean first, boolean sleeping,
-            long now) {
-        final long[] table = sleeping
+    public static long computeNextPssTime(int procState, boolean first, boolean test,
+            boolean sleeping, long now) {
+        final long[] table = test
                 ? (first
-                        ? sFirstAwakePssTimes
-                        : sSameAwakePssTimes)
+                        ? sTestFirstAwakePssTimes
+                        : sTestSameAwakePssTimes)
                 : (first
                         ? sFirstAwakePssTimes
                         : sSameAwakePssTimes);
diff --git a/services/core/java/com/android/server/am/ProcessMemInfo.java b/services/core/java/com/android/server/am/ProcessMemInfo.java
index c94694e..83d29e2 100644
--- a/services/core/java/com/android/server/am/ProcessMemInfo.java
+++ b/services/core/java/com/android/server/am/ProcessMemInfo.java
@@ -24,6 +24,7 @@
     final String adjType;
     final String adjReason;
     long pss;
+    long memtrack;
 
     public ProcessMemInfo(String _name, int _pid, int _oomAdj, int _procState,
             String _adjType, String _adjReason) {
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index d05910b..55aec65 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -583,7 +583,7 @@
         pw.println("    [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]");
         pw.println("    [--details] [--full-details] [--current] [--hours N] [--last N]");
         pw.println("    [--max N] --active] [--commit] [--reset] [--clear] [--write] [-h]");
-        pw.println("    [<package.name>]");
+        pw.println("    [--start-testing] [--stop-testing] [<package.name>]");
         pw.println("  --checkin: perform a checkin: print and delete old committed states.");
         pw.println("  -c: print only state in checkin format.");
         pw.println("  --csv: output data suitable for putting in a spreadsheet.");
@@ -603,6 +603,8 @@
         pw.println("  --clear: clear all stats; does both --reset and deletes old stats.");
         pw.println("  --write: write current in-memory stats to disk.");
         pw.println("  --read: replace current stats with last-written stats.");
+        pw.println("  --start-testing: clear all stats and starting high frequency pss sampling.");
+        pw.println("  --stop-testing: stop high frequency pss sampling.");
         pw.println("  -a: print everything.");
         pw.println("  -h: print this help text.");
         pw.println("  <package.name>: optional name of package to filter output by.");
@@ -636,6 +638,7 @@
         boolean dumpDetails = false;
         boolean dumpFullDetails = false;
         boolean dumpAll = false;
+        boolean quit = false;
         int aggregateHours = 0;
         int lastIndex = 0;
         int maxNum = 2;
@@ -761,14 +764,14 @@
                         mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
                         writeStateLocked(true, true);
                         pw.println("Process stats committed.");
+                        quit = true;
                     }
-                    return;
                 } else if ("--reset".equals(arg)) {
                     synchronized (mAm) {
                         mProcessStats.resetSafely();
                         pw.println("Process stats reset.");
+                        quit = true;
                     }
-                    return;
                 } else if ("--clear".equals(arg)) {
                     synchronized (mAm) {
                         mProcessStats.resetSafely();
@@ -779,20 +782,32 @@
                             }
                         }
                         pw.println("All process stats cleared.");
+                        quit = true;
                     }
-                    return;
                 } else if ("--write".equals(arg)) {
                     synchronized (mAm) {
                         writeStateSyncLocked();
                         pw.println("Process stats written.");
+                        quit = true;
                     }
-                    return;
                 } else if ("--read".equals(arg)) {
                     synchronized (mAm) {
                         readLocked(mProcessStats, mFile);
                         pw.println("Process stats read.");
+                        quit = true;
                     }
-                    return;
+                } else if ("--start-testing".equals(arg)) {
+                    synchronized (mAm) {
+                        mAm.setTestPssMode(true);
+                        pw.println("Started high frequency sampling.");
+                        quit = true;
+                    }
+                } else if ("--stop-testing".equals(arg)) {
+                    synchronized (mAm) {
+                        mAm.setTestPssMode(false);
+                        pw.println("Stopped high frequency sampling.");
+                        quit = true;
+                    }
                 } else if ("-h".equals(arg)) {
                     dumpHelp(pw);
                     return;
@@ -815,6 +830,10 @@
             }
         }
 
+        if (quit) {
+            return;
+        }
+
         if (isCsv) {
             pw.print("Processes running summed over");
             if (!csvSepScreenStats) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index d39f2ed..62de534 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -1332,7 +1332,8 @@
         if (old == null) {
             invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_ADD_DEVICE);
         } else if (!old.equals(info)) {
-            invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_UPDATE_DEVICE);
+            invokeDeviceEventListener(old, HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE);
+            invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_ADD_DEVICE);
         }
     }
 
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index cf19416..2be591b 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -120,7 +120,9 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.text.TextUtils;
 import android.text.format.Formatter;
 import android.text.format.Time;
 import android.util.ArrayMap;
@@ -136,16 +138,17 @@
 import android.util.TrustedTime;
 import android.util.Xml;
 
+import libcore.io.IoUtils;
+
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
 import com.google.android.collect.Lists;
 
-import libcore.io.IoUtils;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -160,7 +163,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import java.util.Objects;
 
 /**
  * Service that maintains low-level network policy rules, using
@@ -253,38 +255,38 @@
     private final boolean mSuppressDefaultPolicy;
 
     /** Defined network policies. */
-    final ArrayMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = new ArrayMap<
-            NetworkTemplate, NetworkPolicy>();
+    final ArrayMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = new ArrayMap<>();
     /** Currently active network rules for ifaces. */
-    private final ArrayMap<NetworkPolicy, String[]> mNetworkRules = new ArrayMap<
-            NetworkPolicy, String[]>();
+    final ArrayMap<NetworkPolicy, String[]> mNetworkRules = new ArrayMap<>();
 
     /** Defined UID policies. */
     final SparseIntArray mUidPolicy = new SparseIntArray();
     /** Currently derived rules for each UID. */
-    private final SparseIntArray mUidRules = new SparseIntArray();
+    final SparseIntArray mUidRules = new SparseIntArray();
 
-    /** UIDs that have been white-listed to always be able to have network access in
-     * power save mode. */
+    /**
+     * UIDs that have been white-listed to always be able to have network access
+     * in power save mode.
+     */
     private final SparseBooleanArray mPowerSaveWhitelistAppIds = new SparseBooleanArray();
 
     /** Set of ifaces that are metered. */
-    private ArraySet<String> mMeteredIfaces = new ArraySet<String>();
+    private ArraySet<String> mMeteredIfaces = new ArraySet<>();
     /** Set of over-limit templates that have been notified. */
-    private final ArraySet<NetworkTemplate> mOverLimitNotified = new ArraySet<NetworkTemplate>();
+    private final ArraySet<NetworkTemplate> mOverLimitNotified = new ArraySet<>();
 
     /** Set of currently active {@link Notification} tags. */
     private final ArraySet<String> mActiveNotifs = new ArraySet<String>();
 
     /** Foreground at both UID and PID granularity. */
-    private final SparseIntArray mUidState = new SparseIntArray();
-    final SparseArray<SparseIntArray> mUidPidState = new SparseArray<SparseIntArray>();
+    final SparseIntArray mUidState = new SparseIntArray();
+    final SparseArray<SparseIntArray> mUidPidState = new SparseArray<>();
 
     /** The current maximum process state that we are considering to be foreground. */
     private int mCurForegroundState = ActivityManager.PROCESS_STATE_TOP;
 
-    private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<
-            INetworkPolicyListener>();
+    private final RemoteCallbackList<INetworkPolicyListener>
+            mListeners = new RemoteCallbackList<>();
 
     final Handler mHandler;
 
@@ -740,21 +742,24 @@
      * data connection status.
      */
     private boolean isTemplateRelevant(NetworkTemplate template) {
-        final TelephonyManager tele = TelephonyManager.from(mContext);
+        if (template.isMatchRuleMobile()) {
+            final TelephonyManager tele = TelephonyManager.from(mContext);
+            final SubscriptionManager sub = SubscriptionManager.from(mContext);
 
-        switch (template.getMatchRule()) {
-            case MATCH_MOBILE_3G_LOWER:
-            case MATCH_MOBILE_4G:
-            case MATCH_MOBILE_ALL:
-                // mobile templates are relevant when SIM is ready and
-                // subscriberId matches.
-                if (tele.getSimState() == SIM_STATE_READY) {
-                    return Objects.equals(tele.getSubscriberId(), template.getSubscriberId());
-                } else {
-                    return false;
+            // Mobile template is relevant when any active subscriber matches
+            final int[] subIds = sub.getActiveSubscriptionIdList();
+            for (int subId : subIds) {
+                final String subscriberId = tele.getSubscriberId(subId);
+                final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
+                        TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false);
+                if (template.matches(probeIdent)) {
+                    return true;
                 }
+            }
+            return false;
+        } else {
+            return true;
         }
-        return true;
     }
 
     /**
@@ -961,6 +966,7 @@
             maybeRefreshTrustedTime();
             synchronized (mRulesLock) {
                 ensureActiveMobilePolicyLocked();
+                normalizePoliciesLocked();
                 updateNetworkEnabledLocked();
                 updateNetworkRulesLocked();
                 updateNotificationsLocked();
@@ -1001,33 +1007,12 @@
     }
 
     /**
-     * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)}
-     * for the given {@link NetworkTemplate}.
+     * Proactively disable networks that match the given
+     * {@link NetworkTemplate}.
      */
     private void setNetworkTemplateEnabled(NetworkTemplate template, boolean enabled) {
-        final TelephonyManager tele = TelephonyManager.from(mContext);
-
-        switch (template.getMatchRule()) {
-            case MATCH_MOBILE_3G_LOWER:
-            case MATCH_MOBILE_4G:
-            case MATCH_MOBILE_ALL:
-                // TODO: offer more granular control over radio states once
-                // 4965893 is available.
-                if (tele.getSimState() == SIM_STATE_READY
-                        && Objects.equals(tele.getSubscriberId(), template.getSubscriberId())) {
-                    setPolicyDataEnable(TYPE_MOBILE, enabled);
-                    setPolicyDataEnable(TYPE_WIMAX, enabled);
-                }
-                break;
-            case MATCH_WIFI:
-                setPolicyDataEnable(TYPE_WIFI, enabled);
-                break;
-            case MATCH_ETHERNET:
-                setPolicyDataEnable(TYPE_ETHERNET, enabled);
-                break;
-            default:
-                throw new IllegalArgumentException("unexpected template");
-        }
+        // TODO: reach into ConnectivityManager to proactively disable bringing
+        // up this network, since we know that traffic will be blocked.
     }
 
     /**
@@ -1036,7 +1021,7 @@
      * remaining quota based on usage cycle and historical stats.
      */
     void updateNetworkRulesLocked() {
-        if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
+        if (LOGV) Slog.v(TAG, "updateNetworkRulesLocked()");
 
         final NetworkState[] states;
         try {
@@ -1203,42 +1188,47 @@
         if (mSuppressDefaultPolicy) return;
 
         final TelephonyManager tele = TelephonyManager.from(mContext);
+        final SubscriptionManager sub = SubscriptionManager.from(mContext);
 
-        // avoid creating policy when SIM isn't ready
-        if (tele.getSimState() != SIM_STATE_READY) return;
+        final int[] subIds = sub.getActiveSubscriptionIdList();
+        for (int subId : subIds) {
+            final String subscriberId = tele.getSubscriberId(subId);
+            ensureActiveMobilePolicyLocked(subscriberId);
+        }
+    }
 
-        final String subscriberId = tele.getSubscriberId();
-        final NetworkIdentity probeIdent = new NetworkIdentity(
-                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false);
-
-        // examine to see if any policy is defined for active mobile
-        boolean mobileDefined = false;
-        for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
-            if (mNetworkPolicy.valueAt(i).template.matches(probeIdent)) {
-                mobileDefined = true;
-                break;
+    private void ensureActiveMobilePolicyLocked(String subscriberId) {
+        // Poke around to see if we already have a policy
+        final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
+                TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false);
+        for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) {
+            final NetworkTemplate template = mNetworkPolicy.keyAt(i);
+            if (template.matches(probeIdent)) {
+                if (LOGD) {
+                    Slog.d(TAG, "Found template " + template + " which matches subscriber "
+                            + NetworkIdentity.scrubSubscriberId(subscriberId));
+                }
+                return;
             }
         }
 
-        if (!mobileDefined) {
-            Slog.i(TAG, "no policy for active mobile network; generating default policy");
+        Slog.i(TAG, "No policy for subscriber " + NetworkIdentity.scrubSubscriberId(subscriberId)
+                + "; generating default policy");
 
-            // build default mobile policy, and assume usage cycle starts today
-            final long warningBytes = mContext.getResources().getInteger(
-                    com.android.internal.R.integer.config_networkPolicyDefaultWarning)
-                    * MB_IN_BYTES;
+        // Build default mobile policy, and assume usage cycle starts today
+        final long warningBytes = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_networkPolicyDefaultWarning) * MB_IN_BYTES;
 
-            final Time time = new Time();
-            time.setToNow();
+        final Time time = new Time();
+        time.setToNow();
 
-            final int cycleDay = time.monthDay;
-            final String cycleTimezone = time.timezone;
+        final int cycleDay = time.monthDay;
+        final String cycleTimezone = time.timezone;
 
-            final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
-            final NetworkPolicy policy = new NetworkPolicy(template, cycleDay, cycleTimezone,
-                    warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true, true);
-            addNetworkPolicyLocked(policy);
-        }
+        final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
+        final NetworkPolicy policy = new NetworkPolicy(template, cycleDay, cycleTimezone,
+                warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true, true);
+        addNetworkPolicyLocked(policy);
     }
 
     private void readPolicyLocked() {
@@ -1321,8 +1311,8 @@
                             inferred = false;
                         }
 
-                        final NetworkTemplate template = new NetworkTemplate(
-                                networkTemplate, subscriberId, networkId);
+                        final NetworkTemplate template = new NetworkTemplate(networkTemplate,
+                                subscriberId, networkId);
                         mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay,
                                 cycleTimezone, warningBytes, limitBytes, lastWarningSnooze,
                                 lastLimitSnooze, metered, inferred));
@@ -1593,11 +1583,7 @@
 
         maybeRefreshTrustedTime();
         synchronized (mRulesLock) {
-            mNetworkPolicy.clear();
-            for (NetworkPolicy policy : policies) {
-                mNetworkPolicy.put(policy.template, policy);
-            }
-
+            normalizePoliciesLocked(policies);
             updateNetworkEnabledLocked();
             updateNetworkRulesLocked();
             updateNotificationsLocked();
@@ -1606,12 +1592,9 @@
     }
 
     void addNetworkPolicyLocked(NetworkPolicy policy) {
-        mNetworkPolicy.put(policy.template, policy);
-
-        updateNetworkEnabledLocked();
-        updateNetworkRulesLocked();
-        updateNotificationsLocked();
-        writePolicyLocked();
+        NetworkPolicy[] policies = getNetworkPolicies();
+        policies = ArrayUtils.appendElement(NetworkPolicy.class, policies, policy);
+        setNetworkPolicies(policies);
     }
 
     @Override
@@ -1620,7 +1603,35 @@
         mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG);
 
         synchronized (mRulesLock) {
-            return mNetworkPolicy.values().toArray(new NetworkPolicy[mNetworkPolicy.size()]);
+            final int size = mNetworkPolicy.size();
+            final NetworkPolicy[] policies = new NetworkPolicy[size];
+            for (int i = 0; i < size; i++) {
+                policies[i] = mNetworkPolicy.valueAt(i);
+            }
+            return policies;
+        }
+    }
+
+    private void normalizePoliciesLocked() {
+        normalizePoliciesLocked(getNetworkPolicies());
+    }
+
+    private void normalizePoliciesLocked(NetworkPolicy[] policies) {
+        final TelephonyManager tele = TelephonyManager.from(mContext);
+        final String[] merged = tele.getMergedSubscriberIds();
+
+        mNetworkPolicy.clear();
+        for (NetworkPolicy policy : policies) {
+            // When two normalized templates conflict, prefer the most
+            // restrictive policy
+            policy.template = NetworkTemplate.normalize(policy.template, merged);
+            final NetworkPolicy existing = mNetworkPolicy.get(policy.template);
+            if (existing == null || existing.compareTo(policy) > 0) {
+                if (existing != null) {
+                    Slog.d(TAG, "Normalization replaced " + existing + " with " + policy);
+                }
+                mNetworkPolicy.put(policy.template, policy);
+            }
         }
     }
 
@@ -1657,6 +1668,7 @@
                     throw new IllegalArgumentException("unexpected type");
             }
 
+            normalizePoliciesLocked();
             updateNetworkEnabledLocked();
             updateNetworkRulesLocked();
             updateNotificationsLocked();
@@ -1784,6 +1796,7 @@
                     mNetworkPolicy.valueAt(i).clearSnooze();
                 }
 
+                normalizePoliciesLocked();
                 updateNetworkEnabledLocked();
                 updateNetworkRulesLocked();
                 updateNotificationsLocked();
@@ -1976,6 +1989,7 @@
 
         // If the set of restricted networks may have changed, re-evaluate those.
         if (restrictedNetworksChanged) {
+            normalizePoliciesLocked();
             updateNetworkRulesLocked();
         }
     }
@@ -2162,17 +2176,6 @@
         }
     }
 
-    /**
-     * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)}.
-     */
-    private void setPolicyDataEnable(int networkType, boolean enabled) {
-        try {
-            mConnManager.setPolicyDataEnable(networkType, enabled);
-        } catch (RemoteException e) {
-            // ignored; service lives in system_server
-        }
-    }
-
     private long getTotalBytes(NetworkTemplate template, long start, long end) {
         try {
             return mNetworkStats.getNetworkTotalBytes(template, start, end);
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 61f9a26..856a076 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -26,9 +26,7 @@
 import static android.content.Intent.ACTION_USER_REMOVED;
 import static android.content.Intent.EXTRA_UID;
 import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
-import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
 import static android.net.ConnectivityManager.isNetworkTypeMobile;
-import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED;
 import static android.net.NetworkStats.IFACE_ALL;
 import static android.net.NetworkStats.SET_ALL;
 import static android.net.NetworkStats.SET_DEFAULT;
@@ -55,8 +53,6 @@
 import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE;
 import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES;
 import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE;
-import static android.telephony.PhoneStateListener.LISTEN_DATA_CONNECTION_STATE;
-import static android.telephony.PhoneStateListener.LISTEN_NONE;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
@@ -102,7 +98,6 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.Global;
-import android.telephony.PhoneStateListener;
 import android.telephony.TelephonyManager;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
@@ -308,10 +303,6 @@
             bootstrapStatsLocked();
         }
 
-        // watch for network interfaces to be claimed
-        final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE);
-        mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
-
         // watch for tethering changes
         final IntentFilter tetherFilter = new IntentFilter(ACTION_TETHER_STATE_CHANGED);
         mContext.registerReceiver(mTetherReceiver, tetherFilter, null, mHandler);
@@ -338,12 +329,6 @@
             // ignored; service lives in system_server
         }
 
-        // watch for networkType changes that aren't broadcast through
-        // CONNECTIVITY_ACTION_IMMEDIATE above.
-        if (!COMBINE_SUBTYPE_ENABLED) {
-            mTeleManager.listen(mPhoneListener, LISTEN_DATA_CONNECTION_STATE);
-        }
-
         registerPollAlarmLocked();
         registerGlobalAlert();
     }
@@ -358,16 +343,11 @@
     }
 
     private void shutdownLocked() {
-        mContext.unregisterReceiver(mConnReceiver);
         mContext.unregisterReceiver(mTetherReceiver);
         mContext.unregisterReceiver(mPollReceiver);
         mContext.unregisterReceiver(mRemovedReceiver);
         mContext.unregisterReceiver(mShutdownReceiver);
 
-        if (!COMBINE_SUBTYPE_ENABLED) {
-            mTeleManager.listen(mPhoneListener, LISTEN_NONE);
-        }
-
         final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
                 : System.currentTimeMillis();
 
@@ -620,6 +600,19 @@
     }
 
     @Override
+    public void forceUpdateIfaces() {
+        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+        assertBandwidthControlEnabled();
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            updateIfaces();
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    @Override
     public void forceUpdate() {
         mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
         assertBandwidthControlEnabled();
@@ -676,20 +669,6 @@
     }
 
     /**
-     * Receiver that watches for {@link IConnectivityManager} to claim network
-     * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()}
-     * with mobile interfaces.
-     */
-    private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            // on background handler thread, and verified CONNECTIVITY_INTERNAL
-            // permission above.
-            updateIfaces();
-        }
-    };
-
-    /**
      * Receiver that watches for {@link Tethering} to claim interface pairs.
      */
     private BroadcastReceiver mTetherReceiver = new BroadcastReceiver() {
@@ -784,35 +763,6 @@
         }
     };
 
-    private int mLastPhoneState = TelephonyManager.DATA_UNKNOWN;
-    private int mLastPhoneNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
-
-    /**
-     * Receiver that watches for {@link TelephonyManager} changes, such as
-     * transitioning between network types.
-     */
-    private PhoneStateListener mPhoneListener = new PhoneStateListener() {
-        @Override
-        public void onDataConnectionStateChanged(int state, int networkType) {
-            final boolean stateChanged = state != mLastPhoneState;
-            final boolean networkTypeChanged = networkType != mLastPhoneNetworkType;
-
-            if (networkTypeChanged && !stateChanged) {
-                // networkType changed without a state change, which means we
-                // need to roll our own update. delay long enough for
-                // ConnectivityManager to process.
-                // TODO: add direct event to ConnectivityService instead of
-                // relying on this delay.
-                if (LOGV) Slog.v(TAG, "triggering delayed updateIfaces()");
-                mHandler.sendMessageDelayed(
-                        mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS);
-            }
-
-            mLastPhoneState = state;
-            mLastPhoneNetworkType = networkType;
-        }
-    };
-
     private void updateIfaces() {
         synchronized (mStatsLock) {
             mWakeLock.acquire();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6f1e851..91637e3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -10199,13 +10199,13 @@
                 // default to original signature matching
                 if (compareSignatures(oldPackage.mSignatures, pkg.mSignatures)
                     != PackageManager.SIGNATURE_MATCH) {
-                    res.setError(INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
+                    res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
                             "New package has a different signature: " + pkgName);
                     return;
                 }
             } else {
                 if(!checkUpgradeKeySetLP(ps, pkg)) {
-                    res.setError(INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
+                    res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
                             "New package not signed by keys specified by upgrade-keysets: "
                             + pkgName);
                     return;
diff --git a/services/core/java/com/android/server/telecom/TelecomLoaderService.java b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
new file mode 100644
index 0000000..64a67fc
--- /dev/null
+++ b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.server.SystemService;
+
+/**
+ * Starts the telecom component by binding to its ITelecomService implementation. Telecom is setup
+ * to run in the system-server process so once it is loaded into memory it will stay running.
+ * @hide
+ */
+public class TelecomLoaderService extends SystemService {
+    private static final String TAG = "TelecomLoaderService";
+
+    private class TelecomServiceConnection implements ServiceConnection {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            // Normally, we would listen for death here, but since telecom runs in the same process
+            // as this loader (process="system") thats redundant here.
+            try {
+                service.linkToDeath(new IBinder.DeathRecipient() {
+                    @Override
+                    public void binderDied() {
+                        connectToTelecom();
+                    }
+                }, 0);
+
+                ServiceManager.addService(Context.TELECOM_SERVICE, service);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed linking to death.");
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            connectToTelecom();
+        }
+    }
+
+    private static final ComponentName SERVICE_COMPONENT = new ComponentName(
+            "com.android.server.telecom",
+            "com.android.server.telecom.TelecomService");
+
+    private static final String SERVICE_ACTION = "com.android.ITelecomService";
+
+    private final Context mContext;
+    private TelecomServiceConnection mServiceConnection;
+
+    public TelecomLoaderService(Context context) {
+        super(context);
+        mContext = context;
+    }
+
+    @Override
+    public void onStart() {
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == PHASE_ACTIVITY_MANAGER_READY) {
+            connectToTelecom();
+        }
+    }
+
+    private void connectToTelecom() {
+        if (mServiceConnection != null) {
+            // TODO: Is unbinding worth doing or wait for system to rebind?
+            mContext.unbindService(mServiceConnection);
+            mServiceConnection = null;
+        }
+
+        TelecomServiceConnection serviceConnection = new TelecomServiceConnection();
+        Intent intent = new Intent(SERVICE_ACTION);
+        intent.setComponent(SERVICE_COMPONENT);
+        int flags = Context.BIND_IMPORTANT | Context.BIND_AUTO_CREATE;
+
+        // Bind to Telecom and register the service
+        if (mContext.bindServiceAsUser(intent, serviceConnection, flags, UserHandle.OWNER)) {
+            mServiceConnection = serviceConnection;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ba89f23..021a6e4 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -617,8 +617,8 @@
 
         mOverscanInsets.set(Math.max(mOverscanFrame.left - mFrame.left, 0),
                 Math.max(mOverscanFrame.top - mFrame.top, 0),
-                Math.min(mFrame.right - mOverscanFrame.right, 0),
-                Math.min(mFrame.bottom - mOverscanFrame.bottom, 0));
+                Math.max(mFrame.right - mOverscanFrame.right, 0),
+                Math.max(mFrame.bottom - mOverscanFrame.bottom, 0));
 
         mContentInsets.set(mContentFrame.left - mFrame.left,
                 mContentFrame.top - mFrame.top,
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b3a696e..334cdf6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -89,6 +89,7 @@
 import com.android.server.search.SearchManagerService;
 import com.android.server.statusbar.StatusBarManagerService;
 import com.android.server.storage.DeviceStorageMonitorService;
+import com.android.server.telecom.TelecomLoaderService;
 import com.android.server.trust.TrustManagerService;
 import com.android.server.tv.TvInputManagerService;
 import com.android.server.twilight.TwilightService;
@@ -428,6 +429,8 @@
             Slog.i(TAG, "Scheduling Policy");
             ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
 
+            mSystemServiceManager.startService(TelecomLoaderService.class);
+
             Slog.i(TAG, "Telephony Registry");
             telephonyRegistry = new TelephonyRegistry(context);
             ServiceManager.addService("telephony.registry", telephonyRegistry);
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index b74716f..0b4d42e 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -916,10 +916,8 @@
     }
 
     private Future<Void> expectPolicyDataEnable(int type, boolean enabled) throws Exception {
-        final FutureAnswer future = new FutureAnswer();
-        mConnManager.setPolicyDataEnable(type, enabled);
-        expectLastCall().andAnswer(future);
-        return future;
+        // TODO: bring back this test
+        return null;
     }
 
     private void expectAdvisePersistThreshold() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index f9a03fc..7383478 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -1023,7 +1023,7 @@
         info.setDetailedState(DetailedState.CONNECTED, null, null);
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(iface);
-        return new NetworkState(info, prop, null, null);
+        return new NetworkState(info, prop, null, null, null, null);
     }
 
     private NetworkStats buildEmptyStats() {
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index abf1ead..20cd037 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.Context;
@@ -1064,7 +1065,7 @@
      *         is never null but the length maybe 0.
      * @hide
      */
-    public int[] getActiveSubscriptionIdList() {
+    public @NonNull int[] getActiveSubscriptionIdList() {
         int[] subId = null;
 
         try {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 751e11b..73e3213 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -40,6 +41,7 @@
 
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -1879,6 +1881,23 @@
     }
 
     /**
+     * Return the set of subscriber IDs that should be considered as "merged
+     * together" for data usage purposes. This is commonly {@code null} to
+     * indicate no merging is required. Any returned subscribers are sorted in a
+     * deterministic order.
+     *
+     * @hide
+     */
+    public @Nullable String[] getMergedSubscriberIds() {
+        try {
+            return getITelephony().getMergedSubscriberIds();
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+        return null;
+    }
+
+    /**
      * Returns the MSISDN string.
      * for a GSM phone. Return null if it is unavailable.
      * <p>
@@ -3490,8 +3509,15 @@
     /** @hide */
     @SystemApi
     public void setDataEnabled(boolean enable) {
+        setDataEnabled(SubscriptionManager.getDefaultDataSubId(), enable);
+    }
+
+    /** @hide */
+    @SystemApi
+    public void setDataEnabled(int subId, boolean enable) {
         try {
-            getITelephony().setDataEnabled(enable);
+            Log.d(TAG, "setDataEnabled: enabled=" + enable);
+            getITelephony().setDataEnabled(subId, enable);
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#setDataEnabled", e);
         }
@@ -3500,12 +3526,21 @@
     /** @hide */
     @SystemApi
     public boolean getDataEnabled() {
+        return getDataEnabled(SubscriptionManager.getDefaultDataSubId());
+    }
+
+    /** @hide */
+    @SystemApi
+    public boolean getDataEnabled(int subId) {
+        boolean retVal;
         try {
-            return getITelephony().getDataEnabled();
+            retVal = getITelephony().getDataEnabled(subId);
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#getDataEnabled", e);
+            retVal = false;
         }
-        return false;
+        Log.d(TAG, "getDataEnabled: retVal=" + retVal);
+        return retVal;
     }
 
     /**
@@ -3593,5 +3628,3 @@
         }
     }
 }
-
-
diff --git a/telephony/java/com/android/ims/internal/IImsCallSession.aidl b/telephony/java/com/android/ims/internal/IImsCallSession.aidl
index d1946e3..b1f2d32 100644
--- a/telephony/java/com/android/ims/internal/IImsCallSession.aidl
+++ b/telephony/java/com/android/ims/internal/IImsCallSession.aidl
@@ -223,6 +223,20 @@
     void sendDtmf(char c, in Message result);
 
     /**
+     * Start a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>,
+     * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15,
+     * and event flash to 16. Currently, event flash is not supported.
+     *
+     * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+     */
+    void startDtmf(char c);
+
+    /**
+     * Stop a DTMF code.
+     */
+    void stopDtmf();
+
+    /**
      * Sends an USSD message.
      *
      * @param ussdMessage USSD message to send
diff --git a/telephony/java/com/android/ims/internal/IImsConfig.aidl b/telephony/java/com/android/ims/internal/IImsConfig.aidl
index c5ccf5f..c17637c 100644
--- a/telephony/java/com/android/ims/internal/IImsConfig.aidl
+++ b/telephony/java/com/android/ims/internal/IImsConfig.aidl
@@ -49,22 +49,22 @@
  */
 interface IImsConfig {
     /**
-     * Gets the value for ims service/capabilities parameters from the master
+     * Gets the value for ims service/capabilities parameters from the provisioned
      * value storage. Synchronous blocking call.
      *
      * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
      * @return value in Integer format.
      */
-    int getMasterValue(int item);
+    int getProvisionedValue(int item);
 
     /**
-     * Gets the value for ims service/capabilities parameters from the master
+     * Gets the value for ims service/capabilities parameters from the provisioned
      * value storage. Synchronous blocking call.
      *
      * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
      * @return value in String format.
      */
-    String getMasterStringValue(int item);
+    String getProvisionedStringValue(int item);
 
     /**
      * Sets the value for IMS service/capabilities parameters by the operator device
@@ -112,4 +112,12 @@
      * @return void
      */
     oneway void setFeatureValue(int feature, int network, int value, ImsConfigListener listener);
+
+    /**
+     * Gets the value for IMS volte provisioned.
+     * This should be the same as the operator provisioned value if applies.
+     *
+     * @return void
+     */
+    boolean getVolteProvisioned();
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index bf7f332..4affad8 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -679,14 +679,14 @@
      *
      * @param enable true to turn on, else false
      */
-    void setDataEnabled(boolean enable);
+    void setDataEnabled(int subId, boolean enable);
 
     /**
      * Get the user enabled state of Mobile Data.
      *
      * @return true on enabled
      */
-    boolean getDataEnabled();
+    boolean getDataEnabled(int subId);
 
     /**
      * Get P-CSCF address from PCO after data connection is established or modified.
@@ -772,6 +772,8 @@
      */
     String getLine1AlphaTagForDisplay(int subId);
 
+    String[] getMergedSubscriberIds();
+
     /**
      * Override the operator branding for the current ICCID.
      *
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RevealActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/RevealActivity.java
index 256a1d4..1216fc4 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/RevealActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RevealActivity.java
@@ -17,12 +17,14 @@
 package com.android.test.hwui;
 
 import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
 import android.animation.AnimatorSet;
 import android.app.Activity;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewAnimationUtils;
@@ -37,6 +39,29 @@
     private boolean mShouldBlock;
     private int mIteration = 0;
 
+    private AnimatorListener mListener = new AnimatorListener() {
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+            Log.d("Reveal", "onAnimatorStart " + animation);
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+            Log.d("Reveal", "onAnimationRepeat " + animation);
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            Log.d("Reveal", "onAnimationEnd " + animation);
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            Log.d("Reveal", "onAnimationCancel " + animation);
+        }
+    };
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -59,6 +84,8 @@
         Animator animator = ViewAnimationUtils.createCircularReveal(view,
                 view.getWidth() / 2, view.getHeight() / 2,
                 0, Math.max(view.getWidth(), view.getHeight()));
+        Log.d("Reveal", "Calling start...");
+        animator.addListener(mListener);
         if (mIteration < 2) {
             animator.setDuration(DURATION);
             animator.start();
@@ -66,6 +93,7 @@
             AnimatorSet set = new AnimatorSet();
             set.playTogether(animator);
             set.setDuration(DURATION);
+            set.addListener(mListener);
             set.start();
         }
 
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index f5f70c5..d23b82e 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -516,12 +516,10 @@
 
     const size_t numFeatures = grp.features.size();
     for (size_t i = 0; i < numFeatures; i++) {
-        if (!grp.features[i]) {
-            continue;
-        }
+        const bool required = grp.features[i];
 
         const String8& featureName = grp.features.keyAt(i);
-        printf("  uses-feature: name='%s'\n",
+        printf("  uses-feature%s: name='%s'\n", (required ? "" : "-not-required"),
                 ResTable::normalizeForOutput(featureName.string()).string());
     }
 
@@ -1844,7 +1842,7 @@
                         }
                     }
 
-                   if (!grp.features.isEmpty()) {
+                    if (!grp.features.isEmpty()) {
                         printFeatureGroup(grp);
                     }
                 }