Merge "Import translations. DO NOT MERGE"
diff --git a/api/current.txt b/api/current.txt
index 3230bd8..15351de 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1132,6 +1132,7 @@
     field public static final int textAppearanceLargeInverse = 16842819; // 0x1010043
     field public static final int textAppearanceLargePopupMenu = 16843521; // 0x1010301
     field public static final int textAppearanceListItem = 16843678; // 0x101039e
+    field public static final int textAppearanceListItemSecondary = 16843838; // 0x101043e
     field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
     field public static final int textAppearanceMedium = 16842817; // 0x1010041
     field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
@@ -10632,6 +10633,7 @@
     method public void setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode);
     method public final void setTileModeY(android.graphics.Shader.TileMode);
     method public void setTint(android.content.res.ColorStateList);
+    method public void setTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public class ClipDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
@@ -10909,6 +10911,7 @@
     method public void setTargetDensity(android.util.DisplayMetrics);
     method public void setTargetDensity(int);
     method public void setTint(android.content.res.ColorStateList);
+    method public void setTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public class PaintDrawable extends android.graphics.drawable.ShapeDrawable {
@@ -10999,6 +11002,9 @@
 
   public class TouchFeedbackDrawable extends android.graphics.drawable.LayerDrawable {
     method public android.graphics.Rect getDirtyBounds();
+    method public android.content.res.ColorStateList getTint();
+    method public void setTint(android.content.res.ColorStateList);
+    method public void setTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public class TransitionDrawable extends android.graphics.drawable.LayerDrawable implements android.graphics.drawable.Drawable.Callback {
@@ -11721,6 +11727,7 @@
     field public static final int CONTROL_AWB_STATE_LOCKED = 3; // 0x3
     field public static final int CONTROL_AWB_STATE_SEARCHING = 1; // 0x1
     field public static final int CONTROL_CAPTURE_INTENT_CUSTOM = 0; // 0x0
+    field public static final int CONTROL_CAPTURE_INTENT_MANUAL = 6; // 0x6
     field public static final int CONTROL_CAPTURE_INTENT_PREVIEW = 1; // 0x1
     field public static final int CONTROL_CAPTURE_INTENT_STILL_CAPTURE = 2; // 0x2
     field public static final int CONTROL_CAPTURE_INTENT_VIDEO_RECORD = 3; // 0x3
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 30c84f6..d8be439 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1534,10 +1534,10 @@
     /**
      * @hide
      */
-    public void setActiveAdmin(ComponentName policyReceiver, boolean refreshing) {
+    public void setActiveAdmin(ComponentName policyReceiver, boolean refreshing, int userHandle) {
         if (mService != null) {
             try {
-                mService.setActiveAdmin(policyReceiver, refreshing, UserHandle.myUserId());
+                mService.setActiveAdmin(policyReceiver, refreshing, userHandle);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1545,6 +1545,13 @@
     }
 
     /**
+     * @hide
+     */
+    public void setActiveAdmin(ComponentName policyReceiver, boolean refreshing) {
+        setActiveAdmin(policyReceiver, refreshing, UserHandle.myUserId());
+    }
+
+    /**
      * Returns the DeviceAdminInfo as defined by the administrator's package info & meta-data
      * @hide
      */
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 101b721..ff3af7c 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -50,6 +50,7 @@
     private boolean mAutoConnect;
     private int mConnState;
     private final Object mStateLock = new Object();
+    private Boolean mDeviceBusy = false;
 
     private static final int CONN_STATE_IDLE = 0;
     private static final int CONN_STATE_CONNECTING = 1;
@@ -166,6 +167,10 @@
                         mConnState = CONN_STATE_IDLE;
                     }
                 }
+
+                synchronized(mDeviceBusy) {
+                    mDeviceBusy = false;
+                }
             }
 
             /**
@@ -301,6 +306,11 @@
                 if (!address.equals(mDevice.getAddress())) {
                     return;
                 }
+
+                synchronized(mDeviceBusy) {
+                    mDeviceBusy = false;
+                }
+
                 if ((status == GATT_INSUFFICIENT_AUTHENTICATION
                   || status == GATT_INSUFFICIENT_ENCRYPTION)
                   && mAuthRetry == false) {
@@ -348,6 +358,11 @@
                 if (!address.equals(mDevice.getAddress())) {
                     return;
                 }
+
+                synchronized(mDeviceBusy) {
+                    mDeviceBusy = false;
+                }
+
                 BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service == null) return;
@@ -425,6 +440,11 @@
                 if (!address.equals(mDevice.getAddress())) {
                     return;
                 }
+
+                synchronized(mDeviceBusy) {
+                    mDeviceBusy = false;
+                }
+
                 BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service == null) return;
@@ -474,6 +494,11 @@
                 if (!address.equals(mDevice.getAddress())) {
                     return;
                 }
+
+                synchronized(mDeviceBusy) {
+                    mDeviceBusy = false;
+                }
+
                 BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service == null) return;
@@ -519,6 +544,11 @@
                 if (!address.equals(mDevice.getAddress())) {
                     return;
                 }
+
+                synchronized(mDeviceBusy) {
+                    mDeviceBusy = false;
+                }
+
                 try {
                     mCallback.onReliableWriteCompleted(BluetoothGatt.this, status);
                 } catch (Exception ex) {
@@ -851,6 +881,11 @@
         BluetoothDevice device = service.getDevice();
         if (device == null) return false;
 
+        synchronized(mDeviceBusy) {
+            if (mDeviceBusy) return false;
+            mDeviceBusy = true;
+        }
+
         try {
             mService.readCharacteristic(mClientIf, device.getAddress(),
                 service.getType(), service.getInstanceId(),
@@ -858,6 +893,7 @@
                 new ParcelUuid(characteristic.getUuid()), AUTHENTICATION_NONE);
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
+            mDeviceBusy = false;
             return false;
         }
 
@@ -890,6 +926,11 @@
         BluetoothDevice device = service.getDevice();
         if (device == null) return false;
 
+        synchronized(mDeviceBusy) {
+            if (mDeviceBusy) return false;
+            mDeviceBusy = true;
+        }
+
         try {
             mService.writeCharacteristic(mClientIf, device.getAddress(),
                 service.getType(), service.getInstanceId(),
@@ -899,6 +940,7 @@
                 characteristic.getValue());
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
+            mDeviceBusy = false;
             return false;
         }
 
@@ -930,6 +972,11 @@
         BluetoothDevice device = service.getDevice();
         if (device == null) return false;
 
+        synchronized(mDeviceBusy) {
+            if (mDeviceBusy) return false;
+            mDeviceBusy = true;
+        }
+
         try {
             mService.readDescriptor(mClientIf, device.getAddress(), service.getType(),
                 service.getInstanceId(), new ParcelUuid(service.getUuid()),
@@ -938,6 +985,7 @@
                 AUTHENTICATION_NONE);
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
+            mDeviceBusy = false;
             return false;
         }
 
@@ -968,6 +1016,11 @@
         BluetoothDevice device = service.getDevice();
         if (device == null) return false;
 
+        synchronized(mDeviceBusy) {
+            if (mDeviceBusy) return false;
+            mDeviceBusy = true;
+        }
+
         try {
             mService.writeDescriptor(mClientIf, device.getAddress(), service.getType(),
                 service.getInstanceId(), new ParcelUuid(service.getUuid()),
@@ -977,6 +1030,7 @@
                 descriptor.getValue());
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
+            mDeviceBusy = false;
             return false;
         }
 
@@ -1034,10 +1088,16 @@
         if (DBG) Log.d(TAG, "executeReliableWrite() - device: " + mDevice.getAddress());
         if (mService == null || mClientIf == 0) return false;
 
+        synchronized(mDeviceBusy) {
+            if (mDeviceBusy) return false;
+            mDeviceBusy = true;
+        }
+
         try {
             mService.endReliableWrite(mClientIf, mDevice.getAddress(), true);
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
+            mDeviceBusy = false;
             return false;
         }
 
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 5d02ae9..0d1b262 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -447,6 +447,15 @@
     public String nativeLibraryDir;
 
     /**
+     * The ABI that this application requires, This is inferred from the ABIs
+     * of the native JNI libraries the application bundles. Will be {@code null}
+     * if this application does not require any particular ABI.
+     *
+     * {@hide}
+     */
+    public String requiredCpuAbi;
+
+    /**
      * The kernel user-ID that has been assigned to this application;
      * currently this is not a unique ID (multiple applications can have
      * the same uid).
@@ -583,6 +592,7 @@
         sourceDir = orig.sourceDir;
         publicSourceDir = orig.publicSourceDir;
         nativeLibraryDir = orig.nativeLibraryDir;
+        requiredCpuAbi = orig.requiredCpuAbi;
         resourceDirs = orig.resourceDirs;
         seinfo = orig.seinfo;
         sharedLibraryFiles = orig.sharedLibraryFiles;
@@ -624,6 +634,7 @@
         dest.writeString(sourceDir);
         dest.writeString(publicSourceDir);
         dest.writeString(nativeLibraryDir);
+        dest.writeString(requiredCpuAbi);
         dest.writeStringArray(resourceDirs);
         dest.writeString(seinfo);
         dest.writeStringArray(sharedLibraryFiles);
@@ -664,6 +675,7 @@
         sourceDir = source.readString();
         publicSourceDir = source.readString();
         nativeLibraryDir = source.readString();
+        requiredCpuAbi = source.readString();
         resourceDirs = source.readStringArray();
         seinfo = source.readString();
         sharedLibraryFiles = source.readStringArray();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 3300e9d..d24a472 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -698,6 +698,25 @@
     public static final int INSTALL_FAILED_DUPLICATE_PERMISSION = -112;
 
     /**
+     * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+     * if the system failed to install the package because its packaged native code did not
+     * match any of the ABIs supported by the system.
+     *
+     * @hide
+     */
+    public static final int INSTALL_FAILED_NO_MATCHING_ABIS = -113;
+
+    /**
+     * Internal return code for NativeLibraryHelper methods to indicate that the package
+     * being processed did not contain any native code. This is placed here only so that
+     * it can belong to the same value space as the other install failure codes.
+     *
+     * @hide
+     */
+    public static final int NO_NATIVE_LIBRARIES = -114;
+
+    /**
      * Flag parameter for {@link #deletePackage} to indicate that you don't want to delete the
      * package's data directory.
      *
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 1e34498..9b1bc53 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -940,6 +940,17 @@
      */
     public static final int CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG = 5;
 
+    /**
+     * <p>This request is for manual capture use case where
+     * the applications want to directly control the capture parameters
+     * (e.g. {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}, {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} etc.).</p>
+     *
+     * @see CaptureRequest#SENSOR_EXPOSURE_TIME
+     * @see CaptureRequest#SENSOR_SENSITIVITY
+     * @see CaptureRequest#CONTROL_CAPTURE_INTENT
+     */
+    public static final int CONTROL_CAPTURE_INTENT_MANUAL = 6;
+
     //
     // Enumeration values for CaptureRequest#CONTROL_EFFECT_MODE
     //
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 7656505..c4e342c 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -714,16 +714,21 @@
      * auto-focus, auto-white balance) routines about the purpose
      * of this capture, to help the camera device to decide optimal 3A
      * strategy.</p>
-     * <p>This control is only effective if <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code>
-     * and any 3A routine is active.</p>
+     * <p>This control (except for MANUAL) is only effective if
+     * <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> and any 3A routine is active.</p>
+     * <p>ZERO_SHUTTER_LAG must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+     * contains ZSL. MANUAL must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+     * contains MANUAL_SENSOR.</p>
      *
      * @see CaptureRequest#CONTROL_MODE
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
      * @see #CONTROL_CAPTURE_INTENT_CUSTOM
      * @see #CONTROL_CAPTURE_INTENT_PREVIEW
      * @see #CONTROL_CAPTURE_INTENT_STILL_CAPTURE
      * @see #CONTROL_CAPTURE_INTENT_VIDEO_RECORD
      * @see #CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT
      * @see #CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG
+     * @see #CONTROL_CAPTURE_INTENT_MANUAL
      */
     public static final Key<Integer> CONTROL_CAPTURE_INTENT =
             new Key<Integer>("android.control.captureIntent", int.class);
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 0d4a4cb..c5e5753 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -461,6 +461,10 @@
             return (T) getFaces();
         } else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) {
             return (T) getFaceRectangles();
+        } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS)) {
+            return (T) getAvailableStreamConfigurations();
+        } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS)) {
+            return (T) getAvailableMinFrameDurations();
         }
 
         // For other keys, get() falls back to getBase()
@@ -481,6 +485,50 @@
         return availableFormats;
     }
 
+    private int[] getAvailableStreamConfigurations() {
+        final int NUM_ELEMENTS_IN_CONFIG = 4;
+        int[] availableConfigs =
+                getBase(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+        if (availableConfigs != null) {
+            if (availableConfigs.length % NUM_ELEMENTS_IN_CONFIG != 0) {
+                Log.w(TAG, "availableStreamConfigurations is malformed, length must be multiple"
+                        + " of " + NUM_ELEMENTS_IN_CONFIG);
+                return availableConfigs;
+            }
+
+            for (int i = 0; i < availableConfigs.length; i += NUM_ELEMENTS_IN_CONFIG) {
+                // JPEG has different value between native and managed side, need override.
+                if (availableConfigs[i] == NATIVE_JPEG_FORMAT) {
+                    availableConfigs[i] = ImageFormat.JPEG;
+                }
+            }
+        }
+
+        return availableConfigs;
+    }
+
+    private long[] getAvailableMinFrameDurations() {
+        final int NUM_ELEMENTS_IN_DURATION = 4;
+        long[] availableMinDurations =
+                getBase(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
+        if (availableMinDurations != null) {
+            if (availableMinDurations.length % NUM_ELEMENTS_IN_DURATION != 0) {
+                Log.w(TAG, "availableStreamConfigurations is malformed, length must be multiple"
+                        + " of " + NUM_ELEMENTS_IN_DURATION);
+                return availableMinDurations;
+            }
+
+            for (int i = 0; i < availableMinDurations.length; i += NUM_ELEMENTS_IN_DURATION) {
+                // JPEG has different value between native and managed side, need override.
+                if (availableMinDurations[i] == NATIVE_JPEG_FORMAT) {
+                    availableMinDurations[i] = ImageFormat.JPEG;
+                }
+            }
+        }
+
+        return availableMinDurations;
+    }
+
     private Face[] getFaces() {
         final int FACE_LANDMARK_SIZE = 6;
 
@@ -607,12 +655,56 @@
             return setAvailableFormats((int[]) value);
         } else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) {
             return setFaceRectangles((Rect[]) value);
+        } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS)) {
+            return setAvailableStreamConfigurations((int[])value);
+        } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS)) {
+            return setAvailableMinFrameDurations((long[])value);
         }
 
         // For other keys, set() falls back to setBase().
         return false;
     }
 
+    private boolean setAvailableStreamConfigurations(int[] value) {
+        final int NUM_ELEMENTS_IN_CONFIG = 4;
+        int[] availableConfigs = value;
+        if (value == null) {
+            // Let setBase() to handle the null value case.
+            return false;
+        }
+
+        int[] newValues = new int[availableConfigs.length];
+        for (int i = 0; i < availableConfigs.length; i++) {
+            newValues[i] = availableConfigs[i];
+            if (i % NUM_ELEMENTS_IN_CONFIG == 0 && availableConfigs[i] == ImageFormat.JPEG) {
+                newValues[i] = NATIVE_JPEG_FORMAT;
+            }
+        }
+
+        setBase(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS, newValues);
+        return true;
+    }
+
+    private boolean setAvailableMinFrameDurations(long[] value) {
+        final int NUM_ELEMENTS_IN_DURATION = 4;
+        long[] availableDurations = value;
+        if (value == null) {
+            // Let setBase() to handle the null value case.
+            return false;
+        }
+
+        long[] newValues = new long[availableDurations.length];
+        for (int i = 0; i < availableDurations.length; i++) {
+            newValues[i] = availableDurations[i];
+            if (i % NUM_ELEMENTS_IN_DURATION == 0 && availableDurations[i] == ImageFormat.JPEG) {
+                newValues[i] = NATIVE_JPEG_FORMAT;
+            }
+        }
+
+        setBase(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS, newValues);
+        return true;
+    }
+
     private boolean setAvailableFormats(int[] value) {
         int[] availableFormat = value;
         if (value == null) {
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index c8051aa..7f1a2e4 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -74,7 +74,14 @@
 
     /** A hardware serial number, if available.  Alphanumeric only, case-insensitive. */ 
     public static final String SERIAL = getString("ro.serialno");
-  
+
+    /**
+     * A list of ABIs (in priority) order supported by this device.
+     *
+     * @hide
+     */
+    public static final String[] SUPPORTED_ABIS = getString("ro.product.cpu.abilist").split(",");
+
     /** Various version strings. */
     public static class VERSION {
         /**
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 79ff49c..c947eda 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -466,6 +466,7 @@
      * @param debugFlags Additional flags.
      * @param targetSdkVersion The target SDK version for the app.
      * @param seInfo null-ok SELinux information for the new process.
+     * @param abi non-null the ABI this app should be started with.
      * @param zygoteArgs Additional arguments to supply to the zygote process.
      * 
      * @return An object that describes the result of the attempt to start the process.
@@ -479,12 +480,12 @@
                                   int debugFlags, int mountExternal,
                                   int targetSdkVersion,
                                   String seInfo,
+                                  String abi,
                                   String[] zygoteArgs) {
         try {
             return startViaZygote(processClass, niceName, uid, gid, gids,
                     debugFlags, mountExternal, targetSdkVersion, seInfo,
-                    null, /* zygoteAbi TODO: Replace this with the real ABI */
-                    zygoteArgs);
+                    abi, zygoteArgs);
         } catch (ZygoteStartFailedEx ex) {
             Log.e(LOG_TAG,
                     "Starting VM process through Zygote failed");
@@ -702,13 +703,6 @@
             primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET, getNumTries(primaryZygoteState));
         }
 
-        // TODO: Revert this temporary change. This is required to test
-        // and submit this change ahead of the package manager changes
-        // that supply this abi.
-        if (abi == null) {
-            return primaryZygoteState;
-        }
-
         if (primaryZygoteState.matches(abi)) {
             return primaryZygoteState;
         }
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index 2ef5b66..939cda9 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -625,12 +625,13 @@
                 return _result;
             }
 
-            public int encryptStorage(String password) throws RemoteException {
+            public int encryptStorage(int type, String password) throws RemoteException {
                 Parcel _data = Parcel.obtain();
                 Parcel _reply = Parcel.obtain();
                 int _result;
                 try {
                     _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeInt(type);
                     _data.writeString(password);
                     mRemote.transact(Stub.TRANSACTION_encryptStorage, _data, _reply, 0);
                     _reply.readException();
@@ -1210,8 +1211,9 @@
                 }
                 case TRANSACTION_encryptStorage: {
                     data.enforceInterface(DESCRIPTOR);
+                    int type = data.readInt();
                     String password = data.readString();
-                    int result = encryptStorage(password);
+                    int result = encryptStorage(type, password);
                     reply.writeNoException();
                     reply.writeInt(result);
                     return true;
@@ -1495,7 +1497,7 @@
     /**
      * Encrypts storage.
      */
-    public int encryptStorage(String password) throws RemoteException;
+    public int encryptStorage(int type, String password) throws RemoteException;
 
     /**
      * Changes the encryption password.
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 144c909..56d5617 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -533,8 +533,7 @@
      * @see #onCreateView(ViewGroup)
      */
     protected void onBindView(View view) {
-        final TextView titleView = (TextView) view.findViewById(
-                com.android.internal.R.id.title);
+        final TextView titleView = (TextView) view.findViewById(com.android.internal.R.id.title);
         if (titleView != null) {
             final CharSequence title = getTitle();
             if (!TextUtils.isEmpty(title)) {
@@ -557,7 +556,7 @@
             }
         }
 
-        ImageView imageView = (ImageView) view.findViewById(com.android.internal.R.id.icon);
+        final ImageView imageView = (ImageView) view.findViewById(com.android.internal.R.id.icon);
         if (imageView != null) {
             if (mIconResId != 0 || mIcon != null) {
                 if (mIcon == null) {
@@ -570,6 +569,11 @@
             imageView.setVisibility(mIcon != null ? View.VISIBLE : View.GONE);
         }
 
+        final View imageFrame = view.findViewById(com.android.internal.R.id.icon_frame);
+        if (imageFrame != null) {
+            imageFrame.setVisibility(mIcon != null ? View.VISIBLE : View.GONE);
+        }
+
         if (mShouldDisableView) {
             setEnabledStateOnViews(view, isEnabled());
         }
diff --git a/core/java/android/provider/SearchIndexablesContract.java b/core/java/android/provider/SearchIndexablesContract.java
index 05f3a1c..1754dce 100644
--- a/core/java/android/provider/SearchIndexablesContract.java
+++ b/core/java/android/provider/SearchIndexablesContract.java
@@ -58,33 +58,64 @@
      * Indexable xml resources colums.
      */
     public static final String[] INDEXABLES_XML_RES_COLUMNS = new String[] {
-            XmlResource.COLUMN_RANK,
-            XmlResource.COLUMN_XML_RESID,
-            XmlResource.COLUMN_CLASS_NAME,
-            XmlResource.COLUMN_ICON_RESID,
-            XmlResource.COLUMN_INTENT_ACTION,
-            XmlResource.COLUMN_INTENT_TARGET_PACKAGE,
-            XmlResource.COLUMN_INTENT_TARGET_CLASS
+            XmlResource.COLUMN_RANK,                    // 0
+            XmlResource.COLUMN_XML_RESID,               // 1
+            XmlResource.COLUMN_CLASS_NAME,              // 2
+            XmlResource.COLUMN_ICON_RESID,              // 3
+            XmlResource.COLUMN_INTENT_ACTION,           // 4
+            XmlResource.COLUMN_INTENT_TARGET_PACKAGE,   // 5
+            XmlResource.COLUMN_INTENT_TARGET_CLASS      // 6
     };
 
     /**
+     * Indexable xml resources colums indices.
+     */
+    public static final int COLUMN_INDEX_XML_RES_RANK = 0;
+    public static final int COLUMN_INDEX_XML_RES_RESID = 1;
+    public static final int COLUMN_INDEX_XML_RES_CLASS_NAME = 2;
+    public static final int COLUMN_INDEX_XML_RES_ICON_RESID = 3;
+    public static final int COLUMN_INDEX_XML_RES_INTENT_ACTION = 4;
+    public static final int COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE = 5;
+    public static final int COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS = 6;
+
+    /**
      * Indexable raw data colums.
      */
     public static final String[] INDEXABLES_RAW_COLUMNS = new String[] {
-            RawData.COLUMN_RANK,
-            RawData.COLUMN_TITLE,
-            RawData.COLUMN_SUMMARY_ON,
-            RawData.COLUMN_SUMMARY_OFF,
-            RawData.COLUMN_KEYWORDS,
-            RawData.COLUMN_SCREEN_TITLE,
-            RawData.COLUMN_CLASS_NAME,
-            RawData.COLUMN_ICON_RESID,
-            RawData.COLUMN_INTENT_ACTION,
-            RawData.COLUMN_INTENT_TARGET_PACKAGE,
-            RawData.COLUMN_INTENT_TARGET_CLASS,
+            RawData.COLUMN_RANK,                    // 0
+            RawData.COLUMN_TITLE,                   // 1
+            RawData.COLUMN_SUMMARY_ON,              // 2
+            RawData.COLUMN_SUMMARY_OFF,             // 3
+            RawData.COLUMN_ENTRIES,                 // 4
+            RawData.COLUMN_KEYWORDS,                // 5
+            RawData.COLUMN_SCREEN_TITLE,            // 6
+            RawData.COLUMN_CLASS_NAME,              // 7
+            RawData.COLUMN_ICON_RESID,              // 8
+            RawData.COLUMN_INTENT_ACTION,           // 9
+            RawData.COLUMN_INTENT_TARGET_PACKAGE,   // 10
+            RawData.COLUMN_INTENT_TARGET_CLASS,     // 11
+            RawData.COLUMN_KEY,                     // 12
     };
 
     /**
+     * Indexable raw data colums indices.
+     */
+    public static final int COLUMN_INDEX_RAW_RANK = 0;
+    public static final int COLUMN_INDEX_RAW_TITLE = 1;
+    public static final int COLUMN_INDEX_RAW_SUMMARY_ON = 2;
+    public static final int COLUMN_INDEX_RAW_SUMMARY_OFF = 3;
+    public static final int COLUMN_INDEX_RAW_ENTRIES = 4;
+    public static final int COLUMN_INDEX_RAW_KEYWORDS = 5;
+    public static final int COLUMN_INDEX_RAW_SCREEN_TITLE = 6;
+    public static final int COLUMN_INDEX_RAW_CLASS_NAME = 7;
+    public static final int COLUMN_INDEX_RAW_ICON_RESID = 8;
+    public static final int COLUMN_INDEX_RAW_INTENT_ACTION = 9;
+    public static final int COLUMN_INDEX_RAW_INTENT_TARGET_PACKAGE = 10;
+    public static final int COLUMN_INDEX_RAW_INTENT_TARGET_CLASS = 11;
+    public static final int COLUMN_INDEX_RAW_KEY = 12;
+
+
+    /**
      * Constants related to a {@link SearchIndexableResource}.
      *
      * This is a description of
@@ -134,6 +165,11 @@
         public static final String COLUMN_SUMMARY_OFF = "summaryOff";
 
         /**
+         * Entries associated with the raw data (when the data can can several values).
+         */
+        public static final String COLUMN_ENTRIES = "entries";
+
+        /**
          * Keywords' raw data.
          */
         public static final String COLUMN_KEYWORDS = "keywords";
@@ -142,6 +178,11 @@
          * Fragment's title associated with the raw data.
          */
         public static final String COLUMN_SCREEN_TITLE = "screenTitle";
+
+        /**
+         * Key associated with the raw data. The key needs to be unique.
+         */
+        public static final String COLUMN_KEY = "key";
     }
 
     /**
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index ad33b6f..eba4f7f 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -838,6 +838,11 @@
         }
     }
 
+    @Override
+    void pauseSurface(Surface surface) {
+        // No-op
+    }
+
     boolean initializeEgl() {
         synchronized (sEglLock) {
             if (sEgl == null && sEglConfig == null) {
@@ -1221,11 +1226,6 @@
         }
     }
 
-    void setDisplayListData(long displayList, long newData) {
-        nSetDisplayListData(displayList, newData);
-    }
-    private static native void nSetDisplayListData(long displayList, long newData);
-
     @Override
     void fence() {
         // Everything is immediate, so this is a no-op
@@ -1317,7 +1317,7 @@
         }
 
         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList");
-        nUpdateRenderNodeProperties(displayList.getNativeDisplayList());
+        nPrepareTree(displayList.getNativeDisplayList());
         try {
             status |= canvas.drawDisplayList(displayList, mRedrawClip,
                     RenderNode.FLAG_CLIP_CHILDREN);
@@ -1476,7 +1476,7 @@
 
     static native void nDestroyLayer(long layerPtr);
 
-    private static native void nUpdateRenderNodeProperties(long displayListPtr);
+    private static native void nPrepareTree(long displayListPtr);
 
     class DrawPerformanceDataProvider extends GraphDataProvider {
         private final int mGraphType;
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 92d85d1..56d96e1 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -234,6 +234,13 @@
     abstract void updateSurface(Surface surface) throws OutOfResourcesException;
 
     /**
+     * Stops any rendering into the surface. Use this if it is unclear whether
+     * or not the surface used by the HardwareRenderer will be changing. It
+     * Suspends any rendering into the surface, but will not do any destruction
+     */
+    abstract void pauseSurface(Surface surface);
+
+    /**
      * Destroys all hardware rendering resources associated with the specified
      * view hierarchy.
      *
@@ -573,8 +580,6 @@
         mRequested = requested;
     }
 
-    abstract void setDisplayListData(long displayList, long newData);
-
     /**
      * Blocks until all previously queued work has completed.
      */
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 78ddf5b..30e4281 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -174,12 +174,10 @@
     public static final int STATUS_DREW = 0x4;
 
     private boolean mValid;
-    private final long mNativeDisplayList;
-    private HardwareRenderer mRenderer;
+    private final long mNativeRenderNode;
 
     private RenderNode(String name) {
-        mNativeDisplayList = nCreate();
-        nSetDisplayListName(mNativeDisplayList, name);
+        mNativeRenderNode = nCreate(name);
     }
 
     /**
@@ -202,7 +200,7 @@
      * stored in this display list.
      *
      * Calling this method will mark the render node invalid until
-     * {@link #end(HardwareRenderer, HardwareCanvas)} is called.
+     * {@link #end(HardwareCanvas)} is called.
      * Only valid render nodes can be replayed.
      *
      * @param width The width of the recording viewport
@@ -210,7 +208,7 @@
      *
      * @return A canvas to record drawing operations.
      *
-     * @see #end(HardwareRenderer, HardwareCanvas)
+     * @see #end(HardwareCanvas)
      * @see #isValid()
      */
     public HardwareCanvas start(int width, int height) {
@@ -229,21 +227,15 @@
      * @see #start(int, int)
      * @see #isValid()
      */
-    public void end(HardwareRenderer renderer, HardwareCanvas endCanvas) {
+    public void end(HardwareCanvas endCanvas) {
         if (!(endCanvas instanceof GLES20RecordingCanvas)) {
             throw new IllegalArgumentException("Passed an invalid canvas to end!");
         }
 
         GLES20RecordingCanvas canvas = (GLES20RecordingCanvas) endCanvas;
         canvas.onPostDraw();
-        long displayListData = canvas.finishRecording();
-        if (renderer != mRenderer) {
-            // If we are changing renderers first destroy with the old
-            // renderer, then set with the new one
-            destroyDisplayListData();
-        }
-        mRenderer = renderer;
-        setDisplayListData(displayListData);
+        long renderNodeData = canvas.finishRecording();
+        nSetDisplayListData(mNativeRenderNode, renderNodeData);
         canvas.recycle();
         mValid = true;
     }
@@ -258,19 +250,10 @@
     public void destroyDisplayListData() {
         if (!mValid) return;
 
-        setDisplayListData(0);
-        mRenderer = null;
+        nSetDisplayListData(mNativeRenderNode, 0);
         mValid = false;
     }
 
-    private void setDisplayListData(long newData) {
-        if (mRenderer != null) {
-            mRenderer.setDisplayListData(mNativeDisplayList, newData);
-        } else {
-            throw new IllegalStateException("Trying to set data without a renderer! data=" + newData);
-        }
-    }
-
     /**
      * Returns whether the RenderNode's display list content is currently usable.
      * If this returns false, the display list should be re-recorded prior to replaying it.
@@ -283,7 +266,7 @@
         if (!mValid) {
             throw new IllegalStateException("The display list is not valid.");
         }
-        return mNativeDisplayList;
+        return mNativeRenderNode;
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -291,15 +274,15 @@
     ///////////////////////////////////////////////////////////////////////////
 
     public boolean hasIdentityMatrix() {
-        return nHasIdentityMatrix(mNativeDisplayList);
+        return nHasIdentityMatrix(mNativeRenderNode);
     }
 
     public void getMatrix(@NonNull Matrix outMatrix) {
-        nGetTransformMatrix(mNativeDisplayList, outMatrix.native_instance);
+        nGetTransformMatrix(mNativeRenderNode, outMatrix.native_instance);
     }
 
     public void getInverseMatrix(@NonNull Matrix outMatrix) {
-        nGetInverseTransformMatrix(mNativeDisplayList, outMatrix.native_instance);
+        nGetInverseTransformMatrix(mNativeRenderNode, outMatrix.native_instance);
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -316,7 +299,7 @@
      * @hide
      */
     public void setCaching(boolean caching) {
-        nSetCaching(mNativeDisplayList, caching);
+        nSetCaching(mNativeRenderNode, caching);
     }
 
     /**
@@ -326,7 +309,7 @@
      * @param clipToBounds true if the display list should clip to its bounds
      */
     public void setClipToBounds(boolean clipToBounds) {
-        nSetClipToBounds(mNativeDisplayList, clipToBounds);
+        nSetClipToBounds(mNativeRenderNode, clipToBounds);
     }
 
     /**
@@ -337,7 +320,7 @@
      *            containing volume.
      */
     public void setProjectBackwards(boolean shouldProject) {
-        nSetProjectBackwards(mNativeDisplayList, shouldProject);
+        nSetProjectBackwards(mNativeRenderNode, shouldProject);
     }
 
     /**
@@ -346,7 +329,7 @@
      * ProjectBackwards=true directly on top of it. Default value is false.
      */
     public void setProjectionReceiver(boolean shouldRecieve) {
-        nSetProjectionReceiver(mNativeDisplayList, shouldRecieve);
+        nSetProjectionReceiver(mNativeRenderNode, shouldRecieve);
     }
 
     /**
@@ -357,14 +340,14 @@
      */
     public void setOutline(Outline outline) {
         if (outline == null) {
-            nSetOutlineEmpty(mNativeDisplayList);
+            nSetOutlineEmpty(mNativeRenderNode);
         } else if (!outline.isValid()) {
             throw new IllegalArgumentException("Outline must be valid");
         } else if (outline.mRect != null) {
-            nSetOutlineRoundRect(mNativeDisplayList, outline.mRect.left, outline.mRect.top,
+            nSetOutlineRoundRect(mNativeRenderNode, outline.mRect.left, outline.mRect.top,
                     outline.mRect.right, outline.mRect.bottom, outline.mRadius);
         } else if (outline.mPath != null) {
-            nSetOutlineConvexPath(mNativeDisplayList, outline.mPath.mNativePath);
+            nSetOutlineConvexPath(mNativeRenderNode, outline.mPath.mNativePath);
         }
     }
 
@@ -374,7 +357,7 @@
      * @param clipToOutline true if clipping to the outline.
      */
     public void setClipToOutline(boolean clipToOutline) {
-        nSetClipToOutline(mNativeDisplayList, clipToOutline);
+        nSetClipToOutline(mNativeRenderNode, clipToOutline);
     }
 
     /**
@@ -382,7 +365,7 @@
      */
     public void setRevealClip(boolean shouldClip, boolean inverseClip,
             float x, float y, float radius) {
-        nSetRevealClip(mNativeDisplayList, shouldClip, inverseClip, x, y, radius);
+        nSetRevealClip(mNativeRenderNode, shouldClip, inverseClip, x, y, radius);
     }
 
     /**
@@ -392,7 +375,7 @@
      * @param matrix A transform matrix to apply to this display list
      */
     public void setStaticMatrix(Matrix matrix) {
-        nSetStaticMatrix(mNativeDisplayList, matrix.native_instance);
+        nSetStaticMatrix(mNativeRenderNode, matrix.native_instance);
     }
 
     /**
@@ -406,7 +389,7 @@
      * @hide
      */
     public void setAnimationMatrix(Matrix matrix) {
-        nSetAnimationMatrix(mNativeDisplayList,
+        nSetAnimationMatrix(mNativeRenderNode,
                 (matrix != null) ? matrix.native_instance : 0);
     }
 
@@ -419,7 +402,7 @@
      * @see #getAlpha()
      */
     public void setAlpha(float alpha) {
-        nSetAlpha(mNativeDisplayList, alpha);
+        nSetAlpha(mNativeRenderNode, alpha);
     }
 
     /**
@@ -430,7 +413,7 @@
      * @see #setAlpha(float)
      */
     public float getAlpha() {
-        return nGetAlpha(mNativeDisplayList);
+        return nGetAlpha(mNativeRenderNode);
     }
 
     /**
@@ -445,7 +428,7 @@
      * @see #hasOverlappingRendering()
      */
     public void setHasOverlappingRendering(boolean hasOverlappingRendering) {
-        nSetHasOverlappingRendering(mNativeDisplayList, hasOverlappingRendering);
+        nSetHasOverlappingRendering(mNativeRenderNode, hasOverlappingRendering);
     }
 
     /**
@@ -457,7 +440,7 @@
      */
     public boolean hasOverlappingRendering() {
         //noinspection SimplifiableIfStatement
-        return nHasOverlappingRendering(mNativeDisplayList);
+        return nHasOverlappingRendering(mNativeRenderNode);
     }
 
     /**
@@ -469,7 +452,7 @@
      * @see #getTranslationX()
      */
     public void setTranslationX(float translationX) {
-        nSetTranslationX(mNativeDisplayList, translationX);
+        nSetTranslationX(mNativeRenderNode, translationX);
     }
 
     /**
@@ -478,7 +461,7 @@
      * @see #setTranslationX(float)
      */
     public float getTranslationX() {
-        return nGetTranslationX(mNativeDisplayList);
+        return nGetTranslationX(mNativeRenderNode);
     }
 
     /**
@@ -490,7 +473,7 @@
      * @see #getTranslationY()
      */
     public void setTranslationY(float translationY) {
-        nSetTranslationY(mNativeDisplayList, translationY);
+        nSetTranslationY(mNativeRenderNode, translationY);
     }
 
     /**
@@ -499,7 +482,7 @@
      * @see #setTranslationY(float)
      */
     public float getTranslationY() {
-        return nGetTranslationY(mNativeDisplayList);
+        return nGetTranslationY(mNativeRenderNode);
     }
 
     /**
@@ -509,7 +492,7 @@
      * @see #getTranslationZ()
      */
     public void setTranslationZ(float translationZ) {
-        nSetTranslationZ(mNativeDisplayList, translationZ);
+        nSetTranslationZ(mNativeRenderNode, translationZ);
     }
 
     /**
@@ -518,7 +501,7 @@
      * @see #setTranslationZ(float)
      */
     public float getTranslationZ() {
-        return nGetTranslationZ(mNativeDisplayList);
+        return nGetTranslationZ(mNativeRenderNode);
     }
 
     /**
@@ -530,7 +513,7 @@
      * @see #getRotation()
      */
     public void setRotation(float rotation) {
-        nSetRotation(mNativeDisplayList, rotation);
+        nSetRotation(mNativeRenderNode, rotation);
     }
 
     /**
@@ -539,7 +522,7 @@
      * @see #setRotation(float)
      */
     public float getRotation() {
-        return nGetRotation(mNativeDisplayList);
+        return nGetRotation(mNativeRenderNode);
     }
 
     /**
@@ -551,7 +534,7 @@
      * @see #getRotationX()
      */
     public void setRotationX(float rotationX) {
-        nSetRotationX(mNativeDisplayList, rotationX);
+        nSetRotationX(mNativeRenderNode, rotationX);
     }
 
     /**
@@ -560,7 +543,7 @@
      * @see #setRotationX(float)
      */
     public float getRotationX() {
-        return nGetRotationX(mNativeDisplayList);
+        return nGetRotationX(mNativeRenderNode);
     }
 
     /**
@@ -572,7 +555,7 @@
      * @see #getRotationY()
      */
     public void setRotationY(float rotationY) {
-        nSetRotationY(mNativeDisplayList, rotationY);
+        nSetRotationY(mNativeRenderNode, rotationY);
     }
 
     /**
@@ -581,7 +564,7 @@
      * @see #setRotationY(float)
      */
     public float getRotationY() {
-        return nGetRotationY(mNativeDisplayList);
+        return nGetRotationY(mNativeRenderNode);
     }
 
     /**
@@ -593,7 +576,7 @@
      * @see #getScaleX()
      */
     public void setScaleX(float scaleX) {
-        nSetScaleX(mNativeDisplayList, scaleX);
+        nSetScaleX(mNativeRenderNode, scaleX);
     }
 
     /**
@@ -602,7 +585,7 @@
      * @see #setScaleX(float)
      */
     public float getScaleX() {
-        return nGetScaleX(mNativeDisplayList);
+        return nGetScaleX(mNativeRenderNode);
     }
 
     /**
@@ -614,7 +597,7 @@
      * @see #getScaleY()
      */
     public void setScaleY(float scaleY) {
-        nSetScaleY(mNativeDisplayList, scaleY);
+        nSetScaleY(mNativeRenderNode, scaleY);
     }
 
     /**
@@ -623,7 +606,7 @@
      * @see #setScaleY(float)
      */
     public float getScaleY() {
-        return nGetScaleY(mNativeDisplayList);
+        return nGetScaleY(mNativeRenderNode);
     }
 
     /**
@@ -635,7 +618,7 @@
      * @see #getPivotX()
      */
     public void setPivotX(float pivotX) {
-        nSetPivotX(mNativeDisplayList, pivotX);
+        nSetPivotX(mNativeRenderNode, pivotX);
     }
 
     /**
@@ -644,7 +627,7 @@
      * @see #setPivotX(float)
      */
     public float getPivotX() {
-        return nGetPivotX(mNativeDisplayList);
+        return nGetPivotX(mNativeRenderNode);
     }
 
     /**
@@ -656,7 +639,7 @@
      * @see #getPivotY()
      */
     public void setPivotY(float pivotY) {
-        nSetPivotY(mNativeDisplayList, pivotY);
+        nSetPivotY(mNativeRenderNode, pivotY);
     }
 
     /**
@@ -665,11 +648,11 @@
      * @see #setPivotY(float)
      */
     public float getPivotY() {
-        return nGetPivotY(mNativeDisplayList);
+        return nGetPivotY(mNativeRenderNode);
     }
 
     public boolean isPivotExplicitlySet() {
-        return nIsPivotExplicitlySet(mNativeDisplayList);
+        return nIsPivotExplicitlySet(mNativeRenderNode);
     }
 
     /**
@@ -683,7 +666,7 @@
      * @see #getCameraDistance()
      */
     public void setCameraDistance(float distance) {
-        nSetCameraDistance(mNativeDisplayList, distance);
+        nSetCameraDistance(mNativeRenderNode, distance);
     }
 
     /**
@@ -692,7 +675,7 @@
      * @see #setCameraDistance(float)
      */
     public float getCameraDistance() {
-        return nGetCameraDistance(mNativeDisplayList);
+        return nGetCameraDistance(mNativeRenderNode);
     }
 
     /**
@@ -704,7 +687,7 @@
      * @see #getLeft()
      */
     public void setLeft(int left) {
-        nSetLeft(mNativeDisplayList, left);
+        nSetLeft(mNativeRenderNode, left);
     }
 
     /**
@@ -713,7 +696,7 @@
      * @see #setLeft(int)
      */
     public float getLeft() {
-        return nGetLeft(mNativeDisplayList);
+        return nGetLeft(mNativeRenderNode);
     }
 
     /**
@@ -725,7 +708,7 @@
      * @see #getTop()
      */
     public void setTop(int top) {
-        nSetTop(mNativeDisplayList, top);
+        nSetTop(mNativeRenderNode, top);
     }
 
     /**
@@ -734,7 +717,7 @@
      * @see #setTop(int)
      */
     public float getTop() {
-        return nGetTop(mNativeDisplayList);
+        return nGetTop(mNativeRenderNode);
     }
 
     /**
@@ -746,7 +729,7 @@
      * @see #getRight()
      */
     public void setRight(int right) {
-        nSetRight(mNativeDisplayList, right);
+        nSetRight(mNativeRenderNode, right);
     }
 
     /**
@@ -755,7 +738,7 @@
      * @see #setRight(int)
      */
     public float getRight() {
-        return nGetRight(mNativeDisplayList);
+        return nGetRight(mNativeRenderNode);
     }
 
     /**
@@ -767,7 +750,7 @@
      * @see #getBottom()
      */
     public void setBottom(int bottom) {
-        nSetBottom(mNativeDisplayList, bottom);
+        nSetBottom(mNativeRenderNode, bottom);
     }
 
     /**
@@ -776,7 +759,7 @@
      * @see #setBottom(int)
      */
     public float getBottom() {
-        return nGetBottom(mNativeDisplayList);
+        return nGetBottom(mNativeRenderNode);
     }
 
     /**
@@ -793,7 +776,7 @@
      * @see View#setBottom(int)
      */
     public void setLeftTopRightBottom(int left, int top, int right, int bottom) {
-        nSetLeftTopRightBottom(mNativeDisplayList, left, top, right, bottom);
+        nSetLeftTopRightBottom(mNativeRenderNode, left, top, right, bottom);
     }
 
     /**
@@ -805,7 +788,7 @@
      * @see View#offsetLeftAndRight(int)
      */
     public void offsetLeftAndRight(float offset) {
-        nOffsetLeftAndRight(mNativeDisplayList, offset);
+        nOffsetLeftAndRight(mNativeRenderNode, offset);
     }
 
     /**
@@ -817,7 +800,7 @@
      * @see View#offsetTopAndBottom(int)
      */
     public void offsetTopAndBottom(float offset) {
-        nOffsetTopAndBottom(mNativeDisplayList, offset);
+        nOffsetTopAndBottom(mNativeRenderNode, offset);
     }
 
     /**
@@ -827,80 +810,80 @@
      * @hide
      */
     public void output() {
-        nOutput(mNativeDisplayList);
+        nOutput(mNativeRenderNode);
     }
 
     ///////////////////////////////////////////////////////////////////////////
     // Native methods
     ///////////////////////////////////////////////////////////////////////////
 
-    private static native long nCreate();
-    private static native void nDestroyDisplayList(long displayList);
-    private static native void nSetDisplayListName(long displayList, String name);
+    private static native long nCreate(String name);
+    private static native void nDestroyRenderNode(long renderNode);
+    private static native void nSetDisplayListData(long renderNode, long newData);
 
     // Matrix
 
-    private static native void nGetTransformMatrix(long displayList, long nativeMatrix);
-    private static native void nGetInverseTransformMatrix(long displayList, long nativeMatrix);
-    private static native boolean nHasIdentityMatrix(long displayList);
+    private static native void nGetTransformMatrix(long renderNode, long nativeMatrix);
+    private static native void nGetInverseTransformMatrix(long renderNode, long nativeMatrix);
+    private static native boolean nHasIdentityMatrix(long renderNode);
 
     // Properties
 
-    private static native void nOffsetTopAndBottom(long displayList, float offset);
-    private static native void nOffsetLeftAndRight(long displayList, float offset);
-    private static native void nSetLeftTopRightBottom(long displayList, int left, int top,
+    private static native void nOffsetTopAndBottom(long renderNode, float offset);
+    private static native void nOffsetLeftAndRight(long renderNode, float offset);
+    private static native void nSetLeftTopRightBottom(long renderNode, int left, int top,
             int right, int bottom);
-    private static native void nSetBottom(long displayList, int bottom);
-    private static native void nSetRight(long displayList, int right);
-    private static native void nSetTop(long displayList, int top);
-    private static native void nSetLeft(long displayList, int left);
-    private static native void nSetCameraDistance(long displayList, float distance);
-    private static native void nSetPivotY(long displayList, float pivotY);
-    private static native void nSetPivotX(long displayList, float pivotX);
-    private static native void nSetCaching(long displayList, boolean caching);
-    private static native void nSetClipToBounds(long displayList, boolean clipToBounds);
-    private static native void nSetProjectBackwards(long displayList, boolean shouldProject);
-    private static native void nSetProjectionReceiver(long displayList, boolean shouldRecieve);
-    private static native void nSetOutlineRoundRect(long displayList, int left, int top,
+    private static native void nSetBottom(long renderNode, int bottom);
+    private static native void nSetRight(long renderNode, int right);
+    private static native void nSetTop(long renderNode, int top);
+    private static native void nSetLeft(long renderNode, int left);
+    private static native void nSetCameraDistance(long renderNode, float distance);
+    private static native void nSetPivotY(long renderNode, float pivotY);
+    private static native void nSetPivotX(long renderNode, float pivotX);
+    private static native void nSetCaching(long renderNode, boolean caching);
+    private static native void nSetClipToBounds(long renderNode, boolean clipToBounds);
+    private static native void nSetProjectBackwards(long renderNode, boolean shouldProject);
+    private static native void nSetProjectionReceiver(long renderNode, boolean shouldRecieve);
+    private static native void nSetOutlineRoundRect(long renderNode, int left, int top,
             int right, int bottom, float radius);
-    private static native void nSetOutlineConvexPath(long displayList, long nativePath);
-    private static native void nSetOutlineEmpty(long displayList);
-    private static native void nSetClipToOutline(long displayList, boolean clipToOutline);
-    private static native void nSetRevealClip(long displayList,
+    private static native void nSetOutlineConvexPath(long renderNode, long nativePath);
+    private static native void nSetOutlineEmpty(long renderNode);
+    private static native void nSetClipToOutline(long renderNode, boolean clipToOutline);
+    private static native void nSetRevealClip(long renderNode,
             boolean shouldClip, boolean inverseClip, float x, float y, float radius);
-    private static native void nSetAlpha(long displayList, float alpha);
-    private static native void nSetHasOverlappingRendering(long displayList,
+    private static native void nSetAlpha(long renderNode, float alpha);
+    private static native void nSetHasOverlappingRendering(long renderNode,
             boolean hasOverlappingRendering);
-    private static native void nSetTranslationX(long displayList, float translationX);
-    private static native void nSetTranslationY(long displayList, float translationY);
-    private static native void nSetTranslationZ(long displayList, float translationZ);
-    private static native void nSetRotation(long displayList, float rotation);
-    private static native void nSetRotationX(long displayList, float rotationX);
-    private static native void nSetRotationY(long displayList, float rotationY);
-    private static native void nSetScaleX(long displayList, float scaleX);
-    private static native void nSetScaleY(long displayList, float scaleY);
-    private static native void nSetStaticMatrix(long displayList, long nativeMatrix);
-    private static native void nSetAnimationMatrix(long displayList, long animationMatrix);
+    private static native void nSetTranslationX(long renderNode, float translationX);
+    private static native void nSetTranslationY(long renderNode, float translationY);
+    private static native void nSetTranslationZ(long renderNode, float translationZ);
+    private static native void nSetRotation(long renderNode, float rotation);
+    private static native void nSetRotationX(long renderNode, float rotationX);
+    private static native void nSetRotationY(long renderNode, float rotationY);
+    private static native void nSetScaleX(long renderNode, float scaleX);
+    private static native void nSetScaleY(long renderNode, float scaleY);
+    private static native void nSetStaticMatrix(long renderNode, long nativeMatrix);
+    private static native void nSetAnimationMatrix(long renderNode, long animationMatrix);
 
-    private static native boolean nHasOverlappingRendering(long displayList);
-    private static native float nGetAlpha(long displayList);
-    private static native float nGetLeft(long displayList);
-    private static native float nGetTop(long displayList);
-    private static native float nGetRight(long displayList);
-    private static native float nGetBottom(long displayList);
-    private static native float nGetCameraDistance(long displayList);
-    private static native float nGetScaleX(long displayList);
-    private static native float nGetScaleY(long displayList);
-    private static native float nGetTranslationX(long displayList);
-    private static native float nGetTranslationY(long displayList);
-    private static native float nGetTranslationZ(long displayList);
-    private static native float nGetRotation(long displayList);
-    private static native float nGetRotationX(long displayList);
-    private static native float nGetRotationY(long displayList);
-    private static native boolean nIsPivotExplicitlySet(long displayList);
-    private static native float nGetPivotX(long displayList);
-    private static native float nGetPivotY(long displayList);
-    private static native void nOutput(long displayList);
+    private static native boolean nHasOverlappingRendering(long renderNode);
+    private static native float nGetAlpha(long renderNode);
+    private static native float nGetLeft(long renderNode);
+    private static native float nGetTop(long renderNode);
+    private static native float nGetRight(long renderNode);
+    private static native float nGetBottom(long renderNode);
+    private static native float nGetCameraDistance(long renderNode);
+    private static native float nGetScaleX(long renderNode);
+    private static native float nGetScaleY(long renderNode);
+    private static native float nGetTranslationX(long renderNode);
+    private static native float nGetTranslationY(long renderNode);
+    private static native float nGetTranslationZ(long renderNode);
+    private static native float nGetRotation(long renderNode);
+    private static native float nGetRotationX(long renderNode);
+    private static native float nGetRotationY(long renderNode);
+    private static native boolean nIsPivotExplicitlySet(long renderNode);
+    private static native float nGetPivotX(long renderNode);
+    private static native float nGetPivotY(long renderNode);
+    private static native void nOutput(long renderNode);
 
     ///////////////////////////////////////////////////////////////////////////
     // Finalization
@@ -909,7 +892,7 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            nDestroyDisplayList(mNativeDisplayList);
+            nDestroyRenderNode(mNativeRenderNode);
         } finally {
             super.finalize();
         }
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index a747ab6..1ecc3c6 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -54,28 +54,46 @@
 
     private int mWidth, mHeight;
     private long mNativeProxy;
+    private boolean mInitialized = false;
 
     ThreadedRenderer(boolean translucent) {
         mNativeProxy = nCreateProxy(translucent);
-        setEnabled(mNativeProxy != 0);
     }
 
     @Override
     void destroy(boolean full) {
+        mInitialized = false;
+        updateEnabledState(null);
         nDestroyCanvas(mNativeProxy);
     }
 
+    private void updateEnabledState(Surface surface) {
+        if (surface == null || !surface.isValid()) {
+            setEnabled(false);
+        } else {
+            setEnabled(mInitialized);
+        }
+    }
+
     @Override
     boolean initialize(Surface surface) throws OutOfResourcesException {
+        mInitialized = true;
+        updateEnabledState(surface);
         return nInitialize(mNativeProxy, surface);
     }
 
     @Override
     void updateSurface(Surface surface) throws OutOfResourcesException {
+        updateEnabledState(surface);
         nUpdateSurface(mNativeProxy, surface);
     }
 
     @Override
+    void pauseSurface(Surface surface) {
+        nPauseSurface(mNativeProxy, surface);
+    }
+
+    @Override
     void destroyHardwareResources(View view) {
         destroyResources(view);
         // TODO: GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
@@ -148,11 +166,6 @@
     }
 
     @Override
-    void setDisplayListData(long displayList, long newData) {
-        nSetDisplayListData(mNativeProxy, displayList, newData);
-    }
-
-    @Override
     void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
         attachInfo.mIgnoreDirtyState = true;
         attachInfo.mDrawingTime = SystemClock.uptimeMillis();
@@ -267,6 +280,7 @@
 
     private static native boolean nInitialize(long nativeProxy, Surface window);
     private static native void nUpdateSurface(long nativeProxy, Surface window);
+    private static native void nPauseSurface(long nativeProxy, Surface window);
     private static native void nSetup(long nativeProxy, int width, int height);
     private static native void nSetDisplayListData(long nativeProxy, long displayList,
             long newData);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6c414f6..9761f1a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13549,11 +13549,10 @@
      * @return A new or reused DisplayList object.
      */
     private void updateDisplayListIfDirty(@NonNull RenderNode renderNode, boolean isLayer) {
-        final HardwareRenderer renderer = getHardwareRenderer();
         if (renderNode == null) {
             throw new IllegalArgumentException("RenderNode must not be null");
         }
-        if (renderer == null || !canHaveDisplayList()) {
+        if (!canHaveDisplayList()) {
             // can't populate RenderNode, don't try
             return;
         }
@@ -13627,21 +13626,13 @@
                     }
                 }
             } finally {
-                renderNode.end(renderer, canvas);
+                renderNode.end(canvas);
                 renderNode.setCaching(caching);
                 if (isLayer) {
                     renderNode.setLeftTopRightBottom(0, 0, width, height);
                 } else {
                     setDisplayListProperties(renderNode);
                 }
-
-                if (renderer != getHardwareRenderer()) {
-                    Log.w(VIEW_LOG_TAG, "View was detached during a draw() call!");
-                    // TODO: Should this be elevated to a crash?
-                    // For now have it behaves the same as it previously did, it
-                    // will result in the DisplayListData being destroyed later
-                    // than it could be but oh well...
-                }
             }
         } else if (!isLayer) {
             mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
@@ -14913,7 +14904,7 @@
         final int height = bounds.height();
         final HardwareCanvas canvas = displayList.start(width, height);
         drawable.draw(canvas);
-        displayList.end(getHardwareRenderer(), canvas);
+        displayList.end(canvas);
 
         // Set up drawable properties that are view-independent.
         displayList.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 94f0683..65ac50d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1421,6 +1421,12 @@
                             host.getMeasuredHeight() + ", params=" + params);
                 }
 
+                if (mAttachInfo.mHardwareRenderer != null) {
+                    // relayoutWindow may decide to destroy mSurface. As that decision
+                    // happens in WindowManager service, we need to be defensive here
+                    // and stop using the surface in case it gets destroyed.
+                    mAttachInfo.mHardwareRenderer.pauseSurface(mSurface);
+                }
                 final int surfaceGenerationId = mSurface.getGenerationId();
                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
                 if (!mDrawDuringWindowsAnimating &&
@@ -1499,7 +1505,7 @@
                                 com.android.internal.R.integer.config_mediumAnimTime);
 
                         layerCanvas.restoreToCount(restoreCount);
-                        layerRenderNode.end(mAttachInfo.mHardwareRenderer, layerCanvas);
+                        layerRenderNode.end(layerCanvas);
                         layerRenderNode.setCaching(true);
                         layerRenderNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
                         mTempRect.set(0, 0, mWidth, mHeight);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 14e7951c..b0a4e24 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1338,7 +1338,6 @@
 
         layout.drawBackground(canvas, highlight, highlightPaint, cursorOffsetVertical,
                 firstLine, lastLine);
-        final HardwareRenderer renderer = mTextView.getHardwareRenderer();
 
         if (layout instanceof DynamicLayout) {
             if (mTextDisplayLists == null) {
@@ -1402,7 +1401,7 @@
                             // No need to untranslate, previous context is popped after
                             // drawDisplayList
                         } finally {
-                            blockDisplayList.end(renderer, hardwareCanvas);
+                            blockDisplayList.end(hardwareCanvas);
                             // Same as drawDisplayList below, handled by our TextView's parent
                             blockDisplayList.setClipToBounds(false);
                         }
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 6d65782..ba419f9 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.content;
 
-import android.os.Build;
+import android.content.pm.PackageManager;
 import android.util.Slog;
 
 import java.io.File;
@@ -31,38 +31,76 @@
 
     private static final boolean DEBUG_NATIVE = false;
 
-    private static native long nativeSumNativeBinaries(String file, String cpuAbi, String cpuAbi2);
-
     /**
-     * Sums the size of native binaries in an APK.
+     * A handle to an opened APK. Used as input to the various NativeLibraryHelper
+     * methods. Allows us to scan and parse the APK exactly once instead of doing
+     * it multiple times.
      *
-     * @param apkFile APK file to scan for native libraries
-     * @return size of all native binary files in bytes
+     * @hide
      */
-    public static long sumNativeBinariesLI(File apkFile) {
-        final String cpuAbi = Build.CPU_ABI;
-        final String cpuAbi2 = Build.CPU_ABI2;
-        return nativeSumNativeBinaries(apkFile.getPath(), cpuAbi, cpuAbi2);
+    public static class ApkHandle {
+        final String apkPath;
+        final long apkHandle;
+
+        public ApkHandle(String path) {
+            apkPath = path;
+            apkHandle = nativeOpenApk(apkPath);
+        }
+
+        public ApkHandle(File apkFile) {
+            apkPath = apkFile.getPath();
+            apkHandle = nativeOpenApk(apkPath);
+        }
+
+        public void close() {
+            nativeClose(apkHandle);
+        }
     }
 
-    private native static int nativeCopyNativeBinaries(String filePath, String sharedLibraryPath,
-            String cpuAbi, String cpuAbi2);
+
+    private static native long nativeOpenApk(String path);
+    private static native void nativeClose(long handle);
+
+    private static native long nativeSumNativeBinaries(long handle, String cpuAbi);
+
+    /**
+     * Sums the size of native binaries in an APK for a given ABI.
+     *
+     * @return size of all native binary files in bytes
+     */
+    public static long sumNativeBinariesLI(ApkHandle handle, String abi) {
+        return nativeSumNativeBinaries(handle.apkHandle, abi);
+    }
+
+    private native static int nativeCopyNativeBinaries(long handle,
+            String sharedLibraryPath, String abiToCopy);
 
     /**
      * Copies native binaries to a shared library directory.
      *
-     * @param apkFile APK file to scan for native libraries
+     * @param handle APK file to scan for native libraries
      * @param sharedLibraryDir directory for libraries to be copied to
      * @return {@link PackageManager#INSTALL_SUCCEEDED} if successful or another
      *         error code from that class if not
      */
-    public static int copyNativeBinariesIfNeededLI(File apkFile, File sharedLibraryDir) {
-        final String cpuAbi = Build.CPU_ABI;
-        final String cpuAbi2 = Build.CPU_ABI2;
-        return nativeCopyNativeBinaries(apkFile.getPath(), sharedLibraryDir.getPath(), cpuAbi,
-                cpuAbi2);
+    public static int copyNativeBinariesIfNeededLI(ApkHandle handle, File sharedLibraryDir,
+            String abi) {
+        return nativeCopyNativeBinaries(handle.apkHandle, sharedLibraryDir.getPath(), abi);
     }
 
+    /**
+     * Checks if a given APK contains native code for any of the provided
+     * {@code supportedAbis}. Returns an index into {@code supportedAbis} if a matching
+     * ABI is found, {@link PackageManager#NO_NATIVE_LIBRARIES} if the
+     * APK doesn't contain any native code, and
+     * {@link PackageManager#INSTALL_FAILED_NO_MATCHING_ABIS} if none of the ABIs match.
+     */
+    public static int findSupportedAbi(ApkHandle handle, String[] supportedAbis) {
+        return nativeFindSupportedAbi(handle.apkHandle, supportedAbis);
+    }
+
+    private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis);
+
     // Convenience method to call removeNativeBinariesFromDirLI(File)
     public static boolean removeNativeBinariesLI(String nativeLibraryPath) {
         return removeNativeBinariesFromDirLI(new File(nativeLibraryPath));
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 2593420..8a0eaa2 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -177,13 +177,13 @@
             break;
         }
         if (ret < 0) {
-            if (errno == EINTR) {
+            if (ret == -EINTR) {
                 continue;
             }
-            if (errno == EINVAL) {
+            if (ret == -EINVAL) {
                 jniThrowException(env, "java/io/IOException", "Event too short");
-            } else if (errno != EAGAIN) {
-                jniThrowIOException(env, errno);  // Will throw on return
+            } else if (ret != -EAGAIN) {
+                jniThrowIOException(env, -ret);  // Will throw on return
             }
             break;
         }
diff --git a/core/jni/android_view_GLRenderer.cpp b/core/jni/android_view_GLRenderer.cpp
index 180c625..6ae6c8f 100644
--- a/core/jni/android_view_GLRenderer.cpp
+++ b/core/jni/android_view_GLRenderer.cpp
@@ -142,19 +142,12 @@
     LayerRenderer::destroyLayer(layer);
 }
 
-static void android_view_GLRenderer_setDisplayListData(JNIEnv* env, jobject clazz,
-        jlong displayListPtr, jlong newDataPtr) {
-    using namespace android::uirenderer;
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    DisplayListData* newData = reinterpret_cast<DisplayListData*>(newDataPtr);
-    displayList->setData(newData);
-}
-
-static void android_view_GLRenderer_updateRenderNodeProperties(JNIEnv* env, jobject clazz,
+static void android_view_GLRenderer_prepareTree(JNIEnv* env, jobject clazz,
         jlong renderNodePtr) {
     using namespace android::uirenderer;
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    renderNode->updateProperties();
+    TreeInfo info = {0};
+    renderNode->prepareTree(info);
 }
 
 static void android_view_GLRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
@@ -195,8 +188,7 @@
 
     { "getSystemTime",         "()J",   (void*) android_view_GLRenderer_getSystemTime },
     { "nDestroyLayer",         "(J)V",  (void*) android_view_GLRenderer_destroyLayer },
-    { "nSetDisplayListData",  "(JJ)V", (void*) android_view_GLRenderer_setDisplayListData },
-    { "nUpdateRenderNodeProperties", "(J)V", (void*) android_view_GLRenderer_updateRenderNodeProperties },
+    { "nPrepareTree", "(J)V", (void*) android_view_GLRenderer_prepareTree },
     { "nInvokeFunctor",        "(JZ)V", (void*) android_view_GLRenderer_invokeFunctor },
 #endif
 
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 4bf5f78..2eb0d78 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -127,7 +127,8 @@
 static jboolean android_view_HardwareLayer_flushChanges(JNIEnv* env, jobject clazz,
         jlong layerUpdaterPtr) {
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
-    return layer->apply();
+    bool ignoredHasFunctors;
+    return layer->apply(&ignoredHasFunctors);
 }
 
 static jlong android_view_HardwareLayer_getLayer(JNIEnv* env, jobject clazz,
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index cf95657..31a1de6 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -41,32 +41,34 @@
 // DisplayList view properties
 // ----------------------------------------------------------------------------
 
-static void android_view_RenderNode_setDisplayListName(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, jstring name) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
+static void android_view_RenderNode_output(JNIEnv* env,
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->output();
+}
+
+static jlong android_view_RenderNode_create(JNIEnv* env, jobject clazz, jstring name) {
+    RenderNode* renderNode = new RenderNode();
+    renderNode->incStrong(0);
     if (name != NULL) {
         const char* textArray = env->GetStringUTFChars(name, NULL);
-        displayList->setName(textArray);
+        renderNode->setName(textArray);
         env->ReleaseStringUTFChars(name, textArray);
     }
+    return reinterpret_cast<jlong>(renderNode);
 }
 
-static void android_view_RenderNode_output(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->output();
+static void android_view_RenderNode_destroyRenderNode(JNIEnv* env,
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->decStrong(0);
 }
 
-static jlong android_view_RenderNode_create(JNIEnv* env, jobject clazz) {
-    RenderNode* displayList = new RenderNode();
-    displayList->incStrong(0);
-    return reinterpret_cast<jlong>(displayList);
-}
-
-static void android_view_RenderNode_destroyDisplayList(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->decStrong(0);
+static void android_view_RenderNode_setDisplayListData(JNIEnv* env,
+        jobject clazz, jlong renderNodePtr, jlong newDataPtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    DisplayListData* newData = reinterpret_cast<DisplayListData*>(newDataPtr);
+    renderNode->setStagingDisplayList(newData);
 }
 
 // ----------------------------------------------------------------------------
@@ -74,201 +76,201 @@
 // ----------------------------------------------------------------------------
 
 static void android_view_RenderNode_setCaching(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, jboolean caching) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setCaching(caching);
+        jobject clazz, jlong renderNodePtr, jboolean caching) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setCaching(caching);
 }
 
 static void android_view_RenderNode_setStaticMatrix(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, jlong matrixPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
+        jobject clazz, jlong renderNodePtr, jlong matrixPtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
-    displayList->mutateStagingProperties().setStaticMatrix(matrix);
+    renderNode->mutateStagingProperties().setStaticMatrix(matrix);
 }
 
 static void android_view_RenderNode_setAnimationMatrix(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, jlong matrixPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
+        jobject clazz, jlong renderNodePtr, jlong matrixPtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
-    displayList->mutateStagingProperties().setAnimationMatrix(matrix);
+    renderNode->mutateStagingProperties().setAnimationMatrix(matrix);
 }
 
 static void android_view_RenderNode_setClipToBounds(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, jboolean clipToBounds) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setClipToBounds(clipToBounds);
+        jobject clazz, jlong renderNodePtr, jboolean clipToBounds) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setClipToBounds(clipToBounds);
 }
 
 static void android_view_RenderNode_setProjectBackwards(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, jboolean shouldProject) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setProjectBackwards(shouldProject);
+        jobject clazz, jlong renderNodePtr, jboolean shouldProject) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setProjectBackwards(shouldProject);
 }
 
 static void android_view_RenderNode_setProjectionReceiver(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, jboolean shouldRecieve) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setProjectionReceiver(shouldRecieve);
+        jobject clazz, jlong renderNodePtr, jboolean shouldRecieve) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setProjectionReceiver(shouldRecieve);
 }
 
 static void android_view_RenderNode_setOutlineRoundRect(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, jint left, jint top,
+        jobject clazz, jlong renderNodePtr, jint left, jint top,
         jint right, jint bottom, jfloat radius) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().mutableOutline().setRoundRect(left, top, right, bottom, radius);
-    displayList->mutateStagingProperties().updateClipPath();
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().mutableOutline().setRoundRect(left, top, right, bottom, radius);
+    renderNode->mutateStagingProperties().updateClipPath();
 }
 
 static void android_view_RenderNode_setOutlineConvexPath(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, jlong outlinePathPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
+        jobject clazz, jlong renderNodePtr, jlong outlinePathPtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     SkPath* outlinePath = reinterpret_cast<SkPath*>(outlinePathPtr);
-    displayList->mutateStagingProperties().mutableOutline().setConvexPath(outlinePath);
-    displayList->mutateStagingProperties().updateClipPath();
+    renderNode->mutateStagingProperties().mutableOutline().setConvexPath(outlinePath);
+    renderNode->mutateStagingProperties().updateClipPath();
 }
 
 static void android_view_RenderNode_setOutlineEmpty(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().mutableOutline().setEmpty();
-    displayList->mutateStagingProperties().updateClipPath();
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().mutableOutline().setEmpty();
+    renderNode->mutateStagingProperties().updateClipPath();
 }
 
 static void android_view_RenderNode_setClipToOutline(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, jboolean clipToOutline) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().mutableOutline().setShouldClip(clipToOutline);
-    displayList->mutateStagingProperties().updateClipPath();
+        jobject clazz, jlong renderNodePtr, jboolean clipToOutline) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().mutableOutline().setShouldClip(clipToOutline);
+    renderNode->mutateStagingProperties().updateClipPath();
 }
 
 static void android_view_RenderNode_setRevealClip(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, jboolean shouldClip, jboolean inverseClip,
+        jobject clazz, jlong renderNodePtr, jboolean shouldClip, jboolean inverseClip,
         jfloat x, jfloat y, jfloat radius) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().mutableRevealClip().set(
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().mutableRevealClip().set(
             shouldClip, inverseClip, x, y, radius);
-    displayList->mutateStagingProperties().updateClipPath();
+    renderNode->mutateStagingProperties().updateClipPath();
 }
 
 static void android_view_RenderNode_setAlpha(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, float alpha) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setAlpha(alpha);
+        jobject clazz, jlong renderNodePtr, float alpha) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setAlpha(alpha);
 }
 
 static void android_view_RenderNode_setHasOverlappingRendering(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, bool hasOverlappingRendering) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setHasOverlappingRendering(hasOverlappingRendering);
+        jobject clazz, jlong renderNodePtr, bool hasOverlappingRendering) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setHasOverlappingRendering(hasOverlappingRendering);
 }
 
 static void android_view_RenderNode_setTranslationX(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, float tx) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setTranslationX(tx);
+        jobject clazz, jlong renderNodePtr, float tx) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setTranslationX(tx);
 }
 
 static void android_view_RenderNode_setTranslationY(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, float ty) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setTranslationY(ty);
+        jobject clazz, jlong renderNodePtr, float ty) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setTranslationY(ty);
 }
 
 static void android_view_RenderNode_setTranslationZ(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, float tz) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setTranslationZ(tz);
+        jobject clazz, jlong renderNodePtr, float tz) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setTranslationZ(tz);
 }
 
 static void android_view_RenderNode_setRotation(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, float rotation) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setRotation(rotation);
+        jobject clazz, jlong renderNodePtr, float rotation) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setRotation(rotation);
 }
 
 static void android_view_RenderNode_setRotationX(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, float rx) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setRotationX(rx);
+        jobject clazz, jlong renderNodePtr, float rx) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setRotationX(rx);
 }
 
 static void android_view_RenderNode_setRotationY(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, float ry) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setRotationY(ry);
+        jobject clazz, jlong renderNodePtr, float ry) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setRotationY(ry);
 }
 
 static void android_view_RenderNode_setScaleX(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, float sx) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setScaleX(sx);
+        jobject clazz, jlong renderNodePtr, float sx) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setScaleX(sx);
 }
 
 static void android_view_RenderNode_setScaleY(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, float sy) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setScaleY(sy);
+        jobject clazz, jlong renderNodePtr, float sy) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setScaleY(sy);
 }
 
 static void android_view_RenderNode_setPivotX(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, float px) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setPivotX(px);
+        jobject clazz, jlong renderNodePtr, float px) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setPivotX(px);
 }
 
 static void android_view_RenderNode_setPivotY(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, float py) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setPivotY(py);
+        jobject clazz, jlong renderNodePtr, float py) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setPivotY(py);
 }
 
 static void android_view_RenderNode_setCameraDistance(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, float distance) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setCameraDistance(distance);
+        jobject clazz, jlong renderNodePtr, float distance) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setCameraDistance(distance);
 }
 
 static void android_view_RenderNode_setLeft(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, int left) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setLeft(left);
+        jobject clazz, jlong renderNodePtr, int left) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setLeft(left);
 }
 
 static void android_view_RenderNode_setTop(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, int top) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setTop(top);
+        jobject clazz, jlong renderNodePtr, int top) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setTop(top);
 }
 
 static void android_view_RenderNode_setRight(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, int right) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setRight(right);
+        jobject clazz, jlong renderNodePtr, int right) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setRight(right);
 }
 
 static void android_view_RenderNode_setBottom(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, int bottom) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setBottom(bottom);
+        jobject clazz, jlong renderNodePtr, int bottom) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setBottom(bottom);
 }
 
 static void android_view_RenderNode_setLeftTopRightBottom(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, int left, int top,
+        jobject clazz, jlong renderNodePtr, int left, int top,
         int right, int bottom) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().setLeftTopRightBottom(left, top, right, bottom);
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setLeftTopRightBottom(left, top, right, bottom);
 }
 
 static void android_view_RenderNode_offsetLeftAndRight(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, float offset) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().offsetLeftRight(offset);
+        jobject clazz, jlong renderNodePtr, float offset) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().offsetLeftRight(offset);
 }
 
 static void android_view_RenderNode_offsetTopAndBottom(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, float offset) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().offsetTopBottom(offset);
+        jobject clazz, jlong renderNodePtr, float offset) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().offsetTopBottom(offset);
 }
 
 // ----------------------------------------------------------------------------
@@ -276,105 +278,105 @@
 // ----------------------------------------------------------------------------
 
 static jboolean android_view_RenderNode_hasOverlappingRendering(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    return displayList->stagingProperties().hasOverlappingRendering();
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().hasOverlappingRendering();
 }
 
 static jfloat android_view_RenderNode_getAlpha(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    return displayList->stagingProperties().getAlpha();
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().getAlpha();
 }
 
 static jfloat android_view_RenderNode_getLeft(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    return displayList->stagingProperties().getLeft();
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().getLeft();
 }
 
 static jfloat android_view_RenderNode_getTop(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    return displayList->stagingProperties().getTop();
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().getTop();
 }
 
 static jfloat android_view_RenderNode_getRight(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    return displayList->stagingProperties().getRight();
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().getRight();
 }
 
 static jfloat android_view_RenderNode_getBottom(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    return displayList->stagingProperties().getBottom();
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().getBottom();
 }
 
 static jfloat android_view_RenderNode_getCameraDistance(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    return displayList->stagingProperties().getCameraDistance();
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().getCameraDistance();
 }
 
 static jfloat android_view_RenderNode_getScaleX(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    return displayList->stagingProperties().getScaleX();
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().getScaleX();
 }
 
 static jfloat android_view_RenderNode_getScaleY(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    return displayList->stagingProperties().getScaleY();
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().getScaleY();
 }
 
 static jfloat android_view_RenderNode_getTranslationX(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    return displayList->stagingProperties().getTranslationX();
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().getTranslationX();
 }
 
 static jfloat android_view_RenderNode_getTranslationY(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    return displayList->stagingProperties().getTranslationY();
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().getTranslationY();
 }
 
 static jfloat android_view_RenderNode_getTranslationZ(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    return displayList->stagingProperties().getTranslationZ();
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().getTranslationZ();
 }
 
 static jfloat android_view_RenderNode_getRotation(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    return displayList->stagingProperties().getRotation();
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().getRotation();
 }
 
 static jfloat android_view_RenderNode_getRotationX(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    return displayList->stagingProperties().getRotationX();
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().getRotationX();
 }
 
 static jfloat android_view_RenderNode_getRotationY(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    return displayList->stagingProperties().getRotationY();
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().getRotationY();
 }
 
 static jboolean android_view_RenderNode_isPivotExplicitlySet(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    return displayList->stagingProperties().isPivotExplicitlySet();
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().isPivotExplicitlySet();
 }
 
 static jboolean android_view_RenderNode_hasIdentityMatrix(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    return displayList->stagingProperties().getMatrixFlags() == 0;
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().getMatrixFlags() == 0;
 }
 
 // ----------------------------------------------------------------------------
@@ -382,16 +384,16 @@
 // ----------------------------------------------------------------------------
 
 static void android_view_RenderNode_getTransformMatrix(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, jlong outMatrixPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
+        jobject clazz, jlong renderNodePtr, jlong outMatrixPtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     SkMatrix* outMatrix = reinterpret_cast<SkMatrix*>(outMatrixPtr);
 
-    displayList->mutateStagingProperties().updateMatrix();
-    const SkMatrix* transformMatrix = displayList->stagingProperties().getTransformMatrix();
+    renderNode->mutateStagingProperties().updateMatrix();
+    const SkMatrix* transformMatrix = renderNode->stagingProperties().getTransformMatrix();
 
-    if (displayList->stagingProperties().getMatrixFlags() == TRANSLATION) {
-        outMatrix->setTranslate(displayList->stagingProperties().getTranslationX(),
-                displayList->stagingProperties().getTranslationY());
+    if (renderNode->stagingProperties().getMatrixFlags() == TRANSLATION) {
+        outMatrix->setTranslate(renderNode->stagingProperties().getTranslationX(),
+                renderNode->stagingProperties().getTranslationY());
     } else if (transformMatrix) {
         *outMatrix = *transformMatrix;
     } else {
@@ -400,9 +402,9 @@
 }
 
 static void android_view_RenderNode_getInverseTransformMatrix(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, jlong outMatrixPtr) {
+        jobject clazz, jlong renderNodePtr, jlong outMatrixPtr) {
     // load transform matrix
-    android_view_RenderNode_getTransformMatrix(env, clazz, displayListPtr, outMatrixPtr);
+    android_view_RenderNode_getTransformMatrix(env, clazz, renderNodePtr, outMatrixPtr);
     SkMatrix* outMatrix = reinterpret_cast<SkMatrix*>(outMatrixPtr);
 
     // return it inverted
@@ -413,17 +415,17 @@
 }
 
 static jfloat android_view_RenderNode_getPivotX(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().updateMatrix();
-    return displayList->stagingProperties().getPivotX();
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().updateMatrix();
+    return renderNode->stagingProperties().getPivotX();
 }
 
 static jfloat android_view_RenderNode_getPivotY(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    displayList->mutateStagingProperties().updateMatrix();
-    return displayList->stagingProperties().getPivotY();
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().updateMatrix();
+    return renderNode->stagingProperties().getPivotY();
 }
 
 #endif // USE_OPENGL_RENDERER
@@ -436,10 +438,9 @@
 
 static JNINativeMethod gMethods[] = {
 #ifdef USE_OPENGL_RENDERER
-    { "nCreate",               "()J",    (void*) android_view_RenderNode_create },
-    { "nDestroyDisplayList",   "(J)V",   (void*) android_view_RenderNode_destroyDisplayList },
-    { "nSetDisplayListName",   "(JLjava/lang/String;)V",
-            (void*) android_view_RenderNode_setDisplayListName },
+    { "nCreate",               "(Ljava/lang/String;)J",    (void*) android_view_RenderNode_create },
+    { "nDestroyRenderNode",   "(J)V",   (void*) android_view_RenderNode_destroyRenderNode },
+    { "nSetDisplayListData",   "(JJ)V", (void*) android_view_RenderNode_setDisplayListData },
     { "nOutput",               "(J)V",  (void*) android_view_RenderNode_output },
 
     { "nSetCaching",           "(JZ)V",  (void*) android_view_RenderNode_setCaching },
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 32890cf..36c8357 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -84,7 +84,7 @@
         jlong proxyPtr, jobject jsurface) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     sp<ANativeWindow> window = android_view_Surface_getNativeWindow(env, jsurface);
-    return proxy->initialize(window.get());
+    return proxy->initialize(window);
 }
 
 static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz,
@@ -94,7 +94,17 @@
     if (jsurface) {
         window = android_view_Surface_getNativeWindow(env, jsurface);
     }
-    proxy->updateSurface(window.get());
+    proxy->updateSurface(window);
+}
+
+static void android_view_ThreadedRenderer_pauseSurface(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jobject jsurface) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    sp<ANativeWindow> window;
+    if (jsurface) {
+        window = android_view_Surface_getNativeWindow(env, jsurface);
+    }
+    proxy->pauseSurface(window);
 }
 
 static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz,
@@ -103,14 +113,6 @@
     proxy->setup(width, height);
 }
 
-static void android_view_ThreadedRenderer_setDisplayListData(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jlong displayListPtr, jlong newDataPtr) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    DisplayListData* newData = reinterpret_cast<DisplayListData*>(newDataPtr);
-    proxy->setDisplayListData(displayList, newData);
-}
-
 static void android_view_ThreadedRenderer_drawDisplayList(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jlong displayListPtr, jint dirtyLeft, jint dirtyTop,
         jint dirtyRight, jint dirtyBottom) {
@@ -203,8 +205,8 @@
     { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
     { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
     { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
+    { "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface },
     { "nSetup", "(JII)V", (void*) android_view_ThreadedRenderer_setup },
-    { "nSetDisplayListData", "(JJJ)V", (void*) android_view_ThreadedRenderer_setDisplayListData },
     { "nDrawDisplayList", "(JJIIII)V", (void*) android_view_ThreadedRenderer_drawDisplayList },
     { "nDestroyCanvas", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvas },
     { "nAttachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_attachFunctor },
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index a860918..230658f 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -19,11 +19,12 @@
 
 #include <android_runtime/AndroidRuntime.h>
 
-#include <utils/Log.h>
-#include <androidfw/ZipFileRO.h>
-#include <androidfw/ZipUtils.h>
 #include <ScopedUtfChars.h>
 #include <UniquePtr.h>
+#include <androidfw/ZipFileRO.h>
+#include <androidfw/ZipUtils.h>
+#include <utils/Log.h>
+#include <utils/Vector.h>
 
 #include <zlib.h>
 
@@ -54,17 +55,19 @@
 namespace android {
 
 // These match PackageManager.java install codes
-typedef enum {
+enum install_status_t {
     INSTALL_SUCCEEDED = 1,
     INSTALL_FAILED_INVALID_APK = -2,
     INSTALL_FAILED_INSUFFICIENT_STORAGE = -4,
     INSTALL_FAILED_CONTAINER_ERROR = -18,
     INSTALL_FAILED_INTERNAL_ERROR = -110,
-} install_status_t;
+    INSTALL_FAILED_NO_MATCHING_ABIS = -113,
+    NO_NATIVE_LIBRARIES = -114
+};
 
 typedef install_status_t (*iterFunc)(JNIEnv*, void*, ZipFileRO*, ZipEntryRO, const char*);
 
-// Equivalent to isFilenameSafe
+// Equivalent to android.os.FileUtils.isFilenameSafe
 static bool
 isFilenameSafe(const char* filename)
 {
@@ -268,126 +271,252 @@
     return INSTALL_SUCCEEDED;
 }
 
-static install_status_t
-iterateOverNativeFiles(JNIEnv *env, jstring javaFilePath, jstring javaCpuAbi, jstring javaCpuAbi2,
-        iterFunc callFunc, void* callArg) {
-    ScopedUtfChars filePath(env, javaFilePath);
-    ScopedUtfChars cpuAbi(env, javaCpuAbi);
-    ScopedUtfChars cpuAbi2(env, javaCpuAbi2);
-
-    UniquePtr<ZipFileRO> zipFile(ZipFileRO::open(filePath.c_str()));
-    if (zipFile.get() == NULL) {
-        ALOGI("Couldn't open APK %s\n", filePath.c_str());
-        return INSTALL_FAILED_INVALID_APK;
+/*
+ * An iterator over all shared libraries in a zip file. An entry is
+ * considered to be a shared library if all of the conditions below are
+ * satisfied :
+ *
+ * - The entry is under the lib/ directory.
+ * - The entry name ends with ".so" and the entry name starts with "lib",
+ *   an exception is made for entries whose name is "gdbserver".
+ * - The entry filename is "safe" (as determined by isFilenameSafe).
+ *
+ */
+class NativeLibrariesIterator {
+private:
+    NativeLibrariesIterator(ZipFileRO* zipFile, void* cookie)
+        : mZipFile(zipFile), mCookie(cookie), mLastSlash(NULL) {
+        fileName[0] = '\0';
     }
 
+public:
+    static NativeLibrariesIterator* create(ZipFileRO* zipFile) {
+        void* cookie = NULL;
+        if (!zipFile->startIteration(&cookie)) {
+            return NULL;
+        }
+
+        return new NativeLibrariesIterator(zipFile, cookie);
+    }
+
+    ZipEntryRO next() {
+        ZipEntryRO next = NULL;
+        while ((next = mZipFile->nextEntry(mCookie)) != NULL) {
+            // Make sure this entry has a filename.
+            if (mZipFile->getEntryFileName(next, fileName, sizeof(fileName))) {
+                continue;
+            }
+
+            // Make sure we're in the lib directory of the ZIP.
+            if (strncmp(fileName, APK_LIB, APK_LIB_LEN)) {
+                continue;
+            }
+
+            // Make sure the filename is at least to the minimum library name size.
+            const size_t fileNameLen = strlen(fileName);
+            static const size_t minLength = APK_LIB_LEN + 2 + LIB_PREFIX_LEN + 1 + LIB_SUFFIX_LEN;
+            if (fileNameLen < minLength) {
+                continue;
+            }
+
+            const char* lastSlash = strrchr(fileName, '/');
+            ALOG_ASSERT(lastSlash != NULL, "last slash was null somehow for %s\n", fileName);
+
+            // Exception: If we find the gdbserver binary, return it.
+            if (!strncmp(lastSlash + 1, GDBSERVER, GDBSERVER_LEN)) {
+                break;
+            }
+
+            // Make sure the filename starts with lib and ends with ".so".
+            if (strncmp(fileName + fileNameLen - LIB_SUFFIX_LEN, LIB_SUFFIX, LIB_SUFFIX_LEN)
+                || strncmp(lastSlash, LIB_PREFIX, LIB_PREFIX_LEN)) {
+                continue;
+            }
+
+            // Make sure the filename is safe.
+            if (!isFilenameSafe(lastSlash + 1)) {
+                continue;
+            }
+
+            mLastSlash = lastSlash;
+            break;
+        }
+
+        return next;
+    }
+
+    inline const char* currentEntry() const {
+        return fileName;
+    }
+
+    inline const char* lastSlash() const {
+        return mLastSlash;
+    }
+
+    virtual ~NativeLibrariesIterator() {
+        mZipFile->endIteration(mCookie);
+    }
+private:
+
     char fileName[PATH_MAX];
-    bool hasPrimaryAbi = false;
+    ZipFileRO* const mZipFile;
+    void* mCookie;
+    const char* mLastSlash;
+};
 
-    void* cookie = NULL;
-    if (!zipFile->startIteration(&cookie)) {
-        ALOGI("Couldn't iterate over APK%s\n", filePath.c_str());
+static install_status_t
+iterateOverNativeFiles(JNIEnv *env, jlong apkHandle, jstring javaCpuAbi,
+                       iterFunc callFunc, void* callArg) {
+    ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle);
+    if (zipFile == NULL) {
         return INSTALL_FAILED_INVALID_APK;
     }
 
+    UniquePtr<NativeLibrariesIterator> it(NativeLibrariesIterator::create(zipFile));
+    if (it.get() == NULL) {
+        return INSTALL_FAILED_INVALID_APK;
+    }
+
+    const ScopedUtfChars cpuAbi(env, javaCpuAbi);
+    if (cpuAbi.c_str() == NULL) {
+        // This would've thrown, so this return code isn't observable by
+        // Java.
+        return INSTALL_FAILED_INVALID_APK;
+    }
     ZipEntryRO entry = NULL;
-    while ((entry = zipFile->nextEntry(cookie)) != NULL) {
-        // Make sure this entry has a filename.
-        if (zipFile->getEntryFileName(entry, fileName, sizeof(fileName))) {
-            continue;
-        }
-
-        // Make sure we're in the lib directory of the ZIP.
-        if (strncmp(fileName, APK_LIB, APK_LIB_LEN)) {
-            continue;
-        }
-
-        // Make sure the filename is at least to the minimum library name size.
-        const size_t fileNameLen = strlen(fileName);
-        static const size_t minLength = APK_LIB_LEN + 2 + LIB_PREFIX_LEN + 1 + LIB_SUFFIX_LEN;
-        if (fileNameLen < minLength) {
-            continue;
-        }
-
-        const char* lastSlash = strrchr(fileName, '/');
-        ALOG_ASSERT(lastSlash != NULL, "last slash was null somehow for %s\n", fileName);
+    while ((entry = it->next()) != NULL) {
+        const char* fileName = it->currentEntry();
+        const char* lastSlash = it->lastSlash();
 
         // Check to make sure the CPU ABI of this file is one we support.
         const char* cpuAbiOffset = fileName + APK_LIB_LEN;
         const size_t cpuAbiRegionSize = lastSlash - cpuAbiOffset;
 
-        ALOGV("Comparing ABIs %s and %s versus %s\n", cpuAbi.c_str(), cpuAbi2.c_str(), cpuAbiOffset);
-        if (cpuAbi.size() == cpuAbiRegionSize
-                && *(cpuAbiOffset + cpuAbi.size()) == '/'
-                && !strncmp(cpuAbiOffset, cpuAbi.c_str(), cpuAbiRegionSize)) {
-            ALOGV("Using primary ABI %s\n", cpuAbi.c_str());
-            hasPrimaryAbi = true;
-        } else if (cpuAbi2.size() == cpuAbiRegionSize
-                && *(cpuAbiOffset + cpuAbi2.size()) == '/'
-                && !strncmp(cpuAbiOffset, cpuAbi2.c_str(), cpuAbiRegionSize)) {
-
-            /*
-             * If this library matches both the primary and secondary ABIs,
-             * only use the primary ABI.
-             */
-            if (hasPrimaryAbi) {
-                ALOGV("Already saw primary ABI, skipping secondary ABI %s\n", cpuAbi2.c_str());
-                continue;
-            } else {
-                ALOGV("Using secondary ABI %s\n", cpuAbi2.c_str());
-            }
-        } else {
-            ALOGV("abi didn't match anything: %s (end at %zd)\n", cpuAbiOffset, cpuAbiRegionSize);
-            continue;
-        }
-
-        // If this is a .so file, check to see if we need to copy it.
-        if ((!strncmp(fileName + fileNameLen - LIB_SUFFIX_LEN, LIB_SUFFIX, LIB_SUFFIX_LEN)
-                    && !strncmp(lastSlash, LIB_PREFIX, LIB_PREFIX_LEN)
-                    && isFilenameSafe(lastSlash + 1))
-                || !strncmp(lastSlash + 1, GDBSERVER, GDBSERVER_LEN)) {
-
-            install_status_t ret = callFunc(env, callArg, zipFile.get(), entry, lastSlash + 1);
+        if (cpuAbi.size() == cpuAbiRegionSize && !strncmp(cpuAbiOffset, cpuAbi.c_str(), cpuAbiRegionSize)) {
+            install_status_t ret = callFunc(env, callArg, zipFile, entry, lastSlash + 1);
 
             if (ret != INSTALL_SUCCEEDED) {
                 ALOGV("Failure for entry %s", lastSlash + 1);
-                zipFile->endIteration(cookie);
                 return ret;
             }
         }
     }
 
-    zipFile->endIteration(cookie);
-
     return INSTALL_SUCCEEDED;
 }
 
+
+static int findSupportedAbi(JNIEnv *env, jlong apkHandle, jobjectArray supportedAbisArray) {
+    const int numAbis = env->GetArrayLength(supportedAbisArray);
+    Vector<ScopedUtfChars*> supportedAbis;
+
+    for (int i = 0; i < numAbis; ++i) {
+        supportedAbis.add(new ScopedUtfChars(env,
+            (jstring) env->GetObjectArrayElement(supportedAbisArray, i)));
+    }
+
+    ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle);
+    if (zipFile == NULL) {
+        return INSTALL_FAILED_INVALID_APK;
+    }
+
+    UniquePtr<NativeLibrariesIterator> it(NativeLibrariesIterator::create(zipFile));
+    if (it.get() == NULL) {
+        return INSTALL_FAILED_INVALID_APK;
+    }
+
+    ZipEntryRO entry = NULL;
+    char fileName[PATH_MAX];
+    int status = NO_NATIVE_LIBRARIES;
+    while ((entry = it->next()) != NULL) {
+        // We're currently in the lib/ directory of the APK, so it does have some native
+        // code. We should return INSTALL_FAILED_NO_MATCHING_ABIS if none of the
+        // libraries match.
+        if (status == NO_NATIVE_LIBRARIES) {
+            status = INSTALL_FAILED_NO_MATCHING_ABIS;
+        }
+
+        const char* fileName = it->currentEntry();
+        const char* lastSlash = it->lastSlash();
+
+        // Check to see if this CPU ABI matches what we are looking for.
+        const char* abiOffset = fileName + APK_LIB_LEN;
+        const size_t abiSize = lastSlash - abiOffset;
+        for (int i = 0; i < numAbis; i++) {
+            const ScopedUtfChars* abi = supportedAbis[i];
+            if (abi->size() == abiSize && !strncmp(abiOffset, abi->c_str(), abiSize)) {
+                // The entry that comes in first (i.e. with a lower index) has the higher priority.
+                if (((i < status) && (status >= 0)) || (status < 0) ) {
+                    status = i;
+                }
+            }
+        }
+    }
+
+    for (int i = 0; i < numAbis; ++i) {
+        delete supportedAbis[i];
+    }
+
+    return status;
+}
+
 static jint
 com_android_internal_content_NativeLibraryHelper_copyNativeBinaries(JNIEnv *env, jclass clazz,
-        jstring javaFilePath, jstring javaNativeLibPath, jstring javaCpuAbi, jstring javaCpuAbi2)
+        jlong apkHandle, jstring javaNativeLibPath, jstring javaCpuAbi)
 {
-    return (jint) iterateOverNativeFiles(env, javaFilePath, javaCpuAbi, javaCpuAbi2,
+    return (jint) iterateOverNativeFiles(env, apkHandle, javaCpuAbi,
             copyFileIfChanged, &javaNativeLibPath);
 }
 
 static jlong
 com_android_internal_content_NativeLibraryHelper_sumNativeBinaries(JNIEnv *env, jclass clazz,
-        jstring javaFilePath, jstring javaCpuAbi, jstring javaCpuAbi2)
+        jlong apkHandle, jstring javaCpuAbi)
 {
     size_t totalSize = 0;
 
-    iterateOverNativeFiles(env, javaFilePath, javaCpuAbi, javaCpuAbi2, sumFiles, &totalSize);
+    iterateOverNativeFiles(env, apkHandle, javaCpuAbi, sumFiles, &totalSize);
 
     return totalSize;
 }
 
+static jint
+com_android_internal_content_NativeLibraryHelper_findSupportedAbi(JNIEnv *env, jclass clazz,
+        jlong apkHandle, jobjectArray javaCpuAbisToSearch)
+{
+    return (jint) findSupportedAbi(env, apkHandle, javaCpuAbisToSearch);
+}
+
+static jlong
+com_android_internal_content_NativeLibraryHelper_openApk(JNIEnv *env, jclass, jstring apkPath)
+{
+    ScopedUtfChars filePath(env, apkPath);
+    ZipFileRO* zipFile = ZipFileRO::open(filePath.c_str());
+
+    return reinterpret_cast<jlong>(zipFile);
+}
+
+static void
+com_android_internal_content_NativeLibraryHelper_close(JNIEnv *env, jclass, jlong apkHandle)
+{
+    delete reinterpret_cast<ZipFileRO*>(apkHandle);
+}
+
 static JNINativeMethod gMethods[] = {
+    {"nativeOpenApk",
+            "(Ljava/lang/String;)J",
+            (void *)com_android_internal_content_NativeLibraryHelper_openApk},
+    {"nativeClose",
+            "(J)V",
+            (void *)com_android_internal_content_NativeLibraryHelper_close},
     {"nativeCopyNativeBinaries",
-            "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
+            "(JLjava/lang/String;Ljava/lang/String;)I",
             (void *)com_android_internal_content_NativeLibraryHelper_copyNativeBinaries},
     {"nativeSumNativeBinaries",
-            "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J",
+            "(JLjava/lang/String;)J",
             (void *)com_android_internal_content_NativeLibraryHelper_sumNativeBinaries},
+    {"nativeFindSupportedAbi",
+            "(J[Ljava/lang/String;)I",
+            (void *)com_android_internal_content_NativeLibraryHelper_findSupportedAbi},
 };
 
 
diff --git a/core/res/res/layout/preference_category_quantum.xml b/core/res/res/layout/preference_category_quantum.xml
new file mode 100644
index 0000000..032e09d
--- /dev/null
+++ b/core/res/res/layout/preference_category_quantum.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Layout used for PreferenceCategory in a PreferenceActivity. -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+android:id/title"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginBottom="16dip"
+    android:textAppearance="@style/TextAppearance.Quantum.Body2"
+    android:textColor="?android:attr/textColorSecondary"
+    android:textStyle="bold"
+    android:paddingStart="?attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?attr/listPreferredItemPaddingEnd"
+    android:paddingTop="16dip" />
diff --git a/core/res/res/layout/preference_child_quantum.xml b/core/res/res/layout/preference_child_quantum.xml
new file mode 100644
index 0000000..690d64a
--- /dev/null
+++ b/core/res/res/layout/preference_child_quantum.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Layout for a visually child-like Preference in a PreferenceActivity. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginStart="?attr/listPreferredItemPaddingStart"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:gravity="center_vertical"
+    android:paddingStart="?attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?attr/listPreferredItemPaddingEnd">
+
+    <LinearLayout
+        android:id="@+android:id/icon_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:minWidth="58dip"
+        android:gravity="left|center_vertical"
+        android:orientation="horizontal">
+        <ImageView
+            android:id="@+android:id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="8dip" />
+    </LinearLayout>
+
+    <RelativeLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:paddingTop="16dip"
+        android:paddingBottom="16dip">
+
+        <TextView android:id="@+android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:textAppearance="?android:attr/textAppearanceListItem" />
+
+        <TextView android:id="@+android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@android:id/title"
+            android:layout_alignStart="@android:id/title"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+            android:textColor="?android:attr/textColorSecondary"
+            android:maxLines="10" />
+
+    </RelativeLayout>
+
+    <!-- Preference should place its actual preference widget here. -->
+    <LinearLayout android:id="@+android:id/widget_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:minWidth="58dip"
+        android:gravity="right|center_vertical"
+        android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/preference_information_quantum.xml b/core/res/res/layout/preference_information_quantum.xml
new file mode 100644
index 0000000..f21640fc
--- /dev/null
+++ b/core/res/res/layout/preference_information_quantum.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Layout for a Preference in a PreferenceActivity. The
+     Preference is able to place a specific widget for its particular
+     type in the "widget_frame" layout. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:gravity="center_vertical"
+    android:paddingStart="?attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?attr/listPreferredItemPaddingEnd">
+
+    <LinearLayout
+        android:id="@+android:id/icon_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:minWidth="58dip"
+        android:gravity="left|center_vertical"
+        android:orientation="horizontal">
+        <ImageView
+            android:id="@+android:id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="8dip" />
+    </LinearLayout>
+
+    <RelativeLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:paddingTop="16dip"
+        android:paddingBottom="16dip">
+
+        <TextView android:id="@+android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:textAppearance="?android:attr/textAppearanceListItem" />
+
+        <TextView android:id="@+android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@android:id/title"
+            android:layout_alignStart="@android:id/title"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+            android:textColor="?android:attr/textColorSecondary"
+            android:maxLines="10" />
+
+    </RelativeLayout>
+
+    <!-- Preference should place its actual preference widget here. -->
+    <LinearLayout android:id="@+android:id/widget_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:minWidth="58dip"
+        android:gravity="right|center_vertical"
+        android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/preference_quantum.xml b/core/res/res/layout/preference_quantum.xml
new file mode 100644
index 0000000..a4fe73d
--- /dev/null
+++ b/core/res/res/layout/preference_quantum.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Layout for a Preference in a PreferenceActivity. The
+     Preference is able to place a specific widget for its particular
+     type in the "widget_frame" layout. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:gravity="center_vertical"
+    android:paddingStart="?attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?attr/listPreferredItemPaddingEnd"
+    android:background="?android:attr/activatedBackgroundIndicator">
+
+    <LinearLayout
+        android:id="@+android:id/icon_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:minWidth="58dip"
+        android:gravity="left|center_vertical"
+        android:orientation="horizontal">
+        <ImageView
+            android:id="@+android:id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:scaleType="centerInside"
+            android:layout_marginEnd="8dip" />
+    </LinearLayout>
+
+    <RelativeLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:paddingTop="16dip"
+        android:paddingBottom="16dip">
+
+        <TextView android:id="@+android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:textAppearance="?android:attr/textAppearanceListItem"
+            android:ellipsize="marquee" />
+
+        <TextView android:id="@+android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@android:id/title"
+            android:layout_alignStart="@android:id/title"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+            android:textColor="?android:attr/textColorSecondary"
+            android:maxLines="10" />
+
+    </RelativeLayout>
+
+    <!-- Preference should place its actual preference widget here. -->
+    <LinearLayout android:id="@+android:id/widget_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:minWidth="58dip"
+        android:gravity="right|center_vertical"
+        android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/preference_widget_checkbox.xml b/core/res/res/layout/preference_widget_checkbox.xml
index 33a43f4..bfd7f0a 100644
--- a/core/res/res/layout/preference_widget_checkbox.xml
+++ b/core/res/res/layout/preference_widget_checkbox.xml
@@ -20,6 +20,5 @@
     android:id="@+android:id/checkbox" 
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:layout_gravity="center"
     android:focusable="false"
     android:clickable="false" />
diff --git a/core/res/res/layout/preference_widget_switch.xml b/core/res/res/layout/preference_widget_switch.xml
index 83ef097..534c7ec 100644
--- a/core/res/res/layout/preference_widget_switch.xml
+++ b/core/res/res/layout/preference_widget_switch.xml
@@ -20,6 +20,5 @@
     android:id="@+android:id/switchWidget"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:layout_gravity="center"
     android:padding="16dip"
     android:focusable="false" />
diff --git a/core/res/res/layout/simple_list_item_1.xml b/core/res/res/layout/simple_list_item_1.xml
index 4249d10..43a5635 100644
--- a/core/res/res/layout/simple_list_item_1.xml
+++ b/core/res/res/layout/simple_list_item_1.xml
@@ -22,5 +22,4 @@
     android:gravity="center_vertical"
     android:paddingStart="?android:attr/listPreferredItemPaddingStart"
     android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:minHeight="?android:attr/listPreferredItemHeightSmall"
-/>
+    android:minHeight="?android:attr/listPreferredItemHeightSmall" />
diff --git a/core/res/res/layout/simple_list_item_2.xml b/core/res/res/layout/simple_list_item_2.xml
index 63c542b..b47a3465 100644
--- a/core/res/res/layout/simple_list_item_2.xml
+++ b/core/res/res/layout/simple_list_item_2.xml
@@ -20,22 +20,19 @@
     android:minHeight="?android:attr/listPreferredItemHeight"
     android:mode="twoLine"
     android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
->
-    
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
 	<TextView android:id="@android:id/text1"
-		android:layout_width="match_parent"
-		android:layout_height="wrap_content"
-    android:layout_marginTop="8dip"
-		android:textAppearance="?android:attr/textAppearanceListItem"
-	/>
-		
+    	android:layout_width="match_parent"
+    	android:layout_height="wrap_content"
+      android:layout_marginTop="8dip"
+    	android:textAppearance="?android:attr/textAppearanceListItem" />
+
 	<TextView android:id="@android:id/text2"
-		android:layout_width="match_parent"
-		android:layout_height="wrap_content"
-		android:layout_below="@android:id/text1"
-    android:layout_alignStart="@android:id/text1"
-		android:textAppearance="?android:attr/textAppearanceSmall"
-	/>
+    	android:layout_width="match_parent"
+    	android:layout_height="wrap_content"
+    	android:layout_below="@android:id/text1"
+      android:layout_alignStart="@android:id/text1"
+    	android:textAppearance="?android:attr/textAppearanceListItemSecondary" />
 
 </TwoLineListItem>
diff --git a/core/res/res/layout/simple_list_item_2_single_choice.xml b/core/res/res/layout/simple_list_item_2_single_choice.xml
index 5629567..65c5856 100644
--- a/core/res/res/layout/simple_list_item_2_single_choice.xml
+++ b/core/res/res/layout/simple_list_item_2_single_choice.xml
@@ -22,31 +22,34 @@
     android:paddingStart="16dip"
     android:paddingEnd="12dip"
     android:minHeight="?android:attr/listPreferredItemHeightSmall">
+
     <LinearLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_weight="1"
         android:orientation="vertical"
         android:gravity="center_vertical">
+
         <TextView android:id="@android:id/text1"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textAppearance="?android:attr/textAppearanceListItem"
             android:textColor="?android:attr/textColorAlertDialogListItem"
             android:gravity="center_vertical|start"
             android:singleLine="true"
-            android:ellipsize="marquee"
-        />
+            android:ellipsize="marquee" />
+        
         <TextView android:id="@android:id/text2"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
             android:textColor="?android:attr/textColorAlertDialogListItem"
             android:gravity="center_vertical|start"
             android:singleLine="true"
-            android:ellipsize="marquee"
-        />
+            android:ellipsize="marquee" />
+        
     </LinearLayout>
+
     <RadioButton
         android:id="@+id/radio"
         android:layout_width="35dip"
@@ -54,6 +57,6 @@
         android:paddingEnd="12dip"
         android:gravity="center_vertical"
         android:focusable="false"
-        android:clickable="false"
-    />
+        android:clickable="false" />
+
 </LinearLayout>
diff --git a/core/res/res/layout/simple_list_item_activated_1.xml b/core/res/res/layout/simple_list_item_activated_1.xml
index 41155e4..9b778d7 100644
--- a/core/res/res/layout/simple_list_item_activated_1.xml
+++ b/core/res/res/layout/simple_list_item_activated_1.xml
@@ -23,5 +23,4 @@
     android:paddingStart="?android:attr/listPreferredItemPaddingStart"
     android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
     android:background="?android:attr/activatedBackgroundIndicator"
-    android:minHeight="?android:attr/listPreferredItemHeightSmall"
-/>
+    android:minHeight="?android:attr/listPreferredItemHeightSmall" />
diff --git a/core/res/res/layout/simple_list_item_activated_2.xml b/core/res/res/layout/simple_list_item_activated_2.xml
index 725697d..5036813 100644
--- a/core/res/res/layout/simple_list_item_activated_2.xml
+++ b/core/res/res/layout/simple_list_item_activated_2.xml
@@ -21,23 +21,20 @@
     android:layout_height="wrap_content"
     android:background="?android:attr/activatedBackgroundIndicator"
     android:minHeight="?android:attr/listPreferredItemHeight"
-    android:mode="twoLine"
->
+    android:mode="twoLine">
 
     <TextView android:id="@android:id/text1"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
         android:layout_marginTop="6dip"
-        android:textAppearance="?android:attr/textAppearanceListItem"
-    />
+        android:textAppearance="?android:attr/textAppearanceListItem" />
 
     <TextView android:id="@android:id/text2"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_below="@android:id/text1"
         android:layout_alignStart="@android:id/text1"
-        android:textAppearance="?android:attr/textAppearanceSmall"
-    />
+        android:textAppearance="?android:attr/textAppearanceListItemSecondary" />
 
 </TwoLineListItem>
diff --git a/core/res/res/layout/simple_list_item_checked.xml b/core/res/res/layout/simple_list_item_checked.xml
index 0c497d6..4673e27 100644
--- a/core/res/res/layout/simple_list_item_checked.xml
+++ b/core/res/res/layout/simple_list_item_checked.xml
@@ -22,5 +22,4 @@
     android:gravity="center_vertical"
     android:checkMark="?android:attr/textCheckMark"
     android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-/>
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" />
diff --git a/core/res/res/layout/simple_list_item_multiple_choice.xml b/core/res/res/layout/simple_list_item_multiple_choice.xml
index 076d8c6..440b6fd 100644
--- a/core/res/res/layout/simple_list_item_multiple_choice.xml
+++ b/core/res/res/layout/simple_list_item_multiple_choice.xml
@@ -22,5 +22,4 @@
     android:gravity="center_vertical"
     android:checkMark="?android:attr/listChoiceIndicatorMultiple"
     android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-/>
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" />
diff --git a/core/res/res/layout/simple_list_item_single_choice.xml b/core/res/res/layout/simple_list_item_single_choice.xml
index 4c1af09..02cb7f7 100644
--- a/core/res/res/layout/simple_list_item_single_choice.xml
+++ b/core/res/res/layout/simple_list_item_single_choice.xml
@@ -22,5 +22,4 @@
     android:gravity="center_vertical"
     android:checkMark="?android:attr/listChoiceIndicatorSingle"
     android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-/>
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 46cb9b22..f364bd0 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -245,6 +245,8 @@
 
         <!-- The preferred TextAppearance for the primary text of list items. -->
         <attr name="textAppearanceListItem" format="reference" />
+        <!-- The preferred TextAppearance for the secondary text of list items. -->
+        <attr name="textAppearanceListItemSecondary" format="reference" />
         <!-- The preferred TextAppearance for the primary text of small list items. -->
         <attr name="textAppearanceListItemSmall" format="reference" />
 
@@ -4409,14 +4411,23 @@
         <!-- When a tint color is set, specifies its Porter-Duff blending mode. The
              default value is src_in, which treats the drawable as an alpha mask. -->
         <attr name="tintMode">
-            <!-- [Sa * Da, Sc * Da] -->
-            <enum name="src_in" value="0" />
-            <!-- [Da, Sc * Da + (1 - Sa) * Dc] -->
-            <enum name="src_atop" value="1" />
-            <!-- [Sa * Da, Sc * Dc] -->
-            <enum name="multiply" value="2" />
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
             <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
-            <enum name="screen" value="3" />
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
         </attr>
     </declare-styleable>
 
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index acdf926..d3bee28 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2148,6 +2148,7 @@
   <public type="attr" name="subtitleTextAppearance" />
   <public type="attr" name="slideEdge" />
   <public type="attr" name="actionBarTheme" />
+  <public type="attr" name="textAppearanceListItemSecondary" />
 
   <public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
 
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index dd148c4..2720d61 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -33,7 +33,7 @@
     <eat-comment/>
 
     <style name="Preference.Quantum">
-        <item name="layout">@layout/preference_holo</item>
+        <item name="layout">@layout/preference_quantum</item>
     </style>
 
     <style name="PreferenceFragment.Quantum">
@@ -42,13 +42,13 @@
     </style>
 
     <style name="Preference.Quantum.Information">
-        <item name="layout">@layout/preference_information_holo</item>
+        <item name="layout">@layout/preference_information_quantum</item>
         <item name="enabled">false</item>
         <item name="shouldDisableView">false</item>
     </style>
 
     <style name="Preference.Quantum.Category">
-        <item name="layout">@layout/preference_category_holo</item>
+        <item name="layout">@layout/preference_category_quantum</item>
         <!-- The title should not dim if the category is disabled, instead only the preference children should dim. -->
         <item name="shouldDisableView">false</item>
         <item name="selectable">false</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b011483..ac6c15d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1835,5 +1835,6 @@
   <java-symbol type="attr" name="titleTextAppearance" />
   <java-symbol type="attr" name="subtitleTextAppearance" />
   <java-symbol type="drawable" name="ic_lock_bugreport" />
+  <java-symbol type="id" name="icon_frame" />
 
 </resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 7aea814..6f9e55b 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -126,6 +126,7 @@
         <item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeight</item>
         <item name="textAppearanceListItem">?android:attr/textAppearanceLarge</item>
         <item name="textAppearanceListItemSmall">?android:attr/textAppearanceLarge</item>
+        <item name="textAppearanceListItemSecondary">?android:attr/textAppearanceSmall</item>
         <item name="listPreferredItemPaddingLeft">6dip</item>
         <item name="listPreferredItemPaddingRight">6dip</item>
         <item name="listPreferredItemPaddingStart">6dip</item>
@@ -349,6 +350,7 @@
         <item name="actionMenuTextAppearance">@android:style/TextAppearance.Holo.Widget.ActionBar.Menu</item>
         <item name="actionMenuTextColor">?android:attr/textColorPrimary</item>
         <item name="actionBarWidgetTheme">@null</item>
+        <item name="actionBarTheme">@null</item>
         <item name="actionBarDivider">?android:attr/dividerVertical</item>
         <item name="actionBarItemBackground">?android:attr/selectableItemBackground</item>
 
@@ -701,6 +703,7 @@
         <item name="itemTextAppearance">@android:style/TextAppearance.Large.Inverse</item>
         <item name="textAppearanceListItem">@android:style/TextAppearance.Large.Inverse</item>
         <item name="textAppearanceListItemSmall">@android:style/TextAppearance.Large.Inverse</item>
+        <item name="textAppearanceListItemSecondary">@android:style/TextAppearance.Small.Inverse</item>
     </style>
 
     <!-- Default heme for the TimePicker dialog windows, which is used by the
@@ -1006,6 +1009,7 @@
         <item name="listPreferredItemHeightLarge">80dip</item>
         <item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeightSmall</item>
         <item name="textAppearanceListItemSmall">?android:attr/textAppearanceMedium</item>
+        <item name="textAppearanceListItemSecondary">?android:attr/textAppearanceSmall</item>
         <item name="listPreferredItemPaddingLeft">8dip</item>
         <item name="listPreferredItemPaddingRight">8dip</item>
         <item name="listPreferredItemPaddingStart">8dip</item>
@@ -1194,6 +1198,7 @@
         <item name="actionBarSize">@dimen/action_bar_default_height</item>
         <item name="actionModePopupWindowStyle">@android:style/Widget.Holo.PopupWindow.ActionMode</item>
         <item name="actionBarWidgetTheme">@null</item>
+        <item name="actionBarTheme">@null</item>
 
         <item name="actionModeCutDrawable">@android:drawable/ic_menu_cut_holo_dark</item>
         <item name="actionModeCopyDrawable">@android:drawable/ic_menu_copy_holo_dark</item>
@@ -1335,6 +1340,7 @@
         <item name="listPreferredItemHeightLarge">80dip</item>
         <item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeightSmall</item>
         <item name="textAppearanceListItemSmall">?android:attr/textAppearanceMedium</item>
+        <item name="textAppearanceListItemSecondary">?android:attr/textAppearanceSmall</item>
         <item name="listPreferredItemPaddingLeft">8dip</item>
         <item name="listPreferredItemPaddingRight">8dip</item>
         <item name="listPreferredItemPaddingStart">8dip</item>
@@ -1526,6 +1532,7 @@
         <item name="actionBarSize">@dimen/action_bar_default_height</item>
         <item name="actionModePopupWindowStyle">@android:style/Widget.Holo.Light.PopupWindow.ActionMode</item>
         <item name="actionBarWidgetTheme">@null</item>
+        <item name="actionBarTheme">@null</item>
 
         <item name="actionModeCutDrawable">@android:drawable/ic_menu_cut_holo_light</item>
         <item name="actionModeCopyDrawable">@android:drawable/ic_menu_copy_holo_light</item>
@@ -1585,6 +1592,7 @@
         <item name="android:windowContentOverlay">@android:drawable/ab_solid_shadow_holo</item>
         <item name="android:actionBarStyle">@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse</item>
         <item name="actionBarWidgetTheme">@android:style/Theme.Holo</item>
+        <item name="actionBarTheme">@null</item>
 
         <item name="actionDropDownStyle">@android:style/Widget.Holo.Spinner.DropDown.ActionBar</item>
         <item name="actionButtonStyle">@android:style/Widget.Holo.ActionButton</item>
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
index b5ac8fa..9e235d6 100644
--- a/core/res/res/values/themes_quantum.xml
+++ b/core/res/res/values/themes_quantum.xml
@@ -109,11 +109,13 @@
         <item name="listPreferredItemHeightSmall">48dip</item>
         <item name="listPreferredItemHeightLarge">80dip</item>
         <item name="dropdownListPreferredItemHeight">?attr/listPreferredItemHeightSmall</item>
-        <item name="textAppearanceListItemSmall">?attr/textAppearanceMedium</item>
-        <item name="listPreferredItemPaddingLeft">8dip</item>
-        <item name="listPreferredItemPaddingRight">8dip</item>
-        <item name="listPreferredItemPaddingStart">8dip</item>
-        <item name="listPreferredItemPaddingEnd">8dip</item>
+        <item name="textAppearanceListItem">@style/TextAppearance.Quantum.Subhead</item>
+        <item name="textAppearanceListItemSmall">@style/TextAppearance.Quantum.Subhead</item>
+        <item name="textAppearanceListItemSecondary">@style/TextAppearance.Quantum.Body1</item>
+        <item name="listPreferredItemPaddingLeft">16dip</item>
+        <item name="listPreferredItemPaddingRight">16dip</item>
+        <item name="listPreferredItemPaddingStart">16dip</item>
+        <item name="listPreferredItemPaddingEnd">16dip</item>
 
         <!-- @hide -->
         <item name="searchResultListItemHeight">58dip</item>
@@ -269,6 +271,7 @@
         <!-- Preference styles -->
         <item name="preferenceScreenStyle">@style/Preference.Quantum.PreferenceScreen</item>
         <item name="preferenceFragmentStyle">@style/PreferenceFragment.Quantum</item>
+        <item name="preferenceFragmentPaddingSide">0dip</item>
         <item name="preferenceCategoryStyle">@style/Preference.Quantum.Category</item>
         <item name="preferenceStyle">@style/Preference.Quantum</item>
         <item name="preferenceInformationStyle">@style/Preference.Quantum.Information</item>
@@ -278,7 +281,7 @@
         <item name="dialogPreferenceStyle">@style/Preference.Quantum.DialogPreference</item>
         <item name="editTextPreferenceStyle">@style/Preference.Quantum.DialogPreference.EditTextPreference</item>
         <item name="ringtonePreferenceStyle">@style/Preference.Quantum.RingtonePreference</item>
-        <item name="preferenceLayoutChild">@layout/preference_child_holo</item>
+        <item name="preferenceLayoutChild">@layout/preference_child_quantum</item>
         <item name="detailsElementBackground">?attr/colorBackground</item>
 
         <!-- Search widget styles -->
@@ -442,11 +445,13 @@
         <item name="listPreferredItemHeightSmall">48dip</item>
         <item name="listPreferredItemHeightLarge">80dip</item>
         <item name="dropdownListPreferredItemHeight">?attr/listPreferredItemHeightSmall</item>
-        <item name="textAppearanceListItemSmall">?attr/textAppearanceMedium</item>
-        <item name="listPreferredItemPaddingLeft">8dip</item>
-        <item name="listPreferredItemPaddingRight">8dip</item>
-        <item name="listPreferredItemPaddingStart">8dip</item>
-        <item name="listPreferredItemPaddingEnd">8dip</item>
+        <item name="textAppearanceListItem">@style/TextAppearance.Quantum.Subhead</item>
+        <item name="textAppearanceListItemSmall">@style/TextAppearance.Quantum.Subhead</item>
+        <item name="textAppearanceListItemSecondary">@style/TextAppearance.Quantum.Body1</item>
+        <item name="listPreferredItemPaddingLeft">16dip</item>
+        <item name="listPreferredItemPaddingRight">16dip</item>
+        <item name="listPreferredItemPaddingStart">16dip</item>
+        <item name="listPreferredItemPaddingEnd">16dip</item>
 
         <!-- @hide -->
         <item name="searchResultListItemHeight">58dip</item>
@@ -601,6 +606,7 @@
         <!-- Preference styles -->
         <item name="preferenceScreenStyle">@style/Preference.Quantum.PreferenceScreen</item>
         <item name="preferenceFragmentStyle">@style/PreferenceFragment.Quantum</item>
+        <item name="preferenceFragmentPaddingSide">0dip</item>
         <item name="preferenceCategoryStyle">@style/Preference.Quantum.Category</item>
         <item name="preferenceStyle">@style/Preference.Quantum</item>
         <item name="preferenceInformationStyle">@style/Preference.Quantum.Information</item>
@@ -610,7 +616,7 @@
         <item name="dialogPreferenceStyle">@style/Preference.Quantum.DialogPreference</item>
         <item name="editTextPreferenceStyle">@style/Preference.Quantum.DialogPreference.EditTextPreference</item>
         <item name="ringtonePreferenceStyle">@style/Preference.Quantum.RingtonePreference</item>
-        <item name="preferenceLayoutChild">@layout/preference_child_holo</item>
+        <item name="preferenceLayoutChild">@layout/preference_child_quantum</item>
         <item name="detailsElementBackground">?attr/colorBackground</item>
 
         <!-- PreferenceFrameLayout attributes -->
@@ -706,6 +712,7 @@
          with an inverse color profile. The dark action bar sharply stands out against
          the light content. -->
     <style name="Theme.Quantum.Light.DarkActionBar">
+        <item name="actionBarWidgetTheme">@null</item>
         <item name="actionBarTheme">@style/Theme.Quantum</item>
     </style>
 
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 19131f2..66a88a2 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -595,7 +595,6 @@
      * Specifies the blending mode used to apply tint.
      *
      * @param tintMode A Porter-Duff blending mode
-     * @hide Pending finalization of supported Modes
      */
     public void setTintMode(Mode tintMode) {
         if (mBitmapState.mTintMode != tintMode) {
@@ -606,10 +605,7 @@
     }
 
     /**
-     * Returns the tint mode for this drawable, or {@code null} if none set.
-     *
-     * @return the tint mode for this drawable, or {@code null} if none set
-     * @hide
+     * @hide only needed by a hack within ProgressBar
      */
     public Mode getTintMode() {
         return mBitmapState.mTintMode;
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 077db7a..21cd5db 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -1248,16 +1248,14 @@
      */
     static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
         switch (value) {
-            case 0:
-                return Mode.SRC_IN;
-            case 1:
-                return Mode.SRC_ATOP;
-            case 2:
-                return Mode.MULTIPLY;
-            case 3:
-                return Mode.SCREEN;
+            case 3: return Mode.SRC_OVER;
+            case 5: return Mode.SRC_IN;
+            case 9: return Mode.SRC_ATOP;
+            case 14: return Mode.MULTIPLY;
+            case 15: return Mode.SCREEN;
+            case 16: return Mode.ADD;
+            default: return defaultMode;
         }
-        return defaultMode;
     }
 }
 
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 66193a5..3e9ca0a 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -345,7 +345,6 @@
      * Specifies the blending mode used to apply tint.
      *
      * @param tintMode A Porter-Duff blending mode
-     * @hide Pending finalization of supported Modes
      */
     public void setTintMode(Mode tintMode) {
         if (mNinePatchState.mTintMode != tintMode) {
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
index 3323a25..2810c43 100644
--- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -124,6 +124,41 @@
         return super.isStateful() || mState.mTint != null && mState.mTint.isStateful();
     }
 
+    /**
+     * Specifies a tint for drawing touch feedback ripples.
+     *
+     * @param tint Color state list to use for tinting touch feedback ripples,
+     *        or null to clear the tint
+     */
+    public void setTint(ColorStateList tint) {
+        if (mState.mTint != tint) {
+            mState.mTint = tint;
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * Returns the tint color for touch feedback ripples.
+     *
+     * @return Color state list to use for tinting touch feedback ripples, or
+     *         null if none set
+     */
+    public ColorStateList getTint() {
+        return mState.mTint;
+    }
+
+    /**
+     * Specifies the blending mode used to draw touch feedback ripples.
+     *
+     * @param tintMode A Porter-Duff blending mode
+     */
+    public void setTintMode(Mode tintMode) {
+        if (mState.mTintMode != tintMode) {
+            mState.mTintMode = tintMode;
+            invalidateSelf();
+        }
+    }
+
     @Override
     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index ce711b6..c64c169 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -62,7 +62,7 @@
     }
 }
 
-bool DeferredLayerUpdater::apply() {
+bool DeferredLayerUpdater::apply(bool* hasFunctors) {
     bool success = true;
     // These properties are applied the same to both layer types
     mLayer->setColorFilter(mColorFilter);
@@ -73,7 +73,11 @@
             success = LayerRenderer::resizeLayer(mLayer, mWidth, mHeight);
         }
         mLayer->setBlend(mBlend);
-        mDisplayList->updateProperties();
+        TreeInfo info = {0};
+        mDisplayList->prepareTree(info);
+        if (info.hasFunctors) {
+            *hasFunctors = true;
+        }
         mLayer->updateDeferred(mDisplayList.get(),
                 mDirtyRect.left, mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom);
         mDirtyRect.setEmpty();
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index ce08c2d..2cc9229 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -77,7 +77,7 @@
 
     ANDROID_API void setPaint(const SkPaint* paint);
 
-    ANDROID_API bool apply();
+    ANDROID_API bool apply(bool* hasFunctors);
 
     ANDROID_API Layer* backingLayer() {
         return mLayer;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index a84aa6b..140a07a 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -192,7 +192,9 @@
             flags, *currentTransform());
     addDrawOp(op);
     mDisplayListData->addChild(op);
-    if (displayList->isProjectionReceiver()) {
+
+    if (displayList->stagingProperties().isProjectionReceiver()) {
+        // use staging property, since recording on UI thread
         mDisplayListData->projectionReceiveIndex = mDisplayListData->displayListOps.size() - 1;
     }
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 9dbcd36..f37487f 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1901,7 +1901,6 @@
     // will be performed by the display list itself
     if (displayList && displayList->isRenderable()) {
         // compute 3d ordering
-        displayList->updateProperties();
         displayList->computeOrdering();
         if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
             status = startFrame();
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 5010076..823ae7b 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -49,7 +49,12 @@
     fflush(file);
 }
 
-RenderNode::RenderNode() : mDestroyed(false), mNeedsPropertiesSync(false), mDisplayListData(0) {
+RenderNode::RenderNode()
+        : mDestroyed(false)
+        , mNeedsPropertiesSync(false)
+        , mNeedsDisplayListDataSync(false)
+        , mDisplayListData(0)
+        , mStagingDisplayListData(0) {
 }
 
 RenderNode::~RenderNode() {
@@ -57,13 +62,15 @@
 
     mDestroyed = true;
     delete mDisplayListData;
+    delete mStagingDisplayListData;
 }
 
-void RenderNode::setData(DisplayListData* data) {
-    delete mDisplayListData;
-    mDisplayListData = data;
-    if (mDisplayListData) {
-        Caches::getInstance().registerFunctors(mDisplayListData->functorCount);
+void RenderNode::setStagingDisplayList(DisplayListData* data) {
+    mNeedsDisplayListDataSync = true;
+    delete mStagingDisplayListData;
+    mStagingDisplayListData = data;
+    if (mStagingDisplayListData) {
+        Caches::getInstance().registerFunctors(mStagingDisplayListData->functorCount);
     }
 }
 
@@ -86,35 +93,45 @@
     ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string());
 }
 
-void RenderNode::updateProperties() {
+void RenderNode::prepareTree(TreeInfo& info) {
+    ATRACE_CALL();
+
+    prepareTreeImpl(info);
+}
+
+void RenderNode::prepareTreeImpl(TreeInfo& info) {
+    pushStagingChanges(info);
+    prepareSubTree(info, mDisplayListData);
+}
+
+void RenderNode::pushStagingChanges(TreeInfo& info) {
     if (mNeedsPropertiesSync) {
         mNeedsPropertiesSync = false;
         mProperties = mStagingProperties;
     }
-
-    if (mDisplayListData) {
-        for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
-            RenderNode* childNode = mDisplayListData->children()[i]->mDisplayList;
-            childNode->updateProperties();
-        }
+    if (mNeedsDisplayListDataSync) {
+        mNeedsDisplayListDataSync = false;
+        // Do a push pass on the old tree to handle freeing DisplayListData
+        // that are no longer used
+        TreeInfo oldTreeInfo = {0};
+        prepareSubTree(oldTreeInfo, mDisplayListData);
+        // TODO: The damage for the old tree should be accounted for
+        delete mDisplayListData;
+        mDisplayListData = mStagingDisplayListData;
+        mStagingDisplayListData = 0;
     }
 }
 
-bool RenderNode::hasFunctors() {
-    if (!mDisplayListData) return false;
-
-    if (mDisplayListData->functorCount) {
-        return true;
-    }
-
-    for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
-        RenderNode* childNode = mDisplayListData->children()[i]->mDisplayList;
-        if (childNode->hasFunctors()) {
-            return true;
+void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
+    if (subtree) {
+        if (!info.hasFunctors) {
+            info.hasFunctors = subtree->functorCount;
+        }
+        for (size_t i = 0; i < subtree->children().size(); i++) {
+            RenderNode* childNode = subtree->children()[i]->mDisplayList;
+            childNode->prepareTreeImpl(info);
         }
     }
-
-    return false;
 }
 
 /*
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index fd0fabc..7853701 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -65,6 +65,11 @@
 class RestoreToCountOp;
 class DrawDisplayListOp;
 
+struct TreeInfo {
+    bool hasFunctors;
+    // TODO: Damage calculations? Flag to skip staging pushes for RT animations?
+};
+
 /**
  * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display properties.
  *
@@ -89,7 +94,7 @@
 
     ANDROID_API static void outputLogBuffer(int fd);
 
-    ANDROID_API void setData(DisplayListData* newData);
+    ANDROID_API void setStagingDisplayList(DisplayListData* newData);
 
     void computeOrdering();
 
@@ -105,6 +110,10 @@
         return mDisplayListData && mDisplayListData->hasDrawOps;
     }
 
+    const char* getName() const {
+        return mName.string();
+    }
+
     void setName(const char* name) {
         if (name) {
             char* lastPeriod = strrchr(name, '.');
@@ -129,10 +138,6 @@
         return mStagingProperties;
     }
 
-    bool isProjectionReceiver() {
-        return properties().isProjectionReceiver();
-    }
-
     int getWidth() {
         return properties().getWidth();
     }
@@ -141,10 +146,7 @@
         return properties().getHeight();
     }
 
-    ANDROID_API void updateProperties();
-
-    // Returns true if this RenderNode or any of its children have functors
-    bool hasFunctors();
+    ANDROID_API void prepareTree(TreeInfo& info);
 
 private:
     typedef key_value_pair_t<float, DrawDisplayListOp*> ZDrawDisplayListOpPair;
@@ -203,6 +205,10 @@
         const char* mText;
     };
 
+    void prepareTreeImpl(TreeInfo& info);
+    void pushStagingChanges(TreeInfo& info);
+    void prepareSubTree(TreeInfo& info, DisplayListData* subtree);
+
     String8 mName;
     bool mDestroyed; // used for debugging crash, TODO: remove once invalid state crash fixed
 
@@ -210,7 +216,9 @@
     RenderProperties mProperties;
     RenderProperties mStagingProperties;
 
+    bool mNeedsDisplayListDataSync;
     DisplayListData* mDisplayListData;
+    DisplayListData* mStagingDisplayListData;
 
     /**
      * Draw time state - these properties are only set and used during rendering
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index c231f6f..c5122e2 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -347,6 +347,7 @@
 
     if (mEglSurface != EGL_NO_SURFACE) {
         mDirtyRegionsEnabled = mGlobalContext->enableDirtyRegions(mEglSurface);
+        mGlobalContext->makeCurrent(mEglSurface);
         mHaveNewSurface = true;
     }
 }
@@ -356,14 +357,15 @@
     mHaveNewSurface = false;
 }
 
-void CanvasContext::makeCurrent() {
+void CanvasContext::requireSurface() {
+    LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
+            "requireSurface() called but no surface set!");
     mGlobalContext->makeCurrent(mEglSurface);
 }
 
 bool CanvasContext::initialize(EGLNativeWindowType window) {
     if (mCanvas) return false;
     setSurface(window);
-    makeCurrent();
     mCanvas = new OpenGLRenderer();
     mCanvas->initProperties();
     return true;
@@ -371,7 +373,11 @@
 
 void CanvasContext::updateSurface(EGLNativeWindowType window) {
     setSurface(window);
-    makeCurrent();
+}
+
+void CanvasContext::pauseSurface(EGLNativeWindowType window) {
+    // TODO: For now we just need a fence, in the future suspend any animations
+    // and such to prevent from trying to render into this surface
 }
 
 void CanvasContext::setup(int width, int height) {
@@ -379,15 +385,12 @@
     mCanvas->setViewport(width, height);
 }
 
-void CanvasContext::setDisplayListData(RenderNode* displayList, DisplayListData* newData) {
-    displayList->setData(newData);
-}
-
-void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters) {
+void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters,
+        bool* hasFunctors) {
     mGlobalContext->makeCurrent(mEglSurface);
     for (size_t i = 0; i < layerUpdaters->size(); i++) {
         DeferredLayerUpdater* update = layerUpdaters->itemAt(i);
-        LOG_ALWAYS_FATAL_IF(!update->apply(), "Failed to update layer!");
+        LOG_ALWAYS_FATAL_IF(!update->apply(hasFunctors), "Failed to update layer!");
         if (update->backingLayer()->deferredUpdateScheduled) {
             mCanvas->pushLayerUpdate(update->backingLayer());
         }
@@ -460,7 +463,7 @@
 
     if (!mCanvas) return;
 
-    makeCurrent();
+    requireSurface();
     Rect dirty;
     mCanvas->invokeFunctors(dirty);
 }
@@ -481,7 +484,8 @@
 
 bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
     requireGlContext();
-    layer->apply();
+    bool hasFunctors;
+    layer->apply(&hasFunctors);
     return LayerRenderer::copyLayer(layer->backingLayer(), bitmap);
 }
 
@@ -491,12 +495,12 @@
 }
 
 Layer* CanvasContext::createRenderLayer(int width, int height) {
-    requireGlContext();
+    requireSurface();
     return LayerRenderer::createRenderLayer(width, height);
 }
 
 Layer* CanvasContext::createTextureLayer() {
-    requireGlContext();
+    requireSurface();
     return LayerRenderer::createTextureLayer();
 }
 
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 6f1c37f..a24162e 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -63,9 +63,9 @@
 
     bool initialize(EGLNativeWindowType window);
     void updateSurface(EGLNativeWindowType window);
+    void pauseSurface(EGLNativeWindowType window);
     void setup(int width, int height);
-    void setDisplayListData(RenderNode* displayList, DisplayListData* newData);
-    void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters);
+    void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, bool* hasFunctors);
     void drawDisplayList(RenderNode* displayList, Rect* dirty);
     void destroyCanvas();
 
@@ -83,7 +83,7 @@
 private:
     void setSurface(EGLNativeWindowType window);
     void swapBuffers();
-    void makeCurrent();
+    void requireSurface();
 
     friend class InvokeFunctorsTask;
     void invokeFunctors();
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 7b509a2..372d0d0 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -30,18 +30,6 @@
 namespace uirenderer {
 namespace renderthread {
 
-SetDisplayListData::SetDisplayListData() : mNewData(0) {}
-
-SetDisplayListData::SetDisplayListData(RenderNode* node, DisplayListData* newData)
-        : mTargetNode(node), mNewData(newData) {
-}
-
-SetDisplayListData::~SetDisplayListData() {}
-
-void SetDisplayListData::apply() const {
-    mTargetNode->setData(mNewData);
-}
-
 DrawFrameTask::DrawFrameTask() : mContext(0), mTaskMode(MODE_INVALID), mRenderNode(0) {
 }
 
@@ -52,13 +40,6 @@
     mContext = context;
 }
 
-void DrawFrameTask::setDisplayListData(RenderNode* renderNode, DisplayListData* newData) {
-    LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to setDisplayListData with!");
-
-    SetDisplayListData setter(renderNode, newData);
-    mDisplayListDataUpdates.push(setter);
-}
-
 void DrawFrameTask::addLayer(DeferredLayerUpdater* layer) {
     LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to addLayer with!");
 
@@ -113,7 +94,8 @@
 void DrawFrameTask::run() {
     ATRACE_NAME("DrawFrame");
 
-    syncFrameState();
+    // canUnblockUiThread is temporary until WebView has a solution for syncing frame state
+    bool canUnblockUiThread = syncFrameState();
 
     if (mTaskMode == MODE_STATE_ONLY) {
         unblockUiThread();
@@ -125,9 +107,6 @@
     sp<RenderNode> renderNode = mRenderNode;
     CanvasContext* context = mContext;
 
-    // This is temporary until WebView has a solution for syncing frame state
-    bool canUnblockUiThread = !requiresSynchronousDraw(renderNode.get());
-
     // From this point on anything in "this" is *UNSAFE TO ACCESS*
     if (canUnblockUiThread) {
         unblockUiThread();
@@ -140,21 +119,20 @@
     }
 }
 
-void DrawFrameTask::syncFrameState() {
+bool DrawFrameTask::syncFrameState() {
     ATRACE_CALL();
 
-    for (size_t i = 0; i < mDisplayListDataUpdates.size(); i++) {
-        const SetDisplayListData& setter = mDisplayListDataUpdates[i];
-        setter.apply();
-    }
-    mDisplayListDataUpdates.clear();
-
-    mContext->processLayerUpdates(&mLayers);
+    bool hasFunctors = false;
+    mContext->processLayerUpdates(&mLayers, &hasFunctors);
 
     // If we don't have an mRenderNode this is a state flush only
     if (mRenderNode.get()) {
-        mRenderNode->updateProperties();
+        TreeInfo info = {0};
+        mRenderNode->prepareTree(info);
+        hasFunctors |= info.hasFunctors;
     }
+
+    return !hasFunctors;
 }
 
 void DrawFrameTask::unblockUiThread() {
@@ -172,10 +150,6 @@
     context->drawDisplayList(renderNode, dirty);
 }
 
-bool DrawFrameTask::requiresSynchronousDraw(RenderNode* renderNode) {
-    return renderNode->hasFunctors();
-}
-
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 4e9b244..a512408 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -37,18 +37,6 @@
 class CanvasContext;
 class RenderThread;
 
-class SetDisplayListData {
-public:
-    // This ctor exists for Vector's usage
-    SetDisplayListData();
-    SetDisplayListData(RenderNode* node, DisplayListData* newData);
-    ~SetDisplayListData();
-    void apply() const;
-private:
-    sp<RenderNode> mTargetNode;
-    DisplayListData* mNewData;
-};
-
 /*
  * This is a special Super Task. It is re-used multiple times by RenderProxy,
  * and contains state (such as layer updaters & new DisplayListDatas) that is
@@ -62,7 +50,6 @@
 
     void setContext(CanvasContext* context);
 
-    void setDisplayListData(RenderNode* renderNode, DisplayListData* newData);
     void addLayer(DeferredLayerUpdater* layer);
     void removeLayer(DeferredLayerUpdater* layer);
 
@@ -81,14 +68,10 @@
     };
 
     void postAndWait(RenderThread* renderThread, TaskMode mode);
-    void syncFrameState();
+    bool syncFrameState();
     void unblockUiThread();
     static void drawRenderNode(CanvasContext* context, RenderNode* renderNode, Rect* dirty);
 
-    // This checks to see if there are any drawGlFunctors which would require
-    // a synchronous drawRenderNode()
-    static bool requiresSynchronousDraw(RenderNode* renderNode);
-
     Mutex mLock;
     Condition mSignal;
 
@@ -100,7 +83,6 @@
     TaskMode mTaskMode;
     sp<RenderNode> mRenderNode;
     Rect mDirty;
-    Vector<SetDisplayListData> mDisplayListDataUpdates;
 
     /*********************************************
      *  Multi frame data
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index e817e61..49b9aca 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -92,10 +92,10 @@
     return (void*) args->context->initialize(args->window);
 }
 
-bool RenderProxy::initialize(EGLNativeWindowType window) {
+bool RenderProxy::initialize(const sp<ANativeWindow>& window) {
     SETUP_TASK(initialize);
     args->context = mContext;
-    args->window = window;
+    args->window = window.get();
     return (bool) postAndWait(task);
 }
 
@@ -104,11 +104,23 @@
     return NULL;
 }
 
-void RenderProxy::updateSurface(EGLNativeWindowType window) {
+void RenderProxy::updateSurface(const sp<ANativeWindow>& window) {
     SETUP_TASK(updateSurface);
     args->context = mContext;
-    args->window = window;
-    post(task);
+    args->window = window.get();
+    postAndWait(task);
+}
+
+CREATE_BRIDGE2(pauseSurface, CanvasContext* context, EGLNativeWindowType window) {
+    args->context->pauseSurface(args->window);
+    return NULL;
+}
+
+void RenderProxy::pauseSurface(const sp<ANativeWindow>& window) {
+    SETUP_TASK(pauseSurface);
+    args->context = mContext;
+    args->window = window.get();
+    postAndWait(task);
 }
 
 CREATE_BRIDGE3(setup, CanvasContext* context, int width, int height) {
@@ -124,10 +136,6 @@
     post(task);
 }
 
-void RenderProxy::setDisplayListData(RenderNode* renderNode, DisplayListData* newData) {
-    mDrawFrameTask.setDisplayListData(renderNode, newData);
-}
-
 void RenderProxy::drawDisplayList(RenderNode* displayList,
         int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) {
     mDrawFrameTask.setRenderNode(displayList);
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index c50da79..1ad3c85 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -59,10 +59,10 @@
     ANDROID_API RenderProxy(bool translucent);
     ANDROID_API virtual ~RenderProxy();
 
-    ANDROID_API bool initialize(EGLNativeWindowType window);
-    ANDROID_API void updateSurface(EGLNativeWindowType window);
+    ANDROID_API bool initialize(const sp<ANativeWindow>& window);
+    ANDROID_API void updateSurface(const sp<ANativeWindow>& window);
+    ANDROID_API void pauseSurface(const sp<ANativeWindow>& window);
     ANDROID_API void setup(int width, int height);
-    ANDROID_API void setDisplayListData(RenderNode* renderNode, DisplayListData* newData);
     ANDROID_API void drawDisplayList(RenderNode* displayList,
             int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
     ANDROID_API void destroyCanvas();
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index f688d81..664c707 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -471,10 +471,6 @@
                 final FocusRequester exFocusOwner = mFocusStack.pop();
                 exFocusOwner.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS);
                 exFocusOwner.release();
-                // clear RCD
-                synchronized(mPRStack) {
-                    clearRemoteControlDisplay_syncAfRcs();
-                }
             }
         }
     }
@@ -535,10 +531,6 @@
             if (signal) {
                 // notify the new top of the stack it gained focus
                 notifyTopOfAudioFocusStack();
-                // there's a new top of the stack, let the remote control know
-                synchronized(mPRStack) {
-                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-                }
             }
         } else {
             // focus is abandoned by a client that's not at the top of the stack,
@@ -582,10 +574,6 @@
             // we removed an entry at the top of the stack:
             //  notify the new top of the stack it gained focus.
             notifyTopOfAudioFocusStack();
-            // there's a new top of the stack, let the remote control know
-            synchronized(mPRStack) {
-                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-            }
         }
     }
 
@@ -694,10 +682,6 @@
             mFocusStack.push(new FocusRequester(mainStreamType, focusChangeHint, fd, cb,
                     clientId, afdh, callingPackageName, Binder.getCallingUid()));
 
-            // there's a new top of the stack, let the remote control know
-            synchronized(mPRStack) {
-                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-            }
         }//synchronized(mAudioFocusLock)
 
         return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
@@ -1237,11 +1221,11 @@
     /**
      * Helper function:
      * Set the new remote control receiver at the top of the RC focus stack.
-     * Called synchronized on mAudioFocusLock, then mPRStack
+     * Called synchronized on mPRStack
      * precondition: mediaIntent != null
      * @return true if mPRStack was changed, false otherwise
      */
-    private boolean pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent,
+    private boolean pushMediaButtonReceiver_syncPrs(PendingIntent mediaIntent,
             ComponentName target, IBinder token) {
         // already at top of stack?
         if (!mPRStack.empty() && mPRStack.peek().hasMatchingMediaButtonIntent(mediaIntent)) {
@@ -1285,10 +1269,10 @@
     /**
      * Helper function:
      * Remove the remote control receiver from the RC focus stack.
-     * Called synchronized on mAudioFocusLock, then mPRStack
+     * Called synchronized on mPRStack
      * precondition: pi != null
      */
-    private void removeMediaButtonReceiver_syncAfRcs(PendingIntent pi) {
+    private void removeMediaButtonReceiver_syncPrs(PendingIntent pi) {
         try {
             for (int index = mPRStack.size()-1; index >= 0; index--) {
                 final PlayerRecord prse = mPRStack.elementAt(index);
@@ -1470,7 +1454,7 @@
      * Helper function:
      * Called synchronized on mPRStack
      */
-    private void clearRemoteControlDisplay_syncAfRcs() {
+    private void clearRemoteControlDisplay_syncPrs() {
         synchronized(mCurrentRcLock) {
             mCurrentRcClient = null;
         }
@@ -1480,20 +1464,20 @@
 
     /**
      * Helper function for code readability: only to be called from
-     *    checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for
+     *    checkUpdateRemoteControlDisplay_syncPrs() which checks the preconditions for
      *    this method.
      * Preconditions:
-     *    - called synchronized mAudioFocusLock then on mPRStack
+     *    - called synchronized on mPRStack
      *    - mPRStack.isEmpty() is false
      */
-    private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
+    private void updateRemoteControlDisplay_syncPrs(int infoChangedFlags) {
         PlayerRecord prse = mPRStack.peek();
         int infoFlagsAboutToBeUsed = infoChangedFlags;
         // this is where we enforce opt-in for information display on the remote controls
         //   with the new AudioManager.registerRemoteControlClient() API
         if (prse.getRcc() == null) {
             //Log.w(TAG, "Can't update remote control display with null remote control client");
-            clearRemoteControlDisplay_syncAfRcs();
+            clearRemoteControlDisplay_syncPrs();
             return;
         }
         synchronized(mCurrentRcLock) {
@@ -1511,62 +1495,25 @@
 
     /**
      * Helper function:
-     * Called synchronized on mAudioFocusLock, then mPRStack
+     * Called synchronized on mPRStack
      * Check whether the remote control display should be updated, triggers the update if required
      * @param infoChangedFlags the flags corresponding to the remote control client information
      *     that has changed, if applicable (checking for the update conditions might trigger a
      *     clear, rather than an update event).
      */
-    private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
+    private void checkUpdateRemoteControlDisplay_syncPrs(int infoChangedFlags) {
         // determine whether the remote control display should be refreshed
-        // if either stack is empty, there is a mismatch, so clear the RC display
-        if (mPRStack.isEmpty() || mFocusStack.isEmpty()) {
-            clearRemoteControlDisplay_syncAfRcs();
+        // if the player record stack is empty, there is nothing to display, so clear the RC display
+        if (mPRStack.isEmpty()) {
+            clearRemoteControlDisplay_syncPrs();
             return;
         }
 
-        // determine which entry in the AudioFocus stack to consider, and compare against the
-        // top of the stack for the media button event receivers : simply using the top of the
-        // stack would make the entry disappear from the RemoteControlDisplay in conditions such as
-        // notifications playing during music playback.
-        // Crawl the AudioFocus stack from the top until an entry is found with the following
-        // characteristics:
-        // - focus gain on STREAM_MUSIC stream
-        // - non-transient focus gain on a stream other than music
-        FocusRequester af = null;
-        try {
-            for (int index = mFocusStack.size()-1; index >= 0; index--) {
-                FocusRequester fr = mFocusStack.elementAt(index);
-                if ((fr.getStreamType() == AudioManager.STREAM_MUSIC)
-                        || (fr.getGainRequest() == AudioManager.AUDIOFOCUS_GAIN)) {
-                    af = fr;
-                    break;
-                }
-            }
-        } catch (ArrayIndexOutOfBoundsException e) {
-            Log.e(TAG, "Wrong index accessing audio focus stack when updating RCD: " + e);
-            af = null;
-        }
-        if (af == null) {
-            clearRemoteControlDisplay_syncAfRcs();
-            return;
-        }
-
-        // if the audio focus and RC owners belong to different packages, there is a mismatch, clear
-        if (!af.hasSamePackage(mPRStack.peek().getCallingPackageName())) {
-            clearRemoteControlDisplay_syncAfRcs();
-            return;
-        }
-        // if the audio focus didn't originate from the same Uid as the one in which the remote
-        //   control information will be retrieved, clear
-        if (!af.hasSameUid(mPRStack.peek().getCallingUid())) {
-            clearRemoteControlDisplay_syncAfRcs();
-            return;
-        }
+        // this is where more rules for refresh go
 
         // refresh conditions were verified: update the remote controls
-        // ok to call: synchronized mAudioFocusLock then on mPRStack, mPRStack is not empty
-        updateRemoteControlDisplay_syncAfRcs(infoChangedFlags);
+        // ok to call: synchronized on mPRStack, mPRStack is not empty
+        updateRemoteControlDisplay_syncPrs(infoChangedFlags);
     }
 
     /**
@@ -1582,35 +1529,33 @@
 
     private void onPromoteRcc(int rccId) {
         if (DEBUG_RC) { Log.d(TAG, "Promoting RCC " + rccId); }
-        synchronized(mAudioFocusLock) {
-            synchronized(mPRStack) {
-                // ignore if given RCC ID is already at top of remote control stack
-                if (!mPRStack.isEmpty() && (mPRStack.peek().getRccId() == rccId)) {
-                    return;
-                }
-                int indexToPromote = -1;
-                try {
-                    for (int index = mPRStack.size()-1; index >= 0; index--) {
-                        final PlayerRecord prse = mPRStack.elementAt(index);
-                        if (prse.getRccId() == rccId) {
-                            indexToPromote = index;
-                            break;
-                        }
+        synchronized(mPRStack) {
+            // ignore if given RCC ID is already at top of remote control stack
+            if (!mPRStack.isEmpty() && (mPRStack.peek().getRccId() == rccId)) {
+                return;
+            }
+            int indexToPromote = -1;
+            try {
+                for (int index = mPRStack.size()-1; index >= 0; index--) {
+                    final PlayerRecord prse = mPRStack.elementAt(index);
+                    if (prse.getRccId() == rccId) {
+                        indexToPromote = index;
+                        break;
                     }
-                    if (indexToPromote >= 0) {
-                        if (DEBUG_RC) { Log.d(TAG, "  moving RCC from index " + indexToPromote
-                                + " to " + (mPRStack.size()-1)); }
-                        final PlayerRecord prse = mPRStack.remove(indexToPromote);
-                        mPRStack.push(prse);
-                        // the RC stack changed, reevaluate the display
-                        checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-                    }
-                } catch (ArrayIndexOutOfBoundsException e) {
-                    // not expected to happen, indicates improper concurrent modification
-                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
                 }
-            }//synchronized(mPRStack)
-        }//synchronized(mAudioFocusLock)
+                if (indexToPromote >= 0) {
+                    if (DEBUG_RC) { Log.d(TAG, "  moving RCC from index " + indexToPromote
+                            + " to " + (mPRStack.size()-1)); }
+                    final PlayerRecord prse = mPRStack.remove(indexToPromote);
+                    mPRStack.push(prse);
+                    // the RC stack changed, reevaluate the display
+                    checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
+                }
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
+            }
+        }//synchronized(mPRStack)
     }
 
     /**
@@ -1621,12 +1566,10 @@
             IBinder token) {
         Log.i(TAG, "  Remote Control   registerMediaButtonIntent() for " + mediaIntent);
 
-        synchronized(mAudioFocusLock) {
-            synchronized(mPRStack) {
-                if (pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver, token)) {
-                    // new RC client, assume every type of information shall be queried
-                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-                }
+        synchronized(mPRStack) {
+            if (pushMediaButtonReceiver_syncPrs(mediaIntent, eventReceiver, token)) {
+                // new RC client, assume every type of information shall be queried
+                checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
             }
         }
     }
@@ -1639,14 +1582,12 @@
     {
         Log.i(TAG, "  Remote Control   unregisterMediaButtonIntent() for " + mediaIntent);
 
-        synchronized(mAudioFocusLock) {
-            synchronized(mPRStack) {
-                boolean topOfStackWillChange = isCurrentRcController(mediaIntent);
-                removeMediaButtonReceiver_syncAfRcs(mediaIntent);
-                if (topOfStackWillChange) {
-                    // current RC client will change, assume every type of info needs to be queried
-                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-                }
+        synchronized(mPRStack) {
+            boolean topOfStackWillChange = isCurrentRcController(mediaIntent);
+            removeMediaButtonReceiver_syncPrs(mediaIntent);
+            if (topOfStackWillChange) {
+                // current RC client will change, assume every type of info needs to be queried
+                checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
             }
         }
     }
@@ -1697,42 +1638,40 @@
             IRemoteControlClient rcClient, String callingPackageName) {
         if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient);
         int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
-        synchronized(mAudioFocusLock) {
-            synchronized(mPRStack) {
-                // store the new display information
-                try {
-                    for (int index = mPRStack.size()-1; index >= 0; index--) {
-                        final PlayerRecord prse = mPRStack.elementAt(index);
-                        if(prse.hasMatchingMediaButtonIntent(mediaIntent)) {
-                            prse.resetControllerInfoForRcc(rcClient, callingPackageName,
-                                    Binder.getCallingUid());
+        synchronized(mPRStack) {
+            // store the new display information
+            try {
+                for (int index = mPRStack.size()-1; index >= 0; index--) {
+                    final PlayerRecord prse = mPRStack.elementAt(index);
+                    if(prse.hasMatchingMediaButtonIntent(mediaIntent)) {
+                        prse.resetControllerInfoForRcc(rcClient, callingPackageName,
+                                Binder.getCallingUid());
 
-                            if (rcClient == null) {
-                                break;
-                            }
-
-                            rccId = prse.getRccId();
-
-                            // there is a new (non-null) client:
-                            //     give the new client the displays (if any)
-                            if (mRcDisplays.size() > 0) {
-                                plugRemoteControlDisplaysIntoClient_syncRcStack(prse.getRcc());
-                            }
+                        if (rcClient == null) {
                             break;
                         }
-                    }//for
-                } catch (ArrayIndexOutOfBoundsException e) {
-                    // not expected to happen, indicates improper concurrent modification
-                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
-                }
 
-                // if the eventReceiver is at the top of the stack
-                // then check for potential refresh of the remote controls
-                if (isCurrentRcController(mediaIntent)) {
-                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-                }
-            }//synchronized(mPRStack)
-        }//synchronized(mAudioFocusLock)
+                        rccId = prse.getRccId();
+
+                        // there is a new (non-null) client:
+                        //     give the new client the displays (if any)
+                        if (mRcDisplays.size() > 0) {
+                            plugRemoteControlDisplaysIntoClient_syncPrs(prse.getRcc());
+                        }
+                        break;
+                    }
+                }//for
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
+            }
+
+            // if the eventReceiver is at the top of the stack
+            // then check for potential refresh of the remote controls
+            if (isCurrentRcController(mediaIntent)) {
+                checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
+            }
+        }//synchronized(mPRStack)
         return rccId;
     }
 
@@ -1743,29 +1682,27 @@
     protected void unregisterRemoteControlClient(PendingIntent mediaIntent,
             IRemoteControlClient rcClient) {
         if (DEBUG_RC) Log.i(TAG, "Unregister remote control client rcClient="+rcClient);
-        synchronized(mAudioFocusLock) {
-            synchronized(mPRStack) {
-                boolean topRccChange = false;
-                try {
-                    for (int index = mPRStack.size()-1; index >= 0; index--) {
-                        final PlayerRecord prse = mPRStack.elementAt(index);
-                        if ((prse.hasMatchingMediaButtonIntent(mediaIntent))
-                                && rcClient.equals(prse.getRcc())) {
-                            // we found the IRemoteControlClient to unregister
-                            prse.resetControllerInfoForNoRcc();
-                            topRccChange = (index == mPRStack.size()-1);
-                            // there can only be one matching RCC in the RC stack, we're done
-                            break;
-                        }
+        synchronized(mPRStack) {
+            boolean topRccChange = false;
+            try {
+                for (int index = mPRStack.size()-1; index >= 0; index--) {
+                    final PlayerRecord prse = mPRStack.elementAt(index);
+                    if ((prse.hasMatchingMediaButtonIntent(mediaIntent))
+                            && rcClient.equals(prse.getRcc())) {
+                        // we found the IRemoteControlClient to unregister
+                        prse.resetControllerInfoForNoRcc();
+                        topRccChange = (index == mPRStack.size()-1);
+                        // there can only be one matching RCC in the RC stack, we're done
+                        break;
                     }
-                } catch (ArrayIndexOutOfBoundsException e) {
-                    // not expected to happen, indicates improper concurrent modification
-                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
                 }
-                if (topRccChange) {
-                    // no more RCC for the RCD, check for potential refresh of the remote controls
-                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-                }
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
+            }
+            if (topRccChange) {
+                // no more RCC for the RCD, check for potential refresh of the remote controls
+                checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
             }
         }
     }
@@ -1843,7 +1780,7 @@
      * Plug each registered display into the specified client
      * @param rcc, guaranteed non null
      */
-    private void plugRemoteControlDisplaysIntoClient_syncRcStack(IRemoteControlClient rcc) {
+    private void plugRemoteControlDisplaysIntoClient_syncPrs(IRemoteControlClient rcc) {
         final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
         while (displayIterator.hasNext()) {
             final DisplayInfoForServer di = displayIterator.next();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index 26498ca..edfa36a 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -552,29 +552,72 @@
         };
         int availableFormatTag = CameraMetadataNative.getTag("android.scaler.availableFormats");
 
-        // Write
-        mMetadata.set(CameraCharacteristics.SCALER_AVAILABLE_FORMATS, availableFormats);
+        Key<int[]> formatKey = CameraCharacteristics.SCALER_AVAILABLE_FORMATS;
 
-        byte[] availableFormatValues = mMetadata.readValues(availableFormatTag);
+        validateArrayMetadataReadWriteOverride(formatKey, availableFormats,
+                expectedIntValues, availableFormatTag);
 
-        ByteBuffer bf = ByteBuffer.wrap(availableFormatValues).order(ByteOrder.nativeOrder());
+        //
+        // android.scaler.availableStreamConfigurations (int x n x 4 array)
+        //
+        final int OUTPUT = CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT;
+        int[] availableStreamConfigs = new int[] {
+                0x20, 3280, 2464, OUTPUT, // RAW16
+                0x23, 3264, 2448, OUTPUT, // YCbCr_420_888
+                0x23, 3200, 2400, OUTPUT, // YCbCr_420_888
+                0x100, 3264, 2448, OUTPUT, // ImageFormat.JPEG
+                0x100, 3200, 2400, OUTPUT, // ImageFormat.JPEG
+                0x100, 2592, 1944, OUTPUT, // ImageFormat.JPEG
+                0x100, 2048, 1536, OUTPUT, // ImageFormat.JPEG
+                0x100, 1920, 1080, OUTPUT  // ImageFormat.JPEG
+        };
+        int[] expectedAvailableStreamConfigs = new int[] {
+                0x20, 3280, 2464, OUTPUT, // RAW16
+                0x23, 3264, 2448, OUTPUT, // YCbCr_420_888
+                0x23, 3200, 2400, OUTPUT, // YCbCr_420_888
+                0x21, 3264, 2448, OUTPUT, // BLOB
+                0x21, 3200, 2400, OUTPUT, // BLOB
+                0x21, 2592, 1944, OUTPUT, // BLOB
+                0x21, 2048, 1536, OUTPUT, // BLOB
+                0x21, 1920, 1080, OUTPUT  // BLOB
+        };
+        int availableStreamConfigTag =
+                CameraMetadataNative.getTag("android.scaler.availableStreamConfigurations");
 
-        assertEquals(expectedIntValues.length * 4, availableFormatValues.length);
-        for (int i = 0; i < expectedIntValues.length; ++i) {
-            assertEquals(expectedIntValues[i], bf.getInt());
-        }
-        // Read
-        byte[] availableFormatsAsByteArray = new byte[expectedIntValues.length * 4];
-        ByteBuffer availableFormatsByteBuffer =
-                ByteBuffer.wrap(availableFormatsAsByteArray).order(ByteOrder.nativeOrder());
-        for (int value : expectedIntValues) {
-            availableFormatsByteBuffer.putInt(value);
-        }
-        mMetadata.writeValues(availableFormatTag, availableFormatsAsByteArray);
+        Key<int[]> configKey = CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
+        validateArrayMetadataReadWriteOverride(configKey, availableStreamConfigs,
+                expectedAvailableStreamConfigs, availableStreamConfigTag);
 
-        int[] resultFormats = mMetadata.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS);
-        assertNotNull("result available formats shouldn't be null", resultFormats);
-        assertArrayEquals(availableFormats, resultFormats);
+        //
+        // android.scaler.availableMinFrameDurations (int x n x 4 array)
+
+        //
+        long[] availableMinDurations = new long[] {
+                0x20, 3280, 2464, 33333336, // RAW16
+                0x23, 3264, 2448, 33333336, // YCbCr_420_888
+                0x23, 3200, 2400, 33333336, // YCbCr_420_888
+                0x100, 3264, 2448, 33333336, // ImageFormat.JPEG
+                0x100, 3200, 2400, 33333336, // ImageFormat.JPEG
+                0x100, 2592, 1944, 33333336, // ImageFormat.JPEG
+                0x100, 2048, 1536, 33333336, // ImageFormat.JPEG
+                0x100, 1920, 1080, 33333336  // ImageFormat.JPEG
+        };
+        long[] expectedAvailableMinDurations = new long[] {
+                0x20, 3280, 2464, 33333336, // RAW16
+                0x23, 3264, 2448, 33333336, // YCbCr_420_888
+                0x23, 3200, 2400, 33333336, // YCbCr_420_888
+                0x21, 3264, 2448, 33333336, // BLOB
+                0x21, 3200, 2400, 33333336, // BLOB
+                0x21, 2592, 1944, 33333336, // BLOB
+                0x21, 2048, 1536, 33333336, // BLOB
+                0x21, 1920, 1080, 33333336  // BLOB
+        };
+        int availableMinDurationsTag =
+                CameraMetadataNative.getTag("android.scaler.availableMinFrameDurations");
+
+        Key<long[]> durationKey = CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS;
+        validateArrayMetadataReadWriteOverride(durationKey, availableMinDurations,
+                expectedAvailableMinDurations, availableMinDurationsTag);
 
         //
         // android.statistics.faces (Face x n array)
@@ -639,4 +682,59 @@
         }
 
     }
+
+    /**
+     * Validate metadata array tag read/write override.
+     *
+     * <p>Only support long and int array for now, can be easily extend to support other
+     * primitive arrays.</p>
+     */
+    private <T> void validateArrayMetadataReadWriteOverride(Key<T> key, T writeValues,
+            T readValues, int tag) {
+        Class<T> type = key.getType();
+        if (!type.isArray()) {
+            throw new IllegalArgumentException("This function expects an key with array type");
+        } else if (type != int[].class && type != long[].class) {
+            throw new IllegalArgumentException("This function expects long or int array values");
+        }
+
+        // Write
+        mMetadata.set(key, writeValues);
+
+        byte[] readOutValues = mMetadata.readValues(tag);
+
+        ByteBuffer bf = ByteBuffer.wrap(readOutValues).order(ByteOrder.nativeOrder());
+
+        int readValuesLength = Array.getLength(readValues);
+        int readValuesNumBytes = readValuesLength * 4;
+        if (type == long[].class) {
+            readValuesNumBytes = readValuesLength * 8;
+        }
+
+        assertEquals(readValuesNumBytes, readOutValues.length);
+        for (int i = 0; i < readValuesLength; ++i) {
+            if (type == int[].class) {
+                assertEquals(Array.getInt(readValues, i), bf.getInt());
+            } else if (type == long[].class) {
+                assertEquals(Array.getLong(readValues, i), bf.getLong());
+            }
+        }
+
+        // Read
+        byte[] readOutValuesAsByteArray = new byte[readValuesNumBytes];
+        ByteBuffer readOutValuesByteBuffer =
+                ByteBuffer.wrap(readOutValuesAsByteArray).order(ByteOrder.nativeOrder());
+        for (int i = 0; i < readValuesLength; ++i) {
+            if (type == int[].class) {
+                readOutValuesByteBuffer.putInt(Array.getInt(readValues, i));
+            } else if (type == long[].class) {
+                readOutValuesByteBuffer.putLong(Array.getLong(readValues, i));
+            }
+        }
+        mMetadata.writeValues(tag, readOutValuesAsByteArray);
+
+        T result = mMetadata.get(key);
+        assertNotNull(key.getName() + " result shouldn't be null", result);
+        assertArrayEquals(writeValues, result);
+    }
 }
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index f68d1a9..48ef9db 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -30,6 +30,7 @@
 import android.content.res.ObbInfo;
 import android.content.res.ObbScanner;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Environment;
 import android.os.Environment.UserEnvironment;
 import android.os.FileUtils;
@@ -341,11 +342,13 @@
         // The .apk file
         String codePath = packageURI.getPath();
         File codeFile = new File(codePath);
+        NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(codePath);
+        final int abi = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_ABIS);
 
         // Calculate size of container needed to hold base APK.
         final int sizeMb;
         try {
-            sizeMb = calculateContainerSize(codeFile, isForwardLocked);
+            sizeMb = calculateContainerSize(handle, codeFile, abi, isForwardLocked);
         } catch (IOException e) {
             Slog.w(TAG, "Problem when trying to copy " + codeFile.getPath());
             return null;
@@ -408,7 +411,14 @@
 
         final File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME);
         if (sharedLibraryDir.mkdir()) {
-            int ret = NativeLibraryHelper.copyNativeBinariesIfNeededLI(codeFile, sharedLibraryDir);
+            int ret = PackageManager.INSTALL_SUCCEEDED;
+            if (abi >= 0) {
+                ret = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle,
+                        sharedLibraryDir, Build.SUPPORTED_ABIS[abi]);
+            } else if (abi != PackageManager.NO_NATIVE_LIBRARIES) {
+                ret = abi;
+            }
+
             if (ret != PackageManager.INSTALL_SUCCEEDED) {
                 Slog.e(TAG, "Could not copy native libraries to " + sharedLibraryDir.getPath());
                 PackageHelper.destroySdDir(newCid);
@@ -822,6 +832,17 @@
         return availSdMb > sizeMb;
     }
 
+    private int calculateContainerSize(File apkFile, boolean forwardLocked) throws IOException {
+        NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(apkFile);
+        final int abi = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_ABIS);
+
+        try {
+            return calculateContainerSize(handle, apkFile, abi, forwardLocked);
+        } finally {
+            handle.close();
+        }
+    }
+
     /**
      * Calculate the container size for an APK. Takes into account the
      * 
@@ -829,7 +850,8 @@
      * @return size in megabytes (2^20 bytes)
      * @throws IOException when there is a problem reading the file
      */
-    private int calculateContainerSize(File apkFile, boolean forwardLocked) throws IOException {
+    private int calculateContainerSize(NativeLibraryHelper.ApkHandle apkHandle,
+            File apkFile, int abiIndex, boolean forwardLocked) throws IOException {
         // Calculate size of container needed to hold base APK.
         long sizeBytes = apkFile.length();
         if (sizeBytes == 0 && !apkFile.exists()) {
@@ -838,7 +860,10 @@
 
         // Check all the native files that need to be copied and add that to the
         // container size.
-        sizeBytes += NativeLibraryHelper.sumNativeBinariesLI(apkFile);
+        if (abiIndex >= 0) {
+            sizeBytes += NativeLibraryHelper.sumNativeBinariesLI(apkHandle,
+                    Build.SUPPORTED_ABIS[abiIndex]);
+        }
 
         if (forwardLocked) {
             sizeBytes += PackageHelper.extractPublicFiles(apkFile.getPath(), null);
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index 96da21f..8297878 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -43,7 +43,11 @@
             android:textSize="24sp"
             android:textColor="#ffffffff"
             android:text="@string/recents_empty_message"
-            android:fontFamily="sans-serif-thin" />
+            android:fontFamily="sans-serif-thin"
+            android:singleLine="true"
+            android:maxLines="2"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal" />
         <ImageView
             android:id="@+id/activity_icon"
             android:layout_width="@dimen/recents_task_view_activity_icon_size"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 77944c8..672c1d0 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -112,5 +112,7 @@
     <integer name="recents_filter_animate_current_views_min_duration">175</integer>
     <!-- The min animation duration for animating views that are newly visible. -->
     <integer name="recents_filter_animate_new_views_min_duration">125</integer>
+    <!-- The min animation duration for animating views that are newly visible. -->
+    <integer name="recents_animate_task_bar_enter_duration">200</integer>
 </resources>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ce05639..ad10545 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -526,4 +526,12 @@
     <string name="description_direction_up">Slide up for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
     <!-- Description of the left direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
     <string name="description_direction_left">"Slide left for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
+
+    <!-- Zen mode: Summary notification content title. [CHAR LIMIT=NONE] -->
+    <plurals name="zen_mode_notification_title">
+        <item quantity="one">Notification hidden</item>
+        <item quantity="other">%d notifications hidden</item>
+    </plurals>
+    <!-- Zen mode: Summary notification content text. [CHAR LIMIT=NONE] -->
+    <string name="zen_mode_notification_text">Touch to show</string>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 8543b97..4fb90cb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -44,6 +44,7 @@
 import android.view.WindowManager;
 import com.android.systemui.R;
 
+import java.util.Iterator;
 import java.util.List;
 
 /** A proxy implementation for the recents component */
@@ -57,8 +58,11 @@
                 Resources res = mContext.getResources();
                 float statusBarHeight = res.getDimensionPixelSize(
                         com.android.internal.R.dimen.status_bar_height);
-                mFirstTaskRect = (Rect) msg.getData().getParcelable("taskRect");
-                mFirstTaskRect.offset(0, (int) statusBarHeight);
+                Bundle replyData = msg.getData().getParcelable(KEY_CONFIGURATION_DATA);
+                mSingleCountFirstTaskRect = replyData.getParcelable(KEY_SINGLE_TASK_STACK_RECT);
+                mSingleCountFirstTaskRect.offset(0, (int) statusBarHeight);
+                mMultipleCountFirstTaskRect = replyData.getParcelable(KEY_MULTIPLE_TASK_STACK_RECT);
+                mMultipleCountFirstTaskRect.offset(0, (int) statusBarHeight);
             }
         }
     }
@@ -89,12 +93,20 @@
         }
     }
 
-    final static int MSG_UPDATE_FOR_CONFIGURATION = 0;
-    final static int MSG_UPDATE_TASK_THUMBNAIL = 1;
-    final static int MSG_PRELOAD_TASKS = 2;
-    final static int MSG_CANCEL_PRELOAD_TASKS = 3;
-    final static int MSG_CLOSE_RECENTS = 4;
-    final static int MSG_TOGGLE_RECENTS = 5;
+    final public static int MSG_UPDATE_FOR_CONFIGURATION = 0;
+    final public static int MSG_UPDATE_TASK_THUMBNAIL = 1;
+    final public static int MSG_PRELOAD_TASKS = 2;
+    final public static int MSG_CANCEL_PRELOAD_TASKS = 3;
+    final public static int MSG_CLOSE_RECENTS = 4;
+    final public static int MSG_TOGGLE_RECENTS = 5;
+
+    final public static String EXTRA_ANIMATING_WITH_THUMBNAIL = "recents.animatingWithThumbnail";
+    final public static String KEY_CONFIGURATION_DATA = "recents.data.updateForConfiguration";
+    final public static String KEY_WINDOW_RECT = "recents.windowRect";
+    final public static String KEY_SYSTEM_INSETS = "recents.systemInsets";
+    final public static String KEY_SINGLE_TASK_STACK_RECT = "recents.singleCountTaskRect";
+    final public static String KEY_MULTIPLE_TASK_STACK_RECT = "recents.multipleCountTaskRect";
+
 
     final static int sMinToggleDelay = 425;
 
@@ -114,7 +126,8 @@
     RecentsServiceConnection mConnection = new RecentsServiceConnection();
 
     View mStatusBarView;
-    Rect mFirstTaskRect = new Rect();
+    Rect mSingleCountFirstTaskRect = new Rect();
+    Rect mMultipleCountFirstTaskRect = new Rect();
     long mLastToggleTime;
 
     public AlternateRecentsComponent(Context context) {
@@ -190,8 +203,8 @@
             // Try and update the recents configuration
             try {
                 Bundle data = new Bundle();
-                data.putParcelable("windowRect", rect);
-                data.putParcelable("systemInsets", new Rect(0, statusBarHeight, 0, 0));
+                data.putParcelable(KEY_WINDOW_RECT, rect);
+                data.putParcelable(KEY_SYSTEM_INSETS, new Rect(0, statusBarHeight, 0, 0));
                 Message msg = Message.obtain(null, MSG_UPDATE_FOR_CONFIGURATION, 0, 0);
                 msg.setData(data);
                 msg.replyTo = mMessenger;
@@ -221,26 +234,29 @@
                 return null;
             }
 
-            Bitmap thumbnail = ssp.getTaskThumbnail(t.persistentId);
-            return thumbnail;
+            return ssp.getTaskThumbnail(t.persistentId);
         }
         return null;
     }
 
-    /** Returns whether there is a first task */
-    boolean hasFirstTask() {
+    /** Returns whether there is are multiple recents tasks */
+    boolean hasMultipleRecentsTask() {
+        // NOTE: Currently there's no method to get the number of non-home tasks, so we have to
+        // compute this ourselves
         SystemServicesProxy ssp = mSystemServicesProxy;
-        List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(1,
+        List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(4,
                 UserHandle.CURRENT.getIdentifier());
-        for (ActivityManager.RecentTaskInfo t : tasks) {
+        Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
+        while (iter.hasNext()) {
+            ActivityManager.RecentTaskInfo t = iter.next();
+
             // Skip tasks in the home stack
             if (ssp.isInHomeStack(t.persistentId)) {
+                iter.remove();
                 continue;
             }
-
-            return true;
         }
-        return false;
+        return (tasks.size() > 1);
     }
 
     /** Converts from the device rotation to the degree */
@@ -287,8 +303,10 @@
         // to launch the first task or dismiss itself
         SystemServicesProxy ssp = mSystemServicesProxy;
         List<ActivityManager.RunningTaskInfo> tasks = ssp.getRunningTasks(1);
+        boolean isTopTaskHome = false;
         if (!tasks.isEmpty()) {
-            ComponentName topActivity = tasks.get(0).topActivity;
+            ActivityManager.RunningTaskInfo topTask = tasks.get(0);
+            ComponentName topActivity = topTask.topActivity;
 
             // Check if the front most activity is recents
             if (topActivity.getPackageName().equals(sRecentsPackage) &&
@@ -311,16 +329,30 @@
                 mLastToggleTime = System.currentTimeMillis();
                 return;
             }
+
+            // Determine whether the top task is currently home
+            isTopTaskHome = ssp.isInHomeStack(topTask.id);
         }
 
         // Otherwise, Recents is not the front-most activity and we should animate into it
-        Rect taskRect = mFirstTaskRect;
-        if (taskRect != null && taskRect.width() > 0 && taskRect.height() > 0 && hasFirstTask()) {
+        boolean hasMultipleTasks = hasMultipleRecentsTask();
+        Rect taskRect = hasMultipleTasks ? mMultipleCountFirstTaskRect : mSingleCountFirstTaskRect;
+        if (!isTopTaskHome && taskRect != null && taskRect.width() > 0 && taskRect.height() > 0) {
             // Loading from thumbnail
             Bitmap thumbnail;
             Bitmap firstThumbnail = loadFirstTaskThumbnail();
-            if (firstThumbnail == null) {
-                // Load the thumbnail from the screenshot
+            if (firstThumbnail != null) {// Create the thumbnail
+                thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
+                        Bitmap.Config.ARGB_8888);
+                int size = Math.min(firstThumbnail.getWidth(), firstThumbnail.getHeight());
+                Canvas c = new Canvas(thumbnail);
+                c.drawBitmap(firstThumbnail, new Rect(0, 0, size, size),
+                        new Rect(0, 0, taskRect.width(), taskRect.height()), null);
+                c.setBitmap(null);
+                // Recycle the old thumbnail
+                firstThumbnail.recycle();
+            } else {
+                // Load the thumbnail from the screenshot if can't get one from the system
                 WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
                 Display display = wm.getDefaultDisplay();
                 Bitmap screenshot = takeScreenshot(display);
@@ -328,35 +360,24 @@
                 int size = Math.min(screenshot.getWidth(), screenshot.getHeight());
                 int statusBarHeight = res.getDimensionPixelSize(
                         com.android.internal.R.dimen.status_bar_height);
-                thumbnail = Bitmap.createBitmap(mFirstTaskRect.width(), mFirstTaskRect.height(),
+                thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
                         Bitmap.Config.ARGB_8888);
                 Canvas c = new Canvas(thumbnail);
                 c.drawBitmap(screenshot, new Rect(0, statusBarHeight, size, statusBarHeight + size),
-                        new Rect(0, 0, mFirstTaskRect.width(), mFirstTaskRect.height()), null);
+                        new Rect(0, 0, taskRect.width(), taskRect.height()), null);
                 c.setBitmap(null);
-                // Recycle the old screenshot
+                // Recycle the temporary screenshot
                 screenshot.recycle();
-            } else {
-                // Create the thumbnail
-                thumbnail = Bitmap.createBitmap(mFirstTaskRect.width(), mFirstTaskRect.height(),
-                        Bitmap.Config.ARGB_8888);
-                int size = Math.min(firstThumbnail.getWidth(), firstThumbnail.getHeight());
-                Canvas c = new Canvas(thumbnail);
-                c.drawBitmap(firstThumbnail, new Rect(0, 0, size, size),
-                        new Rect(0, 0, mFirstTaskRect.width(), mFirstTaskRect.height()), null);
-                c.setBitmap(null);
-                // Recycle the old thumbnail
-                firstThumbnail.recycle();
             }
 
             ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(mStatusBarView,
-                    thumbnail, mFirstTaskRect.left, mFirstTaskRect.top, null);
-            startAlternateRecentsActivity(opts);
+                    thumbnail, taskRect.left, taskRect.top, null);
+            startAlternateRecentsActivity(opts, true);
         } else {
             ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
                     R.anim.recents_from_launcher_enter,
                     R.anim.recents_from_launcher_exit);
-            startAlternateRecentsActivity(opts);
+            startAlternateRecentsActivity(opts, false);
         }
 
         Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
@@ -365,11 +386,12 @@
     }
 
     /** Starts the recents activity */
-    void startAlternateRecentsActivity(ActivityOptions opts) {
+    void startAlternateRecentsActivity(ActivityOptions opts, boolean animatingWithThumbnail) {
         Intent intent = new Intent(sToggleRecentsAction);
         intent.setClassName(sRecentsPackage, sRecentsActivity);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+        intent.putExtra(EXTRA_ANIMATING_WITH_THUMBNAIL, animatingWithThumbnail);
         if (opts != null) {
             mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
                     UserHandle.USER_CURRENT));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 86f188e..cde17f5e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -72,8 +72,6 @@
         public static class Window {
             // The dark background dim is set behind the empty recents view
             public static final float DarkBackgroundDim = 0.5f;
-            // The background dim is set behind the card stack
-            public static final float BackgroundDim = 0.35f;
         }
 
         public static class RecentsTaskLoader {
@@ -98,11 +96,8 @@
         }
 
         public static class TaskView {
-            public static final boolean AnimateFrontTaskIconOnEnterRecents = true;
-            public static final boolean AnimateFrontTaskIconOnLeavingRecents = true;
-
-            public static final boolean UseRoundedCorners = false;
-            public static final float RoundedCornerRadiusDps = 3;
+            public static final boolean AnimateFrontTaskBarOnEnterRecents = true;
+            public static final boolean AnimateFrontTaskBarOnLeavingRecents = true;
         }
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index dd75921..f61c28c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -43,6 +43,7 @@
     boolean mVisible;
     boolean mTaskLaunched;
 
+    // Broadcast receiver to handle messages from our RecentsService
     BroadcastReceiver mServiceBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -63,8 +64,21 @@
         }
     };
 
+    // Broadcast receiver to handle messages from the system
+    BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            finish();
+        }
+    };
+
     /** Updates the set of recent tasks */
-    void updateRecentsTasks() {
+    void updateRecentsTasks(Intent launchIntent) {
+        // Update the configuration based on the launch intent
+        RecentsConfiguration config = RecentsConfiguration.getInstance();
+        config.launchedWithThumbnailAnimation = launchIntent.getBooleanExtra(
+                AlternateRecentsComponent.EXTRA_ANIMATING_WITH_THUMBNAIL, false);
+
         RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
         SpaceNode root = loader.reload(this, Constants.Values.RecentsTaskLoader.PreloadFirstTasksCount);
         ArrayList<TaskStack> stacks = root.getStacks();
@@ -111,12 +125,6 @@
         RecentsTaskLoader.initialize(this);
         RecentsConfiguration.reinitialize(this);
 
-        // Set the background dim
-        WindowManager.LayoutParams wlp = getWindow().getAttributes();
-        wlp.dimAmount = Constants.Values.Window.BackgroundDim;
-        getWindow().setAttributes(wlp);
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
-
         // Create the view hierarchy
         mRecentsView = new RecentsView(this);
         mRecentsView.setCallbacks(this);
@@ -134,7 +142,7 @@
         setContentView(mContainerView);
 
         // Update the recent tasks
-        updateRecentsTasks();
+        updateRecentsTasks(getIntent());
     }
 
     @Override
@@ -154,7 +162,7 @@
         RecentsConfiguration.reinitialize(this);
 
         // Update the recent tasks
-        updateRecentsTasks();
+        updateRecentsTasks(intent);
     }
 
     @Override
@@ -170,12 +178,37 @@
         Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onResume]", "",
                 Console.AnsiRed);
         super.onResume();
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+                "[RecentsActivity|onAttachedToWindow]", "",
+                Console.AnsiRed);
+        super.onAttachedToWindow();
 
         // Register the broadcast receiver to handle messages from our service
         IntentFilter filter = new IntentFilter();
         filter.addAction(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY);
         filter.addAction(RecentsService.ACTION_FINISH_RECENTS_ACTIVITY);
         registerReceiver(mServiceBroadcastReceiver, filter);
+
+        // Register the broadcast receiver to handle messages when the screen is turned off
+        filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_SCREEN_OFF);
+        registerReceiver(mScreenOffReceiver, filter);
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+                "[RecentsActivity|onDetachedFromWindow]", "",
+                Console.AnsiRed);
+        super.onDetachedFromWindow();
+
+        // Unregister any broadcast receivers we have registered
+        unregisterReceiver(mServiceBroadcastReceiver);
+        unregisterReceiver(mScreenOffReceiver);
     }
 
     @Override
@@ -183,9 +216,6 @@
         Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onPause]", "",
                 Console.AnsiRed);
         super.onPause();
-
-        // Unregister any broadcast receivers we have registered
-        unregisterReceiver(mServiceBroadcastReceiver);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 4a0de0b..21460bb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -17,6 +17,7 @@
 package com.android.systemui.recents;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.util.DisplayMetrics;
@@ -38,6 +39,9 @@
 
     public int filteringCurrentViewsMinAnimDuration;
     public int filteringNewViewsMinAnimDuration;
+    public int taskBarEnterAnimDuration;
+
+    public boolean launchedWithThumbnailAnimation;
 
     /** Private constructor */
     private RecentsConfiguration() {}
@@ -62,6 +66,12 @@
         DisplayMetrics dm = res.getDisplayMetrics();
         mDisplayMetrics = dm;
 
+        boolean isLandscape = res.getConfiguration().orientation ==
+                Configuration.ORIENTATION_LANDSCAPE;
+        Console.log(Constants.DebugFlags.UI.MeasureAndLayout,
+                "[RecentsConfiguration|orientation]", isLandscape ? "Landscape" : "Portrait",
+                Console.AnsiGreen);
+
         displayRect.set(0, 0, dm.widthPixels, dm.heightPixels);
         animationPxMovementPerSecond =
                 res.getDimensionPixelSize(R.dimen.recents_animation_movement_in_dps_per_second);
@@ -69,6 +79,8 @@
                 res.getInteger(R.integer.recents_filter_animate_current_views_min_duration);
         filteringNewViewsMinAnimDuration =
                 res.getInteger(R.integer.recents_filter_animate_new_views_min_duration);
+        taskBarEnterAnimDuration =
+                res.getInteger(R.integer.recents_animate_task_bar_enter_duration);
     }
 
     public void updateSystemInsets(Rect insets) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
index 22363bb..f78a999 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
@@ -26,6 +26,7 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.RemoteException;
+import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
 import com.android.systemui.recents.views.TaskStackView;
 import com.android.systemui.recents.views.TaskViewTransform;
@@ -50,36 +51,51 @@
         Context context = mContext.get();
         if (context == null) return;
 
-        if (msg.what == RecentsService.MSG_UPDATE_RECENTS_FOR_CONFIGURATION) {
+        if (msg.what == AlternateRecentsComponent.MSG_UPDATE_FOR_CONFIGURATION) {
             RecentsTaskLoader.initialize(context);
             RecentsConfiguration.reinitialize(context);
 
             try {
                 Bundle data = msg.getData();
-                Rect windowRect = (Rect) data.getParcelable("windowRect");
-                Rect systemInsets = (Rect) data.getParcelable("systemInsets");
+                Rect windowRect = data.getParcelable(AlternateRecentsComponent.KEY_WINDOW_RECT);
+                Rect systemInsets = data.getParcelable(AlternateRecentsComponent.KEY_SYSTEM_INSETS);
 
                 // Create a dummy task stack & compute the rect for the thumbnail to animate to
                 TaskStack stack = new TaskStack(context);
                 TaskStackView tsv = new TaskStackView(context, stack);
-                // Since the nav bar height is already accounted for in the windowRect, don't pass
-                // in a bottom inset
+                Bundle replyData = new Bundle();
+                TaskViewTransform transform;
+
+                // Calculate the target task rect for when there is one task
+                // NOTE: Since the nav bar height is already accounted for in the windowRect, don't
+                // pass in a bottom inset
+                stack.addTask(new Task());
                 tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0);
                 tsv.boundScroll();
-                TaskViewTransform transform = tsv.getStackTransform(0, tsv.getStackScroll());
-                Rect taskRect = new Rect(transform.rect);
+                transform = tsv.getStackTransform(0, tsv.getStackScroll());
+                replyData.putParcelable(AlternateRecentsComponent.KEY_SINGLE_TASK_STACK_RECT,
+                        new Rect(transform.rect));
 
-                data.putParcelable("taskRect", taskRect);
+                // Also calculate the target task rect when there are multiple tasks
+                stack.addTask(new Task());
+                tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0);
+                tsv.setStackScrollRaw(Integer.MAX_VALUE);
+                tsv.boundScroll();
+                transform = tsv.getStackTransform(1, tsv.getStackScroll());
+                replyData.putParcelable(AlternateRecentsComponent.KEY_MULTIPLE_TASK_STACK_RECT,
+                        new Rect(transform.rect));
+
+                data.putParcelable(AlternateRecentsComponent.KEY_CONFIGURATION_DATA, replyData);
                 Message reply = Message.obtain(null,
-                        RecentsService.MSG_UPDATE_RECENTS_FOR_CONFIGURATION, 0, 0);
+                        AlternateRecentsComponent.MSG_UPDATE_FOR_CONFIGURATION, 0, 0);
                 reply.setData(data);
                 msg.replyTo.send(reply);
             } catch (RemoteException re) {
                 re.printStackTrace();
             }
-        } else if (msg.what == RecentsService.MSG_CLOSE_RECENTS) {
+        } else if (msg.what == AlternateRecentsComponent.MSG_CLOSE_RECENTS) {
             // Do nothing
-        } else if (msg.what == RecentsService.MSG_TOGGLE_RECENTS) {
+        } else if (msg.what == AlternateRecentsComponent.MSG_TOGGLE_RECENTS) {
             // Send a broadcast to toggle recents
             Intent intent = new Intent(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY);
             intent.setPackage(context.getPackageName());
@@ -99,11 +115,6 @@
     final static String ACTION_FINISH_RECENTS_ACTIVITY = "action_finish_recents_activity";
     final static String ACTION_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity";
 
-    // XXX: This should be getting the message from recents definition
-    final static int MSG_UPDATE_RECENTS_FOR_CONFIGURATION = 0;
-    final static int MSG_CLOSE_RECENTS = 4;
-    final static int MSG_TOGGLE_RECENTS = 5;
-
     Messenger mSystemUIMessenger = new Messenger(new SystemUIMessageHandler(this));
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index d661f287..3c34e90 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -22,7 +22,6 @@
 import android.content.pm.ActivityInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
@@ -213,6 +212,7 @@
                                 Console.log(Constants.DebugFlags.App.TaskDataLoader,
                                         "    [TaskResourceLoader|loadThumbnail]",
                                         thumbnail);
+                                thumbnail.setHasAlpha(false);
                                 loadThumbnail = thumbnail;
                                 mThumbnailCache.put(t.key, thumbnail);
                             } else {
@@ -331,13 +331,9 @@
 
         // Create the default assets
         Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+        icon.eraseColor(0x00000000);
         mDefaultThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
-        Canvas c = new Canvas();
-        c.setBitmap(icon);
-        c.drawColor(0x00000000);
-        c.setBitmap(mDefaultThumbnail);
-        c.drawColor(0x00000000);
-        c.setBitmap(null);
+        mDefaultThumbnail.eraseColor(0x00000000);
         mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon);
         Console.log(Constants.DebugFlags.App.TaskDataLoader,
                 "[RecentsTaskLoader|defaultBitmaps]",
@@ -362,18 +358,9 @@
         return mSystemServicesProxy;
     }
 
-    /** Reload the set of recent tasks */
-    SpaceNode reload(Context context, int preloadCount) {
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|reload]");
-        Resources res = context.getResources();
-        ArrayList<Task> tasksToForceLoad = new ArrayList<Task>();
-        TaskStack stack = new TaskStack(context);
-        SpaceNode root = new SpaceNode(context);
-        root.setStack(stack);
-
+    private List<ActivityManager.RecentTaskInfo> getRecentTasks(Context context) {
         long t1 = System.currentTimeMillis();
 
-        // Get the recent tasks
         SystemServicesProxy ssp = mSystemServicesProxy;
         List<ActivityManager.RecentTaskInfo> tasks =
                 ssp.getRecentTasks(25, UserHandle.CURRENT.getIdentifier());
@@ -401,6 +388,24 @@
             }
         }
 
+        return tasks;
+    }
+
+    /** Reload the set of recent tasks */
+    SpaceNode reload(Context context, int preloadCount) {
+        long t1 = System.currentTimeMillis();
+
+        Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|reload]");
+        Resources res = context.getResources();
+        ArrayList<Task> tasksToForceLoad = new ArrayList<Task>();
+        TaskStack stack = new TaskStack(context);
+        SpaceNode root = new SpaceNode(context);
+        root.setStack(stack);
+
+        // Get the recent tasks
+        SystemServicesProxy ssp = mSystemServicesProxy;
+        List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks(context);
+
         // Add each task to the task stack
         t1 = System.currentTimeMillis();
         int taskCount = tasks.size();
@@ -454,6 +459,7 @@
                             "[RecentsTaskLoader|loadingTaskThumbnail]");
                     task.thumbnail = ssp.getTaskThumbnail(task.key.id);
                     if (task.thumbnail != null) {
+                        task.thumbnail.setHasAlpha(false);
                         mThumbnailCache.put(task.key, task.thumbnail);
                     } else {
                         task.thumbnail = mDefaultThumbnail;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
index efcd948..505238d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -24,7 +24,6 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 
@@ -52,9 +51,7 @@
         if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
             // Create a dummy icon
             mDummyIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
-            Canvas c = new Canvas(mDummyIcon);
-            c.drawColor(0xFF999999);
-            c.setBitmap(null);
+            mDummyIcon.eraseColor(0xFF999999);
         }
     }
 
@@ -117,9 +114,7 @@
         // If we are mocking, then just return a dummy thumbnail
         if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
             Bitmap thumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
-            Canvas c = new Canvas(thumbnail);
-            c.drawColor(0xff333333);
-            c.setBitmap(null);
+            thumbnail.eraseColor(0xff333333);
             return thumbnail;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index a0ff3b7..189f358 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -69,6 +69,10 @@
 
     TaskCallbacks mCb;
 
+    public Task() {
+        // Only used by RecentsService for task rect calculations.
+    }
+
     public Task(int id, boolean isActive, Intent intent, String activityTitle,
                 Bitmap activityIcon, int userId) {
         this.key = new TaskKey(id, intent);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index a0e5b6a..21e2c1d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -43,7 +43,13 @@
         ArrayList<Task> prevFilteredTasks = new ArrayList<Task>(mFilteredTasks);
         mFilter = filter;
         updateFilteredTasks();
-        return !prevFilteredTasks.equals(mFilteredTasks);
+        if (!prevFilteredTasks.equals(mFilteredTasks)) {
+            return true;
+        } else {
+            // If the tasks are exactly the same pre/post filter, then just reset it
+            mFilter = null;
+            return false;
+        }
     }
 
     /** Removes the task filter and returns the previous touch state */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 1ebe231..ec28379 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -108,6 +108,7 @@
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int width = MeasureSpec.getSize(widthMeasureSpec);
+        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
         int height = MeasureSpec.getSize(heightMeasureSpec);
         int heightMode = MeasureSpec.getMode(heightMeasureSpec);
 
@@ -118,6 +119,7 @@
 
         // We measure our stack views sans the status bar.  It will handle the nav bar itself.
         RecentsConfiguration config = RecentsConfiguration.getInstance();
+        int childWidth = width - config.systemInsets.right;
         int childHeight = height - config.systemInsets.top;
 
         // Measure each child
@@ -125,7 +127,7 @@
         for (int i = 0; i < childCount; i++) {
             final View child = getChildAt(i);
             if (child.getVisibility() != GONE) {
-                child.measure(widthMeasureSpec,
+                child.measure(MeasureSpec.makeMeasureSpec(childWidth, widthMode),
                         MeasureSpec.makeMeasureSpec(childHeight, heightMode));
             }
         }
@@ -255,11 +257,11 @@
                             | Intent.FLAG_ACTIVITY_TASK_ON_HOME
                             | Intent.FLAG_ACTIVITY_NEW_TASK);
                     try {
+                        UserHandle taskUser = new UserHandle(task.userId);
                         if (opts != null) {
-                            getContext().startActivityAsUser(i, opts.toBundle(),
-                                    new UserHandle(task.userId));
+                            getContext().startActivityAsUser(i, opts.toBundle(), taskUser);
                         } else {
-                            getContext().startActivityAsUser(i, new UserHandle(task.userId));
+                            getContext().startActivityAsUser(i, taskUser);
                         }
                     } catch (ActivityNotFoundException anfe) {
                         Console.logError(getContext(), "Could not start Activity");
@@ -275,7 +277,7 @@
                 Constants.DebugFlags.App.TimeRecentsLaunchKey, "onTaskLaunched");
 
         // Launch the app right away if there is no task view, otherwise, animate the icon out first
-        if (tv == null || !Constants.Values.TaskView.AnimateFrontTaskIconOnLeavingRecents) {
+        if (tv == null || !Constants.Values.TaskView.AnimateFrontTaskBarOnLeavingRecents) {
             post(launchRunnable);
         } else {
             tv.animateOnLeavingRecents(launchRunnable);
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 fa06764..728aaad 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -171,7 +171,7 @@
             transform.visible = false;
         } else {
             transform.rect.offset(0, transform.translationY);
-            Utilities.scaleRectAboutCenter(transform.rect, scale);
+            Utilities.scaleRectAboutCenter(transform.rect, transform.scale);
             transform.visible = Rect.intersects(mRect, transform.rect);
         }
         transform.t = t;
@@ -388,8 +388,14 @@
         int stackHeight = mStackRectSansPeek.height();
         int maxScrollHeight = taskHeight + (int) ((numTasks - 1) *
                 Constants.Values.TaskStackView.StackOverlapPct * taskHeight);
-        mMinScroll = Math.min(stackHeight, maxScrollHeight) - stackHeight;
-        mMaxScroll = maxScrollHeight - stackHeight;
+
+        if (numTasks <= 1) {
+            // If there is only one task, then center the task in the stack rect (sans peek)
+            mMinScroll = mMaxScroll = -(stackHeight - taskHeight) / 2;
+        } else {
+            mMinScroll = Math.min(stackHeight, maxScrollHeight) - stackHeight;
+            mMaxScroll = maxScrollHeight - stackHeight;
+        }
 
         // Debug logging
         if (Constants.DebugFlags.UI.MeasureAndLayout) {
@@ -479,8 +485,8 @@
                 // Clip against the next view (if we aren't animating its alpha)
                 nextTv = (TaskView) getChildAt(curIndex + 1);
                 if (nextTv.getAlpha() == 1f) {
-                    Rect curRect = tv.getClippingRect(mTmpRect, false);
-                    Rect nextRect = nextTv.getClippingRect(mTmpRect2, true);
+                    Rect curRect = tv.getClippingRect(mTmpRect);
+                    Rect nextRect = nextTv.getClippingRect(mTmpRect2);
                     RecentsConfiguration config = RecentsConfiguration.getInstance();
                     // The hit rects are relative to the task view, which needs to be offset by the
                     // system bar height
@@ -523,9 +529,8 @@
         int minHeight = (int) (mStackRect.height() -
                 (Constants.Values.TaskStackView.StackPeekHeightPct * mStackRect.height()));
         int size = Math.min(minHeight, Math.min(mStackRect.width(), mStackRect.height()));
-        int centerX = mStackRect.centerX();
-        mTaskRect.set(centerX - size / 2, mStackRectSansPeek.top,
-                centerX + size / 2, mStackRectSansPeek.top + size);
+        mTaskRect.set(mStackRect.left, mStackRectSansPeek.top,
+                mStackRect.right, mStackRectSansPeek.top + size);
 
         // Update the scroll bounds
         updateMinMaxScroll(false);
@@ -558,8 +563,9 @@
             requestSynchronizeStackViewsWithModel();
             synchronizeStackViewsWithModel();
 
-            // Animate the icon of the first task view
-            if (Constants.Values.TaskView.AnimateFrontTaskIconOnEnterRecents) {
+            // Animate the task bar of the first task view
+            if (config.launchedWithThumbnailAnimation &&
+                    Constants.Values.TaskView.AnimateFrontTaskBarOnEnterRecents) {
                 TaskView tv = (TaskView) getChildAt(getChildCount() - 1);
                 if (tv != null) {
                     tv.animateOnEnterRecents();
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 e99fecb..a3056ec 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -20,9 +20,8 @@
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.content.Context;
-import android.graphics.Bitmap;
 import android.graphics.Canvas;
-import android.graphics.Color;
+import android.graphics.Outline;
 import android.graphics.Path;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -36,8 +35,6 @@
 import com.android.systemui.recents.Utilities;
 import com.android.systemui.recents.model.Task;
 
-import java.util.Random;
-
 
 /* A task view */
 public class TaskView extends FrameLayout implements View.OnClickListener, Task.TaskCallbacks {
@@ -54,8 +51,6 @@
     TaskBarView mBarView;
     TaskViewCallbacks mCb;
 
-    Path mRoundedRectClipPath = new Path();
-
 
     public TaskView(Context context) {
         this(context, null);
@@ -71,7 +66,6 @@
 
     public TaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        setWillNotDraw(false);
     }
 
     @Override
@@ -85,31 +79,6 @@
         }
     }
 
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
-        // Update the rounded rect clip path
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        float radius = config.pxFromDp(Constants.Values.TaskView.RoundedCornerRadiusDps);
-        mRoundedRectClipPath.reset();
-        mRoundedRectClipPath.addRoundRect(new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight()),
-                radius, radius, Path.Direction.CW);
-    }
-
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        int restoreCount = 0;
-        if (Constants.Values.TaskView.UseRoundedCorners) {
-            restoreCount = canvas.save();
-            canvas.clipPath(mRoundedRectClipPath);
-        }
-        super.dispatchDraw(canvas);
-        if (Constants.Values.TaskView.UseRoundedCorners) {
-            canvas.restoreToCount(restoreCount);
-        }
-    }
-
     /** Set callback */
     void setCallbacks(TaskViewCallbacks cb) {
         mCb = cb;
@@ -195,7 +164,7 @@
                 .translationY(0)
                 .setStartDelay(235)
                 .setInterpolator(BakedBezierInterpolator.INSTANCE)
-                .setDuration(Utilities.calculateTranslationAnimationDuration(translate))
+                .setDuration(config.taskBarEnterAnimDuration)
                 .withLayer()
                 .start();
     }
@@ -214,23 +183,21 @@
             .setInterpolator(BakedBezierInterpolator.INSTANCE)
             .setDuration(Utilities.calculateTranslationAnimationDuration(translate))
             .withLayer()
-            .withEndAction(r)
+            .withEndAction(new Runnable() {
+                @Override
+                public void run() {
+                    post(r);
+                }
+            })
             .start();
     }
 
     /** Returns the rect we want to clip (it may not be the full rect) */
-    Rect getClippingRect(Rect outRect, boolean accountForRoundedRects) {
+    Rect getClippingRect(Rect outRect) {
         getHitRect(outRect);
         // XXX: We should get the hit rect of the thumbnail view and intersect, but this is faster
         outRect.right = outRect.left + mThumbnailView.getRight();
         outRect.bottom = outRect.top + mThumbnailView.getBottom();
-        // We need to shrink the next rect by the rounded corners since those are draw on
-        // top of the current view
-        if (accountForRoundedRects) {
-            RecentsConfiguration config = RecentsConfiguration.getInstance();
-            float radius = config.pxFromDp(Constants.Values.TaskView.RoundedCornerRadiusDps);
-            outRect.inset((int) radius, (int) radius);
-        }
         return outRect;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 844b964..f1299fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -109,9 +109,6 @@
     public static final int EXPANDED_LEAVE_ALONE = -10000;
     public static final int EXPANDED_FULL_OPEN = -10001;
 
-    private static final String EXTRA_INTERCEPT = "android.intercept";
-    private static final float INTERCEPTED_ALPHA = .2f;
-
     protected CommandQueue mCommandQueue;
     protected IStatusBarService mBarService;
     protected H mHandler = createHandler();
@@ -1049,7 +1046,6 @@
         if (DEBUG) {
             Log.d(TAG, "addNotificationViews: added at " + pos);
         }
-        updateInterceptedState(entry);
         updateExpansionStates();
         updateNotificationIcons();
     }
@@ -1082,32 +1078,10 @@
 
     protected void setZenMode(int mode) {
         if (!isDeviceProvisioned()) return;
-        final boolean change = mZenMode != mode;
         mZenMode = mode;
-        final int N = mNotificationData.size();
-        for (int i = 0; i < N; i++) {
-            final NotificationData.Entry entry = mNotificationData.get(i);
-            if (change && !shouldIntercept()) {
-                entry.notification.getNotification().extras.putBoolean(EXTRA_INTERCEPT, false);
-            }
-            updateInterceptedState(entry);
-        }
         updateNotificationIcons();
     }
 
-    private boolean shouldIntercept() {
-        return mZenMode != Settings.Global.ZEN_MODE_OFF;
-    }
-
-    protected boolean shouldIntercept(Notification n) {
-        return shouldIntercept() && n.extras.getBoolean(EXTRA_INTERCEPT);
-    }
-
-    private void updateInterceptedState(NotificationData.Entry entry) {
-        final boolean intercepted = shouldIntercept(entry.notification.getNotification());
-        entry.row.findViewById(R.id.container).setAlpha(intercepted ? INTERCEPTED_ALPHA : 1);
-    }
-
     protected abstract void haltTicker();
     protected abstract void setAreThereNotifications();
     protected abstract void updateNotificationIcons();
@@ -1312,7 +1286,6 @@
         } else {
             entry.content.setOnClickListener(null);
         }
-        updateInterceptedState(entry);
     }
 
     protected void notifyHeadsUpScreenOn(boolean screenOn) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
new file mode 100644
index 0000000..d563968
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
@@ -0,0 +1,119 @@
+/*
+ * 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.systemui.statusbar;
+
+import android.app.Notification;
+import android.content.Context;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Process;
+import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
+import android.view.View;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.NotificationData.Entry;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+
+public class InterceptedNotifications {
+    private static final String TAG = "InterceptedNotifications";
+    private static final String EXTRA_INTERCEPT = "android.intercept";
+
+    private final Context mContext;
+    private final PhoneStatusBar mBar;
+    private final ArrayMap<IBinder, StatusBarNotification> mIntercepted
+            = new ArrayMap<IBinder, StatusBarNotification>();
+
+    private Binder mSynKey;
+
+    public InterceptedNotifications(Context context, PhoneStatusBar bar) {
+        mContext = context;
+        mBar = bar;
+    }
+
+    public void releaseIntercepted() {
+        final int n = mIntercepted.size();
+        for (int i = 0; i < n; i++) {
+            final IBinder key = mIntercepted.keyAt(i);
+            final StatusBarNotification sbn = mIntercepted.valueAt(i);
+            sbn.getNotification().extras.putBoolean(EXTRA_INTERCEPT, false);
+            mBar.addNotification(key, sbn);
+        }
+        mIntercepted.clear();
+        updateSyntheticNotification();
+    }
+
+    public boolean tryIntercept(IBinder key, StatusBarNotification notification) {
+        if (!notification.getNotification().extras.getBoolean(EXTRA_INTERCEPT)) return false;
+        mIntercepted.put(key, notification);
+        updateSyntheticNotification();
+        return true;
+    }
+
+    public void remove(IBinder key) {
+        if (mIntercepted.remove(key) != null) {
+            updateSyntheticNotification();
+        }
+    }
+
+    public boolean isSyntheticEntry(Entry ent) {
+        return mSynKey != null && ent.key.equals(mSynKey);
+    }
+
+    public void update(IBinder key, StatusBarNotification notification) {
+        if (mIntercepted.containsKey(key)) {
+            mIntercepted.put(key, notification);
+        }
+    }
+
+    private void updateSyntheticNotification() {
+        if (mIntercepted.isEmpty()) {
+            if (mSynKey != null) {
+                mBar.removeNotification(mSynKey);
+                mSynKey = null;
+            }
+            return;
+        }
+        final Notification n = new Notification.Builder(mContext)
+                .setSmallIcon(R.drawable.stat_sys_zen_limited)
+                .setContentTitle(mContext.getResources().getQuantityString(
+                        R.plurals.zen_mode_notification_title,
+                        mIntercepted.size(), mIntercepted.size()))
+                .setContentText(mContext.getString(R.string.zen_mode_notification_text))
+                .setOngoing(true)
+                .build();
+        final StatusBarNotification sbn = new StatusBarNotification(mContext.getPackageName(),
+                mContext.getBasePackageName(),
+                TAG.hashCode(), TAG, Process.myUid(), Process.myPid(), 0, n,
+                mBar.getCurrentUserHandle());
+        if (mSynKey == null) {
+            mSynKey = new Binder();
+            mBar.addNotification(mSynKey, sbn);
+        } else {
+           mBar.updateNotification(mSynKey, sbn);
+        }
+        final NotificationData.Entry entry = mBar.mNotificationData.findByKey(mSynKey);
+        entry.content.setOnClickListener(mSynClickListener);
+    }
+
+    private final View.OnClickListener mSynClickListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            releaseIntercepted();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 4730f2f..f3dd7e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -59,6 +59,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.provider.Settings.Global;
 import android.service.notification.StatusBarNotification;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
@@ -89,11 +90,11 @@
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.GestureRecorder;
+import com.android.systemui.statusbar.InterceptedNotifications;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.NotificationData.Entry;
 import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.StatusBarIconView;
-
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.DateView;
@@ -101,7 +102,6 @@
 import com.android.systemui.statusbar.policy.LocationController;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.RotationLockController;
-
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 import java.io.FileDescriptor;
@@ -347,6 +347,7 @@
         }};
 
     private Runnable mOnFlipRunnable;
+    private InterceptedNotifications mIntercepted;
 
     public void setOnFlipRunnable(Runnable onFlipRunnable) {
         mOnFlipRunnable = onFlipRunnable;
@@ -357,7 +358,11 @@
         super.setZenMode(mode);
         if (mModeIcon == null) return;
         if (!isDeviceProvisioned()) return;
-        mModeIcon.setVisibility(mode != Settings.Global.ZEN_MODE_OFF ? View.VISIBLE : View.GONE);
+        final boolean zen = mode != Settings.Global.ZEN_MODE_OFF;
+        mModeIcon.setVisibility(zen ? View.VISIBLE : View.GONE);
+        if (!zen) {
+            mIntercepted.releaseIntercepted();
+        }
     }
 
     @Override
@@ -365,7 +370,7 @@
         mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
                 .getDefaultDisplay();
         updateDisplaySize();
-
+        mIntercepted = new InterceptedNotifications(mContext, this);
         super.start(); // calls createAndAddWindows()
 
         addNavigationBar();
@@ -931,49 +936,54 @@
         mStatusIcons.removeViewAt(viewIndex);
     }
 
+    public UserHandle getCurrentUserHandle() {
+        return new UserHandle(mCurrentUserId);
+    }
+
     public void addNotification(IBinder key, StatusBarNotification notification) {
         if (DEBUG) Log.d(TAG, "addNotification score=" + notification.getScore());
         Entry shadeEntry = createNotificationViews(key, notification);
         if (shadeEntry == null) {
             return;
         }
-        if (!shouldIntercept(notification.getNotification())) {
-            if (mUseHeadsUp && shouldInterrupt(notification)) {
-                if (DEBUG) Log.d(TAG, "launching notification in heads up mode");
-                Entry interruptionCandidate = new Entry(key, notification, null);
-                ViewGroup holder = mHeadsUpNotificationView.getHolder();
-                if (inflateViewsForHeadsUp(interruptionCandidate, holder)) {
-                    mInterruptingNotificationTime = System.currentTimeMillis();
-                    mInterruptingNotificationEntry = interruptionCandidate;
-                    shadeEntry.setInterruption();
+        if (mZenMode != Global.ZEN_MODE_OFF && mIntercepted.tryIntercept(key, notification)) {
+            return;
+        }
+        if (mUseHeadsUp && shouldInterrupt(notification)) {
+            if (DEBUG) Log.d(TAG, "launching notification in heads up mode");
+            Entry interruptionCandidate = new Entry(key, notification, null);
+            ViewGroup holder = mHeadsUpNotificationView.getHolder();
+            if (inflateViewsForHeadsUp(interruptionCandidate, holder)) {
+                mInterruptingNotificationTime = System.currentTimeMillis();
+                mInterruptingNotificationEntry = interruptionCandidate;
+                shadeEntry.setInterruption();
 
-                    // 1. Populate mHeadsUpNotificationView
-                    mHeadsUpNotificationView.setNotification(mInterruptingNotificationEntry);
+                // 1. Populate mHeadsUpNotificationView
+                mHeadsUpNotificationView.setNotification(mInterruptingNotificationEntry);
 
-                    // 2. Animate mHeadsUpNotificationView in
-                    mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP);
+                // 2. Animate mHeadsUpNotificationView in
+                mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP);
 
-                    // 3. Set alarm to age the notification off
-                    resetHeadsUpDecayTimer();
-                }
-            } else if (notification.getNotification().fullScreenIntent != null) {
-                // Stop screensaver if the notification has a full-screen intent.
-                // (like an incoming phone call)
-                awakenDreams();
+                // 3. Set alarm to age the notification off
+                resetHeadsUpDecayTimer();
+            }
+        } else if (notification.getNotification().fullScreenIntent != null) {
+            // Stop screensaver if the notification has a full-screen intent.
+            // (like an incoming phone call)
+            awakenDreams();
 
-                // not immersive & a full-screen alert should be shown
-                if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
-                try {
-                    notification.getNotification().fullScreenIntent.send();
-                } catch (PendingIntent.CanceledException e) {
-                }
-            } else {
-                // usual case: status bar visible & not immersive
+            // not immersive & a full-screen alert should be shown
+            if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
+            try {
+                notification.getNotification().fullScreenIntent.send();
+            } catch (PendingIntent.CanceledException e) {
+            }
+        } else {
+            // usual case: status bar visible & not immersive
 
-                // show the ticker if there isn't already a heads up
-                if (mInterruptingNotificationEntry == null) {
-                    tick(null, notification, true);
-                }
+            // show the ticker if there isn't already a heads up
+            if (mInterruptingNotificationEntry == null) {
+                tick(null, notification, true);
             }
         }
         addNotificationViews(shadeEntry);
@@ -991,6 +1001,12 @@
         }
     }
 
+    @Override
+    public void updateNotification(IBinder key, StatusBarNotification notification) {
+        super.updateNotification(key, notification);
+        mIntercepted.update(key, notification);
+    }
+
     public void removeNotification(IBinder key) {
         StatusBarNotification old = removeNotificationViews(key);
         if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
@@ -1012,7 +1028,7 @@
                 animateCollapsePanels();
             }
         }
-
+        mIntercepted.remove(key);
         setAreThereNotifications();
     }
 
@@ -1129,7 +1145,7 @@
                 // in "public" mode (atop a secure keyguard), secret notifs are totally hidden
                 continue;
             }
-            if (shouldIntercept(ent.notification.getNotification())) {
+            if (mIntercepted.isSyntheticEntry(ent)) {
                 continue;
             }
             toShow.add(ent.icon);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 35f873e..c3db55e 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3176,8 +3176,9 @@
                     // The active window also determined events from which
                     // windows are delivered.
                     synchronized (mLock) {
+                        mFocusedWindowId = getFocusedWindowId();
                         if (mWindowsForAccessibilityCallback == null
-                                && windowId == getFocusedWindowId()) {
+                                && windowId == mFocusedWindowId) {
                             mActiveWindowId = windowId;
                         }
                     }
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index b6e761c..7ec9b82 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -52,6 +52,7 @@
 import android.os.storage.IMountShutdownObserver;
 import android.os.storage.IObbActionListener;
 import android.os.storage.OnObbStateChangeListener;
+import android.os.storage.StorageManager;
 import android.os.storage.StorageResultCode;
 import android.os.storage.StorageVolume;
 import android.text.TextUtils;
@@ -2145,8 +2146,8 @@
         }
     }
 
-    public int encryptStorage(String password) {
-        if (TextUtils.isEmpty(password)) {
+    public int encryptStorage(int type, String password) {
+        if (TextUtils.isEmpty(password) && type != StorageManager.CRYPT_TYPE_DEFAULT) {
             throw new IllegalArgumentException("password cannot be empty");
         }
 
@@ -2160,7 +2161,7 @@
         }
 
         try {
-            mConnector.execute("cryptfs", "enablecrypto", "inplace",
+            mConnector.execute("cryptfs", "enablecrypto", "inplace", CRYPTO_TYPES[type],
                                new SensitiveArg(toHex(password)));
         } catch (NativeDaemonConnectorException e) {
             // Encryption failed
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5bfb3fb..7607419 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2756,11 +2756,16 @@
                 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
             }
 
+            String requiredAbi = app.info.requiredCpuAbi;
+            if (requiredAbi == null) {
+                requiredAbi = Build.SUPPORTED_ABIS[0];
+            }
+
             // Start the process.  It will either succeed and return a result containing
             // the PID of the new process, or else throw a RuntimeException.
             Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
                     app.processName, uid, uid, gids, debugFlags, mountExternal,
-                    app.info.targetSdkVersion, app.info.seinfo, null);
+                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, null);
 
             BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
             synchronized (bs) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ff90cae..747d0a7 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -60,8 +60,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
-import android.content.ServiceConnection;
 import android.content.IntentSender.SendIntentException;
+import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ContainerEncryptionParams;
@@ -74,14 +74,15 @@
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
 import android.content.pm.InstrumentationInfo;
+import android.content.pm.ManifestDigest;
 import android.content.pm.PackageCleanItem;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInfoLite;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
-import android.content.pm.PackageUserState;
 import android.content.pm.PackageParser.ActivityIntentInfo;
 import android.content.pm.PackageStats;
+import android.content.pm.PackageUserState;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
@@ -89,7 +90,6 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.Signature;
-import android.content.pm.ManifestDigest;
 import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.pm.VerifierInfo;
@@ -100,6 +100,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
+import android.os.Environment.UserEnvironment;
 import android.os.FileObserver;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -116,7 +117,6 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
-import android.os.Environment.UserEnvironment;
 import android.os.UserManager;
 import android.security.KeyStore;
 import android.security.SystemKeyStore;
@@ -2054,6 +2054,7 @@
                 pkg.applicationInfo.dataDir =
                         getDataPathForPackage(packageName, 0).getPath();
                 pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString;
+                pkg.applicationInfo.requiredCpuAbi = ps.requiredCpuAbiString;
             }
             return generatePackageInfo(pkg, flags, userId);
         }
@@ -3994,6 +3995,8 @@
         codePath = pkg.mScanPath;
         // Set application objects path explicitly.
         setApplicationInfoPaths(pkg, codePath, resPath);
+        // Applications can run with the primary Cpu Abi unless otherwise is specified
+        pkg.applicationInfo.requiredCpuAbi = null;
         // Note that we invoke the following method only if we are about to unpack an application
         PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode
                 | SCAN_UPDATE_SIGNATURE, currentTime, user);
@@ -4565,6 +4568,7 @@
             // the PkgSetting exists already and doesn't have to be created.
             pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,
                     destResourceFile, pkg.applicationInfo.nativeLibraryDir,
+                    pkg.applicationInfo.requiredCpuAbi,
                     pkg.applicationInfo.flags, user, false);
             if (pkgSetting == null) {
                 Slog.w(TAG, "Creating application package " + pkg.packageName + " failed");
@@ -4870,11 +4874,20 @@
                         }
 
                         try {
-                            if (copyNativeLibrariesForInternalApp(scanFile, nativeLibraryDir) != PackageManager.INSTALL_SUCCEEDED) {
+                            int copyRet = copyNativeLibrariesForInternalApp(scanFile, nativeLibraryDir);
+                            if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
                                 Slog.e(TAG, "Unable to copy native libraries");
                                 mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
                                 return null;
                             }
+
+                            // We've successfully copied native libraries across, so we make a
+                            // note of what ABI we're using
+                            if (copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
+                                pkg.applicationInfo.requiredCpuAbi = Build.SUPPORTED_ABIS[copyRet];
+                            } else {
+                                pkg.applicationInfo.requiredCpuAbi = null;
+                            }
                         } catch (IOException e) {
                             Slog.e(TAG, "Unable to copy native libraries", e);
                             mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
@@ -5430,7 +5443,21 @@
          * If this is an internal application or our nativeLibraryPath points to
          * the app-lib directory, unpack the libraries if necessary.
          */
-        return NativeLibraryHelper.copyNativeBinariesIfNeededLI(scanFile, nativeLibraryDir);
+        final NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(scanFile);
+        try {
+            int abi = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_ABIS);
+            if (abi >= 0) {
+                int copyRet = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle,
+                        nativeLibraryDir, Build.SUPPORTED_ABIS[abi]);
+                if (copyRet != PackageManager.INSTALL_SUCCEEDED) {
+                    return copyRet;
+                }
+            }
+
+            return abi;
+        } finally {
+            handle.close();
+        }
     }
 
     private void killApplication(String pkgName, int appId, String reason) {
@@ -8384,7 +8411,7 @@
             }
             try {
                 int copyRet = copyNativeLibrariesForInternalApp(codeFile, nativeLibraryFile);
-                if (copyRet != PackageManager.INSTALL_SUCCEEDED) {
+                if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
                     return copyRet;
                 }
             } catch (IOException e) {
@@ -11898,8 +11925,17 @@
                                     final File newNativeDir = new File(newNativePath);
 
                                     if (!isForwardLocked(pkg) && !isExternal(pkg)) {
-                                        NativeLibraryHelper.copyNativeBinariesIfNeededLI(
-                                                new File(newCodePath), newNativeDir);
+                                        // NOTE: We do not report any errors from the APK scan and library
+                                        // copy at this point.
+                                        NativeLibraryHelper.ApkHandle handle =
+                                                new NativeLibraryHelper.ApkHandle(newCodePath);
+                                        final int abi = NativeLibraryHelper.findSupportedAbi(
+                                                handle, Build.SUPPORTED_ABIS);
+                                        if (abi >= 0) {
+                                            NativeLibraryHelper.copyNativeBinariesIfNeededLI(
+                                                    handle, newNativeDir, Build.SUPPORTED_ABIS[abi]);
+                                        }
+                                        handle.close();
                                     }
                                     final int[] users = sUserManager.getUserIds();
                                     for (int user : users) {
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index b447861..15df3d2 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -30,8 +30,8 @@
     SharedUserSetting sharedUser;
 
     PackageSetting(String name, String realName, File codePath, File resourcePath,
-            String nativeLibraryPathString, int pVersionCode, int pkgFlags) {
-        super(name, realName, codePath, resourcePath, nativeLibraryPathString, pVersionCode,
+            String nativeLibraryPathString, String requiredCpuAbiString, int pVersionCode, int pkgFlags) {
+        super(name, realName, codePath, resourcePath, nativeLibraryPathString, requiredCpuAbiString, pVersionCode,
                 pkgFlags);
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 2a5698b9..c8af9d1 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -50,6 +50,7 @@
     File resourcePath;
     String resourcePathString;
     String nativeLibraryPathString;
+    String requiredCpuAbiString;
     long timeStamp;
     long firstInstallTime;
     long lastUpdateTime;
@@ -77,11 +78,11 @@
     /* package name of the app that installed this package */
     String installerPackageName;
     PackageSettingBase(String name, String realName, File codePath, File resourcePath,
-            String nativeLibraryPathString, int pVersionCode, int pkgFlags) {
+            String nativeLibraryPathString, String requiredCpuAbiString, int pVersionCode, int pkgFlags) {
         super(pkgFlags);
         this.name = name;
         this.realName = realName;
-        init(codePath, resourcePath, nativeLibraryPathString, pVersionCode);
+        init(codePath, resourcePath, nativeLibraryPathString, requiredCpuAbiString, pVersionCode);
     }
 
     /**
@@ -98,6 +99,7 @@
         resourcePath = base.resourcePath;
         resourcePathString = base.resourcePathString;
         nativeLibraryPathString = base.nativeLibraryPathString;
+        requiredCpuAbiString = base.requiredCpuAbiString;
         timeStamp = base.timeStamp;
         firstInstallTime = base.firstInstallTime;
         lastUpdateTime = base.lastUpdateTime;
@@ -125,12 +127,13 @@
     }
 
     void init(File codePath, File resourcePath, String nativeLibraryPathString,
-            int pVersionCode) {
+            String requiredCpuAbiString, int pVersionCode) {
         this.codePath = codePath;
         this.codePathString = codePath.toString();
         this.resourcePath = resourcePath;
         this.resourcePathString = resourcePath.toString();
         this.nativeLibraryPathString = nativeLibraryPathString;
+        this.requiredCpuAbiString = requiredCpuAbiString;
         this.versionCode = pVersionCode;
     }
 
@@ -161,6 +164,7 @@
         grantedPermissions = base.grantedPermissions;
         gids = base.gids;
 
+        requiredCpuAbiString = base.requiredCpuAbiString;
         timeStamp = base.timeStamp;
         firstInstallTime = base.firstInstallTime;
         lastUpdateTime = base.lastUpdateTime;
diff --git a/services/core/java/com/android/server/pm/PendingPackage.java b/services/core/java/com/android/server/pm/PendingPackage.java
index c17cc46..36c3a34 100644
--- a/services/core/java/com/android/server/pm/PendingPackage.java
+++ b/services/core/java/com/android/server/pm/PendingPackage.java
@@ -22,8 +22,8 @@
     final int sharedId;
 
     PendingPackage(String name, String realName, File codePath, File resourcePath,
-            String nativeLibraryPathString, int sharedId, int pVersionCode, int pkgFlags) {
-        super(name, realName, codePath, resourcePath, nativeLibraryPathString, pVersionCode,
+            String nativeLibraryPathString, String requiredCpuAbiString, int sharedId, int pVersionCode, int pkgFlags) {
+        super(name, realName, codePath, resourcePath, nativeLibraryPathString, requiredCpuAbiString, pVersionCode,
                 pkgFlags);
         this.sharedId = sharedId;
     }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index d1e34a1..80f716c 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -217,10 +217,10 @@
 
     PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,
             String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
-            String nativeLibraryPathString, int pkgFlags, UserHandle user, boolean add) {
+            String nativeLibraryPathString, String requiredCpuAbiString, int pkgFlags, UserHandle user, boolean add) {
         final String name = pkg.packageName;
         PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath,
-                resourcePath, nativeLibraryPathString, pkg.mVersionCode, pkgFlags,
+                resourcePath, nativeLibraryPathString, requiredCpuAbiString, pkg.mVersionCode, pkgFlags,
                 user, add, true /* allowInstall */);
         return p;
     }
@@ -302,7 +302,7 @@
             p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
         }
         PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath,
-                p.nativeLibraryPathString, p.appId, p.versionCode, p.pkgFlags);
+                p.nativeLibraryPathString, p.requiredCpuAbiString, p.appId, p.versionCode, p.pkgFlags);
         mDisabledSysPackages.remove(name);
         return ret;
     }
@@ -316,7 +316,7 @@
     }
 
     PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
-            String nativeLibraryPathString, int uid, int vc, int pkgFlags) {
+            String nativeLibraryPathString, String requiredCpuAbiString, int uid, int vc, int pkgFlags) {
         PackageSetting p = mPackages.get(name);
         if (p != null) {
             if (p.appId == uid) {
@@ -326,7 +326,7 @@
                     "Adding duplicate package, keeping first: " + name);
             return null;
         }
-        p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString,
+        p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString, requiredCpuAbiString,
                 vc, pkgFlags);
         p.appId = uid;
         if (addUserIdLPw(uid, p, name)) {
@@ -395,10 +395,11 @@
 
     private PackageSetting getPackageLPw(String name, PackageSetting origPackage,
             String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
-            String nativeLibraryPathString, int vc, int pkgFlags,
+            String nativeLibraryPathString, String requiredCpuAbiString, int vc, int pkgFlags,
             UserHandle installUser, boolean add, boolean allowInstall) {
         PackageSetting p = mPackages.get(name);
         if (p != null) {
+            p.requiredCpuAbiString = requiredCpuAbiString;
             if (!p.codePath.equals(codePath)) {
                 // Check to see if its a disabled system app
                 if ((p.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
@@ -442,7 +443,7 @@
             if (origPackage != null) {
                 // We are consuming the data from an existing package.
                 p = new PackageSetting(origPackage.name, name, codePath, resourcePath,
-                        nativeLibraryPathString, vc, pkgFlags);
+                        nativeLibraryPathString, requiredCpuAbiString, vc, pkgFlags);
                 if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
                         + name + " is adopting original package " + origPackage.name);
                 // Note that we will retain the new package's signature so
@@ -459,7 +460,7 @@
                 p.setTimeStamp(codePath.lastModified());
             } else {
                 p = new PackageSetting(name, realName, codePath, resourcePath,
-                        nativeLibraryPathString, vc, pkgFlags);
+                        nativeLibraryPathString, requiredCpuAbiString, vc, pkgFlags);
                 p.setTimeStamp(codePath.lastModified());
                 p.sharedUser = sharedUser;
                 // If this is not a system app, it starts out stopped.
@@ -585,6 +586,8 @@
                 && !nativeLibraryPath.equalsIgnoreCase(p.nativeLibraryPathString)) {
             p.nativeLibraryPathString = nativeLibraryPath;
         }
+        // Update the required Cpu Abi
+        p.requiredCpuAbiString = pkg.applicationInfo.requiredCpuAbi;
         // Update version code if needed
         if (pkg.mVersionCode != p.versionCode) {
             p.versionCode = pkg.mVersionCode;
@@ -1551,6 +1554,9 @@
         if (pkg.nativeLibraryPathString != null) {
             serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString);
         }
+        if (pkg.requiredCpuAbiString != null) {
+           serializer.attribute(null, "requiredCpuAbi", pkg.requiredCpuAbiString);
+        }
         if (pkg.sharedUser == null) {
             serializer.attribute(null, "userId", Integer.toString(pkg.appId));
         } else {
@@ -1593,6 +1599,9 @@
         if (pkg.nativeLibraryPathString != null) {
             serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString);
         }
+        if (pkg.requiredCpuAbiString != null) {
+           serializer.attribute(null, "requiredCpuAbi", pkg.requiredCpuAbiString);
+        }
         serializer.attribute(null, "flags", Integer.toString(pkg.pkgFlags));
         serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
         serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
@@ -1861,7 +1870,7 @@
             if (idObj != null && idObj instanceof SharedUserSetting) {
                 PackageSetting p = getPackageLPw(pp.name, null, pp.realName,
                         (SharedUserSetting) idObj, pp.codePath, pp.resourcePath,
-                        pp.nativeLibraryPathString, pp.versionCode, pp.pkgFlags,
+                        pp.nativeLibraryPathString, pp.requiredCpuAbiString, pp.versionCode, pp.pkgFlags,
                         null, true /* add */, false /* allowInstall */);
                 if (p == null) {
                     PackageManagerService.reportSettingsProblem(Log.WARN,
@@ -2281,6 +2290,8 @@
         String codePathStr = parser.getAttributeValue(null, "codePath");
         String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
         String nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
+        String requiredCpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi");
+
         if (resourcePathStr == null) {
             resourcePathStr = codePathStr;
         }
@@ -2300,7 +2311,7 @@
             pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED;
         }
         PackageSetting ps = new PackageSetting(name, realName, codePathFile,
-                new File(resourcePathStr), nativeLibraryPathStr, versionCode, pkgFlags);
+                new File(resourcePathStr), nativeLibraryPathStr, requiredCpuAbiString, versionCode, pkgFlags);
         String timeStampStr = parser.getAttributeValue(null, "ft");
         if (timeStampStr != null) {
             try {
@@ -2367,6 +2378,7 @@
         String codePathStr = null;
         String resourcePathStr = null;
         String nativeLibraryPathStr = null;
+        String requiredCpuAbiString = null;
         String systemStr = null;
         String installerPackageName = null;
         String uidError = null;
@@ -2386,6 +2398,8 @@
             codePathStr = parser.getAttributeValue(null, "codePath");
             resourcePathStr = parser.getAttributeValue(null, "resourcePath");
             nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
+            requiredCpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi");
+
             version = parser.getAttributeValue(null, "version");
             if (version != null) {
                 try {
@@ -2462,7 +2476,7 @@
                                 + parser.getPositionDescription());
             } else if (userId > 0) {
                 packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
-                        new File(resourcePathStr), nativeLibraryPathStr, userId, versionCode,
+                        new File(resourcePathStr), nativeLibraryPathStr, requiredCpuAbiString, userId, versionCode,
                         pkgFlags);
                 if (PackageManagerService.DEBUG_SETTINGS)
                     Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId="
@@ -2480,7 +2494,7 @@
                 userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
                 if (userId > 0) {
                     packageSetting = new PendingPackage(name.intern(), realName, new File(
-                            codePathStr), new File(resourcePathStr), nativeLibraryPathStr, userId,
+                            codePathStr), new File(resourcePathStr), nativeLibraryPathStr, requiredCpuAbiString, userId,
                             versionCode, pkgFlags);
                     packageSetting.setTimeStamp(timeStamp);
                     packageSetting.firstInstallTime = firstInstallTime;
@@ -2509,6 +2523,7 @@
             packageSetting.uidError = "true".equals(uidError);
             packageSetting.installerPackageName = installerPackageName;
             packageSetting.nativeLibraryPathString = nativeLibraryPathStr;
+            packageSetting.requiredCpuAbiString = requiredCpuAbiString;
             // Handle legacy string here for single-user mode
             final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
             if (enabledStr != null) {
@@ -3008,6 +3023,7 @@
         pw.print(prefix); pw.print("  codePath="); pw.println(ps.codePathString);
         pw.print(prefix); pw.print("  resourcePath="); pw.println(ps.resourcePathString);
         pw.print(prefix); pw.print("  nativeLibraryPath="); pw.println(ps.nativeLibraryPathString);
+        pw.print(prefix); pw.print("  requiredCpuAbi="); pw.println(ps.requiredCpuAbiString);
         pw.print(prefix); pw.print("  versionCode="); pw.print(ps.versionCode);
         if (ps.pkg != null) {
             pw.print(" targetSdk="); pw.print(ps.pkg.applicationInfo.targetSdkVersion);
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 972b088..79c4a50 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -151,8 +151,11 @@
 
     private void removeUser(int userId) {
         synchronized (mLock) {
+            UserState userState = mUserStates.get(userId);
+            if (userState == null) {
+                return;
+            }
             // Release created sessions.
-            UserState userState = getUserStateLocked(userId);
             for (SessionState state : userState.sessionStateMap.values()) {
                 if (state.session != null) {
                     try {
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
index 2ef3d5f..7c3ab6f 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
@@ -115,6 +115,7 @@
                         "android.database.ContentObserver", // for Digital clock
                         "com.android.i18n.phonenumbers.*",  // for TextView with autolink attribute
                         "android.app.DatePickerDialog",     // b.android.com/28318
+                        "android.app.TimePickerDialog",     // b.android.com/61515
                     },
                     excludeClasses,
                     new String[] {