Merge "Corp badging for Recents"
diff --git a/Android.mk b/Android.mk
index 84d5dc5..adc9ef1 100644
--- a/Android.mk
+++ b/Android.mk
@@ -420,6 +420,8 @@
 	frameworks/base/core/java/android/view/MotionEvent.aidl \
 	frameworks/base/core/java/android/view/Surface.aidl \
 	frameworks/base/core/java/android/view/WindowManager.aidl \
+	frameworks/base/core/java/android/view/WindowAnimationFrameStats.aidl \
+	frameworks/base/core/java/android/view/WindowContentFrameStats.aidl \
 	frameworks/base/core/java/android/widget/RemoteViews.aidl \
 	frameworks/base/core/java/com/android/internal/textservice/ISpellCheckerService.aidl \
 	frameworks/base/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl \
diff --git a/api/current.txt b/api/current.txt
index 3230bd8..7de59d5e 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
@@ -4452,6 +4453,7 @@
     ctor public Notification.Builder(android.content.Context);
     method public android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
     method public android.app.Notification.Builder addExtras(android.os.Bundle);
+    method public android.app.Notification.Builder addPerson(java.lang.String);
     method public android.app.Notification build();
     method public android.os.Bundle getExtras();
     method public deprecated android.app.Notification getNotification();
@@ -4750,9 +4752,13 @@
   }
 
   public final class UiAutomation {
+    method public void clearWindowAnimationFrameStats();
+    method public boolean clearWindowContentFrameStats(int);
     method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
     method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
+    method public android.view.WindowAnimationFrameStats getWindowAnimationFrameStats();
+    method public android.view.WindowContentFrameStats getWindowContentFrameStats(int);
     method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
     method public boolean injectInputEvent(android.view.InputEvent, boolean);
     method public final boolean performGlobalAction(int);
@@ -10632,6 +10638,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 +10916,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 +11007,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 {
@@ -11020,8 +11031,6 @@
     method public void setAnimationFraction(float);
     method public void setColorFilter(android.graphics.ColorFilter);
     method public void setDuration(long);
-    method public void setIntrinsicHeight(int);
-    method public void setIntrinsicWidth(int);
     method public void setPadding(android.graphics.Rect);
     method public void setPadding(int, int, int, int);
     method public void setRepeatCount(int);
@@ -11721,6 +11730,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
@@ -28437,6 +28447,18 @@
     method public static android.view.FocusFinder getInstance();
   }
 
+  public abstract class FrameStats {
+    ctor public FrameStats();
+    method public final long getEndTimeNano();
+    method public final int getFrameCount();
+    method public final long getFramePresentedTimeNano(int);
+    method public final long getRefreshPeriodNano();
+    method public final long getStartTimeNano();
+    field public static final long UNDEFINED_TIME_NANO = -1L; // 0xffffffffffffffffL
+    field protected long[] mFramesPresentedTimeNano;
+    field protected long mRefreshPeriodNano;
+  }
+
   public class GestureDetector {
     ctor public deprecated GestureDetector(android.view.GestureDetector.OnGestureListener, android.os.Handler);
     ctor public deprecated GestureDetector(android.view.GestureDetector.OnGestureListener);
@@ -30761,6 +30783,20 @@
     method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
   }
 
+  public final class WindowAnimationFrameStats extends android.view.FrameStats implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public final class WindowContentFrameStats extends android.view.FrameStats implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getFramePostedTimeNano(int);
+    method public long getFrameReadyTimeNano(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
   public class WindowId implements android.os.Parcelable {
     method public int describeContents();
     method public boolean isFocused();
diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl
index 09bf829..347de97 100644
--- a/core/java/android/app/IUiAutomationConnection.aidl
+++ b/core/java/android/app/IUiAutomationConnection.aidl
@@ -19,6 +19,8 @@
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.graphics.Bitmap;
 import android.view.InputEvent;
+import android.view.WindowContentFrameStats;
+import android.view.WindowAnimationFrameStats;
 import android.os.ParcelFileDescriptor;
 
 /**
@@ -26,7 +28,7 @@
  * on behalf of an instrumentation that it runs. These operations require
  * special permissions which the shell user has but the instrumentation does
  * not. Running privileged operations by the shell user on behalf of an
- * instrumentation is needed for running UiTestCases. 
+ * instrumentation is needed for running UiTestCases.
  *
  * {@hide}
  */
@@ -37,4 +39,8 @@
     boolean setRotation(int rotation);
     Bitmap takeScreenshot(int width, int height);
     void shutdown();
+    boolean clearWindowContentFrameStats(int windowId);
+    WindowContentFrameStats getWindowContentFrameStats(int windowId);
+    void clearWindowAnimationFrameStats();
+    WindowAnimationFrameStats getWindowAnimationFrameStats();
 }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 36d2635..fe629f6 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1311,6 +1311,7 @@
         private Notification mPublicVersion = null;
         private boolean mQuantumTheme;
         private final LegacyNotificationUtil mLegacyNotificationUtil;
+        private ArrayList<String> mPeople;
 
         /**
          * Constructs a new Builder with the defaults:
@@ -1338,6 +1339,7 @@
             mWhen = System.currentTimeMillis();
             mAudioStreamType = STREAM_DEFAULT;
             mPriority = PRIORITY_DEFAULT;
+            mPeople = new ArrayList<String>();
 
             // TODO: Decide on targetSdk from calling app whether to use quantum theme.
             mQuantumTheme = true;
@@ -1723,6 +1725,16 @@
         }
 
         /**
+         * Add a person that is relevant to this notification.
+         *
+         * @see Notification#EXTRA_PEOPLE
+         */
+        public Builder addPerson(String handle) {
+            mPeople.add(handle);
+            return this;
+        }
+
+        /**
          * Merge additional metadata into this notification.
          *
          * <p>Values within the Bundle will replace existing extras values in this Builder.
@@ -2149,6 +2161,9 @@
             if (mLargeIcon != null) {
                 extras.putParcelable(EXTRA_LARGE_ICON, mLargeIcon);
             }
+            if (!mPeople.isEmpty()) {
+                extras.putStringArray(EXTRA_PEOPLE, mPeople.toArray(new String[mPeople.size()]));
+            }
         }
 
         /**
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 354a19f..8523d0c 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -33,6 +33,8 @@
 import android.view.InputEvent;
 import android.view.KeyEvent;
 import android.view.Surface;
+import android.view.WindowAnimationFrameStats;
+import android.view.WindowContentFrameStats;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityInteractionClient;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -674,6 +676,148 @@
         }
     }
 
+    /**
+     * Clears the frame statistics for the content of a given window. These
+     * statistics contain information about the most recently rendered content
+     * frames.
+     *
+     * @param windowId The window id.
+     * @return Whether the window is present and its frame statistics
+     *         were cleared.
+     *
+     * @see android.view.WindowContentFrameStats
+     * @see #getWindowContentFrameStats(int)
+     * @see #getWindows()
+     * @see AccessibilityWindowInfo#getId() AccessibilityWindowInfo.getId()
+     */
+    public boolean clearWindowContentFrameStats(int windowId) {
+        synchronized (mLock) {
+            throwIfNotConnectedLocked();
+        }
+        try {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "Clearing content frame stats for window: " + windowId);
+            }
+            // Calling out without a lock held.
+            return mUiAutomationConnection.clearWindowContentFrameStats(windowId);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error clearing window content frame stats!", re);
+        }
+        return false;
+    }
+
+    /**
+     * Gets the frame statistics for a given window. These statistics contain
+     * information about the most recently rendered content frames.
+     * <p>
+     * A typical usage requires clearing the window frame statistics via {@link
+     * #clearWindowContentFrameStats(int)} followed by an interaction with the UI and
+     * finally getting the window frame statistics via calling this method.
+     * </p>
+     * <pre>
+     * // Assume we have at least one window.
+     * final int windowId = getWindows().get(0).getId();
+     *
+     * // Start with a clean slate.
+     * uiAutimation.clearWindowContentFrameStats(windowId);
+     *
+     * // Do stuff with the UI.
+     *
+     * // Get the frame statistics.
+     * WindowContentFrameStats stats = uiAutomation.getWindowContentFrameStats(windowId);
+     * </pre>
+     *
+     * @param windowId The window id.
+     * @return The window frame statistics, or null if the window is not present.
+     *
+     * @see android.view.WindowContentFrameStats
+     * @see #clearWindowContentFrameStats(int)
+     * @see #getWindows()
+     * @see AccessibilityWindowInfo#getId() AccessibilityWindowInfo.getId()
+     */
+    public WindowContentFrameStats getWindowContentFrameStats(int windowId) {
+        synchronized (mLock) {
+            throwIfNotConnectedLocked();
+        }
+        try {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "Getting content frame stats for window: " + windowId);
+            }
+            // Calling out without a lock held.
+            return mUiAutomationConnection.getWindowContentFrameStats(windowId);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error getting window content frame stats!", re);
+        }
+        return null;
+    }
+
+    /**
+     * Clears the window animation rendering statistics. These statistics contain
+     * information about the most recently rendered window animation frames, i.e.
+     * for window transition animations.
+     *
+     * @see android.view.WindowAnimationFrameStats
+     * @see #getWindowAnimationFrameStats()
+     * @see android.R.styleable#WindowAnimation
+     */
+    public void clearWindowAnimationFrameStats() {
+        synchronized (mLock) {
+            throwIfNotConnectedLocked();
+        }
+        try {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "Clearing window animation frame stats");
+            }
+            // Calling out without a lock held.
+            mUiAutomationConnection.clearWindowAnimationFrameStats();
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error clearing window animation frame stats!", re);
+        }
+    }
+
+    /**
+     * Gets the window animation frame statistics. These statistics contain
+     * information about the most recently rendered window animation frames, i.e.
+     * for window transition animations.
+     *
+     * <p>
+     * A typical usage requires clearing the window animation frame statistics via
+     * {@link #clearWindowAnimationFrameStats()} followed by an interaction that causes
+     * a window transition which uses a window animation and finally getting the window
+     * animation frame statistics by calling this method.
+     * </p>
+     * <pre>
+     * // Start with a clean slate.
+     * uiAutimation.clearWindowAnimationFrameStats();
+     *
+     * // Do stuff to trigger a window transition.
+     *
+     * // Get the frame statistics.
+     * WindowAnimationFrameStats stats = uiAutomation.getWindowAnimationFrameStats();
+     * </pre>
+     *
+     * @return The window animation frame statistics.
+     *
+     * @see android.view.WindowAnimationFrameStats
+     * @see #clearWindowAnimationFrameStats()
+     * @see android.R.styleable#WindowAnimation
+     */
+    public WindowAnimationFrameStats getWindowAnimationFrameStats() {
+        synchronized (mLock) {
+            throwIfNotConnectedLocked();
+        }
+        try {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "Getting window animation frame stats");
+            }
+            // Calling out without a lock held.
+            return mUiAutomationConnection.getWindowAnimationFrameStats();
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error getting window animation frame stats!", re);
+        }
+        return null;
+    }
+
     private static float getDegreesForRotation(int value) {
         switch (value) {
             case Surface.ROTATION_90: {
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 91b0d7c..fa40286 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -22,12 +22,15 @@
 import android.graphics.Bitmap;
 import android.hardware.input.InputManager;
 import android.os.Binder;
+import android.os.IBinder;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.view.IWindowManager;
 import android.view.InputEvent;
 import android.view.SurfaceControl;
+import android.view.WindowAnimationFrameStats;
+import android.view.WindowContentFrameStats;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.IAccessibilityManager;
 
@@ -47,6 +50,9 @@
     private final IWindowManager mWindowManager = IWindowManager.Stub.asInterface(
             ServiceManager.getService(Service.WINDOW_SERVICE));
 
+    private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager.Stub.asInterface(
+            ServiceManager.getService(Service.ACCESSIBILITY_SERVICE));
+
     private final Object mLock = new Object();
 
     private final Binder mToken = new Binder();
@@ -144,6 +150,76 @@
     }
 
     @Override
+    public boolean clearWindowContentFrameStats(int windowId) throws RemoteException {
+        synchronized (mLock) {
+            throwIfCalledByNotTrustedUidLocked();
+            throwIfShutdownLocked();
+            throwIfNotConnectedLocked();
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            IBinder token = mAccessibilityManager.getWindowToken(windowId);
+            if (token == null) {
+                return false;
+            }
+            return mWindowManager.clearWindowContentFrameStats(token);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public WindowContentFrameStats getWindowContentFrameStats(int windowId) throws RemoteException {
+        synchronized (mLock) {
+            throwIfCalledByNotTrustedUidLocked();
+            throwIfShutdownLocked();
+            throwIfNotConnectedLocked();
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            IBinder token = mAccessibilityManager.getWindowToken(windowId);
+            if (token == null) {
+                return null;
+            }
+            return mWindowManager.getWindowContentFrameStats(token);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void clearWindowAnimationFrameStats() {
+        synchronized (mLock) {
+            throwIfCalledByNotTrustedUidLocked();
+            throwIfShutdownLocked();
+            throwIfNotConnectedLocked();
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            SurfaceControl.clearAnimationFrameStats();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public WindowAnimationFrameStats getWindowAnimationFrameStats() {
+        synchronized (mLock) {
+            throwIfCalledByNotTrustedUidLocked();
+            throwIfShutdownLocked();
+            throwIfNotConnectedLocked();
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            WindowAnimationFrameStats stats = new WindowAnimationFrameStats();
+            SurfaceControl.getAnimationFrameStats(stats);
+            return stats;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
     public void shutdown() {
         synchronized (mLock) {
             if (isConnectedLocked()) {
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/CaptureResultExtras.aidl b/core/java/android/hardware/camera2/CaptureResultExtras.aidl
new file mode 100644
index 0000000..6587f02
--- /dev/null
+++ b/core/java/android/hardware/camera2/CaptureResultExtras.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2;
+
+/** @hide */
+parcelable CaptureResultExtras;
diff --git a/core/java/android/hardware/camera2/CaptureResultExtras.java b/core/java/android/hardware/camera2/CaptureResultExtras.java
new file mode 100644
index 0000000..e5c2c1c
--- /dev/null
+++ b/core/java/android/hardware/camera2/CaptureResultExtras.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+public class CaptureResultExtras implements Parcelable {
+    private int requestId;
+    private int subsequenceId;
+    private int afTriggerId;
+    private int precaptureTriggerId;
+    private long frameNumber;
+
+    public static final Parcelable.Creator<CaptureResultExtras> CREATOR =
+            new Parcelable.Creator<CaptureResultExtras>() {
+        @Override
+        public CaptureResultExtras createFromParcel(Parcel in) {
+            return new CaptureResultExtras(in);
+        }
+
+        @Override
+        public CaptureResultExtras[] newArray(int size) {
+            return new CaptureResultExtras[size];
+        }
+    };
+
+    private CaptureResultExtras(Parcel in) {
+        readFromParcel(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(requestId);
+        dest.writeInt(subsequenceId);
+        dest.writeInt(afTriggerId);
+        dest.writeInt(precaptureTriggerId);
+        dest.writeLong(frameNumber);
+    }
+
+    public void readFromParcel(Parcel in) {
+        requestId = in.readInt();
+        subsequenceId = in.readInt();
+        afTriggerId = in.readInt();
+        precaptureTriggerId = in.readInt();
+        frameNumber = in.readLong();
+    }
+
+    public int getRequestId() {
+        return requestId;
+    }
+
+    public int getSubsequenceId() {
+        return subsequenceId;
+    }
+
+    public int getAfTriggerId() {
+        return afTriggerId;
+    }
+
+    public int getPrecaptureTriggerId() {
+        return precaptureTriggerId;
+    }
+
+    public long getFrameNumber() {
+        return frameNumber;
+    }
+
+}
diff --git a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index 02a73d66..a14d38b 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -17,6 +17,7 @@
 package android.hardware.camera2;
 
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.CaptureResultExtras;
 
 /** @hide */
 interface ICameraDeviceCallbacks
@@ -25,8 +26,9 @@
      * Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
      */
 
-    oneway void onCameraError(int errorCode);
+    oneway void onCameraError(int errorCode, in CaptureResultExtras resultExtras);
     oneway void onCameraIdle();
-    oneway void onCaptureStarted(int requestId, long timestamp);
-    oneway void onResultReceived(int requestId, in CameraMetadataNative result);
+    oneway void onCaptureStarted(in CaptureResultExtras resultExtras, long timestamp);
+    oneway void onResultReceived(in CameraMetadataNative result,
+                                 in CaptureResultExtras resultExtras);
 }
diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
index 1936963..d77f3d1 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -20,6 +20,8 @@
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.CaptureRequest;
 
+import android.hardware.camera2.LongParcelable;
+
 /** @hide */
 interface ICameraDeviceUser
 {
@@ -31,9 +33,13 @@
     // ints here are status_t
 
     // non-negative value is the requestId. negative value is status_t
-    int submitRequest(in CaptureRequest request, boolean streaming);
+    int submitRequest(in CaptureRequest request, boolean streaming,
+                      out LongParcelable lastFrameNumber);
 
-    int cancelRequest(int requestId);
+    int submitRequestList(in List<CaptureRequest> requestList, boolean streaming,
+                          out LongParcelable lastFrameNumber);
+
+    int cancelRequest(int requestId, out LongParcelable lastFrameNumber);
 
     int deleteStream(int streamId);
 
@@ -46,5 +52,5 @@
 
     int waitUntilIdle();
 
-    int flush();
+    int flush(out LongParcelable lastFrameNumber);
 }
diff --git a/core/java/android/hardware/camera2/LongParcelable.aidl b/core/java/android/hardware/camera2/LongParcelable.aidl
new file mode 100644
index 0000000..7d7e51b
--- /dev/null
+++ b/core/java/android/hardware/camera2/LongParcelable.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2;
+
+/** @hide */
+parcelable LongParcelable;
\ No newline at end of file
diff --git a/core/java/android/hardware/camera2/LongParcelable.java b/core/java/android/hardware/camera2/LongParcelable.java
new file mode 100644
index 0000000..97b0631
--- /dev/null
+++ b/core/java/android/hardware/camera2/LongParcelable.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+public class LongParcelable implements Parcelable {
+    private long number;
+
+    public LongParcelable() {
+        this.number = 0;
+    }
+
+    public LongParcelable(long number) {
+        this.number = number;
+    }
+
+    public static final Parcelable.Creator<LongParcelable> CREATOR =
+            new Parcelable.Creator<LongParcelable>() {
+        @Override
+        public LongParcelable createFromParcel(Parcel in) {
+            return new LongParcelable(in);
+        }
+
+        @Override
+        public LongParcelable[] newArray(int size) {
+            return new LongParcelable[size];
+        }
+    };
+
+    private LongParcelable(Parcel in) {
+        readFromParcel(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(number);
+    }
+
+    public void readFromParcel(Parcel in) {
+        number = in.readLong();
+    }
+
+    public long getNumber() {
+        return number;
+    }
+
+    public void setNumber(long number) {
+        this.number = number;
+    }
+
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index ecc461e..cd44b51 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -21,8 +21,10 @@
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.CaptureResultExtras;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.LongParcelable;
 import android.hardware.camera2.utils.CameraBinderDecorator;
 import android.hardware.camera2.utils.CameraRuntimeException;
 import android.os.Handler;
@@ -33,10 +35,12 @@
 import android.util.SparseArray;
 import android.view.Surface;
 
+import java.util.AbstractMap.SimpleEntry;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.TreeSet;
 
 /**
  * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
@@ -69,10 +73,24 @@
 
     private final String mCameraId;
 
+    /**
+     * A list tracking request and its expected last frame.
+     * Updated when calling ICameraDeviceUser methods.
+     */
+    private final List<SimpleEntry</*frameNumber*/Long, /*requestId*/Integer>>
+            mFrameNumberRequestPairs = new ArrayList<SimpleEntry<Long, Integer>>();
+
+    /**
+     * An object tracking received frame numbers.
+     * Updated when receiving callbacks from ICameraDeviceCallbacks.
+     */
+    private final FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker();
+
     // Runnables for all state transitions, except error, which needs the
     // error code argument
 
     private final Runnable mCallOnOpened = new Runnable() {
+        @Override
         public void run() {
             if (!CameraDevice.this.isClosed()) {
                 mDeviceListener.onOpened(CameraDevice.this);
@@ -81,6 +99,7 @@
     };
 
     private final Runnable mCallOnUnconfigured = new Runnable() {
+        @Override
         public void run() {
             if (!CameraDevice.this.isClosed()) {
                 mDeviceListener.onUnconfigured(CameraDevice.this);
@@ -89,6 +108,7 @@
     };
 
     private final Runnable mCallOnActive = new Runnable() {
+        @Override
         public void run() {
             if (!CameraDevice.this.isClosed()) {
                 mDeviceListener.onActive(CameraDevice.this);
@@ -97,6 +117,7 @@
     };
 
     private final Runnable mCallOnBusy = new Runnable() {
+        @Override
         public void run() {
             if (!CameraDevice.this.isClosed()) {
                 mDeviceListener.onBusy(CameraDevice.this);
@@ -105,12 +126,14 @@
     };
 
     private final Runnable mCallOnClosed = new Runnable() {
+        @Override
         public void run() {
             mDeviceListener.onClosed(CameraDevice.this);
         }
     };
 
     private final Runnable mCallOnIdle = new Runnable() {
+        @Override
         public void run() {
             if (!CameraDevice.this.isClosed()) {
                 mDeviceListener.onIdle(CameraDevice.this);
@@ -119,6 +142,7 @@
     };
 
     private final Runnable mCallOnDisconnected = new Runnable() {
+        @Override
         public void run() {
             if (!CameraDevice.this.isClosed()) {
                 mDeviceListener.onDisconnected(CameraDevice.this);
@@ -249,22 +273,26 @@
     @Override
     public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
             throws CameraAccessException {
-        return submitCaptureRequest(request, listener, handler, /*streaming*/false);
+        if (DEBUG) {
+            Log.d(TAG, "calling capture");
+        }
+        List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
+        requestList.add(request);
+        return submitCaptureRequest(requestList, listener, handler, /*streaming*/false);
     }
 
     @Override
     public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
             Handler handler) throws CameraAccessException {
+        // TODO: remove this. Throw IAE if the request is null or empty. Need to update API doc.
         if (requests.isEmpty()) {
             Log.w(TAG, "Capture burst request list is empty, do nothing!");
             return -1;
         }
-        // TODO
-        throw new UnsupportedOperationException("Burst capture implemented yet");
-
+        return submitCaptureRequest(requests, listener, handler, /*streaming*/false);
     }
 
-    private int submitCaptureRequest(CaptureRequest request, CaptureListener listener,
+    private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureListener listener,
             Handler handler, boolean repeating) throws CameraAccessException {
 
         // Need a valid handler, or current thread needs to have a looper, if
@@ -281,8 +309,13 @@
                 stopRepeating();
             }
 
+            LongParcelable lastFrameNumberRef = new LongParcelable();
             try {
-                requestId = mRemoteDevice.submitRequest(request, repeating);
+                requestId = mRemoteDevice.submitRequestList(requestList, repeating,
+                        /*out*/lastFrameNumberRef);
+                if (!repeating) {
+                    Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
+                }
             } catch (CameraRuntimeException e) {
                 throw e.asChecked();
             } catch (RemoteException e) {
@@ -290,12 +323,29 @@
                 return -1;
             }
             if (listener != null) {
-                mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener, request,
-                        handler, repeating));
+                mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener,
+                        requestList, handler, repeating));
             }
 
+            long lastFrameNumber = lastFrameNumberRef.getNumber();
+            /**
+             * If it's the first repeating request, then returned lastFrameNumber can be
+             * negative. Otherwise, it should always be non-negative.
+             */
+            if (((lastFrameNumber < 0) && (requestId > 0))
+                    || ((lastFrameNumber < 0) && (!repeating))) {
+                throw new AssertionError(String.format("returned bad frame number %d",
+                        lastFrameNumber));
+            }
             if (repeating) {
+                if (mRepeatingRequestId != REQUEST_ID_NONE) {
+                    mFrameNumberRequestPairs.add(
+                            new SimpleEntry<Long, Integer>(lastFrameNumber, mRepeatingRequestId));
+                }
                 mRepeatingRequestId = requestId;
+            } else {
+                mFrameNumberRequestPairs.add(
+                        new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
             }
 
             if (mIdle) {
@@ -310,18 +360,20 @@
     @Override
     public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
             Handler handler) throws CameraAccessException {
-        return submitCaptureRequest(request, listener, handler, /*streaming*/true);
+        List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
+        requestList.add(request);
+        return submitCaptureRequest(requestList, listener, handler, /*streaming*/true);
     }
 
     @Override
     public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
             Handler handler) throws CameraAccessException {
+        // TODO: remove this. Throw IAE if the request is null or empty. Need to update API doc.
         if (requests.isEmpty()) {
             Log.w(TAG, "Set Repeating burst request list is empty, do nothing!");
             return -1;
         }
-        // TODO
-        throw new UnsupportedOperationException("Burst capture implemented yet");
+        return submitCaptureRequest(requests, listener, handler, /*streaming*/true);
     }
 
     @Override
@@ -340,7 +392,15 @@
                 }
 
                 try {
-                    mRemoteDevice.cancelRequest(requestId);
+                    LongParcelable lastFrameNumberRef = new LongParcelable();
+                    mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
+                    long lastFrameNumber = lastFrameNumberRef.getNumber();
+                    if ((lastFrameNumber < 0) && (requestId > 0)) {
+                        throw new AssertionError(String.format("returned bad frame number %d",
+                                lastFrameNumber));
+                    }
+                    mFrameNumberRequestPairs.add(
+                            new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
                 } catch (CameraRuntimeException e) {
                     throw e.asChecked();
                 } catch (RemoteException e) {
@@ -379,7 +439,17 @@
 
             mDeviceHandler.post(mCallOnBusy);
             try {
-                mRemoteDevice.flush();
+                LongParcelable lastFrameNumberRef = new LongParcelable();
+                mRemoteDevice.flush(/*out*/lastFrameNumberRef);
+                if (mRepeatingRequestId != REQUEST_ID_NONE) {
+                    long lastFrameNumber = lastFrameNumberRef.getNumber();
+                    if (lastFrameNumber < 0) {
+                        Log.e(TAG, String.format("returned bad frame number %d", lastFrameNumber));
+                    }
+                    mFrameNumberRequestPairs.add(
+                            new SimpleEntry<Long, Integer>(lastFrameNumber, mRepeatingRequestId));
+                    mRepeatingRequestId = REQUEST_ID_NONE;
+                }
             } catch (CameraRuntimeException e) {
                 throw e.asChecked();
             } catch (RemoteException e) {
@@ -425,18 +495,18 @@
 
         private final boolean mRepeating;
         private final CaptureListener mListener;
-        private final CaptureRequest mRequest;
+        private final List<CaptureRequest> mRequestList;
         private final Handler mHandler;
 
-        CaptureListenerHolder(CaptureListener listener, CaptureRequest request, Handler handler,
-                boolean repeating) {
+        CaptureListenerHolder(CaptureListener listener, List<CaptureRequest> requestList,
+                Handler handler, boolean repeating) {
             if (listener == null || handler == null) {
                 throw new UnsupportedOperationException(
                     "Must have a valid handler and a valid listener");
             }
             mRepeating = repeating;
             mHandler = handler;
-            mRequest = request;
+            mRequestList = new ArrayList<CaptureRequest>(requestList);
             mListener = listener;
         }
 
@@ -448,8 +518,24 @@
             return mListener;
         }
 
+        public CaptureRequest getRequest(int subsequenceId) {
+            if (subsequenceId >= mRequestList.size()) {
+                throw new IllegalArgumentException(
+                        String.format(
+                                "Requested subsequenceId %d is larger than request list size %d.",
+                                subsequenceId, mRequestList.size()));
+            } else {
+                if (subsequenceId < 0) {
+                    throw new IllegalArgumentException(String.format(
+                            "Requested subsequenceId %d is negative", subsequenceId));
+                } else {
+                    return mRequestList.get(subsequenceId);
+                }
+            }
+        }
+
         public CaptureRequest getRequest() {
-            return mRequest;
+            return getRequest(0);
         }
 
         public Handler getHandler() {
@@ -458,6 +544,105 @@
 
     }
 
+    /**
+     * This class tracks the last frame number for submitted requests.
+     */
+    public class FrameNumberTracker {
+
+        private long mCompletedFrameNumber = -1;
+        private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>();
+
+        private void update() {
+            Iterator<Long> iter = mFutureErrorSet.iterator();
+            while (iter.hasNext()) {
+                long errorFrameNumber = iter.next();
+                if (errorFrameNumber == mCompletedFrameNumber + 1) {
+                    mCompletedFrameNumber++;
+                    iter.remove();
+                } else {
+                    break;
+                }
+            }
+        }
+
+        /**
+         * This function is called every time when a result or an error is received.
+         * @param frameNumber: the frame number corresponding to the result or error
+         * @param isError: true if it is an error, false if it is not an error
+         */
+        public void updateTracker(long frameNumber, boolean isError) {
+            if (isError) {
+                mFutureErrorSet.add(frameNumber);
+            } else {
+                /**
+                 * HAL cannot send an OnResultReceived for frame N unless it knows for
+                 * sure that all frames prior to N have either errored out or completed.
+                 * So if the current frame is not an error, then all previous frames
+                 * should have arrived. The following line checks whether this holds.
+                 */
+                if (frameNumber != mCompletedFrameNumber + 1) {
+                    throw new AssertionError(String.format(
+                            "result frame number %d comes out of order",
+                            frameNumber));
+                }
+                mCompletedFrameNumber++;
+            }
+            update();
+        }
+
+        public long getCompletedFrameNumber() {
+            return mCompletedFrameNumber;
+        }
+
+    }
+
+    private void checkAndFireSequenceComplete() {
+        long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
+        Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator();
+        while (iter.hasNext()) {
+            final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next();
+            if (frameNumberRequestPair.getKey() <= completedFrameNumber) {
+
+                // remove request from mCaptureListenerMap
+                final int requestId = frameNumberRequestPair.getValue();
+                final CaptureListenerHolder holder;
+                synchronized (mLock) {
+                    int index = CameraDevice.this.mCaptureListenerMap.indexOfKey(requestId);
+                    holder = (index >= 0) ? CameraDevice.this.mCaptureListenerMap.valueAt(index)
+                            : null;
+                    if (holder != null) {
+                        CameraDevice.this.mCaptureListenerMap.removeAt(index);
+                    }
+                }
+                iter.remove();
+
+                // Call onCaptureSequenceCompleted
+                if (holder != null) {
+                    Runnable resultDispatch = new Runnable() {
+                        @Override
+                        public void run() {
+                            if (!CameraDevice.this.isClosed()){
+                                if (DEBUG) {
+                                    Log.d(TAG, String.format(
+                                            "fire sequence complete for request %d",
+                                            requestId));
+                                }
+
+                                holder.getListener().onCaptureSequenceCompleted(
+                                    CameraDevice.this,
+                                    requestId,
+                                    // TODO: this is problematic, crop long to int
+                                    frameNumberRequestPair.getKey().intValue());
+                            }
+                        }
+                    };
+                    holder.getHandler().post(resultDispatch);
+                }
+
+            }
+        }
+    }
+
     public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
 
         //
@@ -492,7 +677,7 @@
         }
 
         @Override
-        public void onCameraError(final int errorCode) {
+        public void onCameraError(final int errorCode, CaptureResultExtras resultExtras) {
             Runnable r = null;
             if (isClosed()) return;
 
@@ -507,6 +692,7 @@
                     case ERROR_CAMERA_DEVICE:
                     case ERROR_CAMERA_SERVICE:
                         r = new Runnable() {
+                            @Override
                             public void run() {
                                 if (!CameraDevice.this.isClosed()) {
                                     mDeviceListener.onError(CameraDevice.this, errorCode);
@@ -517,6 +703,11 @@
                 }
                 CameraDevice.this.mDeviceHandler.post(r);
             }
+
+            // Fire onCaptureSequenceCompleted
+            mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/true);
+            checkAndFireSequenceComplete();
+
         }
 
         @Override
@@ -535,7 +726,8 @@
         }
 
         @Override
-        public void onCaptureStarted(int requestId, final long timestamp) {
+        public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
+            int requestId = resultExtras.getRequestId();
             if (DEBUG) {
                 Log.d(TAG, "Capture started for id " + requestId);
             }
@@ -555,11 +747,12 @@
             // Dispatch capture start notice
             holder.getHandler().post(
                 new Runnable() {
+                    @Override
                     public void run() {
                         if (!CameraDevice.this.isClosed()) {
                             holder.getListener().onCaptureStarted(
                                 CameraDevice.this,
-                                holder.getRequest(),
+                                holder.getRequest(resultExtras.getSubsequenceId()),
                                 timestamp);
                         }
                     }
@@ -567,48 +760,18 @@
         }
 
         @Override
-        public void onResultReceived(int requestId, CameraMetadataNative result)
-                throws RemoteException {
+        public void onResultReceived(CameraMetadataNative result,
+                CaptureResultExtras resultExtras) throws RemoteException {
+            int requestId = resultExtras.getRequestId();
             if (DEBUG) {
                 Log.d(TAG, "Received result for id " + requestId);
             }
-            final CaptureListenerHolder holder;
+            final CaptureListenerHolder holder =
+                    CameraDevice.this.mCaptureListenerMap.get(requestId);
 
             Boolean quirkPartial = result.get(CaptureResult.QUIRKS_PARTIAL_RESULT);
             boolean quirkIsPartialResult = (quirkPartial != null && quirkPartial);
 
-            synchronized (mLock) {
-                // TODO: move this whole map into this class to make it more testable,
-                //        exposing the methods necessary like subscribeToRequest, unsubscribe..
-                // TODO: make class static class
-
-                holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
-
-                // Clean up listener once we no longer expect to see it.
-                if (holder != null && !holder.isRepeating() && !quirkIsPartialResult) {
-                    CameraDevice.this.mCaptureListenerMap.remove(requestId);
-                }
-
-                // TODO: add 'capture sequence completed' callback to the
-                // service, and clean up repeating requests there instead.
-
-                // If we received a result for a repeating request and have
-                // prior repeating requests queued for deletion, remove those
-                // requests from mCaptureListenerMap.
-                if (holder != null && holder.isRepeating() && !quirkIsPartialResult
-                        && mRepeatingRequestIdDeletedList.size() > 0) {
-                    Iterator<Integer> iter = mRepeatingRequestIdDeletedList.iterator();
-                    while (iter.hasNext()) {
-                        int deletedRequestId = iter.next();
-                        if (deletedRequestId < requestId) {
-                            CameraDevice.this.mCaptureListenerMap.remove(deletedRequestId);
-                            iter.remove();
-                        }
-                    }
-                }
-
-            }
-
             // Check if we have a listener for this
             if (holder == null) {
                 return;
@@ -616,7 +779,7 @@
 
             if (isClosed()) return;
 
-            final CaptureRequest request = holder.getRequest();
+            final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
             final CaptureResult resultAsCapture = new CaptureResult(result, request, requestId);
 
             Runnable resultDispatch = null;
@@ -651,6 +814,12 @@
             }
 
             holder.getHandler().post(resultDispatch);
+
+            // Fire onCaptureSequenceCompleted
+            if (!quirkIsPartialResult) {
+                mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/false);
+                checkAndFireSequenceComplete();
+            }
         }
 
     }
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/AnimationRenderStats.aidl b/core/java/android/view/AnimationRenderStats.aidl
new file mode 100644
index 0000000..4599708
--- /dev/null
+++ b/core/java/android/view/AnimationRenderStats.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+parcelable AnimationRenderStats;
diff --git a/core/java/android/view/FrameStats.java b/core/java/android/view/FrameStats.java
new file mode 100644
index 0000000..541b336
--- /dev/null
+++ b/core/java/android/view/FrameStats.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This is the base class for frame statistics.
+ */
+public abstract class FrameStats {
+    /**
+     * Undefined time.
+     */
+    public static final long UNDEFINED_TIME_NANO = -1;
+
+    protected long mRefreshPeriodNano;
+    protected long[] mFramesPresentedTimeNano;
+
+    /**
+     * Gets the refresh period of the display hosting the window(s) for
+     * which these statistics apply.
+     *
+     * @return The refresh period in nanoseconds.
+     */
+    public final long getRefreshPeriodNano() {
+        return mRefreshPeriodNano;
+    }
+
+    /**
+     * Gets the number of frames for which there is data.
+     *
+     * @return The number of frames.
+     */
+    public final int getFrameCount() {
+        return mFramesPresentedTimeNano != null
+                ? mFramesPresentedTimeNano.length : 0;
+    }
+
+    /**
+     * Gets the start time of the interval for which these statistics
+     * apply. The start interval is the time when the first frame was
+     * presented.
+     *
+     * @return The start time in nanoseconds or {@link #UNDEFINED_TIME_NANO}
+     *         if there is no frame data.
+     */
+    public final long getStartTimeNano() {
+        if (getFrameCount() <= 0) {
+            return UNDEFINED_TIME_NANO;
+        }
+        return mFramesPresentedTimeNano[0];
+    }
+
+    /**
+     * Gets the end time of the interval for which these statistics
+     * apply. The end interval is the time when the last frame was
+     * presented.
+     *
+     * @return The end time in nanoseconds or {@link #UNDEFINED_TIME_NANO}
+     *         if there is no frame data.
+     */
+    public final long getEndTimeNano() {
+        if (getFrameCount() <= 0) {
+            return UNDEFINED_TIME_NANO;
+        }
+        return mFramesPresentedTimeNano[mFramesPresentedTimeNano.length - 1];
+    }
+
+    /**
+     * Get the time a frame at a given index was presented.
+     *
+     * @param index The frame index.
+     * @return The presented time in nanoseconds or {@link #UNDEFINED_TIME_NANO}
+     *         if the frame is not presented yet.
+     */
+    public final long getFramePresentedTimeNano(int index) {
+        if (mFramesPresentedTimeNano == null) {
+            throw new IndexOutOfBoundsException();
+        }
+        return mFramesPresentedTimeNano[index];
+    }
+}
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index bcdfda6..eba4f7f 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -1226,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
@@ -1322,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);
@@ -1481,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 7d46cab..56d96e1 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -580,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/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 8f542bb..80d5bf2 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -37,6 +37,7 @@
 import android.view.InputChannel;
 import android.view.InputDevice;
 import android.view.IInputFilter;
+import android.view.WindowContentFrameStats;
 
 /**
  * System private interface to the window manager.
@@ -233,4 +234,20 @@
      * Device is in safe mode.
      */
     boolean isSafeModeEnabled();
+
+    /**
+     * Clears the frame statistics for a given window.
+     *
+     * @param token The window token.
+     * @return Whether the frame statistics were cleared.
+     */
+    boolean clearWindowContentFrameStats(IBinder token);
+
+    /**
+     * Gets the content frame statistics for a given window.
+     *
+     * @param token The window token.
+     * @return The frame statistics or null if the window does not exist.
+     */
+    WindowContentFrameStats getWindowContentFrameStats(IBinder token);
 }
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/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 5a8d2c8..2d55a01 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -20,7 +20,6 @@
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.Region;
-import android.view.Surface;
 import android.os.IBinder;
 import android.util.Log;
 import android.view.Surface.OutOfResourcesException;
@@ -59,6 +58,11 @@
     private static native void nativeSetWindowCrop(long nativeObject, int l, int t, int r, int b);
     private static native void nativeSetLayerStack(long nativeObject, int layerStack);
 
+    private static native boolean nativeClearContentFrameStats(long nativeObject);
+    private static native boolean nativeGetContentFrameStats(long nativeObject, WindowContentFrameStats outStats);
+    private static native boolean nativeClearAnimationFrameStats();
+    private static native boolean nativeGetAnimationFrameStats(WindowAnimationFrameStats outStats);
+
     private static native IBinder nativeGetBuiltInDisplay(int physicalDisplayId);
     private static native IBinder nativeCreateDisplay(String name, boolean secure);
     private static native void nativeDestroyDisplay(IBinder displayToken);
@@ -357,6 +361,24 @@
         nativeSetTransparentRegionHint(mNativeObject, region);
     }
 
+    public boolean clearContentFrameStats() {
+        checkNotReleased();
+        return nativeClearContentFrameStats(mNativeObject);
+    }
+
+    public boolean getContentFrameStats(WindowContentFrameStats outStats) {
+        checkNotReleased();
+        return nativeGetContentFrameStats(mNativeObject, outStats);
+    }
+
+    public static boolean clearAnimationFrameStats() {
+        return nativeClearAnimationFrameStats();
+    }
+
+    public static boolean getAnimationFrameStats(WindowAnimationFrameStats outStats) {
+        return nativeGetAnimationFrameStats(outStats);
+    }
+
     /**
      * Sets an alpha value for the entire Surface.  This value is combined with the
      * per-pixel alpha.  It may be used with opaque Surfaces.
@@ -542,7 +564,6 @@
         return nativeGetBuiltInDisplay(builtInDisplayId);
     }
 
-
     /**
      * Copy the current screen contents into the provided {@link Surface}
      *
@@ -592,7 +613,6 @@
         screenshot(display, consumer, 0, 0, 0, 0, true, false);
     }
 
-
     /**
      * Copy the current screen contents into a bitmap and return it.
      *
@@ -626,8 +646,8 @@
     }
 
     /**
-     * Like {@link SurfaceControl#screenshot(int, int, int, int)} but includes all
-     * Surfaces in the screenshot.
+     * Like {@link SurfaceControl#screenshot(int, int, int, int, boolean)} but
+     * includes all Surfaces in the screenshot.
      *
      * @param width The desired width of the returned bitmap; the raw
      * screen will be scaled down to this size.
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 2e0f509..789b761 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -166,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();
@@ -195,12 +190,12 @@
 
     @Override
     void detachFunctor(long functor) {
-        nDetachFunctor(mNativeProxy, functor);
+        // no-op, we never attach functors to need to detach them
     }
 
     @Override
     void attachFunctor(AttachInfo attachInfo, long functor) {
-        nAttachFunctor(mNativeProxy, functor);
+        invokeFunctor(functor, true);
     }
 
     @Override
@@ -294,8 +289,6 @@
     private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
     private static native void nDestroyCanvas(long nativeProxy);
 
-    private static native void nAttachFunctor(long nativeProxy, long functor);
-    private static native void nDetachFunctor(long nativeProxy, long functor);
     private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion);
 
     private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
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 2d503bf..65ac50d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1505,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/view/WindowAnimationFrameStats.aidl b/core/java/android/view/WindowAnimationFrameStats.aidl
new file mode 100644
index 0000000..77f544b
--- /dev/null
+++ b/core/java/android/view/WindowAnimationFrameStats.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+parcelable WindowAnimationFrameStats;
diff --git a/core/java/android/view/WindowAnimationFrameStats.java b/core/java/android/view/WindowAnimationFrameStats.java
new file mode 100644
index 0000000..c60b96c
--- /dev/null
+++ b/core/java/android/view/WindowAnimationFrameStats.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class contains window animation frame statistics. For example, a window
+ * animation is usually performed when the application is transitioning from one
+ * activity to another. The frame statistics are a snapshot for the time interval
+ * from {@link #getStartTimeNano()} to {@link #getEndTimeNano()}.
+ * <p>
+ * The key idea is that in order to provide a smooth user experience the system should
+ * run window animations at a specific time interval obtained by calling {@link
+ * #getRefreshPeriodNano()}. If the system does not render a frame every refresh
+ * period the user will see irregular window transitions. The time when the frame was
+ * actually presented on the display by calling {@link #getFramePresentedTimeNano(int)}.
+ */
+public final class WindowAnimationFrameStats extends FrameStats implements Parcelable {
+    /**
+     * @hide
+     */
+    public WindowAnimationFrameStats() {
+        /* do nothing */
+    }
+
+    /**
+     * Initializes this isntance.
+     *
+     * @param refreshPeriodNano The display refresh period.
+     * @param framesPresentedTimeNano The presented frame times.
+     *
+     * @hide
+     */
+    public void init(long refreshPeriodNano, long[] framesPresentedTimeNano) {
+        mRefreshPeriodNano = refreshPeriodNano;
+        mFramesPresentedTimeNano = framesPresentedTimeNano;
+    }
+
+    private WindowAnimationFrameStats(Parcel parcel) {
+        mRefreshPeriodNano = parcel.readLong();
+        mFramesPresentedTimeNano = parcel.createLongArray();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeLong(mRefreshPeriodNano);
+        parcel.writeLongArray(mFramesPresentedTimeNano);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("WindowAnimationFrameStats[");
+        builder.append("frameCount:" + getFrameCount());
+        builder.append(", fromTimeNano:" + getStartTimeNano());
+        builder.append(", toTimeNano:" + getEndTimeNano());
+        builder.append(']');
+        return builder.toString();
+    }
+
+    public static final Creator<WindowAnimationFrameStats> CREATOR =
+            new Creator<WindowAnimationFrameStats>() {
+                @Override
+                public WindowAnimationFrameStats createFromParcel(Parcel parcel) {
+                    return new WindowAnimationFrameStats(parcel);
+                }
+
+                @Override
+                public WindowAnimationFrameStats[] newArray(int size) {
+                    return new WindowAnimationFrameStats[size];
+                }
+            };
+}
diff --git a/core/java/android/view/WindowContentFrameStats.aidl b/core/java/android/view/WindowContentFrameStats.aidl
new file mode 100644
index 0000000..aa9c2d6
--- /dev/null
+++ b/core/java/android/view/WindowContentFrameStats.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+parcelable WindowContentFrameStats;
diff --git a/core/java/android/view/WindowContentFrameStats.java b/core/java/android/view/WindowContentFrameStats.java
new file mode 100644
index 0000000..c6da2fb
--- /dev/null
+++ b/core/java/android/view/WindowContentFrameStats.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class contains window content frame statistics. For example, a window content
+ * is rendred in frames when a view is scrolled. The frame statistics are a snapshot
+ * for the time interval from {@link #getStartTimeNano()} to {@link #getEndTimeNano()}.
+ * <p>
+ * The key idea is that in order to provide a smooth user experience an application
+ * has to draw a frame at a specific time interval obtained by calling {@link
+ * #getRefreshPeriodNano()}. If the application does not render a frame every refresh
+ * period the user will see irregular UI transitions.
+ * </p>
+ * <p>
+ * An application posts a frame for presentation by synchronously rendering its contents
+ * in a buffer which is then posted or posting a buffer to which the application is
+ * asychronously rendering the content via GL. After the frame is posted and rendered
+ * (potentially asynchronosly) it is presented to the user. The time a frame was posted
+ * can be obtained via {@link #getFramePostedTimeNano(int)}, the time a frame content
+ * was rendered and ready for dsiplay (GL case) via {@link #getFrameReadyTimeNano(int)},
+ * and the time a frame was presented on the screen via {@link #getFramePresentedTimeNano(int)}.
+ * </p>
+ */
+public final class WindowContentFrameStats extends FrameStats implements Parcelable {
+    private long[] mFramesPostedTimeNano;
+    private long[] mFramesReadyTimeNano;
+
+    /**
+     * @hide
+     */
+    public WindowContentFrameStats() {
+        /* do nothing */
+    }
+
+    /**
+     * Initializes this isntance.
+     *
+     * @param refreshPeriodNano The display refresh period.
+     * @param framesPostedTimeNano The times in milliseconds for when the frame contents were posted.
+     * @param framesPresentedTimeNano The times in milliseconds for when the frame contents were presented.
+     * @param framesReadyTimeNano The times in milliseconds for when the frame contents were ready to be presented.
+     *
+     * @hide
+     */
+    public void init(long refreshPeriodNano, long[] framesPostedTimeNano,
+            long[] framesPresentedTimeNano, long[] framesReadyTimeNano) {
+        mRefreshPeriodNano = refreshPeriodNano;
+        mFramesPostedTimeNano = framesPostedTimeNano;
+        mFramesPresentedTimeNano = framesPresentedTimeNano;
+        mFramesReadyTimeNano = framesReadyTimeNano;
+    }
+
+    private WindowContentFrameStats(Parcel parcel) {
+        mRefreshPeriodNano = parcel.readLong();
+        mFramesPostedTimeNano = parcel.createLongArray();
+        mFramesPresentedTimeNano = parcel.createLongArray();
+        mFramesReadyTimeNano = parcel.createLongArray();
+    }
+
+    /**
+     * Get the time a frame at a given index was posted by the producer (e.g. the application).
+     * It is either explicitly set or defaulted to the time when the render buffer was posted.
+     * <p>
+     * <strong>Note:</strong> A frame can be posted and still it contents being rendered
+     * asynchronously in GL. To get the time the frame content was completely rendered and
+     * ready to display call {@link #getFrameReadyTimeNano(int)}.
+     * </p>
+     *
+     * @param index The frame index.
+     * @return The posted time in nanoseconds.
+     */
+    public long getFramePostedTimeNano(int index) {
+        if (mFramesPostedTimeNano == null) {
+            throw new IndexOutOfBoundsException();
+        }
+        return mFramesPostedTimeNano[index];
+    }
+
+    /**
+     * Get the time a frame at a given index was ready for presentation.
+     * <p>
+     * <strong>Note:</strong> A frame can be posted and still it contents being rendered
+     * asynchronously in GL. In such a case this is the time when the frame contents were
+     * completely rendered.
+     * </p>
+     *
+     * @param index The frame index.
+     * @return The ready time in nanoseconds or {@link #UNDEFINED_TIME_NANO}
+     *         if the frame is not ready yet.
+     */
+    public long getFrameReadyTimeNano(int index) {
+        if (mFramesReadyTimeNano == null) {
+            throw new IndexOutOfBoundsException();
+        }
+        return mFramesReadyTimeNano[index];
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeLong(mRefreshPeriodNano);
+        parcel.writeLongArray(mFramesPostedTimeNano);
+        parcel.writeLongArray(mFramesPresentedTimeNano);
+        parcel.writeLongArray(mFramesReadyTimeNano);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("WindowContentFrameStats[");
+        builder.append("frameCount:" + getFrameCount());
+        builder.append(", fromTimeNano:" + getStartTimeNano());
+        builder.append(", toTimeNano:" + getEndTimeNano());
+        builder.append(']');
+        return builder.toString();
+    }
+
+    public static final Parcelable.Creator<WindowContentFrameStats> CREATOR =
+            new Creator<WindowContentFrameStats>() {
+                @Override
+                public WindowContentFrameStats createFromParcel(Parcel parcel) {
+                    return new WindowContentFrameStats(parcel);
+                }
+
+                @Override
+                public WindowContentFrameStats[] newArray(int size) {
+                    return new WindowContentFrameStats[size];
+                }
+            };
+}
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index fe3e5c6..b6570cc 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -57,4 +57,6 @@
 
     void temporaryEnableAccessibilityStateUntilKeyguardRemoved(in ComponentName service,
             boolean touchExplorationEnabled);
+
+    IBinder getWindowToken(int windowId);
 }
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/java/com/android/internal/notification/PeopleNotificationScorer.java b/core/java/com/android/internal/notification/PeopleNotificationScorer.java
new file mode 100644
index 0000000..efb5f63
--- /dev/null
+++ b/core/java/com/android/internal/notification/PeopleNotificationScorer.java
@@ -0,0 +1,227 @@
+/*
+* 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.internal.notification;
+
+import android.app.Notification;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.LruCache;
+import android.util.Slog;
+
+/**
+ * This {@link NotificationScorer} attempts to validate people references.
+ * Also elevates the priority of real people.
+ */
+public class PeopleNotificationScorer implements NotificationScorer {
+    private static final String TAG = "PeopleNotificationScorer";
+    private static final boolean DBG = false;
+
+    private static final boolean ENABLE_PEOPLE_SCORER = true;
+    private static final String SETTING_ENABLE_PEOPLE_SCORER = "people_scorer_enabled";
+    private static final String[] LOOKUP_PROJECTION = { Contacts._ID };
+    private static final int MAX_PEOPLE = 10;
+    private static final int PEOPLE_CACHE_SIZE = 200;
+    // see NotificationManagerService
+    private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
+
+    protected boolean mEnabled;
+    private Context mContext;
+
+    // maps raw person handle to resolved person object
+    private LruCache<String, LookupResult> mPeopleCache;
+
+    private float findMaxContactScore(Bundle extras) {
+        if (extras == null) {
+            return 0f;
+        }
+
+        final String[] people = extras.getStringArray(Notification.EXTRA_PEOPLE);
+        if (people == null || people.length == 0) {
+            return 0f;
+        }
+
+        float rank = 0f;
+        for (int personIdx = 0; personIdx < people.length && personIdx < MAX_PEOPLE; personIdx++) {
+            final String handle = people[personIdx];
+            if (TextUtils.isEmpty(handle)) continue;
+
+            LookupResult lookupResult = mPeopleCache.get(handle);
+            if (lookupResult == null || lookupResult.isExpired()) {
+                final Uri uri = Uri.parse(handle);
+                if ("tel".equals(uri.getScheme())) {
+                    if (DBG) Slog.w(TAG, "checking telephone URI: " + handle);
+                    lookupResult = lookupPhoneContact(handle, uri.getSchemeSpecificPart());
+                } else if (handle.startsWith(Contacts.CONTENT_LOOKUP_URI.toString())) {
+                    if (DBG) Slog.w(TAG, "checking lookup URI: " + handle);
+                    lookupResult = resolveContactsUri(handle, uri);
+                } else {
+                    if (DBG) Slog.w(TAG, "unsupported URI " + handle);
+                }
+            } else {
+                if (DBG) Slog.w(TAG, "using cached lookupResult: " + lookupResult.mId);
+            }
+            if (lookupResult != null) {
+                rank = Math.max(rank, lookupResult.getRank());
+            }
+        }
+        return rank;
+    }
+
+    private LookupResult lookupPhoneContact(final String handle, final String number) {
+        LookupResult lookupResult = null;
+        Cursor c = null;
+        try {
+            Uri numberUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
+                    Uri.encode(number));
+            c = mContext.getContentResolver().query(numberUri, LOOKUP_PROJECTION, null, null, null);
+            if (c != null && c.getCount() > 0) {
+                c.moveToFirst();
+                final int idIdx = c.getColumnIndex(Contacts._ID);
+                final int id = c.getInt(idIdx);
+                if (DBG) Slog.w(TAG, "is valid: " + id);
+                lookupResult = new LookupResult(id);
+            }
+        } catch(Throwable t) {
+            Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t);
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+        if (lookupResult == null) {
+            lookupResult = new LookupResult(LookupResult.INVALID_ID);
+        }
+        mPeopleCache.put(handle, lookupResult);
+        return lookupResult;
+    }
+
+    private LookupResult resolveContactsUri(String handle, final Uri personUri) {
+        LookupResult lookupResult = null;
+        Cursor c = null;
+        try {
+            c = mContext.getContentResolver().query(personUri, LOOKUP_PROJECTION, null, null, null);
+            if (c != null && c.getCount() > 0) {
+                c.moveToFirst();
+                final int idIdx = c.getColumnIndex(Contacts._ID);
+                final int id = c.getInt(idIdx);
+                if (DBG) Slog.w(TAG, "is valid: " + id);
+                lookupResult = new LookupResult(id);
+            }
+        } catch(Throwable t) {
+            Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t);
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+        if (lookupResult == null) {
+            lookupResult = new LookupResult(LookupResult.INVALID_ID);
+        }
+        mPeopleCache.put(handle, lookupResult);
+        return lookupResult;
+    }
+
+    private final static int clamp(int x, int low, int high) {
+        return (x < low) ? low : ((x > high) ? high : x);
+    }
+
+    // TODO: rework this function before shipping
+    private static int priorityBumpMap(int incomingScore) {
+        //assumption is that scale runs from [-2*pm, 2*pm]
+        int pm = NOTIFICATION_PRIORITY_MULTIPLIER;
+        int theScore = incomingScore;
+        // enforce input in range
+        theScore = clamp(theScore, -2 * pm, 2 * pm);
+        if (theScore != incomingScore) return incomingScore;
+        // map -20 -> -20 and -10 -> 5 (when pm = 10)
+        if (theScore <= -pm) {
+            theScore += 1.5 * (theScore + 2 * pm);
+        } else {
+            // map 0 -> 10, 10 -> 15, 20 -> 20;
+            theScore += 0.5 * (2 * pm - theScore);
+        }
+        if (DBG) Slog.v(TAG, "priorityBumpMap: score before: " + incomingScore
+                + ", score after " + theScore + ".");
+        return theScore;
+    }
+
+    @Override
+    public void initialize(Context context) {
+        if (DBG) Slog.v(TAG, "Initializing  " + getClass().getSimpleName() + ".");
+        mContext = context;
+        mPeopleCache = new LruCache<String, LookupResult>(PEOPLE_CACHE_SIZE);
+        mEnabled = ENABLE_PEOPLE_SCORER && 1 == Settings.Global.getInt(
+                mContext.getContentResolver(), SETTING_ENABLE_PEOPLE_SCORER, 0);
+    }
+
+    @Override
+    public int getScore(Notification notification, int score) {
+        if (notification == null || !mEnabled) {
+            if (DBG) Slog.w(TAG, "empty notification? scorer disabled?");
+            return score;
+        }
+        float contactScore = findMaxContactScore(notification.extras);
+        if (contactScore > 0f) {
+            if (DBG) Slog.v(TAG, "Notification references a real contact. Promoted!");
+            score = priorityBumpMap(score);
+        } else {
+            if (DBG) Slog.v(TAG, "Notification lacks any valid contact reference. Not promoted!");
+        }
+        return score;
+    }
+
+    private static class LookupResult {
+        private static final long CONTACT_REFRESH_MILLIS = 60 * 60 * 1000;  // 1hr
+        public static final int INVALID_ID = -1;
+
+        private final long mExpireMillis;
+        private int mId;
+
+        public LookupResult(int id) {
+            mId = id;
+            mExpireMillis = System.currentTimeMillis() + CONTACT_REFRESH_MILLIS;
+        }
+
+        public boolean isExpired() {
+            return mExpireMillis < System.currentTimeMillis();
+        }
+
+        public boolean isInvalid() {
+            return mId == INVALID_ID || isExpired();
+        }
+
+        public float getRank() {
+            if (isInvalid()) {
+                return 0f;
+            } else {
+                return 1f;  // TODO: finer grained score
+            }
+        }
+
+        public LookupResult setId(int id) {
+            mId = id;
+            return this;
+        }
+    }
+}
+
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_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 159ffb2..8141a00 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -34,6 +34,7 @@
 #include <gui/SurfaceComposerClient.h>
 
 #include <ui/DisplayInfo.h>
+#include <ui/FrameStats.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
 
@@ -64,6 +65,16 @@
     delete ((ScreenshotClient*) context);
 }
 
+static struct {
+    nsecs_t UNDEFINED_TIME_NANO;
+    jmethodID init;
+} gWindowContentFrameStatsClassInfo;
+
+static struct {
+    nsecs_t UNDEFINED_TIME_NANO;
+    jmethodID init;
+} gWindowAnimationFrameStatsClassInfo;
+
 // ----------------------------------------------------------------------------
 
 static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
@@ -371,6 +382,151 @@
     SurfaceComposerClient::unblankDisplay(token);
 }
 
+static jboolean nativeClearContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject) {
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    status_t err = ctrl->clearLayerFrameStats();
+
+    if (err < 0 && err != NO_INIT) {
+        doThrowIAE(env);
+    }
+
+    // The other end is not ready, just report we failed.
+    if (err == NO_INIT) {
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+static jboolean nativeGetContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject,
+    jobject outStats) {
+    FrameStats stats;
+
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    status_t err = ctrl->getLayerFrameStats(&stats);
+    if (err < 0 && err != NO_INIT) {
+        doThrowIAE(env);
+    }
+
+    // The other end is not ready, fine just return empty stats.
+    if (err == NO_INIT) {
+        return JNI_FALSE;
+    }
+
+    jlong refreshPeriodNano = static_cast<jlong>(stats.refreshPeriodNano);
+    size_t frameCount = stats.desiredPresentTimesNano.size();
+
+    jlongArray postedTimesNanoDst = env->NewLongArray(frameCount);
+    if (postedTimesNanoDst == NULL) {
+        return JNI_FALSE;
+    }
+
+    jlongArray presentedTimesNanoDst = env->NewLongArray(frameCount);
+    if (presentedTimesNanoDst == NULL) {
+        return JNI_FALSE;
+    }
+
+    jlongArray readyTimesNanoDst = env->NewLongArray(frameCount);
+    if (readyTimesNanoDst == NULL) {
+        return JNI_FALSE;
+    }
+
+    nsecs_t postedTimesNanoSrc[frameCount];
+    nsecs_t presentedTimesNanoSrc[frameCount];
+    nsecs_t readyTimesNanoSrc[frameCount];
+
+    for (size_t i = 0; i < frameCount; i++) {
+        nsecs_t postedTimeNano = stats.desiredPresentTimesNano[i];
+        if (postedTimeNano == INT64_MAX) {
+            postedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
+        }
+        postedTimesNanoSrc[i] = postedTimeNano;
+
+        nsecs_t presentedTimeNano = stats.actualPresentTimesNano[i];
+        if (presentedTimeNano == INT64_MAX) {
+            presentedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
+        }
+        presentedTimesNanoSrc[i] = presentedTimeNano;
+
+        nsecs_t readyTimeNano = stats.frameReadyTimesNano[i];
+        if (readyTimeNano == INT64_MAX) {
+            readyTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
+        }
+        readyTimesNanoSrc[i] = readyTimeNano;
+    }
+
+    env->SetLongArrayRegion(postedTimesNanoDst, 0, frameCount, postedTimesNanoSrc);
+    env->SetLongArrayRegion(presentedTimesNanoDst, 0, frameCount, presentedTimesNanoSrc);
+    env->SetLongArrayRegion(readyTimesNanoDst, 0, frameCount, readyTimesNanoSrc);
+
+    env->CallVoidMethod(outStats, gWindowContentFrameStatsClassInfo.init, refreshPeriodNano,
+            postedTimesNanoDst, presentedTimesNanoDst, readyTimesNanoDst);
+
+    if (env->ExceptionCheck()) {
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+static jboolean nativeClearAnimationFrameStats(JNIEnv* env, jclass clazz) {
+    status_t err = SurfaceComposerClient::clearAnimationFrameStats();
+
+    if (err < 0 && err != NO_INIT) {
+        doThrowIAE(env);
+    }
+
+    // The other end is not ready, just report we failed.
+    if (err == NO_INIT) {
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+static jboolean nativeGetAnimationFrameStats(JNIEnv* env, jclass clazz, jobject outStats) {
+    FrameStats stats;
+
+    status_t err = SurfaceComposerClient::getAnimationFrameStats(&stats);
+    if (err < 0 && err != NO_INIT) {
+        doThrowIAE(env);
+    }
+
+    // The other end is not ready, fine just return empty stats.
+    if (err == NO_INIT) {
+        return JNI_FALSE;
+    }
+
+    jlong refreshPeriodNano = static_cast<jlong>(stats.refreshPeriodNano);
+    size_t frameCount = stats.desiredPresentTimesNano.size();
+
+    jlongArray presentedTimesNanoDst = env->NewLongArray(frameCount);
+    if (presentedTimesNanoDst == NULL) {
+        return JNI_FALSE;
+    }
+
+    nsecs_t presentedTimesNanoSrc[frameCount];
+
+    for (size_t i = 0; i < frameCount; i++) {
+        nsecs_t presentedTimeNano = stats.desiredPresentTimesNano[i];
+        if (presentedTimeNano == INT64_MAX) {
+            presentedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
+        }
+        presentedTimesNanoSrc[i] = presentedTimeNano;
+    }
+
+    env->SetLongArrayRegion(presentedTimesNanoDst, 0, frameCount, presentedTimesNanoSrc);
+
+    env->CallVoidMethod(outStats, gWindowAnimationFrameStatsClassInfo.init, refreshPeriodNano,
+            presentedTimesNanoDst);
+
+    if (env->ExceptionCheck()) {
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod sSurfaceControlMethods[] = {
@@ -426,6 +582,14 @@
             (void*)nativeBlankDisplay },
     {"nativeUnblankDisplay", "(Landroid/os/IBinder;)V",
             (void*)nativeUnblankDisplay },
+    {"nativeClearContentFrameStats", "(J)Z",
+            (void*)nativeClearContentFrameStats },
+    {"nativeGetContentFrameStats", "(JLandroid/view/WindowContentFrameStats;)Z",
+            (void*)nativeGetContentFrameStats },
+    {"nativeClearAnimationFrameStats", "()Z",
+            (void*)nativeClearAnimationFrameStats },
+    {"nativeGetAnimationFrameStats", "(Landroid/view/WindowAnimationFrameStats;)Z",
+            (void*)nativeGetAnimationFrameStats },
 };
 
 int register_android_view_SurfaceControl(JNIEnv* env)
@@ -441,6 +605,19 @@
     gPhysicalDisplayInfoClassInfo.xDpi = env->GetFieldID(clazz, "xDpi", "F");
     gPhysicalDisplayInfoClassInfo.yDpi = env->GetFieldID(clazz, "yDpi", "F");
     gPhysicalDisplayInfoClassInfo.secure = env->GetFieldID(clazz, "secure", "Z");
+
+    jclass frameStatsClazz = env->FindClass("android/view/FrameStats");
+    jfieldID undefined_time_nano_field =  env->GetStaticFieldID(frameStatsClazz, "UNDEFINED_TIME_NANO", "J");
+    nsecs_t undefined_time_nano = env->GetStaticLongField(frameStatsClazz, undefined_time_nano_field);
+
+    jclass contFrameStatsClazz = env->FindClass("android/view/WindowContentFrameStats");
+    gWindowContentFrameStatsClassInfo.init =  env->GetMethodID(contFrameStatsClazz, "init", "(J[J[J[J)V");
+    gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO = undefined_time_nano;
+
+    jclass animFrameStatsClazz = env->FindClass("android/view/WindowAnimationFrameStats");
+    gWindowAnimationFrameStatsClassInfo.init =  env->GetMethodID(animFrameStatsClazz, "init", "(J[J)V");
+    gWindowAnimationFrameStatsClassInfo.UNDEFINED_TIME_NANO = undefined_time_nano;
+
     return err;
 }
 
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 20a61bf..30d3e0c 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -113,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) {
@@ -135,20 +127,6 @@
     proxy->destroyCanvas();
 }
 
-static void android_view_ThreadedRenderer_attachFunctor(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jlong functorPtr) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
-    proxy->attachFunctor(functor);
-}
-
-static void android_view_ThreadedRenderer_detachFunctor(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jlong functorPtr) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
-    proxy->detachFunctor(functor);
-}
-
 static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jlong functorPtr, jboolean waitForCompletion) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
@@ -215,11 +193,8 @@
     { "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 },
-    { "nDetachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_detachFunctor },
     { "nInvokeFunctor", "(JJZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
     { "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext },
     { "nCreateDisplayListLayer", "(JII)J", (void*) android_view_ThreadedRenderer_createDisplayListLayer },
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/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0f772f1..a83942f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1921,6 +1921,18 @@
         android:description="@string/permdesc_filter_events"
         android:protectionLevel="signature" />
 
+    <!-- @hide Allows an application to retrieve the window token from the accessibility manager. -->
+    <permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN"
+        android:label="@string/permlab_retrieveWindowToken"
+        android:description="@string/permdesc_retrieveWindowToken"
+        android:protectionLevel="signature" />
+
+    <!-- @hide Allows an application to collect frame statistics -->
+    <permission android:name="android.permission.FRAME_STATS"
+         android:label="@string/permlab_frameStats"
+         android:description="@string/permdesc_frameStats"
+         android:protectionLevel="signature" />
+
     <!-- @hide Allows an application to temporary enable accessibility on the device. -->
     <permission android:name="android.permission.TEMPORARY_ENABLE_ACCESSIBILITY"
         android:label="@string/permlab_temporary_enable_accessibility"
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-af/strings.xml b/core/res/res/values-af/strings.xml
index b9bdfb9..88f5c54 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n legstuk-diens te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"skakel met \'n toestel-admin"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Laat die houer toe om bedoelings na \'n toesteladministrateur te stuur. Dit moet nooit vir normale programme nodig wees nie."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"voeg \'n toesteladministrateur by of verwyder een"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Laat die houer aktiewe toesteladministrateurs byvoeg of verwyder. Behoort nooit nodig te wees vir normale programme nie."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"verander skermoriëntasie"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 22246c1..9795461 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ ፍርግም አገልግሎት ለመጠረዝ  ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ከመሣሪያ አስተዳደር ጋር ተገናኝ"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ያዡ በይነመረብን ለመሣሪያ አስተዳዳሪ ለመላክ ይፈቅዳሉ። ለመደበኛ መተግበሪያዎች በፍፁም አያስፈልግም።"</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"የመሣሪያ አስተዳዳሪ ያክሉ ወይም ያስወግዱ"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"ያዢው ንቁ የመሣሪያ አስተዳዳሪዎች እንዲያክል ወይም እንዲያስወግድ ያስችለዋል። ለመደበኛ መተግበሪያዎች ጭራሽ ሊያስፈልግ አይገባም።"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"የማያ ገፀ አቀማመጥን ለውጥ"</string>
@@ -688,7 +692,7 @@
     <string name="permlab_setInputCalibration" msgid="4902620118878467615">"የግቤት መሣሪያ ማስተካከያ ቀይር"</string>
     <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"መተግበሪያው የማያ ንካ የማስተካከያ ልኬቶቹን እንዲቀይር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ ሊያስፈልግ አይገባም።"</string>
     <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"የDRM የምስክር ወረቀቶች ላይ ይድረሱ"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"አንድ መተግበሪያ የDRM የምስክር ወረቀቶችን እንዲሰጥና እንዲጠም ያስችላል። ለመደበኛ መተግበሪያዎች በፍጹም አስፈላጊ አይሆንም።"</string>
+    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"አንድ መተግበሪያ የDRM የምስክር ወረቀቶችን እንዲሰጥና እንዲጠቀም ያስችላል። ለመደበኛ መተግበሪያዎች በፍጹም አስፈላጊ አይሆንም።"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"የይለፍ ቃል ደንቦች አዘጋጅ"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"በማያ-መክፈት የተፈቀዱ የይለፍ ቃል ርዝመት እና ቁምፊዎች ተቆጣጠር።"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"የማሳያ-ክፈት ሙከራዎችን አሳይ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 9efd8eb..101c4dc 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة الأداة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"التفاعل مع مشرف الجهاز"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"للسماح للمالك بإرسال الأهداف إلى أحد مشرفي الجهاز. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"إضافة مشرف جهاز أو إزالته"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"للسماح بحامل البطاقة بإضافة مشرفي أجهزة نشطين أو إزالتهم. لا يلزم ذلك أبدًا للتطبيقات العادية."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"تغيير اتجاه الشاشة"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 366de7c..499280e 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за приспособления. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"взаимодействие с администратор на устройството"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Разрешава на притежателя да изпраща намерения до администратор на устройството. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"добавяне или премахване на администратор на устройства"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Разрешава на притежателя да добавя или премахва администратори на активни устройства. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"промяна на ориентацията на екрана"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 6cba689..1d063f6 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei de widget. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar amb un administrador del dispositiu"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet que el titular enviï intents a un administrador del sistema. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"afegeix un administrador al dispositiu o suprimeix-lo"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permet que el titular afegeixi administradors actius al dispositiu o en suprimeixi. No s\'hauria de necessitar per a les aplicacions normals."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"canviar l\'orientació de la pantalla"</string>
@@ -687,7 +691,7 @@
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permet que una aplicació conegui les observacions sobre les condicions de la xarxa. No s\'ha de necessitar mai per a aplicacions normals."</string>
     <string name="permlab_setInputCalibration" msgid="4902620118878467615">"canviar el calibratge del dispositiu d\'entrada"</string>
     <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permet que l\'aplicació modifiqui els paràmetres de calibratge de la pantalla tàctil. No ha de ser mai necessari per a aplicacions normals."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"accés als certificats de DRM"</string>
+    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"accedir als certificats de DRM"</string>
     <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permet que una aplicació proporcioni i utilitzi certificats de gestió de drets digitals (DRM, Digital Rights Management). No ha de ser mai necessari per a aplicacions normals."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir les normes de contrasenya"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controla la longitud i els caràcters permesos a les contrasenyes de desbloqueig de pantalla."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index b4972ef..6a14d0e 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Umožňuje držiteli navázat se na nejvyšší úroveň služby widgetu. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"komunikovat se správcem zařízení"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Umožňuje držiteli oprávnění odesílat informace správci zařízení. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"přidat nebo odebrat správce zařízení"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Opravňuje držitele přidávat nebo odebírat aktivní správce zařízení. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"změna orientace obrazovky"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index d3469f1..3c113f0 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Tillader, at brugeren kan forpligte sig til en grænseflade for en widgettjeneste på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikere med en enhedsadministrator"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Tillader, at brugeren kan sende hensigter til en enhedsadministrator. Dette bør aldrig være nødvendigt for almindelige apps."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"tilføje eller fjerne en enhedsadministrator"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Tillader, at man tilføjer eller fjerner aktive enhedsadministratorer. Dette burde aldrig være nødvendigt til normale apps."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"skift skærmretning"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 52ea81c..c2c8600 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ermöglicht dem Halter, sich an die Oberfläche eines Widget-Dienstes auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"Interaktion mit einem Geräteadministrator"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ermöglicht dem Halter, Intents an einen Geräteadministrator zu senden. Sollte nie für normale Apps benötigt werden."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"Geräteadministrator hinzufügen oder entfernen"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Ermöglicht dem Inhaber, aktive Geräteadministratoren hinzuzufügen oder zu entfernen. Sollte für normale Apps nie benötigt werden."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"Bildschirmausrichtung ändern"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 8b7e618..e1e9106 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας γραφικών στοιχείων. Δεν απαιτείται για κανονικές εφαρμογές."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"επικοινωνία με έναν διαχειριστή συσκευής"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Επιτρέπει στον κάτοχο την αποστολή στόχων σε έναν διαχειριστή συσκευής. Δεν είναι απαραίτητο για συνήθεις εφαρμογές."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"προσθήκη ή κατάργηση ενός διαχειριστή συσκευής"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Επιτρέπει στον κάτοχο να προσθέτει ή να καταργεί ενεργούς διαχειριστές συσκευών. Δεν θα πρέπει να ζητείται ποτέ για κανονικές εφαρμογές."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"αλλαγή προσανατολισμού οθόνης"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 179691b..8da35f1 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Allows the holder to bind to the top-level interface of a widget service. Should never be needed for normal apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interact with device admin"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Allows the holder to send intents to a device administrator. Should never be needed for normal apps."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"add or remove a device admin"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Allows the holder to add or remove active device administrators. Should never be needed for normal apps."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"change screen orientation"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 179691b..8da35f1 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Allows the holder to bind to the top-level interface of a widget service. Should never be needed for normal apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interact with device admin"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Allows the holder to send intents to a device administrator. Should never be needed for normal apps."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"add or remove a device admin"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Allows the holder to add or remove active device administrators. Should never be needed for normal apps."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"change screen orientation"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index dc67e27..ae96d40 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite al propietario vincularse a la interfaz de nivel superior del servicio de widget. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con un administrador de dispositivos"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite enviar intentos a un administrador de dispositivos. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"agregar o eliminar un administrador de dispositivos"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite al propietario agregar o eliminar administradores de dispositivos activos. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar la orientación de la pantalla"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 8386b02..638b9f4 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite enlazar con la interfaz de nivel superior de un servicio de widget. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con el administrador de un dispositivo"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite que se envíen intentos a un administrador de dispositivos. Las aplicaciones normales nunca deberían necesitar este permiso."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"añadir o eliminar un administrador de dispositivos"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite añadir o eliminar administradores de dispositivos activos. No debe ser necesario para aplicaciones normales."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar orientación de la pantalla"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 4d15e4a..adb033f 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lubab omanikul siduda vidina teenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"seadme administraatoriga suhtlemine"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Võimaldab omanikul saata kavatsusi seadme administraatorile. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"seadme administraatori lisamine või eemaldamine"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Võimaldab omanikul lisada või eemaldada aktiivseid seadme administraatoreid. Tavarakenduste puhul ei tohiks see kunagi vajalik olla."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"muuda ekraani paigutust"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index b621d49..3375255 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"به دارنده اجازه می‌دهد که به رابط سطح بالای سرویس ابزارک متصل شود. هرگز برای برنامه‌های معمولی مورد نیاز نیست."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"تعامل با یک سرپرست دستگاه"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"‏به دارنده اجازه می‎دهد اهداف خود را به سرپرست دستگاه ارسال کند. برنامه‎های معمولی هیچگاه به این ویژگی نیازی ندارند."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"اضافه یا حذف سرپرست دستگاه"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"به دارنده اجازه می‌دهد سرپرستان دستگاه فعال را اضافه یا حذف کند.هرگز نباید برای برنامه‌های عادی مورد نیاز باشد."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"تغییر جهت صفحه"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 6dd5e56..d2bf01c 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Antaa sovelluksen sitoutua widget-palvelun ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikoi laitteen järjestelmänvalvojan kanssa"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Antaa sovelluksen lähettää aikomuksia laitteen järjestelmänvalvojalle. Ei tavallisten sovellusten käyttöön."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"lisää tai poista laitteen järjestelmänvalvoja"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Haltija voi lisätä tai poistaa aktiivisen laitteen järjestelmänvalvojia. Tätä ei pitäisi tarvita tavallisille sovelluksille."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"muuta näytön suuntaa"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 7a8c975..74df7fe 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de widget. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir avec l\'administrateur d\'un périphérique"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet à l\'application autorisée d\'envoyer des intentions à l\'administrateur de l\'appareil. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ajouter ou supprimer un administrateur de l\'appareil"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permet à l\'application d\'ajouter ou de supprimer des administrateurs actifs de l\'appareil. Les applications standards ne devraient jamais utiliser cette autorisation."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"modifier l\'orientation de l\'écran"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index a57823f..691c6a4 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service widget. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir avec l\'administrateur du périphérique"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet à l\'application autorisée d\'envoyer des intentions à l\'administrateur de l\'appareil. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ajouter ou supprimer un administrateur de l\'appareil"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permet à l\'application autorisée d\'ajouter ou de supprimer des administrateurs actifs de l\'appareil. Les applications standards ne devraient pas nécessiter cette autorisation."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"Changement d\'orientation de l\'écran"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index bdba457..1419bc4 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"धारक को किसी विजेट सेवा के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देता है. सामान्‍य ऐप्स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"किसी उपकरण व्‍यवस्‍थापक के साथ सहभागिता करें"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"धारक को किसी उपकरण व्‍यवस्‍थापक को उद्देश्य भेजने देता है. सामान्‍य ऐप्स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"उपकरण उपकरण सुचारू ढ़ंग से चलाने वाले को जोड़ें या निकालें"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"धारक को सक्रिय डिवाइस व्यवस्थापकों को जोड़ने या निकालने देता है. सामान्य ऐप्स  के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"स्‍क्रीन अभिविन्‍यास बदलें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index fcd51ab..dde0a5b 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge widgeta. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcija s administratorom uređaja"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Nositelju omogućuje slanje namjera administratoru uređaja. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"dodavanje ili uklanjanje administratora uređaja"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Omogućuje nositelju dodavanje ili uklanjanje administratora aktivnih uređaja. Nikada ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"promjena orijentacije zaslona"</string>
@@ -688,7 +692,7 @@
     <string name="permlab_setInputCalibration" msgid="4902620118878467615">"promjena kalibracije uređaja za unos"</string>
     <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Omogućuje aplikaciji izmjenu parametara kalibracije dodirnog zaslona. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
     <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"pristup DRM certifikatima"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Aplikaciji omogućuje pružanje i korištenje DRM certifikata. Nikad ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
+    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Aplikaciji omogućuje pružanje i korištenje DRM certifikata. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Postavi pravila zaporke"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Upravljajte duljinom zaporki za otključavanje zaslona i dopuštenim znakovima u tim zaporkama."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Nadgledaj pokušaje otključavanja zaslona"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 4932e88..41a1fb9 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lehetővé teszi a használó számára, hogy csatlakozzon egy modulszolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"az eszközkezelő használata"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Lehetővé teszi a tulajdonos számára, hogy célokat küldjön egy eszközkezelőnek. A normál alkalmazásoknak erre soha nincs szüksége."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"eszközrendszergazda hozzáadása vagy eltávolítása"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Lehetővé teszi a tulajdonos számára, hogy aktív eszközrendszergazdákat adjon meg vagy távolítson el. A normál alkalmazásoknál erre soha nincs szükség."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"képernyő irányának módosítása"</string>
@@ -688,7 +692,7 @@
     <string name="permlab_setInputCalibration" msgid="4902620118878467615">"beviteli eszköz kalibrációjának módosítása"</string>
     <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Lehetővé teszi, hogy az alkalmazás módosítsa az érintőképernyő kalibrációs paramétereit. A normál alkalmazásoknál erre elvileg soha nincs szükség."</string>
     <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM-tanúsítványokhoz való hozzáférés"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Engedélyezi egy alkalmazás számára a DRM-tanúsítványokhoz való hozzáférést és azok használatát. Átlagos alkalmazásoknak erre nem lehet szüksége."</string>
+    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Engedélyezi egy alkalmazás számára a DRM-tanúsítványokhoz való hozzáférést és azok használatát. Átlagos alkalmazásoknak erre nem lehet szükségük."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Jelszavakkal kapcsolatos szabályok beállítása"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"A képernyőzár-feloldási jelszavakban engedélyezett karakterek és hosszúság vezérlése."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Képernyőzár-feloldási kísérletek figyelése"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 805f77b..d2f7c13 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Թույլ է տալիս սեփականատիրոջը միանալ վիջեթ ծառայության վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"փոխգործակցել սարքի կառավարչի հետ"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Թույլ է տալիս սեփականատիրոջը ուղարկել մտադրություններ սարքի կառավարչին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ավելացնել կամ հեռացնել սարքի արդմինիստրատոր"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Թույլ է տալիս սեփականատիրոջը ավելացնել կամ հեռացնել սարքի ակտիվ ադմինիստրատորներ: Երբեք չպետք է անհրաժեշտ լինի սովորական ծրագրերին:"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"փոխել էկրանի դիրքավորումը"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index e161466..b1d94e6 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan widget. Tidak pernah diperlukan oleh apl normal."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan admin perangkat"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Mengizinkan pemegang mengirimkan tujuan kepada administrator perangkat. Tidak pernah diperlukan oleh apl normal."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"menambah atau menghapus admin perangkat"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Memungkinkan pemegang menambahkan atau menghapus administrator perangkat aktif. Tidak pernah dibutuhkan oleh aplikasi normal."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"ubah orientasi layar"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 740075f..27b05d1 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Consente l\'associazione all\'interfaccia principale di un servizio widget. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interazione con un amministratore dispositivo"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Consente l\'invio di intent a un amministratore del dispositivo. L\'autorizzazione non dovrebbe mai essere necessaria per le normali applicazioni."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"aggiungere o rimuovere un amministratore del dispositivo"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Consente al titolare di aggiungere o rimuovere gli amministratori attivi del dispositivo. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"modifica orientamento dello schermo"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 61754c3..222dfe3 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"‏מאפשר למשתמש לבצע איגוד לממשק הרמה העליונה של שירות Widget. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"קיים אינטראקציה עם מנהל המכשיר"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"מאפשר למשתמש לשלוח כוונות למנהל התקנים. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"הוספה או הסרה של מנהלי מכשיר"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"מאפשרת לבעלים להוסיף או להסיר מנהלי מכשיר פעילים. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"שנה את כיוון המסך"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 62ee883..d1e1308 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ウィジェットサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"デバイス管理者との通信"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"デバイス管理者へのintentの送信を所有者に許可します。通常のアプリでは不要です。"</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"端末の管理者の追加または削除"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"有効な端末の管理者を追加または削除することを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"画面の向きの変更"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 4855f27..9ea2503 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"აპს შეეძლება ზედა დონის ინტერფეისის ვიჯეტთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"მოწყობილობის ადმინთან ინტერაქცია"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"აპს შეეძლება მოწყობილობის ადმინისტრატორისთვის intent ობიექტების გაგზავნა. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"მოწყობილობის ადმინისტრატორს დამატება ან ამოშლა"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"საშუალებას აძლევს მფლობელს დაამატოს ან ამოშალოს მოწყობილობის აქტიური ადმინისტრატორები. ჩვეულებრივ აპებს, ალბათ, არასოდეს დაჭირდება"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"ეკრანის ორიენტაციის შეცვლა"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 73769fb..8dbd6ac 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ឲ្យ​ម្ចាស់​ចង​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​សេវាកម្ម​ធាតុ​ក្រាហ្វិក។ មិន​គួរ​​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ទាក់ទង​ជា​មួយ​អ្នកគ្រប់គ្រង​ឧបករណ៍"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ឲ្យ​ម្ចាស់​ផ្ញើ​គោលបំណង​​ទៅ​អ្នក​គ្រប់គ្រង​ឧបករណ៍។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"បន្ថែម​ ឬ​លុប​កម្មវិធី​គ្រប់គ្រង​​​ឧបករណ៍"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"អនុញ្ញាត​​​ឲ្យ​ម្ចាស់​​​បន្ថែម​ ឬ​លុប​កម្មវិធី​គ្រប់គ្រង​ឧបករណ៍​សកម្ម​ចេញ​។ មិន​គួរ​ប្រើ​សម្រាប់​កម្មវិធី​​ធម្មតា​ទេ​។"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"ប្ដូរ​ទិស​អេក្រង់"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index bb26d4f..a389466 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"권한을 가진 프로그램이 위젯 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"기기 관리자와 상호 작용"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"권한을 가진 프로그램이 기기 관리자에게 인텐트를 보낼 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"기기 관리자 추가 또는 삭제"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"권한을 가진 프로그램이 활성화된 기기의 관리자를 추가 또는 삭제하도록 합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"화면 방향 변경"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 60b7da4..79b8a33 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ອະນຸຍາດໃຫ້ຜູ່ຖືຜູກກັບອິນເຕີເຟດລະດັບສູງສຸດ ຂອງບໍລິການວິເຈັດ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ຕິດຕໍ່ກັບຜູ່ເບິ່ງແຍງອຸປະກອນ"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງສົ່ງເຈດຕະນາຫາຜູ່ເບິ່ງແຍງລະບົບອຸປະກອນ. ແອັບຯທົ່ວໄປບໍ່ຄວນຈຳເປັນຕ້ອງໃຊ້."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ເພີ່ມ ຫຼືລຶບຜູ່ເບິ່ງແຍງລະບົບອຸປະກອນ"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງສາມາດລຶບ ຫຼືລຶບຂໍ້ມູນອຸປະກອນທີ່ນຳໃຊ້ໄດ້. ແອັບຯທົ່ວໄປບໍ່ຈຳເປັນຕ້ອງໃຊ້."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"ປ່ຽນລວງຂອງໜ້າຈໍ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index b40e10b..99184d2 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Leidžiama savininkui susisaistyti su aukščiausio lygio valdiklio paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"sąveikauti su įrenginio administratoriumi"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Leidžiama savininkui siųsti tikslus įrenginio administratoriui. Įprastoms programoms to neturėtų prireikti."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"pridėti arba pašalinti įrenginio administratorių"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Savininkui leidžiama pridėti aktyvių įrenginio administratorių arba juos pašalinti. Neturėtų reikėti įprastoms programoms."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"keisti ekrano padėtį"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 6b91a6d..433115c 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ļauj īpašniekam izveidot saiti ar logrīka pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"mijiedarboties ar ierīces administratoru"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ļauj īpašniekam nosūtīt informāciju par nodomiem ierīces administratoram. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"pievienot vai noņemt ierīces administratoru"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Ļauj īpašniekam pievienot vai noņemt aktīvos ierīces administratorus. Nekad nav nepieciešama parastām lietotnēm."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"mainīt ekrāna orientāciju"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index ea1baa1..442b856 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Эзэмшигч нь виджет үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"төхөөрөмжийн админтай харилцан үйлчлэх"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Эзэмшигч нь төхөөрөмжийн админруу интент илгээх боломжтой. Энгийн апп-д шаардлагагүй."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"төхөөрөмжийн админ нэмэх, хасах"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Эзэмшигч нь идэвхтэй төхөөрөмжийн администраторыг нэмэх, хасах боломжтой. Энгийн апп-д шаардлагагүй."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"дэлгэцний чиглэлийг солих"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 219e47b..27c413d 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan widget. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan pentadbir peranti"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Membenarkan pemegang menghantar tujuan kepada pentadbir peranti. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"tambah atau alih keluar pentadbir peranti"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Membenarkan pemegang menambah atau mengalih keluar pentadbir peranti aktif. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"tukar orientasi skrin"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 593d260..a6d186f 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lar innehaveren binde seg til det øverste nivået av grensesnittet for en modultjeneste. Skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunisere med enhetsadministrator"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Lar innehaveren sende hensikter til en enhetsadministrator. Skal aldri være nødvendig for normale apper."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"legge til eller fjerne en enhetsadministrator"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Tillater innehaveren å legge til eller fjerne aktive enhetsadministratorer. Dette skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"snu skjermen"</string>
@@ -688,7 +692,7 @@
     <string name="permlab_setInputCalibration" msgid="4902620118878467615">"endre kalibreringen av inndataenheter"</string>
     <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Lar appen endre kalibrasjonsparametrene for berøringsskjermen. Denne tillatelsen bør aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"tilgang til DRM-sertifikater"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Lar en app klargjøre og bruke DRM-sertifikater. Denne tillatelsen bør aldri være nødvendig for vanlige apper."</string>
+    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Tillater at en app klargjøre og bruke DRM-sertifikater. Denne tillatelsen bør aldri være nødvendig for vanlige apper."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Angi passordregler"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller tillatt lengde og tillatte tegn i passord for opplåsing av skjerm."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåk forsøk på opplåsing av skjerm"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 9225c23..9014f5a 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een widgetservice. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactie met apparaatbeheer"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Hiermee kan de houder intenties verzenden naar een apparaatbeheerder. Nooit vereist voor normale apps."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"een apparaatbeheerder toevoegen of verwijderen"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Hiermee kan de rechtenhouder actieve apparaatbeheerders toevoegen of verwijderen. Nooit vereist voor normale apps."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"schermstand wijzigen"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 931c24c..b08e236 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi widżetów. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcja z administratorem urządzenia"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Zezwala na wysyłanie intencji do administratora urządzenia. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"dodaj lub usuń administratora urządzenia"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Umożliwia właścicielowi dodawanie i usuwanie aktywnych administratorów urządzenia. Ta opcja nie jest wykorzystywana w przypadku standardowych aplikacji."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"zmienianie orientacji ekranu"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 9eb7512..379e3dd 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite que o titular vincule a interface de nível superior de um serviço de widget. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir com um administrador do dispositivo"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite ao titular enviar intenções para um administrador do aparelho. Nunca deverá ser necessário para aplicações normais."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"adicionar ou remover um administrador de dispositivos"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite que o titular adicione ou remova administradores de dispositivos ativos. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"mudar orientação do ecrã"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index fd75660..7feb69b 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite que o proprietário utilize a interface de nível superior de um serviço de widget. Nunca deve ser necessário para aplicativos normais."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir com o administrador de um dispositivo"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite que o proprietário envie tentativas ao administrador de um aparelho. Nunca deve ser necessário para aplicativos normais."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"adicionar ou remover um administrador do dispositivo"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite que o proprietário adicione ou remova administradores do dispositivo ativos. Não deve ser necessário para aplicativos comuns."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"alterar orientação da tela"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 4e9806b..7fc7436 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -601,6 +601,10 @@
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interacziun cun in administratur dad apparats"</string>
     <!-- no translation found for permdesc_bindDeviceAdmin (569715419543907930) -->
     <skip />
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
     <skip />
     <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index a8a75a5..2dfc1870 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unui serviciu widget. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interacţionare cu administratorul unui dispozitiv"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite proprietarului să trimită intenţii către un administrator al dispozitivului. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"adăugarea sau eliminarea unui administrator de dispozitiv"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite proprietarului să adauge sau să elimine administratorii activi ai dispozitivului. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"modificare orientare ecran"</string>
@@ -687,7 +691,7 @@
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite unei aplicații să asculte observații despre starea rețelei. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_setInputCalibration" msgid="4902620118878467615">"schimbați calibrarea dispozitivului de intrare"</string>
     <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permite aplicației să modifice parametrii de calibrare a ecranului tactil. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"accesați certificatele DRM"</string>
+    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"accesează certificatele DRM"</string>
     <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permite unei aplicații să furnizeze și să utilizeze certificate DRM. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Setaţi reguli pentru parolă"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Stabiliţi lungimea şi tipul de caractere permise în parolele pentru deblocarea ecranului."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index d142e9a..7f07d6d 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Приложение сможет подключаться к базовому интерфейсу службы виджетов. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"Взаимодействие с администратором устройства"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Приложение сможет отправлять объекты intent администратору устройства. Это разрешение не используется обычными приложениями."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"Добавление/удаление администратора устройства"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Владелец сможет добавлять и удалять администраторов устройства (используется лишь в некоторых приложениях)."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"Изменение ориентации экрана"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 707bdf1..aa467bb 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby miniaplikácií. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"komunikovať so správcom zariadenia"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Umožňuje držiteľovi odosielať informácie správcovi zariadenia. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"pridanie alebo odstránenie správcu zariadenia"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Umožňuje držiteľovi pridať alebo odstrániť správcov aktívnych zariadení. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"zmena orientácie obrazovky"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index e93b128..808026c 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lastniku omogoča povezovanje z vmesnikom storitve pripomočka najvišje ravni. Tega ni treba nikoli uporabiti za navadne programe."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcija s skrbnikom naprave"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Omogoča lastniku, da pošlje namere skrbniku naprave. Nikoli se ne uporablja za navadne programe."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"dodajanje ali odstranjevanje skrbnikov naprave"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Imetniku omogoča, da doda ali odstrani aktivne skrbnike naprave. Normalne aplikacije tega načeloma ne potrebujejo."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"spreminjanje usmerjenosti zaslona"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index b2928e4..0fed1e3 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозвољава власнику да се обавеже на интерфејс услуге виџета највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"интеракција са администратором уређаја"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Омогућава да власник шаље своје намере администратору уређаја. Уобичајене апликације никада не би требало да је користе."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"додавање или уклањање администратора уређаја"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Дозвољава власнику да додаје или уклања активне администраторе уређаја. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"промена положаја екрана"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index b134a85..5afc0cd 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en widget. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"arbeta med en enhetsadministratör"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Tillåter att innehavaren skickar avsikter till en enhetsadministratör. Vanliga appar behöver aldrig göra detta."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"lägga till eller ta bort en enhetsadministratör"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Innehavaren får lägga till eller ta bort aktiva enhetsadministratörer. Detta ska normalt inte behövas för vanliga appar."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"ändra bildskärmens rikting"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 8f319f3..9885014 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Inaruhusu mmiliki kushurutisha kusano ya kiwango cha juu ya huduma ya wijeti. Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"jiunge na msimamizi wa kifaa"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Inamruhusu mmiliki kutuma malengo kwa msimamizi wa kifaa. Haipaswi kuhitajika kwa programu za kawaida."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ongeza au ondoa msimamizi wa kifaa"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Inaruhusu mmiliki kuongeza au kuondoa wasimamizi wa kifaa waliopo. Kamwe kisihitajike kwa ajili ya programu za kawaida."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"badilisha uelekezo wa skrini"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index ecb3a58..ee35eae 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของบริการวิดเจ็ต ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ติดต่อกับผู้ดูแลอุปกรณ์"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"อนุญาตให้ผู้ใช้ส่งการติดต่อไปยังโปรแกรมควบคุมอุปกรณ์ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"เพิ่มหรือลบผู้ดูแลระบบอุปกรณ์"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"อนุญาตให้เจ้าของเพิ่มหรือลบผู้ดูแลระบบอุปกรณ์ที่ใช้งาน ไม่ควรต้องใช้สำหรับแอปปกติ"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"เปลี่ยนการวางแนวหน้าจอ"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 0a5e64c..ba7033e 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng serbisyo ng widget. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"makipag-ugnay sa tagapangasiwa ng device"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Pinapayagan ang mga may-ari na magpadala ng mga layunin sa administrator ng device. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"magdagdag o mag-alis ng admin ng device"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Pinapayagan ang may-ari na magdagdag o mag-alis ng mga aktibong administrator ng device. Hindi dapat kailanganin kailanman para sa normal na apps."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"baguhin ang orientation ng screen"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 72e149f..e78e291 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Cihazın sahibine bir widget hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"bir cihaz yöneticisi ile etkileşimde bulun"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Cihazın sahibinin cihaz yöneticisine amaç göndermesine izin verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"cihaz yöneticisi ekle veya kaldır"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"İzin sahibine, etkin cihaz yöneticileri ekleyip kaldırma izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"ekran yönünü değiştir"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 563d5ee..e31392e 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби віджетів. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"взаємодіяти з адмін. пристрою"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Дозволяє власнику надсилати задавані функції адміністратору пристрою. Ніколи не застосовується для звичайних програм."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"додавати чи вилучати адміністраторів пристрою"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Дозволяє власнику додавати чи вилучати активних адміністраторів пристрою. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"змінювати орієнтацію екрана"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 8c424c3..ea0ef68c 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ tiện ích con. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"tương tác với quản trị viên thiết bị"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Cho phép chủ sở hữu gửi các ý định đến quản trị viên thiết bị. Không cần thiết cho các ứng dụng thông thường."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"thêm hoặc xóa quản trị viên thiết bị"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Cho phép chủ sở hữu thêm hoặc xóa quản trị viên thiết bị đang hoạt động. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"thay đổi hướng màn hình"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index acb4a81..73f2b8d 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允许应用绑定到小部件服务的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"与设备管理器交互"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允许用户将意向发送给设备管理员。普通应用绝不需要此权限。"</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"添加或删除设备管理员"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"允许应用添加或删除有效的设备管理员。普通应用绝不需要此权限。"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"更改屏幕显示方向"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index deb5a11..fa499d9 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允許應用程式繫結至小工具服務的頂層介面 (不建議一般應用程式使用)。"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"與裝置管理員互動"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允許應用程式將調用請求傳送至裝置管理員 (不建議一般應用程式使用)。"</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"新增或移除裝置管理員"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"允許應用程式新增或移除有效的裝置管理員 (不建議一般應用程式使用)。"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"更改屏幕瀏覽方向"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index b058860..6bf2593 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允許應用程式繫結至小工具服務的頂層介面 (一般應用程式不需使用)。"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"與裝置管理員互動"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允許應用程式將調用請求傳送至裝置管理員 (一般應用程式不需使用)。"</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"新增或移除裝置管理員"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"允許應用程式新增或移除有效的裝置管理員 (一般應用程式並不需要)。"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"變更螢幕顯示方向"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index aacd3c1..1359dd9 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -384,6 +384,10 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lensizakalo yesinqunjwana. Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"xhumana nomphathi wedivaysi"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ivumela ummeli ukuthumela okuqukethwe kumphathi wedivaysi. Akusoze kwadingeka kwizinhlelo zokusebenza ezivamile."</string>
+    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
+    <skip />
+    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
+    <skip />
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"engeza noma susa umlawuli wedivayisi"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Ivumela umnikazi ukuthi angeze noma asuse abalawuli bedivayisi esebenzayo. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"shintsha ukujikeleza kwesikrini"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 46cb9b2..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/config.xml b/core/res/res/values/config.xml
index fbe066a..d5e78a5 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1370,7 +1370,7 @@
     </string-array>
 
     <string-array name="config_notificationScorers">
-        <item>com.android.internal.notification.DemoContactNotificationScorer</item>
+        <item>com.android.internal.notification.PeopleNotificationScorer</item>
     </string-array>
 
     <!-- Flag indicating that this device does not rotate and will always remain in its default
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/strings.xml b/core/res/res/values/strings.xml
index 4a121d1..6266393 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -830,6 +830,20 @@
          user consent.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_retrieveWindowToken">retrieve window token</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_retrieveWindowToken">Allows an application to retrieve
+        the window token. Malicious apps may perfrom unauthorized interaction with
+        the application window impersonating the system.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_frameStats">retrieve frame statistics</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_frameStats">Allows an application to collect
+        frame statistics. Malicious apps may observe the frame statistics
+        of windows from other apps.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_filter_events">filter events</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_filter_events">Allows an application to register an input filter
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/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 6c0b722..3e68574 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -17,8 +17,8 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.res.Resources;
-import android.content.res.TypedArray;
 import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.Matrix;
@@ -47,6 +47,7 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
+
 /**
  * This lets you create a drawable based on an XML vector graphic
  * It can be defined in an XML file with the <code>&lt;vector></code> element.
@@ -172,7 +173,8 @@
     private static final int DEFAULT_DURATION = 1000;
     private static final long DEFAULT_INFINITE_DURATION = 60 * 60 * 1000;
 
-    private VectorDrawableState mVectorState;
+    private final VectorDrawableState mVectorState;
+
     private int mAlpha = 0xFF;
 
     public VectorDrawable() {
@@ -282,14 +284,17 @@
 
     @Override
     protected boolean onStateChange(int[] state) {
+        super.onStateChange(state);
+
         mVectorState.mVAnimatedPath.setState(state);
-        int direction = mVectorState.mVAnimatedPath.getTrigger(state);
-        if (direction>0) {
+
+        final int direction = mVectorState.mVAnimatedPath.getTrigger(state);
+        if (direction > 0) {
             animateForward();
-        } else if (direction<0) {
+        } else if (direction < 0) {
             animateBackward();
         }
-        super.onStateChange(state);
+
         invalidateSelf();
         return true;
     }
@@ -310,7 +315,11 @@
 
     @Override
     public void draw(Canvas canvas) {
-        mVectorState.mVAnimatedPath.draw(canvas);
+        final int saveCount = canvas.save();
+        final Rect bounds = getBounds();
+        canvas.translate(bounds.left, bounds.top);
+        mVectorState.mVAnimatedPath.draw(canvas, bounds.width(), bounds.height());
+        canvas.restoreToCount(saveCount);
     }
 
     @Override
@@ -327,10 +336,6 @@
         // TODO: support color filter
     }
 
-    /**
-     * Returns a {@link android.graphics.PixelFormat graphics.PixelFormat}
-     * value of TRANSLUCENT.
-     */
     @Override
     public int getOpacity() {
         return PixelFormat.TRANSLUCENT;
@@ -364,38 +369,14 @@
         invalidateSelf();
     }
 
-    /**
-     * Sets the intrinsic (default) width for this shape.
-     *
-     * @param width the intrinsic width (in pixels)
-     */
-    public void setIntrinsicWidth(int width) {
-        if (mVectorState.mIntrinsicWidth != width) {
-            mVectorState.mIntrinsicWidth = width;
-            invalidateSelf();
-        }
-    }
-
-    /**
-     * Sets the intrinsic (default) height for this shape.
-     *
-     * @param height the intrinsic height (in pixels)
-     */
-    public void setIntrinsicHeight(int height) {
-        if (mVectorState.mIntrinsicHeight != height) {
-            mVectorState.mIntrinsicHeight = height;
-            invalidateSelf();
-        }
-    }
-
     @Override
     public int getIntrinsicWidth() {
-        return mVectorState.mIntrinsicWidth;
+        return (int) mVectorState.mVAnimatedPath.mBaseWidth;
     }
 
     @Override
     public int getIntrinsicHeight() {
-        return mVectorState.mIntrinsicHeight;
+        return (int) mVectorState.mVAnimatedPath.mBaseHeight;
     }
 
     @Override
@@ -408,25 +389,6 @@
         }
     }
 
-    /** @hide */
-    public static VectorDrawable create(Resources resources, int rid) {
-        try {
-            VectorDrawable drawable = new VectorDrawable();
-            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
-            factory.setNamespaceAware(true);
-            XmlPullParser xpp = resources.getXml(rid);
-            AttributeSet attrs = Xml.asAttributeSet(xpp);
-            drawable.inflate(resources, xpp, attrs);
-            drawable.setAnimationFraction(0);
-            return drawable;
-        } catch (XmlPullParserException e) {
-            Log.e(LOGTAG, "parser error", e);
-        } catch (IOException e) {
-            Log.e(LOGTAG, "parser error", e);
-        }
-        return null;
-    }
-
     @Override
     public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
@@ -450,6 +412,27 @@
         }
     }
 
+    /** @hide */
+    public static VectorDrawable create(Resources resources, int rid) {
+        try {
+            final XmlPullParser xpp = resources.getXml(rid);
+            final AttributeSet attrs = Xml.asAttributeSet(xpp);
+            final XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+            factory.setNamespaceAware(true);
+
+            final VectorDrawable drawable = new VectorDrawable();
+            drawable.inflate(resources, xpp, attrs);
+            drawable.setAnimationFraction(0);
+
+            return drawable;
+        } catch (XmlPullParserException e) {
+            Log.e(LOGTAG, "parser error", e);
+        } catch (IOException e) {
+            Log.e(LOGTAG, "parser error", e);
+        }
+        return null;
+    }
+
     private VAnimatedPath inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
             Theme theme) throws XmlPullParserException, IOException {
         final VAnimatedPath animatedPath = new VAnimatedPath();
@@ -543,9 +526,6 @@
     private void setAnimatedPath(VAnimatedPath animatedPath) {
         mVectorState.mVAnimatedPath = animatedPath;
 
-        setIntrinsicWidth((int) mVectorState.mVAnimatedPath.mBaseWidth);
-        setIntrinsicHeight((int) mVectorState.mVAnimatedPath.mBaseHeight);
-
         long duration = mVectorState.mVAnimatedPath.getTotalAnimationDuration();
         if (duration == -1) { // if it set to infinite set to 1 hour
             duration = DEFAULT_INFINITE_DURATION; // TODO define correct approach for infinite
@@ -575,18 +555,12 @@
         ValueAnimator mBasicAnimator;
         VAnimatedPath mVAnimatedPath;
         Rect mPadding;
-        int mIntrinsicHeight;
-        int mIntrinsicWidth;
 
         public VectorDrawableState(VectorDrawableState copy) {
             if (copy != null) {
                 mChangingConfigurations = copy.mChangingConfigurations;
                 mVAnimatedPath = new VAnimatedPath(copy.mVAnimatedPath);
                 mPadding = new Rect(copy.mPadding);
-                mIntrinsicHeight = copy.mIntrinsicHeight;
-                mIntrinsicWidth = copy.mIntrinsicWidth;
-            } else {
-                mVAnimatedPath = new VAnimatedPath();
             }
         }
 
@@ -612,17 +586,31 @@
     }
 
     private static class VAnimatedPath {
-        private ArrayList<VAnimation> mCurrentAnimList = null;
+        private static final int [] TRIGGER_MAP = {
+                0,
+                R.attr.state_pressed,
+                R.attr.state_focused,
+                R.attr.state_hovered,
+                R.attr.state_selected,
+                R.attr.state_checkable,
+                R.attr.state_checked,
+                R.attr.state_activated,
+                R.attr.state_focused
+        };
+
+        private final Path mPath = new Path();
+        private final Path mRenderPath = new Path();
+        private final Matrix mMatrix = new Matrix();
+
+        private ArrayList<VAnimation> mCurrentAnimList;
         private VPath[] mCurrentPaths;
-        private float mAnimationValue = 0; // value goes from 0 to 1
-        private Paint mStrokePaint = null;
-        private Paint mFillPaint = null;
+        private Paint mStrokePaint;
+        private Paint mFillPaint;
         private PathMeasure mPathMeasure;
-        private Path mPath = new Path();
-        private Path mRenderPath = new Path();
-        private Matrix mMatrix = new Matrix();
-        private long mTotalDuration;
+
         private int[] mCurrentState = new int[0];
+        private float mAnimationValue;
+        private long mTotalDuration;
         private int mTrigger;
         private boolean mTriggerState;
 
@@ -634,11 +622,9 @@
         float mViewportHeight;
 
         public VAnimatedPath() {
-            setup();
         }
 
         public VAnimatedPath(VAnimatedPath copy) {
-            setup();
             mCurrentAnimList = new ArrayList<VAnimation>(copy.mCurrentAnimList);
             mGroupList.addAll(copy.mGroupList);
             if (copy.mCurrentPaths != null) {
@@ -703,28 +689,7 @@
         }
 
         public void setTrigger(int trigger){
-            final int [] lut = {
-                    0,
-                    R.attr.state_pressed,
-                    R.attr.state_focused,
-                    R.attr.state_hovered,
-                    R.attr.state_selected,
-                    R.attr.state_checkable,
-                    R.attr.state_checked,
-                    R.attr.state_activated,
-                    R.attr.state_focused
-            };
-
-            mTrigger = lut[trigger];
-         }
-
-        private void setup(){
-            mStrokePaint = new Paint();
-            mStrokePaint.setStyle(Paint.Style.STROKE);
-            mStrokePaint.setAntiAlias(true);
-            mFillPaint = new Paint();
-            mFillPaint.setStyle(Paint.Style.FILL);
-            mFillPaint.setAntiAlias(true);
+            mTrigger = VAnimatedPath.getStateForTrigger(trigger);
         }
 
         public long getTotalAnimationDuration() {
@@ -780,16 +745,12 @@
             }
         }
 
-        public void draw(Canvas canvas) {
+        public void draw(Canvas canvas, int w, int h) {
             if (mCurrentPaths == null) {
                 Log.e(LOGTAG,"mCurrentPaths == null");
                 return;
             }
 
-            // TODO: This should probably use getBounds().
-            final int w = canvas.getWidth();
-            final int h = canvas.getHeight();
-
             for (int i = 0; i < mCurrentPaths.length; i++) {
                 if (mCurrentPaths[i] != null && mCurrentPaths[i].isVisible(mCurrentState)) {
                     drawPath(mCurrentPaths[i], canvas, w, h);
@@ -801,7 +762,7 @@
             final float scale = Math.min(h / mViewportHeight, w / mViewportWidth);
 
             vPath.toPath(mPath);
-            Path path = mPath;
+            final Path path = mPath;
 
             if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) {
                 float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f;
@@ -839,24 +800,36 @@
             }
 
             if (vPath.mFillColor != 0) {
+                if (mFillPaint == null) {
+                    mFillPaint = new Paint();
+                    mFillPaint.setStyle(Paint.Style.FILL);
+                    mFillPaint.setAntiAlias(true);
+                }
+
                 mFillPaint.setColor(vPath.mFillColor);
-                int alpha = 0xFF & (vPath.mFillColor >> 24);
-                mFillPaint.setAlpha(alpha);
                 canvas.drawPath(mRenderPath, mFillPaint);
             }
 
             if (vPath.mStrokeColor != 0) {
+                if (mStrokePaint == null) {
+                    mStrokePaint = new Paint();
+                    mStrokePaint.setStyle(Paint.Style.STROKE);
+                    mStrokePaint.setAntiAlias(true);
+                }
+
+                final Paint strokePaint = mStrokePaint;
                 if (vPath.mStrokeLineJoin != null) {
-                    mStrokePaint.setStrokeJoin(vPath.mStrokeLineJoin);
+                    strokePaint.setStrokeJoin(vPath.mStrokeLineJoin);
                 }
+
                 if (vPath.mStrokeLineCap != null) {
-                    mStrokePaint.setStrokeCap(vPath.mStrokeLineCap);
+                    strokePaint.setStrokeCap(vPath.mStrokeLineCap);
                 }
-                mStrokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale);
-                mStrokePaint.setColor(vPath.mStrokeColor);
-                mStrokePaint.setAlpha(0xFF & (vPath.mStrokeColor >> 24));
-                mStrokePaint.setStrokeWidth(vPath.mStrokeWidth * scale);
-                canvas.drawPath(mRenderPath, mStrokePaint);
+
+                strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale);
+                strokePaint.setColor(vPath.mStrokeColor);
+                strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale);
+                canvas.drawPath(mRenderPath, strokePaint);
             }
         }
 
@@ -926,7 +899,7 @@
 
         private void parseViewport(Resources r, AttributeSet attrs)
                 throws XmlPullParserException {
-            TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
+            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
             mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, 0);
             mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, 0);
             if (mViewportWidth == 0 || mViewportHeight == 0) {
@@ -938,7 +911,7 @@
 
         private void parseSize(Resources r, AttributeSet attrs)
                 throws XmlPullParserException  {
-            TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize);
+            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize);
             mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, 0);
             mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, 0);
             if (mBaseWidth == 0 || mBaseHeight == 0) {
@@ -947,6 +920,10 @@
             }
             a.recycle();
         }
+
+        private static final int getStateForTrigger(int trigger) {
+            return TRIGGER_MAP[trigger];
+        }
     }
 
     private static class VAnimation {
@@ -1324,8 +1301,8 @@
 
         boolean mAnimated = false;
         boolean mClip = false;
-        Paint.Cap mStrokeLineCap = null;
-        Paint.Join mStrokeLineJoin = null;
+        Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
+        Paint.Join mStrokeLineJoin = Paint.Join.MITER;
         float mStrokeMiterlimit = 4;
 
         private VNode[] mNode = null;
@@ -1775,32 +1752,29 @@
             return returnPath;
         }
 
-        private static int rgbInterpolate(float t, int color1, int color2) {
-            int ret;
-            if (color1 == color2) {
-                return color2;
-            }
-            if (color1 == 0) {
-                return color2;
-            }
-            if (color2 == 0) {
-                return color1;
+        private static int rgbInterpolate(float fraction, int startColor, int endColor) {
+            if (startColor == endColor) {
+                return startColor;
+            } else if (startColor == 0) {
+                return endColor;
+            } else if (endColor == 0) {
+                return startColor;
             }
 
-            float t1 = 1 - t;
-            ret = 0xFF & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t)));
-            color1 >>= 8;
-                    color2 >>= 8;
+            final int startA = (startColor >> 24) & 0xff;
+            final int startR = (startColor >> 16) & 0xff;
+            final int startG = (startColor >> 8) & 0xff;
+            final int startB = startColor & 0xff;
 
-                    ret |= 0xFF00 & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t)) << 8);
-                    color1 >>= 8;
-                    color2 >>= 8;
-            ret |= 0xFF0000 & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t)) << 16);
-            color1 >>= 8;
-            color2 >>= 8;
-            ret |= 0xFF000000 & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t)) << 24);
+            final int endA = (endColor >> 24) & 0xff;
+            final int endR = (endColor >> 16) & 0xff;
+            final int endG = (endColor >> 8) & 0xff;
+            final int endB = endColor & 0xff;
 
-            return ret;
+            return ((startA + (int)(fraction * (endA - startA))) << 24) |
+                    ((startR + (int)(fraction * (endR - startR))) << 16) |
+                    ((startG + (int)(fraction * (endG - startG))) << 8) |
+                    ((startB + (int)(fraction * (endB - startB))));
         }
 
         public boolean isVisible(int[] state) {
@@ -1852,27 +1826,25 @@
             }
         }
 
-        private void nodeListToPath(VNode[] node, Path path) {
-            float[] current = new float[4];
-            for (int i = 0; i < node.length; i++) {
-                addCommand(path, current, node[i].mType, node[i].mParams);
-            }
-        }
-
         public static void createPath(VNode[] node, Path path) {
             float[] current = new float[4];
+            char previousCommand = 'm';
             for (int i = 0; i < node.length; i++) {
-                addCommand(path, current, node[i].mType, node[i].mParams);
+                addCommand(path, current, previousCommand, node[i].mType, node[i].mParams);
+                previousCommand = node[i].mType;
             }
         }
 
-        private static void addCommand(Path path, float[] current, char cmd, float[] val) {
+        private static void addCommand(Path path, float[] current,
+                char previousCmd, char cmd, float[] val) {
 
             int incr = 2;
             float currentX = current[0];
             float currentY = current[1];
             float ctrlPointX = current[2];
             float ctrlPointY = current[3];
+            float reflectiveCtrlPointX;
+            float reflectiveCtrlPointY;
 
             switch (cmd) {
                 case 'z':
@@ -1952,12 +1924,8 @@
                         currentY = val[k + 0];
                         break;
                     case 'c': // curveto - Draws a cubic Bézier curve (relative)
-                        path.rCubicTo(val[k + 0],
-                                val[k + 1],
-                                val[k + 2],
-                                val[k + 3],
-                                val[k + 4],
-                                val[k + 5]);
+                        path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
+                                val[k + 4], val[k + 5]);
 
                         ctrlPointX = currentX + val[k + 2];
                         ctrlPointY = currentY + val[k + 3];
@@ -1966,20 +1934,22 @@
 
                         break;
                     case 'C': // curveto - Draws a cubic Bézier curve
-                        path.cubicTo(val[k + 0],
-                                val[k + 1],
-                                val[k + 2],
-                                val[k + 3],
-                                val[k + 4],
-                                val[k + 5]);
+                        path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
+                                val[k + 4], val[k + 5]);
                         currentX = val[k + 4];
                         currentY = val[k + 5];
                         ctrlPointX = val[k + 2];
                         ctrlPointY = val[k + 3];
-
                         break;
                     case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
-                        path.rCubicTo(currentX - ctrlPointX, currentY  - ctrlPointY,
+                        reflectiveCtrlPointX = 0;
+                        reflectiveCtrlPointY = 0;
+                        if (previousCmd == 'c' || previousCmd == 's'
+                                || previousCmd == 'C' || previousCmd == 'S') {
+                            reflectiveCtrlPointX = currentX - ctrlPointX;
+                            reflectiveCtrlPointY = currentY - ctrlPointY;
+                        }
+                        path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
                                 val[k + 0], val[k + 1],
                                 val[k + 2], val[k + 3]);
 
@@ -1989,47 +1959,63 @@
                         currentY += val[k + 3];
                         break;
                     case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
-                        path.cubicTo(2 * currentX - ctrlPointX,
-                                2 * currentY - ctrlPointY,
-                                val[k + 0],
-                                val[k + 1],
-                                val[k + 2],
-                                val[k + 3]);
-                        currentX = val[k + 2];
-                        currentY = val[k + 3];
+                        reflectiveCtrlPointX = currentX;
+                        reflectiveCtrlPointY = currentY;
+                        if (previousCmd == 'c' || previousCmd == 's'
+                                || previousCmd == 'C' || previousCmd == 'S') {
+                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
+                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
+                        }
+                        path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
+                                val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
                         ctrlPointX = val[k + 0];
                         ctrlPointY = val[k + 1];
+                        currentX = val[k + 2];
+                        currentY = val[k + 3];
                         break;
                     case 'q': // Draws a quadratic Bézier (relative)
                         path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
+                        ctrlPointX = currentX + val[k + 0];
+                        ctrlPointY = currentY + val[k + 1];
                         currentX += val[k + 2];
                         currentY += val[k + 3];
-                        ctrlPointX = val[k + 0];
-                        ctrlPointY = val[k + 1];
                         break;
                     case 'Q': // Draws a quadratic Bézier
                         path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
-                        currentX = val[k + 2];
-                        currentY = val[k + 3];
                         ctrlPointX = val[k + 0];
                         ctrlPointY = val[k + 1];
+                        currentX = val[k + 2];
+                        currentY = val[k + 3];
                         break;
                     case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
-                        path.rQuadTo(currentX - ctrlPointX, currentY - ctrlPointY,
+                        reflectiveCtrlPointX = 0;
+                        reflectiveCtrlPointY = 0;
+                        if (previousCmd == 'q' || previousCmd == 't'
+                                || previousCmd == 'Q' || previousCmd == 'T') {
+                            reflectiveCtrlPointX = currentX - ctrlPointX;
+                            reflectiveCtrlPointY = currentY - ctrlPointY;
+                        }
+                        path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
                                 val[k + 0], val[k + 1]);
-                        ctrlPointX = ctrlPointX + currentX;
-                        ctrlPointY = ctrlPointY + currentY;
+                        ctrlPointX = reflectiveCtrlPointX;
+                        ctrlPointY = reflectiveCtrlPointY;
                         currentX += val[k + 0];
                         currentY += val[k + 1];
-
                         break;
                     case 'T': // Draws a quadratic Bézier curve (reflective control point)
-                        path.quadTo(currentX * 2 - ctrlPointX, currentY * 2 - ctrlPointY,
+                        reflectiveCtrlPointX = currentX;
+                        reflectiveCtrlPointY = currentY;
+                        if (previousCmd == 'q' || previousCmd == 't'
+                                || previousCmd == 'Q' || previousCmd == 'T') {
+                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
+                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
+                        }
+                        path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
                                 val[k + 0], val[k + 1]);
+                        ctrlPointX = reflectiveCtrlPointX;
+                        ctrlPointY = reflectiveCtrlPointY;
                         currentX = val[k + 0];
-                        currentY = val[k + 1]; // TODO: Check this logic
-                        ctrlPointX = -(val[k + 0] - currentX);
-                        ctrlPointY = -(val[k + 1] - currentY);
+                        currentY = val[k + 1];
                         break;
                     case 'a': // Draws an elliptical arc
                         // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
@@ -2047,7 +2033,6 @@
                         currentY += val[k + 6];
                         ctrlPointX = currentX;
                         ctrlPointY = currentY;
-
                         break;
                     case 'A': // Draws an elliptical arc
                         drawArc(path,
@@ -2066,6 +2051,7 @@
                         ctrlPointY = currentY;
                         break;
                 }
+                previousCmd = cmd;
             }
             current[0] = currentX;
             current[1] = currentY;
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index ce711b6..8b23955 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -41,6 +41,7 @@
 
 DeferredLayerUpdater::~DeferredLayerUpdater() {
     SkSafeUnref(mColorFilter);
+    setTransform(0);
     if (mLayer) {
         mCaches.resourceCache.decrementRefcount(mLayer);
     }
@@ -62,7 +63,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 +74,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/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 fa0fb8a..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();
 
@@ -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 af35344..3638184 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -313,14 +313,11 @@
         , mDirtyRegionsEnabled(false)
         , mOpaque(!translucent)
         , mCanvas(0)
-        , mHaveNewSurface(false)
-        , mInvokeFunctorsPending(false)
-        , mInvokeFunctorsTask(this) {
+        , mHaveNewSurface(false) {
     mGlobalContext = GlobalContext::get();
 }
 
 CanvasContext::~CanvasContext() {
-    removeFunctorsTask();
     destroyCanvas();
 }
 
@@ -385,15 +382,13 @@
     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) {
+    LOG_ALWAYS_FATAL_IF(!mCanvas, "Cannot process layer updates without a canvas!");
     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());
         }
@@ -434,60 +429,23 @@
     }
 }
 
-void InvokeFunctorsTask::run() {
-    mContext->invokeFunctors();
-}
-
-void CanvasContext::attachFunctor(Functor* functor) {
-    if (!mCanvas) return;
-
-    mCanvas->attachFunctor(functor);
-    removeFunctorsTask();
-    queueFunctorsTask(0);
-}
-
-void CanvasContext::detachFunctor(Functor* functor) {
-    if (!mCanvas) return;
-
-    mCanvas->detachFunctor(functor);
-}
-
 void CanvasContext::invokeFunctor(Functor* functor) {
+    ATRACE_CALL();
     DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
     if (mGlobalContext->hasContext()) {
         requireGlContext();
         mode = DrawGlInfo::kModeProcess;
     }
-    (*functor)(mode, NULL);
-}
-
-void CanvasContext::invokeFunctors() {
-    mInvokeFunctorsPending = false;
-
-    if (!mCanvas) return;
-
-    requireSurface();
-    Rect dirty;
-    mCanvas->invokeFunctors(dirty);
-}
-
-void CanvasContext::removeFunctorsTask() {
-    if (!mInvokeFunctorsPending) return;
-
-    mInvokeFunctorsPending = false;
-    mRenderThread.remove(&mInvokeFunctorsTask);
-}
-
-void CanvasContext::queueFunctorsTask(int delayMs) {
-    if (mInvokeFunctorsPending) return;
-
-    mInvokeFunctorsPending = true;
-    mRenderThread.queueDelayed(&mInvokeFunctorsTask, delayMs);
+    // TODO: Remove the dummy info in the future
+    DrawGlInfo dummyInfo;
+    memset(&dummyInfo, 0, sizeof(DrawGlInfo));
+    (*functor)(mode, &dummyInfo);
 }
 
 bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
     requireGlContext();
-    layer->apply();
+    bool hasFunctors;
+    layer->apply(&hasFunctors);
     return LayerRenderer::copyLayer(layer->backingLayer(), bitmap);
 }
 
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 9f64944..dcb5957 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -43,17 +43,6 @@
 class CanvasContext;
 class RenderThread;
 
-class InvokeFunctorsTask : public RenderTask {
-public:
-    InvokeFunctorsTask(CanvasContext* context)
-        : mContext(context) {}
-
-    virtual void run();
-
-private:
-    CanvasContext* mContext;
-};
-
 // This per-renderer class manages the bridge between the global EGL context
 // and the render surface.
 class CanvasContext {
@@ -65,15 +54,12 @@
     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();
 
     bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
 
-    void attachFunctor(Functor* functor);
-    void detachFunctor(Functor* functor);
     void invokeFunctor(Functor* functor);
 
     void runWithGlContext(RenderTask* task);
@@ -86,11 +72,6 @@
     void swapBuffers();
     void requireSurface();
 
-    friend class InvokeFunctorsTask;
-    void invokeFunctors();
-    void removeFunctorsTask();
-    void queueFunctorsTask(int delayMs = FUNCTOR_PROCESS_DELAY);
-
     void requireGlContext();
 
     GlobalContext* mGlobalContext;
@@ -101,10 +82,6 @@
     bool mOpaque;
     OpenGLRenderer* mCanvas;
     bool mHaveNewSurface;
-
-    bool mInvokeFunctorsPending;
-    InvokeFunctorsTask mInvokeFunctorsTask;
-
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 7b509a2..cf6c8db 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -30,19 +30,7 @@
 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) {
+DrawFrameTask::DrawFrameTask() : mContext(0), mRenderNode(0) {
 }
 
 DrawFrameTask::~DrawFrameTask() {
@@ -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!");
 
@@ -88,23 +69,14 @@
     LOG_ALWAYS_FATAL_IF(!mRenderNode.get(), "Cannot drawFrame with no render node!");
     LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
 
-    postAndWait(renderThread, MODE_FULL);
+    postAndWait(renderThread);
 
     // Reset the single-frame data
     mDirty.setEmpty();
     mRenderNode = 0;
 }
 
-void DrawFrameTask::flushStateChanges(RenderThread* renderThread) {
-    LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
-
-    postAndWait(renderThread, MODE_STATE_ONLY);
-}
-
-void DrawFrameTask::postAndWait(RenderThread* renderThread, TaskMode mode) {
-    LOG_ALWAYS_FATAL_IF(mode == MODE_INVALID, "That's not a real mode, silly!");
-
-    mTaskMode = mode;
+void DrawFrameTask::postAndWait(RenderThread* renderThread) {
     AutoMutex _lock(mLock);
     renderThread->queue(this);
     mSignal.wait(mLock);
@@ -113,21 +85,14 @@
 void DrawFrameTask::run() {
     ATRACE_NAME("DrawFrame");
 
-    syncFrameState();
-
-    if (mTaskMode == MODE_STATE_ONLY) {
-        unblockUiThread();
-        return;
-    }
+    // canUnblockUiThread is temporary until WebView has a solution for syncing frame state
+    bool canUnblockUiThread = syncFrameState();
 
     // Grab a copy of everything we need
     Rect dirtyCopy(mDirty);
     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 +105,17 @@
     }
 }
 
-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();
+    bool hasFunctors = false;
+    mContext->processLayerUpdates(&mLayers, &hasFunctors);
 
-    mContext->processLayerUpdates(&mLayers);
+    TreeInfo info = {0};
+    mRenderNode->prepareTree(info);
+    hasFunctors |= info.hasFunctors;
 
-    // If we don't have an mRenderNode this is a state flush only
-    if (mRenderNode.get()) {
-        mRenderNode->updateProperties();
-    }
+    return !hasFunctors;
 }
 
 void DrawFrameTask::unblockUiThread() {
@@ -172,10 +133,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..055d4cf 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,33 +50,21 @@
 
     void setContext(CanvasContext* context);
 
-    void setDisplayListData(RenderNode* renderNode, DisplayListData* newData);
     void addLayer(DeferredLayerUpdater* layer);
     void removeLayer(DeferredLayerUpdater* layer);
 
     void setRenderNode(RenderNode* renderNode);
     void setDirty(int left, int top, int right, int bottom);
     void drawFrame(RenderThread* renderThread);
-    void flushStateChanges(RenderThread* renderThread);
 
     virtual void run();
 
 private:
-    enum TaskMode {
-        MODE_INVALID,
-        MODE_FULL,
-        MODE_STATE_ONLY,
-    };
-
-    void postAndWait(RenderThread* renderThread, TaskMode mode);
-    void syncFrameState();
+    void postAndWait(RenderThread* renderThread);
+    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;
 
@@ -97,10 +73,8 @@
     /*********************************************
      *  Single frame data
      *********************************************/
-    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 a7c955e..b233ae9 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -75,9 +75,6 @@
 
 void RenderProxy::destroyContext() {
     if (mContext) {
-        // Flush any pending changes to ensure all garbage is destroyed
-        mDrawFrameTask.flushStateChanges(&mRenderThread);
-
         SETUP_TASK(destroyContext);
         args->context = mContext;
         mContext = 0;
@@ -136,10 +133,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);
@@ -153,45 +146,18 @@
 }
 
 void RenderProxy::destroyCanvas() {
-    // If the canvas is being destroyed we won't be drawing again anytime soon
-    // So flush any pending state changes to allow for resource cleanup.
-    mDrawFrameTask.flushStateChanges(&mRenderThread);
-
     SETUP_TASK(destroyCanvas);
     args->context = mContext;
     post(task);
 }
 
-CREATE_BRIDGE2(attachFunctor, CanvasContext* context, Functor* functor) {
-    args->context->attachFunctor(args->functor);
-    return NULL;
-}
-
-void RenderProxy::attachFunctor(Functor* functor) {
-    SETUP_TASK(attachFunctor);
-    args->context = mContext;
-    args->functor = functor;
-    post(task);
-}
-
-CREATE_BRIDGE2(detachFunctor, CanvasContext* context, Functor* functor) {
-    args->context->detachFunctor(args->functor);
-    return NULL;
-}
-
-void RenderProxy::detachFunctor(Functor* functor) {
-    SETUP_TASK(detachFunctor);
-    args->context = mContext;
-    args->functor = functor;
-    post(task);
-}
-
 CREATE_BRIDGE2(invokeFunctor, CanvasContext* context, Functor* functor) {
     args->context->invokeFunctor(args->functor);
     return NULL;
 }
 
 void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) {
+    ATRACE_CALL();
     SETUP_TASK(invokeFunctor);
     args->context = mContext;
     args->functor = functor;
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 489bf20c1..3eb8ed8 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -63,13 +63,10 @@
     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();
 
-    ANDROID_API void attachFunctor(Functor* functor);
-    ANDROID_API void detachFunctor(Functor* functor);
     ANDROID_API void invokeFunctor(Functor* functor, bool waitForCompletion);
 
     ANDROID_API void runWithGlContext(RenderTask* task);
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index 664c707..214306c 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -1064,10 +1064,8 @@
     private boolean mHasRemotePlayback;
 
     /**
-     *  The stack of remote control event receivers.
-     *  Code sections and methods that modify the remote control event receiver stack are
-     *  synchronized on mPRStack, but also BEFORE on mFocusLock as any change in either
-     *  stack, audio focus or RC, can lead to a change in the remote control display
+     * The stack of remote control event receivers.
+     * All read and write operations on mPRStack are synchronized.
      */
     private final Stack<PlayerRecord> mPRStack = new Stack<PlayerRecord>();
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index d157478..89886ef 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -23,6 +23,7 @@
 import android.hardware.IProCameraCallbacks;
 import android.hardware.IProCameraUser;
 import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureResultExtras;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.impl.CameraMetadataNative;
@@ -151,21 +152,50 @@
 
     static class DummyCameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
 
-        @Override
-        public void onCameraError(int errorCode) {
-        }
-
-        @Override
-        public void onCameraIdle() {
-        }
-
-        @Override
-        public void onCaptureStarted(int requestId, long timestamp) {
-        }
-
-        @Override
-        public void onResultReceived(int frameId, CameraMetadataNative result)
+        /*
+         * (non-Javadoc)
+         * @see
+         * android.hardware.camera2.ICameraDeviceCallbacks#onCameraError(int,
+         * android.hardware.camera2.CaptureResultExtras)
+         */
+        public void onCameraError(int errorCode, CaptureResultExtras resultExtras)
                 throws RemoteException {
+            // TODO Auto-generated method stub
+
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see
+         * android.hardware.camera2.ICameraDeviceCallbacks#onCaptureStarted(
+         * android.hardware.camera2.CaptureResultExtras, long)
+         */
+        public void onCaptureStarted(CaptureResultExtras resultExtras, long timestamp)
+                throws RemoteException {
+            // TODO Auto-generated method stub
+
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see
+         * android.hardware.camera2.ICameraDeviceCallbacks#onResultReceived(
+         * android.hardware.camera2.impl.CameraMetadataNative,
+         * android.hardware.camera2.CaptureResultExtras)
+         */
+        public void onResultReceived(CameraMetadataNative result, CaptureResultExtras resultExtras)
+                throws RemoteException {
+            // TODO Auto-generated method stub
+
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see android.hardware.camera2.ICameraDeviceCallbacks#onCameraIdle()
+         */
+        public void onCameraIdle() throws RemoteException {
+            // TODO Auto-generated method stub
+
         }
     }
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 5f3ba74..74ce997 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -21,6 +21,7 @@
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResultExtras;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.impl.CameraMetadataNative;
@@ -84,20 +85,50 @@
 
     public class DummyCameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
 
-        @Override
-        public void onCameraError(int errorCode) {
+        /*
+         * (non-Javadoc)
+         * @see
+         * android.hardware.camera2.ICameraDeviceCallbacks#onCameraError(int,
+         * android.hardware.camera2.CaptureResultExtras)
+         */
+        public void onCameraError(int errorCode, CaptureResultExtras resultExtras)
+                throws RemoteException {
+            // TODO Auto-generated method stub
+
         }
 
-        @Override
-        public void onCameraIdle() {
+        /*
+         * (non-Javadoc)
+         * @see android.hardware.camera2.ICameraDeviceCallbacks#onCameraIdle()
+         */
+        public void onCameraIdle() throws RemoteException {
+            // TODO Auto-generated method stub
+
         }
 
-        @Override
-        public void onCaptureStarted(int requestId, long timestamp) {
+        /*
+         * (non-Javadoc)
+         * @see
+         * android.hardware.camera2.ICameraDeviceCallbacks#onCaptureStarted(
+         * android.hardware.camera2.CaptureResultExtras, long)
+         */
+        public void onCaptureStarted(CaptureResultExtras resultExtras, long timestamp)
+                throws RemoteException {
+            // TODO Auto-generated method stub
+
         }
 
-        @Override
-        public void onResultReceived(int frameId, CameraMetadataNative result) {
+        /*
+         * (non-Javadoc)
+         * @see
+         * android.hardware.camera2.ICameraDeviceCallbacks#onResultReceived(
+         * android.hardware.camera2.impl.CameraMetadataNative,
+         * android.hardware.camera2.CaptureResultExtras)
+         */
+        public void onResultReceived(CameraMetadataNative result, CaptureResultExtras resultExtras)
+                throws RemoteException {
+            // TODO Auto-generated method stub
+
         }
     }
 
@@ -139,7 +170,7 @@
     }
 
     private int submitCameraRequest(CaptureRequest request, boolean streaming) throws Exception {
-        int requestId = mCameraUser.submitRequest(request, streaming);
+        int requestId = mCameraUser.submitRequest(request, streaming, null);
         assertTrue(
                 "Request IDs should be non-negative (expected: >= 0, actual: " + requestId + ")",
                 requestId >= 0);
@@ -252,13 +283,13 @@
 
         CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */false);
         CaptureRequest request1 = builder.build();
-        int status = mCameraUser.submitRequest(request1, /* streaming */false);
+        int status = mCameraUser.submitRequest(request1, /* streaming */false, null);
         assertEquals("Expected submitRequest to return BAD_VALUE " +
                 "since we had 0 surface targets set.", CameraBinderTestUtils.BAD_VALUE, status);
 
         builder.addTarget(mSurface);
         CaptureRequest request2 = builder.build();
-        status = mCameraUser.submitRequest(request2, /* streaming */false);
+        status = mCameraUser.submitRequest(request2, /* streaming */false, null);
         assertEquals("Expected submitRequest to return BAD_VALUE since " +
                 "the target surface wasn't registered with createStream.",
                 CameraBinderTestUtils.BAD_VALUE, status);
@@ -292,15 +323,15 @@
         assertNotSame("Request IDs should be unique for multiple requests", requestId1,
                 requestIdStreaming);
 
-        int status = mCameraUser.cancelRequest(-1);
+        int status = mCameraUser.cancelRequest(-1, null);
         assertEquals("Invalid request IDs should not be cancellable",
                 CameraBinderTestUtils.BAD_VALUE, status);
 
-        status = mCameraUser.cancelRequest(requestId1);
+        status = mCameraUser.cancelRequest(requestId1, null);
         assertEquals("Non-streaming request IDs should not be cancellable",
                 CameraBinderTestUtils.BAD_VALUE, status);
 
-        status = mCameraUser.cancelRequest(requestIdStreaming);
+        status = mCameraUser.cancelRequest(requestIdStreaming, null);
         assertEquals("Streaming request IDs should be cancellable", CameraBinderTestUtils.NO_ERROR,
                 status);
 
@@ -339,7 +370,7 @@
             CameraBinderTestUtils.INVALID_OPERATION, status);
 
         // Test good case, waitUntilIdle when there is no active repeating request
-        status = mCameraUser.cancelRequest(requestIdStreaming);
+        status = mCameraUser.cancelRequest(requestIdStreaming, null);
         assertEquals(CameraBinderTestUtils.NO_ERROR, status);
         status = mCameraUser.waitUntilIdle();
         assertEquals(CameraBinderTestUtils.NO_ERROR, status);
@@ -351,16 +382,14 @@
         CaptureRequest request = createDefaultBuilder(/* needStream */true).build();
 
         // Test both single request and streaming request.
-        int requestId1 = submitCameraRequest(request, /* streaming */false);
         verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).times(1)).onResultReceived(
-                eq(requestId1),
-                argThat(matcher));
+                argThat(matcher),
+                any(CaptureResultExtras.class));
 
-        int streamingId = submitCameraRequest(request, /* streaming */true);
         verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).atLeast(NUM_CALLBACKS_CHECKED))
                 .onResultReceived(
-                        eq(streamingId),
-                        argThat(matcher));
+                        argThat(matcher),
+                        any(CaptureResultExtras.class));
     }
 
     @SmallTest
@@ -372,13 +401,13 @@
         // Test both single request and streaming request.
         int requestId1 = submitCameraRequest(request, /* streaming */false);
         verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).times(1)).onCaptureStarted(
-                eq(requestId1),
+                any(CaptureResultExtras.class),
                 anyLong());
 
         int streamingId = submitCameraRequest(request, /* streaming */true);
         verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).atLeast(NUM_CALLBACKS_CHECKED))
                 .onCaptureStarted(
-                        eq(streamingId),
+                        any(CaptureResultExtras.class),
                         timestamps.capture());
 
         long timestamp = 0; // All timestamps should be larger than 0.
@@ -401,7 +430,7 @@
         SystemClock.sleep(WAIT_FOR_WORK_MS);
 
         // Cancel and make sure we eventually quiesce
-        status = mCameraUser.cancelRequest(streamingId);
+        status = mCameraUser.cancelRequest(streamingId, null);
 
         verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(1)).onCameraIdle();
 
@@ -422,14 +451,14 @@
         int status;
 
         // Initial flush should work
-        status = mCameraUser.flush();
+        status = mCameraUser.flush(null);
         assertEquals(CameraBinderTestUtils.NO_ERROR, status);
 
         // Then set up a stream
         CaptureRequest request = createDefaultBuilder(/* needStream */true).build();
 
         // Flush should still be a no-op, really
-        status = mCameraUser.flush();
+        status = mCameraUser.flush(null);
         assertEquals(CameraBinderTestUtils.NO_ERROR, status);
 
         // Submit a few capture requests
@@ -440,7 +469,7 @@
         int requestId5 = submitCameraRequest(request, /* streaming */false);
 
         // Then flush and wait for idle
-        status = mCameraUser.flush();
+        status = mCameraUser.flush(null);
         assertEquals(CameraBinderTestUtils.NO_ERROR, status);
 
         verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(1)).onCameraIdle();
@@ -452,7 +481,7 @@
         SystemClock.sleep(WAIT_FOR_WORK_MS);
 
         // Then flush and wait for the idle callback
-        status = mCameraUser.flush();
+        status = mCameraUser.flush(null);
         assertEquals(CameraBinderTestUtils.NO_ERROR, status);
 
         verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(2)).onCameraIdle();
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/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 19286c8..e1c17cb 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -87,6 +87,8 @@
     <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.BLUETOOTH_STACK" />
     <uses-permission android:name="android.permission.GET_ACCOUNTS" />
+    <uses-permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN" />
+    <uses-permission android:name="android.permission.RENDER_STATS" />
 
     <application android:label="@string/app_label">
         <provider
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_off.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_off_alpha.png
similarity index 100%
rename from packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_off.png
rename to packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_off_alpha.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_on.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_on_alpha.png
similarity index 100%
rename from packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_on.png
rename to packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_on_alpha.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldpi/ic_qs_color_space_alpha.png b/packages/SystemUI/res/drawable-ldpi/ic_qs_color_space_alpha.png
deleted file mode 100644
index 46d2a16..0000000
--- a/packages/SystemUI/res/drawable-ldpi/ic_qs_color_space_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldpi/ic_qs_contrast_alpha.png b/packages/SystemUI/res/drawable-ldpi/ic_qs_contrast_alpha.png
deleted file mode 100644
index 704b4ec..0000000
--- a/packages/SystemUI/res/drawable-ldpi/ic_qs_contrast_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldpi/ic_qs_inversion_alpha.png b/packages/SystemUI/res/drawable-ldpi/ic_qs_inversion_alpha.png
deleted file mode 100644
index d56efb5..0000000
--- a/packages/SystemUI/res/drawable-ldpi/ic_qs_inversion_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_off.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_off_alpha.png
similarity index 100%
rename from packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_off.png
rename to packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_off_alpha.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_on.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_on_alpha.png
similarity index 100%
rename from packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_on.png
rename to packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_on_alpha.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_off.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_off_alpha.png
similarity index 100%
rename from packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_off.png
rename to packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_off_alpha.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_on_alpha.png
similarity index 100%
rename from packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_on.png
rename to packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_on_alpha.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_off.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_off_alpha.png
similarity index 100%
rename from packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_off.png
rename to packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_off_alpha.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_on.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_on_alpha.png
similarity index 100%
rename from packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_on.png
rename to packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_on_alpha.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_qs_brightness_auto_off.xml b/packages/SystemUI/res/drawable/ic_qs_brightness_auto_off.xml
new file mode 100644
index 0000000..b7fe5ab
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_brightness_auto_off.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/ic_qs_brightness_auto_off_alpha"
+    android:tint="?android:attr/colorControlNormal" />
diff --git a/packages/SystemUI/res/drawable/ic_qs_brightness_auto_on.xml b/packages/SystemUI/res/drawable/ic_qs_brightness_auto_on.xml
new file mode 100644
index 0000000..e17b533
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_brightness_auto_on.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/ic_qs_brightness_auto_on_alpha"
+    android:tint="?android:attr/colorControlNormal" />
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index a6f4e9b..46fbaff 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -13,27 +13,26 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<LinearLayout 
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     style="@style/BrightnessDialogContainer">
 
     <ImageView
         android:id="@+id/brightness_icon"
-	    android:layout_width="wrap_content"
-	    android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
         android:paddingEnd="10dp"
         android:src="@drawable/ic_qs_brightness_auto_off"
-        />
+        android:contentDescription="@null" />
+
     <com.android.systemui.settings.ToggleSlider
         android:id="@+id/brightness_slider"
         android:layout_width="0dp"
         android:layout_height="40dp"
-        android:layout_weight="1"
-        android:layout_marginEnd="2dp"
         android:layout_gravity="center_vertical"
-        systemui:text="@string/status_bar_settings_auto_brightness_label"
-        />
+        android:layout_marginEnd="2dp"
+        android:layout_weight="1"
+        systemui:text="@string/status_bar_settings_auto_brightness_label" />
+
 </LinearLayout>
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 64c67b1..f61c28c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -73,7 +73,12 @@
     };
 
     /** 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();
@@ -137,7 +142,7 @@
         setContentView(mContainerView);
 
         // Update the recent tasks
-        updateRecentsTasks();
+        updateRecentsTasks(getIntent());
     }
 
     @Override
@@ -157,7 +162,7 @@
         RecentsConfiguration.reinitialize(this);
 
         // Update the recent tasks
-        updateRecentsTasks();
+        updateRecentsTasks(intent);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 94a655f..21460bb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -39,6 +39,9 @@
 
     public int filteringCurrentViewsMinAnimDuration;
     public int filteringNewViewsMinAnimDuration;
+    public int taskBarEnterAnimDuration;
+
+    public boolean launchedWithThumbnailAnimation;
 
     /** Private constructor */
     private RecentsConfiguration() {}
@@ -76,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 5aa99bb..fd0f6d1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -359,18 +359,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());
@@ -398,6 +389,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();
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 9da1b47..ff062f6c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -77,6 +77,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, userId);
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 141d870..ec28379 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -277,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 c9a491e..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,7 +529,6 @@
         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(mStackRect.left, mStackRectSansPeek.top,
                 mStackRect.right, mStackRectSansPeek.top + size);
 
@@ -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..2f135ec 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();
@@ -141,7 +138,8 @@
 
     protected IDreamManager mDreamManager;
     PowerManager mPowerManager;
-    protected int mRowHeight;
+    protected int mRowMinHeight;
+    protected int mRowMaxHeight;
 
     // public mode, private notifications, etc
     private boolean mLockscreenPublicMode = false;
@@ -883,7 +881,7 @@
             }
         }
         entry.row = row;
-        entry.row.setRowHeight(mRowHeight);
+        entry.row.setHeightRange(mRowMinHeight, mRowMaxHeight);
         entry.content = content;
         entry.expanded = contentViewLocal;
         entry.expandedPublic = publicViewLocal;
@@ -1049,7 +1047,6 @@
         if (DEBUG) {
             Log.d(TAG, "addNotificationViews: added at " + pos);
         }
-        updateInterceptedState(entry);
         updateExpansionStates();
         updateNotificationIcons();
     }
@@ -1059,17 +1056,19 @@
     }
 
     protected void updateExpansionStates() {
+
+        // TODO: Handle user expansion better
         int N = mNotificationData.size();
         for (int i = 0; i < N; i++) {
             NotificationData.Entry entry = mNotificationData.get(i);
             if (!entry.row.isUserLocked()) {
                 if (i == (N-1)) {
                     if (DEBUG) Log.d(TAG, "expanding top notification at " + i);
-                    entry.row.setExpanded(true);
+                    entry.row.setSystemExpanded(true);
                 } else {
                     if (!entry.row.isUserExpanded()) {
                         if (DEBUG) Log.d(TAG, "collapsing notification at " + i);
-                        entry.row.setExpanded(false);
+                        entry.row.setSystemExpanded(false);
                     } else {
                         if (DEBUG) Log.d(TAG, "ignoring user-modified notification at " + i);
                     }
@@ -1082,32 +1081,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();
@@ -1244,13 +1221,14 @@
             if (DEBUG) Log.d(TAG, "contents was " + (contentsUnchanged ? "unchanged" : "changed"));
             if (DEBUG) Log.d(TAG, "order was " + (orderUnchanged ? "unchanged" : "changed"));
             if (DEBUG) Log.d(TAG, "notification is " + (isTopAnyway ? "top" : "not top"));
-            final boolean wasExpanded = oldEntry.row.isUserExpanded();
             removeNotificationViews(key);
             addNotificationViews(key, notification);  // will also replace the heads up
-            if (wasExpanded) {
-                final NotificationData.Entry newEntry = mNotificationData.findByKey(key);
-                newEntry.row.setExpanded(true);
-                newEntry.row.setUserExpanded(true);
+            final NotificationData.Entry newEntry = mNotificationData.findByKey(key);
+            final boolean userChangedExpansion = oldEntry.row.hasUserChangedExpansion();
+            if (userChangedExpansion) {
+                boolean userExpanded = oldEntry.row.isUserExpanded();
+                newEntry.row.applyExpansionToLayout(userExpanded);
+                newEntry.row.setUserExpanded(userExpanded);
             }
         }
 
@@ -1312,7 +1290,6 @@
         } else {
             entry.content.setOnClickListener(null);
         }
-        updateInterceptedState(entry);
     }
 
     protected void notifyHeadsUpScreenOn(boolean screenOn) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index b3d8688..2daf619 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -22,30 +22,49 @@
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
+import com.android.internal.widget.SizeAdaptiveLayout;
 import com.android.systemui.R;
 
 public class ExpandableNotificationRow extends FrameLayout {
-    private int mRowHeight;
+    private int mRowMinHeight;
+    private int mRowMaxHeight;
 
-    /** does this row contain layouts that can adapt to row expansion */
+    /** Does this row contain layouts that can adapt to row expansion */
     private boolean mExpandable;
-    /** has the user manually expanded this row */
+    /** Has the user actively changed the expansion state of this row */
+    private boolean mHasUserChangedExpansion;
+    /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
     private boolean mUserExpanded;
-    /** is the user touching this row */
+    /** Is the user touching this row */
     private boolean mUserLocked;
-    /** are we showing the "public" version */
+    /** Are we showing the "public" version */
     private boolean mShowingPublic;
 
+    /**
+     * Is this notification expanded by the system. The expansion state can be overridden by the
+     * user expansion.
+     */
+    private boolean mIsSystemExpanded;
+    private SizeAdaptiveLayout mPublicLayout;
+    private SizeAdaptiveLayout mPrivateLayout;
+    private int mMaxExpandHeight;
+    private boolean mMaxHeightNeedsUpdate;
+
     public ExpandableNotificationRow(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
-    public int getRowHeight() {
-        return mRowHeight;
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mPublicLayout = (SizeAdaptiveLayout) findViewById(R.id.expandedPublic);
+        mPrivateLayout = (SizeAdaptiveLayout) findViewById(R.id.expanded);
     }
 
-    public void setRowHeight(int rowHeight) {
-        this.mRowHeight = rowHeight;
+    public void setHeightRange(int rowMinHeight, int rowMaxHeight) {
+        mRowMinHeight = rowMinHeight;
+        mRowMaxHeight = rowMaxHeight;
+        mMaxHeightNeedsUpdate = true;
     }
 
     public boolean isExpandable() {
@@ -56,11 +75,24 @@
         mExpandable = expandable;
     }
 
+    /**
+     * @return whether the user has changed the expansion state
+     */
+    public boolean hasUserChangedExpansion() {
+        return mHasUserChangedExpansion;
+    }
+
     public boolean isUserExpanded() {
         return mUserExpanded;
     }
 
+    /**
+     * Set this notification to be expanded by the user
+     *
+     * @param userExpanded whether the user wants this notification to be expanded
+     */
     public void setUserExpanded(boolean userExpanded) {
+        mHasUserChangedExpansion = true;
         mUserExpanded = userExpanded;
     }
 
@@ -72,25 +104,102 @@
         mUserLocked = userLocked;
     }
 
-    public void setExpanded(boolean expand) {
+    /**
+     * @return has the system set this notification to be expanded
+     */
+    public boolean isSystemExpanded() {
+        return mIsSystemExpanded;
+    }
+
+    /**
+     * Set this notification to be expanded by the system.
+     *
+     * @param expand whether the system wants this notification to be expanded.
+     */
+    public void setSystemExpanded(boolean expand) {
+        mIsSystemExpanded = expand;
+        applyExpansionToLayout(expand);
+    }
+
+    /**
+     * Apply an expansion state to the layout.
+     *
+     * @param expand should the layout be in the expanded state
+     */
+    public void applyExpansionToLayout(boolean expand) {
         ViewGroup.LayoutParams lp = getLayoutParams();
         if (expand && mExpandable) {
             lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
         } else {
-            lp.height = mRowHeight;
+            lp.height = mRowMinHeight;
         }
         setLayoutParams(lp);
     }
 
+    /**
+     * If {@link #isExpanded()} then this is the greatest possible height this view can
+     * get and otherwise it is {@link #mRowMinHeight}.
+     *
+     * @return the maximum allowed expansion height of this view.
+     */
+    public int getMaximumAllowedExpandHeight() {
+        boolean inExpansionState = isExpanded();
+        if (!inExpansionState) {
+            // not expanded, so we return the collapsed size
+            return mRowMinHeight;
+        }
+
+        return mShowingPublic ? mRowMinHeight : getMaxExpandHeight();
+    }
+
+
+
+    private void updateMaxExpandHeight() {
+        ViewGroup.LayoutParams lp = getLayoutParams();
+        int oldHeight = lp.height;
+        lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        setLayoutParams(lp);
+        measure(View.MeasureSpec.makeMeasureSpec(getMeasuredWidth(), View.MeasureSpec.EXACTLY),
+                View.MeasureSpec.makeMeasureSpec(mRowMaxHeight, View.MeasureSpec.AT_MOST));
+        lp.height = oldHeight;
+        setLayoutParams(lp);
+        mMaxExpandHeight = getMeasuredHeight();
+    }
+
+    /**
+     * Check whether the view state is currently expanded. This is given by the system in {@link
+     * #setSystemExpanded(boolean)} and can be overridden by user expansion or
+     * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
+     * view can differ from this state, if layout params are modified from outside.
+     *
+     * @return whether the view state is currently expanded.
+     */
+    private boolean isExpanded() {
+        return !hasUserChangedExpansion() && isSystemExpanded() || isUserExpanded();
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        mMaxHeightNeedsUpdate = true;
+    }
+
     public void setShowingPublic(boolean show) {
         mShowingPublic = show;
-        final ViewGroup publicLayout = (ViewGroup) findViewById(R.id.expandedPublic);
 
         // bail out if no public version
-        if (publicLayout.getChildCount() == 0) return;
+        if (mPublicLayout.getChildCount() == 0) return;
 
         // TODO: animation?
-        publicLayout.setVisibility(show ? View.VISIBLE : View.GONE);
-        findViewById(R.id.expanded).setVisibility(show ? View.GONE : View.VISIBLE);
+        mPublicLayout.setVisibility(show ? View.VISIBLE : View.GONE);
+        mPrivateLayout.setVisibility(show ? View.GONE : View.VISIBLE);
+    }
+
+    public int getMaxExpandHeight() {
+        if (mMaxHeightNeedsUpdate) {
+            updateMaxExpandHeight();
+            mMaxHeightNeedsUpdate = false;
+        }
+        return mMaxExpandHeight;
     }
 }
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/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 2d2f2f1..6f93bed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -139,6 +139,7 @@
      * @param expandedHeight the new expanded height
      */
     private void updateNotificationStackHeight(float expandedHeight) {
+        mNotificationStackScroller.setIsExpanded(expandedHeight > 0.0f);
         float childOffset = getRelativeTop(mNotificationStackScroller)
                 - mNotificationParent.getTranslationY();
         int newStackHeight = (int) (expandedHeight - childOffset);
@@ -168,4 +169,16 @@
     protected int getDesiredMeasureHeight() {
         return mMaxPanelHeight;
     }
+
+    @Override
+    protected void onExpandingStarted() {
+        super.onExpandingStarted();
+        mNotificationStackScroller.onExpansionStarted();
+    }
+
+    @Override
+    protected void onExpandingFinished() {
+        super.onExpandingFinished();
+        mNotificationStackScroller.onExpansionStopped();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 20fb225..6922ca5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -216,6 +216,7 @@
                 mTimeAnimator.end();
                 mRubberbanding = false;
                 mClosing = false;
+                onExpandingFinished();
             }
         }
     };
@@ -230,6 +231,12 @@
         mRubberbandingEnabled = enable;
     }
 
+    protected void onExpandingFinished() {
+    }
+
+    protected void onExpandingStarted() {
+    }
+
     private void runPeekAnimation() {
         if (DEBUG) logf("peek to height=%.1f", mPeekHeight);
         if (mTimeAnimator.isStarted()) {
@@ -398,7 +405,7 @@
                 initVelocityTracker();
                 trackMovement(event);
                 mTimeAnimator.cancel(); // end any outstanding animations
-                mBar.onTrackingStarted(PanelView.this);
+                onTrackingStarted();
                 mInitialOffsetOnTouch = mExpandedHeight;
                 if (mExpandedHeight == 0) {
                     mJustPeeked = true;
@@ -443,7 +450,7 @@
                     mHandleView.setPressed(false);
                     postInvalidate(); // catch the press state change
                 }
-                mBar.onTrackingStopped(PanelView.this);
+                onTrackingStopped();
                 trackMovement(event);
 
                 float vel = getCurrentVelocity();
@@ -458,6 +465,15 @@
         return true;
     }
 
+    protected void onTrackingStopped() {
+        mBar.onTrackingStopped(PanelView.this);
+    }
+
+    protected void onTrackingStarted() {
+        mBar.onTrackingStarted(PanelView.this);
+        onExpandingStarted();
+    }
+
     private float getCurrentVelocity() {
         float vel = 0;
         float yVel = 0, xVel = 0;
@@ -561,6 +577,7 @@
                         mInitialOffsetOnTouch = mExpandedHeight;
                         mInitialTouchY = y;
                         mTracking = true;
+                        onTrackingStarted();
                         return true;
                     }
                 }
@@ -598,6 +615,8 @@
 
         if (always||mVel != 0) {
             animationTick(0); // begin the animation
+        } else {
+            onExpandingFinished();
         }
     }
 
@@ -770,6 +789,7 @@
         if (!isFullyCollapsed()) {
             mTimeAnimator.cancel();
             mClosing = true;
+            onExpandingStarted();
             // collapse() should never be a rubberband, even if an animation is already running
             mRubberbanding = false;
             fling(-mSelfCollapseVelocityPx, /*always=*/ true);
@@ -780,6 +800,7 @@
         if (DEBUG) logf("expand: " + this);
         if (isFullyCollapsed()) {
             mBar.startOpeningPanel(this);
+            onExpandingStarted();
             fling(mSelfExpandVelocityPx, /*always=*/ true);
         } else if (DEBUG) {
             if (DEBUG) logf("skipping expansion: is expanded");
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..841f3ca 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);
@@ -2625,7 +2641,8 @@
         }
 
         mHeadsUpNotificationDecay = res.getInteger(R.integer.heads_up_notification_decay);
-        mRowHeight =  res.getDimensionPixelSize(R.dimen.notification_row_min_height);
+        mRowMinHeight =  res.getDimensionPixelSize(R.dimen.notification_row_min_height);
+        mRowMaxHeight =  res.getDimensionPixelSize(R.dimen.notification_row_max_height);
 
         if (false) Log.v(TAG, "updateResources");
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index 79932a7..2dba669 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -78,7 +78,7 @@
         }
 
         if (mHeadsUp != null) {
-            mHeadsUp.row.setExpanded(true);
+            mHeadsUp.row.setSystemExpanded(true);
             mHeadsUp.row.setShowingPublic(false);
             if (mContentHolder == null) {
                 // too soon!
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index e2d6c5b..f31896a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -89,7 +89,7 @@
      * The current State this Layout is in
      */
     private final StackScrollState mCurrentStackScrollState = new StackScrollState(this);
-    
+
     private OnChildLocationsChangedListener mListener;
 
     public NotificationStackScrollLayout(Context context) {
@@ -336,7 +336,7 @@
                 continue;
             }
             float top = slidingChild.getTranslationY();
-            float bottom = top + slidingChild.getMeasuredHeight();
+            float bottom = top + slidingChild.getHeight();
             int left = slidingChild.getLeft();
             int right = slidingChild.getRight();
 
@@ -713,6 +713,13 @@
     protected void onViewRemoved(View child) {
         super.onViewRemoved(child);
         mCurrentStackScrollState.removeViewStateForView(child);
+        mStackScrollAlgorithm.notifyChildrenChanged(this);
+    }
+
+    @Override
+    protected void onViewAdded(View child) {
+        super.onViewAdded(child);
+        mStackScrollAlgorithm.notifyChildrenChanged(this);
     }
 
     private boolean onInterceptTouchEventScroll(MotionEvent ev) {
@@ -858,6 +865,21 @@
         return Math.max(getHeight() - mContentHeight, 0);
     }
 
+    public void onExpansionStarted() {
+        mStackScrollAlgorithm.onExpansionStarted(mCurrentStackScrollState);
+    }
+
+    public void onExpansionStopped() {
+        mStackScrollAlgorithm.onExpansionStopped();
+    }
+
+    public void setIsExpanded(boolean isExpanded) {
+        mStackScrollAlgorithm.setIsExpanded(isExpanded);
+        if (!isExpanded) {
+            mOwnScrollY = 0;
+        }
+    }
+
     /**
      * A listener that is notified when some child locations might have changed.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 4745f3b..5506a55 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -21,6 +21,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
 
 /**
  * The Algorithm of the {@link com.android.systemui.statusbar.stack
@@ -46,6 +47,11 @@
 
     private float mLayoutHeight;
     private StackScrollAlgorithmState mTempAlgorithmState = new StackScrollAlgorithmState();
+    private boolean mIsExpansionChanging;
+    private int mFirstChildMaxHeight;
+    private boolean mIsExpanded;
+    private View mFirstChildWhileExpanding;
+    private boolean mExpandedOnStart;
 
     public StackScrollAlgorithm(Context context) {
         initConstants(context);
@@ -117,8 +123,11 @@
             StackScrollAlgorithmState algorithmState) {
         float stackHeight = getLayoutHeight();
 
+        // The starting position of the bottom stack peek
+        float bottomPeekStart = stackHeight - mBottomStackPeekSize;
+
         // The position where the bottom stack starts.
-        float transitioningPositionStart = stackHeight - mCollapsedSize - mBottomStackPeekSize;
+        float transitioningPositionStart = bottomPeekStart - mCollapsedSize;
 
         // The y coordinate of the current child.
         float currentYPosition = 0.0f;
@@ -151,8 +160,8 @@
                 // Case 2:
                 // First element of regular scrollview comes next, so the position is just the
                 // scrolling position
-                nextYPosition = Math.min(scrollOffset, transitioningPositionStart);
-                childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING;
+                nextYPosition = updateStateForFirstScrollingChild(transitioningPositionStart,
+                        childViewState, scrollOffset);
             } else if (nextYPosition >= transitioningPositionStart) {
                 if (currentYPosition >= transitioningPositionStart) {
                     // Case 3:
@@ -186,6 +195,32 @@
         }
     }
 
+    /**
+     * Update the state for the first child which is in the regular scrolling area.
+     *
+     * @param transitioningPositionStart the transition starting position of the bottom stack
+     * @param childViewState the view state of the child
+     * @param scrollOffset the position in the regular scroll view after this child
+     * @return the next child position
+     */
+    private float updateStateForFirstScrollingChild(float transitioningPositionStart,
+            StackScrollState.ViewState childViewState, float scrollOffset) {
+        childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING;
+        if (scrollOffset < transitioningPositionStart) {
+            return scrollOffset;
+        } else {
+            return transitioningPositionStart;
+        }
+    }
+
+    private int getMaxAllowedChildHeight(View child) {
+        if (child instanceof ExpandableNotificationRow) {
+            ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+            return row.getMaximumAllowedExpandHeight();
+        }
+        return child.getHeight();
+    }
+
     private float updateStateForChildTransitioningInBottom(StackScrollAlgorithmState algorithmState,
             float stackHeight, float transitioningPositionStart, float currentYPosition,
             StackScrollState.ViewState childViewState, int childHeight, float nextYPosition) {
@@ -335,7 +370,17 @@
                 }
             } else {
                 algorithmState.lastTopStackIndex = i;
+                if (i == 0) {
 
+                    // The starting position of the bottom stack peek
+                    float bottomPeekStart = getLayoutHeight() - mBottomStackPeekSize;
+                    // Collapse and expand the first child while the shade is being expanded
+                    float maxHeight = mIsExpansionChanging && child == mFirstChildWhileExpanding
+                            ? mFirstChildMaxHeight
+                            : childHeight;
+                    childViewState.height = (int) Math.max(Math.min(bottomPeekStart, maxHeight),
+                            mCollapsedSize);
+                }
                 // We are already past the stack so we can end the loop
                 break;
             }
@@ -381,6 +426,47 @@
         this.mLayoutHeight = layoutHeight;
     }
 
+    public void onExpansionStarted(StackScrollState currentState) {
+        mIsExpansionChanging = true;
+        mExpandedOnStart = mIsExpanded;
+        ViewGroup hostView = currentState.getHostView();
+        updateFirstChildHeightWhileExpanding(hostView);
+    }
+
+    private void updateFirstChildHeightWhileExpanding(ViewGroup hostView) {
+        if (hostView.getChildCount() > 0) {
+            mFirstChildWhileExpanding = hostView.getChildAt(0);
+            if (mExpandedOnStart) {
+
+                // We are collapsing the shade, so the first child can get as most as high as the
+                // current height.
+                mFirstChildMaxHeight = mFirstChildWhileExpanding.getHeight();
+            } else {
+
+                // We are expanding the shade, expand it to its full height.
+                mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding);
+            }
+        } else {
+            mFirstChildWhileExpanding = null;
+            mFirstChildMaxHeight = 0;
+        }
+    }
+
+    public void onExpansionStopped() {
+        mIsExpansionChanging = false;
+        mFirstChildWhileExpanding = null;
+    }
+
+    public void setIsExpanded(boolean isExpanded) {
+        this.mIsExpanded = isExpanded;
+    }
+
+    public void notifyChildrenChanged(ViewGroup hostView) {
+        if (mIsExpansionChanging) {
+            updateFirstChildHeightWhileExpanding(hostView);
+        }
+    }
+
     class StackScrollAlgorithmState {
 
         /**
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 35f873e..53ac063 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -132,6 +132,8 @@
     private static final String TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED =
             "temporaryEnableAccessibilityStateUntilKeyguardRemoved";
 
+    private static final String GET_WINDOW_TOKEN = "getWindowToken";
+
     private static final ComponentName sFakeAccessibilityServiceComponentName =
             new ComponentName("foo.bar", "FakeService");
 
@@ -360,6 +362,7 @@
         }, UserHandle.ALL, intentFilter, null, null);
     }
 
+    @Override
     public int addClient(IAccessibilityManagerClient client, int userId) {
         synchronized (mLock) {
             final int resolvedUserId = mSecurityPolicy
@@ -388,6 +391,7 @@
         }
     }
 
+    @Override
     public boolean sendAccessibilityEvent(AccessibilityEvent event, int userId) {
         synchronized (mLock) {
             final int resolvedUserId = mSecurityPolicy
@@ -412,6 +416,7 @@
         return (OWN_PROCESS_ID != Binder.getCallingPid());
     }
 
+    @Override
     public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
         synchronized (mLock) {
             final int resolvedUserId = mSecurityPolicy
@@ -430,6 +435,7 @@
         }
     }
 
+    @Override
     public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType,
             int userId) {
         List<AccessibilityServiceInfo> result = null;
@@ -463,6 +469,7 @@
         return result;
     }
 
+    @Override
     public void interrupt(int userId) {
         CopyOnWriteArrayList<Service> services;
         synchronized (mLock) {
@@ -485,6 +492,7 @@
         }
     }
 
+    @Override
     public int addAccessibilityInteractionConnection(IWindow windowToken,
             IAccessibilityInteractionConnection connection, int userId) throws RemoteException {
         synchronized (mLock) {
@@ -521,6 +529,7 @@
         }
     }
 
+    @Override
     public void removeAccessibilityInteractionConnection(IWindow window) {
         synchronized (mLock) {
             mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
@@ -570,6 +579,7 @@
         return -1;
     }
 
+    @Override
     public void registerUiTestAutomationService(IBinder owner,
             IAccessibilityServiceClient serviceClient,
             AccessibilityServiceInfo accessibilityServiceInfo) {
@@ -612,6 +622,7 @@
         }
     }
 
+    @Override
     public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) {
         synchronized (mLock) {
             UserState userState = getCurrentUserStateLocked();
@@ -630,6 +641,7 @@
         }
     }
 
+    @Override
     public void temporaryEnableAccessibilityStateUntilKeyguardRemoved(
             ComponentName service, boolean touchExplorationEnabled) {
         mSecurityPolicy.enforceCallingPermission(
@@ -662,6 +674,29 @@
         }
     }
 
+    @Override
+    public IBinder getWindowToken(int windowId) {
+        mSecurityPolicy.enforceCallingPermission(
+                Manifest.permission.RETRIEVE_WINDOW_TOKEN,
+                GET_WINDOW_TOKEN);
+        synchronized (mLock) {
+            final int resolvedUserId = mSecurityPolicy
+                    .resolveCallingUserIdEnforcingPermissionsLocked(
+                            UserHandle.getCallingUserId());
+            if (resolvedUserId != mCurrentUserId) {
+                return null;
+            }
+            if (mSecurityPolicy.findWindowById(windowId) == null) {
+                return null;
+            }
+            IBinder token = mGlobalWindowTokens.get(windowId);
+            if (token != null) {
+                return token;
+            }
+            return getCurrentUserStateLocked().mWindowTokens.get(windowId);
+        }
+    }
+
     boolean onGesture(int gestureId) {
         synchronized (mLock) {
             boolean handled = notifyGestureLocked(gestureId, false);
@@ -689,7 +724,7 @@
      * @param outBounds The output to which to write the focus bounds.
      * @return Whether accessibility focus was found and the bounds are populated.
      */
-    // TODO: (multi-display) Make sure this works for multiple displays. 
+    // TODO: (multi-display) Make sure this works for multiple displays.
     boolean getAccessibilityFocusBoundsInActiveWindow(Rect outBounds) {
         // Instead of keeping track of accessibility focus events per
         // window to be able to find the focus in the active window,
@@ -3176,8 +3211,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/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b12ae4f..c24f53f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -24,6 +24,7 @@
 import android.util.TimeUtils;
 import android.view.IWindowId;
 
+import android.view.WindowContentFrameStats;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.policy.PolicyManager;
 import com.android.internal.policy.impl.PhoneWindowManager;
@@ -626,6 +627,8 @@
 
     private final PointerEventDispatcher mPointerEventDispatcher;
 
+    private WindowContentFrameStats mTempWindowRenderStats;
+
     final class DragInputEventReceiver extends InputEventReceiver {
         public DragInputEventReceiver(InputChannel inputChannel, Looper looper) {
             super(inputChannel, looper);
@@ -10264,6 +10267,51 @@
         return mSafeMode;
     }
 
+    @Override
+    public boolean clearWindowContentFrameStats(IBinder token) {
+        if (!checkCallingPermission(Manifest.permission.FRAME_STATS,
+                "clearWindowContentFrameStats()")) {
+            throw new SecurityException("Requires FRAME_STATS permission");
+        }
+        synchronized (mWindowMap) {
+            WindowState windowState = mWindowMap.get(token);
+            if (windowState == null) {
+                return false;
+            }
+            SurfaceControl surfaceControl = windowState.mWinAnimator.mSurfaceControl;
+            if (surfaceControl == null) {
+                return false;
+            }
+            return surfaceControl.clearContentFrameStats();
+        }
+    }
+
+    @Override
+    public WindowContentFrameStats getWindowContentFrameStats(IBinder token) {
+        if (!checkCallingPermission(Manifest.permission.FRAME_STATS,
+                "getWindowContentFrameStats()")) {
+            throw new SecurityException("Requires FRAME_STATS permission");
+        }
+        synchronized (mWindowMap) {
+            WindowState windowState = mWindowMap.get(token);
+            if (windowState == null) {
+                return null;
+            }
+            SurfaceControl surfaceControl = windowState.mWinAnimator.mSurfaceControl;
+            if (surfaceControl == null) {
+                return null;
+            }
+            if (mTempWindowRenderStats == null) {
+                mTempWindowRenderStats = new WindowContentFrameStats();
+            }
+            WindowContentFrameStats stats = mTempWindowRenderStats;
+            if (!surfaceControl.getContentFrameStats(stats)) {
+                return null;
+            }
+            return stats;
+        }
+    }
+
     void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
         pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
         mPolicy.dump("    ", pw, args);
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
index 6ca1aa7..bb2bebf 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
@@ -46,8 +46,8 @@
             android:rotation="46.757"
             android:pivotX="162"
             android:pivotY="173.5"
-            android:fill="?attr/android:colorControlNormal"
-            android:stroke="?attr/android:colorControlNormal"
+            android:fill="?android:attr/colorControlNormal"
+            android:stroke="?android:attr/colorControlNormal"
             android:strokeWidth="3"
             android:strokeLineCap="round"
             android:strokeLineJoin="round" />
@@ -56,7 +56,7 @@
         <path
             android:name="box3"
             android:pathData="m187,147l-1,55l-49,-1l2,-53l48,0z"
-            android:stroke="?attr/android:colorControlNormal"
+            android:stroke="?android:attr/colorControlNormal"
             android:strokeWidth="10"
             android:strokeLineCap="round"
             android:strokeLineJoin="round" />
@@ -65,7 +65,7 @@
         <path
             android:name="box4"
             android:pathData="m248,74l0,164l-177,0l1,-165l173,-1l3,2z"
-            android:stroke="?attr/android:colorControlNormal"
+            android:stroke="?android:attr/colorControlNormal"
             android:strokeWidth="30"
             android:strokeLineCap="round"
             android:strokeLineJoin="round" />
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 743a26c..1f2342a 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -23,22 +23,11 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
-import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
 import android.os.RemoteException;
 import android.util.DisplayMetrics;
-import android.view.Display;
-import android.view.Gravity;
-import android.view.IApplicationToken;
-import android.view.IInputFilter;
-import android.view.IOnKeyguardExitResult;
-import android.view.IRotationWatcher;
-import android.view.IWindowManager;
-import android.view.IWindowSession;
-
-import java.util.List;
 
 /**
  * Basic implementation of {@link IWindowManager} so that {@link Display} (and
@@ -462,4 +451,16 @@
         // TODO Auto-generated method stub
         return false;
     }
+
+    @Override
+    public boolean clearWindowContentRenderStats(IBinder token) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public WindowContentFrameStats getWindowContentRenderStats(IBinder token) {
+        // TODO Auto-generated method stub
+        return null;
+    }
 }
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[] {