Merge "Remove "final" from TextToSpeechClient class."
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 71c278d..eeff753 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4453,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();
@@ -4751,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);
@@ -11026,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);
@@ -12155,6 +12158,7 @@
   public final class HdmiCecClient {
     method public boolean isTvOn();
     method public void sendActiveSource();
+    method public void sendGiveDevicePowerStatus(int);
     method public void sendImageViewOn();
     method public void sendInactiveSource();
     method public void sendTextViewOn();
@@ -19732,7 +19736,8 @@
 
   public final class PowerManager {
     method public void goToSleep(long);
-    method public boolean isScreenOn();
+    method public boolean isInteractive();
+    method public deprecated boolean isScreenOn();
     method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
     method public void reboot(java.lang.String);
     method public void userActivity(long, boolean);
@@ -28409,6 +28414,7 @@
     method public float getRefreshRate();
     method public int getRotation();
     method public void getSize(android.graphics.Point);
+    method public int getState();
     method public deprecated int getWidth();
     method public boolean isValid();
     field public static final int DEFAULT_DISPLAY = 0; // 0x0
@@ -28416,6 +28422,10 @@
     field public static final int FLAG_PRIVATE = 4; // 0x4
     field public static final int FLAG_SECURE = 2; // 0x2
     field public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 1; // 0x1
+    field public static final int STATE_DOZING = 3; // 0x3
+    field public static final int STATE_OFF = 1; // 0x1
+    field public static final int STATE_ON = 2; // 0x2
+    field public static final int STATE_UNKNOWN = 0; // 0x0
   }
 
   public class DragEvent implements android.os.Parcelable {
@@ -28444,6 +28454,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);
@@ -28749,7 +28771,7 @@
     field public static final int FLAG_SOFT_KEYBOARD = 2; // 0x2
     field public static final int FLAG_TRACKING = 512; // 0x200
     field public static final int FLAG_VIRTUAL_HARD_KEY = 64; // 0x40
-    field public static final int FLAG_WOKE_HERE = 1; // 0x1
+    field public static final deprecated int FLAG_WOKE_HERE = 1; // 0x1
     field public static final int KEYCODE_0 = 7; // 0x7
     field public static final int KEYCODE_1 = 8; // 0x8
     field public static final int KEYCODE_2 = 9; // 0x9
@@ -30768,6 +30790,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();
@@ -30869,7 +30905,7 @@
     field public static final int FLAG_SHOW_WALLPAPER = 1048576; // 0x100000
     field public static final int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000
     field public static final int FLAG_SPLIT_TOUCH = 8388608; // 0x800000
-    field public static final int FLAG_TOUCHABLE_WHEN_WAKING = 64; // 0x40
+    field public static final deprecated int FLAG_TOUCHABLE_WHEN_WAKING = 64; // 0x40
     field public static final int FLAG_TRANSLUCENT_NAVIGATION = 134217728; // 0x8000000
     field public static final int FLAG_TRANSLUCENT_STATUS = 67108864; // 0x4000000
     field public static final int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 3e8d6a0..c520b58 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -138,8 +138,10 @@
 
 #if defined(__LP64__)
 static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
+static const char ZYGOTE_NICE_NAME[] = "zygote64";
 #else
 static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";
+static const char ZYGOTE_NICE_NAME[] = "zygote";
 #endif
 
 int main(int argc, char* const argv[])
@@ -185,16 +187,19 @@
         const char* arg = argv[i++];
         if (strcmp(arg, "--zygote") == 0) {
             zygote = true;
-            niceName = "zygote";
+            niceName = ZYGOTE_NICE_NAME;
         } else if (strcmp(arg, "--start-system-server") == 0) {
             startSystemServer = true;
         } else if (strcmp(arg, "--application") == 0) {
             application = true;
         } else if (strncmp(arg, "--nice-name=", 12) == 0) {
             niceName = arg + 12;
-        } else {
+        } else if (strncmp(arg, "--", 2) != 0) {
             className.setTo(arg);
             break;
+        } else {
+            --i;
+            break;
         }
     }
 
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/content/Intent.java b/core/java/android/content/Intent.java
index 9881428..a7d5606 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1417,15 +1417,38 @@
     // Standard intent broadcast actions (see action variable).
 
     /**
-     * Broadcast Action: Sent after the screen turns off.
+     * Broadcast Action: Sent when the device goes to sleep and becomes non-interactive.
+     * <p>
+     * For historical reasons, the name of this broadcast action refers to the power
+     * state of the screen but it is actually sent in response to changes in the
+     * overall interactive state of the device.
+     * </p><p>
+     * This broadcast is sent when the device becomes non-interactive which may have
+     * nothing to do with the screen turning off.  To determine the
+     * actual state of the screen, use {@link android.view.Display#getState}.
+     * </p><p>
+     * See {@link android.os.PowerManager#isInteractive} for details.
+     * </p>
      *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF";
+
     /**
-     * Broadcast Action: Sent after the screen turns on.
+     * Broadcast Action: Sent when the device wakes up and becomes interactive.
+     * <p>
+     * For historical reasons, the name of this broadcast action refers to the power
+     * state of the screen but it is actually sent in response to changes in the
+     * overall interactive state of the device.
+     * </p><p>
+     * This broadcast is sent when the device becomes interactive which may have
+     * nothing to do with the screen turning on.  To determine the
+     * actual state of the screen, use {@link android.view.Display#getState}.
+     * </p><p>
+     * See {@link android.os.PowerManager#isInteractive} for details.
+     * </p>
      *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
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/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 03fa1d5..cec90cd 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -58,16 +58,6 @@
     public abstract boolean isProximitySensorAvailable();
 
     /**
-     * Called by the power manager to blank all displays.
-     */
-    public abstract void blankAllDisplaysFromPowerManager();
-
-    /**
-     * Called by the power manager to unblank all displays.
-     */
-    public abstract void unblankAllDisplaysFromPowerManager();
-
-    /**
      * Returns information about the specified logical display.
      *
      * @param displayId The logical display id.
@@ -254,12 +244,10 @@
         void onStateChanged();
         void onProximityPositive();
         void onProximityNegative();
+        void onDisplayStateChange(int state); // one of the Display state constants
 
         void acquireSuspendBlocker();
         void releaseSuspendBlocker();
-
-        void blankAllDisplays();
-        void unblankAllDisplays();
     }
 
     /**
diff --git a/core/java/android/hardware/hdmi/HdmiCecClient.java b/core/java/android/hardware/hdmi/HdmiCecClient.java
index 1f382e6..cd86cd8 100644
--- a/core/java/android/hardware/hdmi/HdmiCecClient.java
+++ b/core/java/android/hardware/hdmi/HdmiCecClient.java
@@ -88,7 +88,7 @@
     }
 
     /**
-     * Send &lt;TextViewOn&gt; message.
+     * Send &lt;Text View On&gt; message.
      */
     public void sendTextViewOn() {
         try {
@@ -99,7 +99,7 @@
     }
 
     /**
-     * Send &lt;ImageViewOn&gt; message.
+     * Send &lt;Image View On&gt; message.
      */
     public void sendImageViewOn() {
         try {
@@ -110,6 +110,20 @@
     }
 
     /**
+     * Send &lt;Give Device Power Status&gt; message.
+     *
+     * @param address logical address of the device to send the message to, such as
+     *        {@link HdmiCec#ADDR_TV}.
+     */
+    public void sendGiveDevicePowerStatus(int address) {
+        try {
+            mService.sendGiveDevicePowerStatus(mBinder, address);
+        } catch (RemoteException e) {
+            Log.e(TAG, "sendGiveDevicePowerStatus threw exception ", e);
+        }
+    }
+
+    /**
      * Returns true if the TV or attached display is powered on.
      * <p>
      * The result of this method is only meaningful on playback devices (where the device
diff --git a/core/java/android/hardware/hdmi/IHdmiCecService.aidl b/core/java/android/hardware/hdmi/IHdmiCecService.aidl
index b5df131..ecdd345 100644
--- a/core/java/android/hardware/hdmi/IHdmiCecService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiCecService.aidl
@@ -33,6 +33,7 @@
     void sendInactiveSource(IBinder b);
     void sendImageViewOn(IBinder b);
     void sendTextViewOn(IBinder b);
+    void sendGiveDevicePowerStatus(IBinder b, int address);
     boolean isTvOn(IBinder b);
     void sendMessage(IBinder b, in HdmiCecMessage message);
 }
diff --git a/core/java/android/hardware/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java
index 8be94d0..6a392dd 100644
--- a/core/java/android/hardware/input/InputManagerInternal.java
+++ b/core/java/android/hardware/input/InputManagerInternal.java
@@ -25,12 +25,18 @@
  * @hide Only for use within the system server.
  */
 public abstract class InputManagerInternal {
+    public abstract boolean injectInputEvent(InputEvent event, int displayId, int mode);
+
     /**
-     * Sets information about the displays as needed by the input system.
-     * The input system should copy this information if required.
+     * Called by the display manager to set information about the displays as needed
+     * by the input system.  The input system must copy this information to retain it.
      */
     public abstract void setDisplayViewports(DisplayViewport defaultViewport,
             DisplayViewport externalTouchViewport);
 
-    public abstract boolean injectInputEvent(InputEvent event, int displayId, int mode);
+    /**
+     * Called by the power manager to tell the input manager whether it should start
+     * watching for wake events.
+     */
+    public abstract void setInteractive(boolean interactive);
 }
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index be3c0cc..6c7b08d 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -40,8 +40,8 @@
     void wakeUp(long time);
     void goToSleep(long time, int reason);
     void nap(long time);
+    boolean isInteractive();
 
-    boolean isScreenOn();
     void reboot(boolean confirm, String reason, boolean wait);
     void shutdown(boolean confirm, boolean wait);
     void crash(String message);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index a195200..f8d7c3e 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -601,21 +601,64 @@
     }
 
     /**
-      * Returns whether the screen is currently on.
+      * Returns true if the device is in an interactive state.
       * <p>
-      * Only indicates whether the screen is on.  The screen could be either bright or dim.
+      * For historical reasons, the name of this method refers to the power state of
+      * the screen but it actually describes the overall interactive state of
+      * the device.  This method has been replaced by {@link #isInteractive}.
       * </p><p>
-      * {@samplecode
-      * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
-      * boolean isScreenOn = pm.isScreenOn();
-      * }
+      * The value returned by this method only indicates whether the device is
+      * in an interactive state which may have nothing to do with the screen being
+      * on or off.  To determine the actual state of the screen,
+      * use {@link android.view.Display#getState}.
       * </p>
       *
-      * @return whether the screen is on (bright or dim).
+      * @return True if the device is in an interactive state.
+      *
+      * @deprecated Use {@link #isInteractive} instead.
       */
+    @Deprecated
     public boolean isScreenOn() {
+        return isInteractive();
+    }
+
+    /**
+     * Returns true if the device is in an interactive state.
+     * <p>
+     * When this method returns true, the device is awake and ready to interact
+     * with the user (although this is not a guarantee that the user is actively
+     * interacting with the device just this moment).  The main screen is usually
+     * turned on while in this state.  Certain features, such as the proximity
+     * sensor, may temporarily turn off the screen while still leaving the device in an
+     * interactive state.  Note in particular that the device is still considered
+     * to be interactive while dreaming (since dreams can be interactive) but not
+     * when it is dozing or asleep.
+     * </p><p>
+     * When this method returns false, the device is dozing or asleep and must
+     * be awoken before it will become ready to interact with the user again.  The
+     * main screen is usually turned off while in this state.  Certain features,
+     * such as "ambient mode" may cause the main screen to remain on (albeit in a
+     * low power state) to display system-provided content while the device dozes.
+     * </p><p>
+     * The system will send a {@link android.content.Intent#ACTION_SCREEN_ON screen on}
+     * or {@link android.content.Intent#ACTION_SCREEN_OFF screen off} broadcast
+     * whenever the interactive state of the device changes.  For historical reasons,
+     * the names of these broadcasts refer to the power state of the screen
+     * but they are actually sent in response to changes in the overall interactive
+     * state of the device, as described by this method.
+     * </p><p>
+     * Services may use the non-interactive state as a hint to conserve power
+     * since the user is not present.
+     * </p>
+     *
+     * @return True if the device is in an interactive state.
+     *
+     * @see android.content.Intent#ACTION_SCREEN_ON
+     * @see android.content.Intent#ACTION_SCREEN_OFF
+     */
+    public boolean isInteractive() {
         try {
-            return mService.isScreenOn();
+            return mService.isInteractive();
         } catch (RemoteException e) {
             return false;
         }
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index de9eeff..2303d65 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -789,10 +789,20 @@
             return;
         }
 
-        // start it up
-        if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
-        mStarted = true;
-        onDreamingStarted();
+        // We need to defer calling onDreamingStarted until after onWindowAttached,
+        // which is posted to the handler by addView, so we post onDreamingStarted
+        // to the handler also.  Need to watch out here in case detach occurs before
+        // this callback is invoked.
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                if (mWindow != null) {
+                    if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
+                    mStarted = true;
+                    onDreamingStarted();
+                }
+            }
+        });
     }
 
     private void safelyFinish() {
diff --git a/core/java/android/tv/TvInputInfo.java b/core/java/android/tv/TvInputInfo.java
index 90625d8..90e4177 100644
--- a/core/java/android/tv/TvInputInfo.java
+++ b/core/java/android/tv/TvInputInfo.java
@@ -87,6 +87,34 @@
         return 0;
     }
 
+    @Override
+    public int hashCode() {
+        return mId.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+
+        if (!(o instanceof TvInputInfo)) {
+            return false;
+        }
+
+        TvInputInfo obj = (TvInputInfo) o;
+        return mId.equals(obj.mId)
+                && mService.serviceInfo.packageName.equals(obj.mService.serviceInfo.packageName)
+                && mService.serviceInfo.name.equals(obj.mService.serviceInfo.name);
+    }
+
+    @Override
+    public String toString() {
+        return "TvInputInfo{id=" + mId
+                + ", pkg=" + mService.serviceInfo.packageName
+                + ", service=" + mService.serviceInfo.name + "}";
+    }
+
     /**
      * Used to package this object into a {@link Parcel}.
      *
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/Display.java b/core/java/android/view/Display.java
index d3f63b4..d7a913d 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -204,6 +204,36 @@
     public static final int TYPE_VIRTUAL = 5;
 
     /**
+     * Display state: The display state is unknown.
+     *
+     * @see #getState
+     */
+    public static final int STATE_UNKNOWN = 0;
+
+    /**
+     * Display state: The display is off.
+     *
+     * @see #getState
+     */
+    public static final int STATE_OFF = 1;
+
+    /**
+     * Display state: The display is on.
+     *
+     * @see #getState
+     */
+    public static final int STATE_ON = 2;
+
+    /**
+     * Display state: The display is dozing in a low-power state; it may be showing
+     * system-provided content while the device is in a non-interactive state.
+     *
+     * @see #getState
+     * @see android.os.PowerManager#isInteractive
+     */
+    public static final int STATE_DOZING = 3;
+
+    /**
      * Internal method to create a display.
      * Applications should use {@link android.view.WindowManager#getDefaultDisplay()}
      * or {@link android.hardware.display.DisplayManager#getDisplay}
@@ -630,6 +660,19 @@
     }
 
     /**
+     * Gets the state of the display, such as whether it is on or off.
+     *
+     * @return The state of the display: one of {@link #STATE_OFF}, {@link #STATE_ON},
+     * {@link #STATE_DOZING}, or {@link #STATE_UNKNOWN}.
+     */
+    public int getState() {
+        synchronized (this) {
+            updateDisplayInfoLocked();
+            return mIsValid ? mDisplayInfo.state : STATE_UNKNOWN;
+        }
+    }
+
+    /**
      * Returns true if the specified UID has access to this display.
      * @hide
      */
@@ -720,5 +763,22 @@
                 return Integer.toString(type);
         }
     }
-}
 
+    /**
+     * @hide
+     */
+    public static String stateToString(int state) {
+        switch (state) {
+            case STATE_UNKNOWN:
+                return "UNKNOWN";
+            case STATE_OFF:
+                return "OFF";
+            case STATE_ON:
+                return "ON";
+            case STATE_DOZING:
+                return "DOZING";
+            default:
+                return Integer.toString(state);
+        }
+    }
+}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 7fd7b83..b0fe0fa 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -180,6 +180,11 @@
     public float physicalYDpi;
 
     /**
+     * The state of the display, such as {@link android.view.Display#STATE_ON}.
+     */
+    public int state;
+
+    /**
      * The UID of the application that owns this display, or zero if it is owned by the system.
      * <p>
      * If the display is private, then only the owner can use it.
@@ -248,6 +253,7 @@
                 && logicalDensityDpi == other.logicalDensityDpi
                 && physicalXDpi == other.physicalXDpi
                 && physicalYDpi == other.physicalYDpi
+                && state == other.state
                 && ownerUid == other.ownerUid
                 && Objects.equal(ownerPackageName, other.ownerPackageName);
     }
@@ -280,6 +286,7 @@
         logicalDensityDpi = other.logicalDensityDpi;
         physicalXDpi = other.physicalXDpi;
         physicalYDpi = other.physicalYDpi;
+        state = other.state;
         ownerUid = other.ownerUid;
         ownerPackageName = other.ownerPackageName;
     }
@@ -307,6 +314,7 @@
         logicalDensityDpi = source.readInt();
         physicalXDpi = source.readFloat();
         physicalYDpi = source.readFloat();
+        state = source.readInt();
         ownerUid = source.readInt();
         ownerPackageName = source.readString();
     }
@@ -335,6 +343,7 @@
         dest.writeInt(logicalDensityDpi);
         dest.writeFloat(physicalXDpi);
         dest.writeFloat(physicalYDpi);
+        dest.writeInt(state);
         dest.writeInt(ownerUid);
         dest.writeString(ownerPackageName);
     }
@@ -431,7 +440,7 @@
         sb.append(smallestNominalAppHeight);
         sb.append(", ");
         sb.append(refreshRate);
-        sb.append(" fps, rotation");
+        sb.append(" fps, rotation ");
         sb.append(rotation);
         sb.append(", density ");
         sb.append(logicalDensityDpi);
@@ -446,6 +455,8 @@
         if (address != null) {
             sb.append(", address ").append(address);
         }
+        sb.append(", state ");
+        sb.append(Display.stateToString(state));
         if (ownerUid != 0 || ownerPackageName != null) {
             sb.append(", owner ").append(ownerPackageName);
             sb.append(" (uid ").append(ownerUid).append(")");
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/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/KeyEvent.java b/core/java/android/view/KeyEvent.java
index c183f08..c3f429c 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1166,7 +1166,11 @@
 
     /**
      * This mask is set if the device woke because of this key event.
+     *
+     * @deprecated This flag will never be set by the system since the system
+     * consumes all wake keys itself.
      */
+    @Deprecated
     public static final int FLAG_WOKE_HERE = 0x1;
 
     /**
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 1ecc3c6..789b761 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -190,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
@@ -289,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/VolumePanel.java b/core/java/android/view/VolumePanel.java
index b05225b..8eae629 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -27,6 +27,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.media.AudioService;
 import android.media.AudioSystem;
@@ -238,6 +240,7 @@
             cleanUp();
         }
 
+        @Override
         public void onDismiss(DialogInterface unused) {
             mContext.unregisterReceiver(this);
             cleanUp();
@@ -259,8 +262,8 @@
         mAudioService = volumeService;
 
         // For now, only show master volume if master volume is supported
-        boolean useMasterVolume = context.getResources().getBoolean(
-                com.android.internal.R.bool.config_useMasterVolume);
+       final boolean useMasterVolume = context.getResources().getBoolean(
+               R.bool.config_useMasterVolume);
         if (useMasterVolume) {
             for (int i = 0; i < STREAMS.length; i++) {
                 StreamResources streamRes = STREAMS[i];
@@ -268,10 +271,18 @@
             }
         }
 
-        LayoutInflater inflater = (LayoutInflater) context
-                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        View view = mView = inflater.inflate(R.layout.volume_adjust, null);
+        final TypedArray a = context.obtainStyledAttributes(null,
+                com.android.internal.R.styleable.AlertDialog,
+                com.android.internal.R.attr.alertDialogStyle, 0);
+        final Drawable background = a.getDrawable(R.styleable.AlertDialog_fullBright);
+        a.recycle();
+
+        final LayoutInflater inflater = (LayoutInflater) context.getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+        mView = inflater.inflate(R.layout.volume_adjust, null);
+        mView.setBackground(background);
         mView.setOnTouchListener(new View.OnTouchListener() {
+            @Override
             public boolean onTouch(View v, MotionEvent event) {
                 resetTimeout();
                 return false;
@@ -279,10 +290,11 @@
         });
         mPanel = (ViewGroup) mView.findViewById(R.id.visible_panel);
         mSliderGroup = (ViewGroup) mView.findViewById(R.id.slider_group);
-        mMoreButton = (ImageView) mView.findViewById(R.id.expand_button);
-        mDivider = (ImageView) mView.findViewById(R.id.expand_button_divider);
+        mMoreButton = mView.findViewById(R.id.expand_button);
+        mDivider = mView.findViewById(R.id.expand_button_divider);
 
         mDialog = new Dialog(context, R.style.Theme_Panel_Volume) {
+            @Override
             public boolean onTouchEvent(MotionEvent event) {
                 if (isShowing() && event.getAction() == MotionEvent.ACTION_OUTSIDE &&
                         sConfirmSafeVolumeDialog == null) {
@@ -292,22 +304,25 @@
                 return false;
             }
         };
+        
         mDialog.setTitle("Volume control"); // No need to localize
         mDialog.setContentView(mView);
         mDialog.setOnDismissListener(new OnDismissListener() {
+            @Override
             public void onDismiss(DialogInterface dialog) {
                 mActiveStreamType = -1;
                 mAudioManager.forceVolumeControlStream(mActiveStreamType);
             }
         });
+
         // Change some window properties
-        Window window = mDialog.getWindow();
+        final Window window = mDialog.getWindow();
         window.setGravity(Gravity.TOP);
-        LayoutParams lp = window.getAttributes();
+
+        final LayoutParams lp = window.getAttributes();
         lp.token = null;
         // Offset from the top
-        lp.y = mContext.getResources().getDimensionPixelOffset(
-                com.android.internal.R.dimen.volume_panel_top);
+        lp.y = mContext.getResources().getDimensionPixelOffset(R.dimen.volume_panel_top);
         lp.type = LayoutParams.TYPE_VOLUME_OVERLAY;
         lp.width = LayoutParams.WRAP_CONTENT;
         lp.height = LayoutParams.WRAP_CONTENT;
@@ -320,6 +335,7 @@
 
         mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
         mShowCombinedVolumes = !mVoiceCapable && !useMasterVolume;
+        
         // If we don't want to show multiple volumes, hide the settings button and divider
         if (!mShowCombinedVolumes) {
             mMoreButton.setVisibility(View.GONE);
@@ -328,10 +344,10 @@
             mMoreButton.setOnClickListener(this);
         }
 
-        boolean masterVolumeOnly = context.getResources().getBoolean(
-                com.android.internal.R.bool.config_useMasterVolume);
-        boolean masterVolumeKeySounds = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_useVolumeKeySounds);
+        final boolean masterVolumeOnly = context.getResources().getBoolean(
+                R.bool.config_useMasterVolume);
+        final boolean masterVolumeKeySounds = mContext.getResources().getBoolean(
+                R.bool.config_useVolumeKeySounds);
 
         mPlayMasterStreamTones = masterVolumeOnly && masterVolumeKeySounds;
 
@@ -347,7 +363,7 @@
         final IntentFilter filter = new IntentFilter();
         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
         mContext.registerReceiver(new BroadcastReceiver() {
-
+            @Override
             public void onReceive(Context context, Intent intent) {
                 final String action = intent.getAction();
 
@@ -400,17 +416,21 @@
     }
 
     private void createSliders() {
-        LayoutInflater inflater = (LayoutInflater) mContext
-                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        final Resources res = mContext.getResources();
+        final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+
         mStreamControls = new HashMap<Integer, StreamControl>(STREAMS.length);
-        Resources res = mContext.getResources();
+
         for (int i = 0; i < STREAMS.length; i++) {
             StreamResources streamRes = STREAMS[i];
-            int streamType = streamRes.streamType;
+
+            final int streamType = streamRes.streamType;
             if (mVoiceCapable && streamRes == StreamResources.NotificationStream) {
                 streamRes = StreamResources.RingerStream;
             }
-            StreamControl sc = new StreamControl();
+
+            final StreamControl sc = new StreamControl();
             sc.streamType = streamType;
             sc.group = (ViewGroup) inflater.inflate(R.layout.volume_adjust_item, null);
             sc.group.setTag(sc);
@@ -421,7 +441,7 @@
             sc.iconMuteRes = streamRes.iconMuteRes;
             sc.icon.setImageResource(sc.iconRes);
             sc.seekbarView = (SeekBar) sc.group.findViewById(R.id.seekbar);
-            int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
+            final int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
                     streamType == AudioSystem.STREAM_VOICE_CALL) ? 1 : 0;
             sc.seekbarView.setMax(getStreamMaxVolume(streamType) + plusOne);
             sc.seekbarView.setOnSeekBarChangeListener(this);
@@ -433,7 +453,7 @@
     private void reorderSliders(int activeStreamType) {
         mSliderGroup.removeAllViews();
 
-        StreamControl active = mStreamControls.get(activeStreamType);
+        final StreamControl active = mStreamControls.get(activeStreamType);
         if (active == null) {
             Log.e("VolumePanel", "Missing stream type! - " + activeStreamType);
             mActiveStreamType = -1;
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/WindowManager.java b/core/java/android/view/WindowManager.java
index 53a4c0d0..d5a7d33 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -610,7 +610,10 @@
          * screen is pressed, you will receive this first touch event.  Usually
          * the first touch event is consumed by the system since the user can
          * not see what they are pressing on.
+         *
+         * @deprecated This flag has no effect.
          */
+        @Deprecated
         public static final int FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040;
         
         /** Window flag: as long as this window is visible to the user, keep
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index bd203c8..e68d4c0 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -90,8 +90,7 @@
     public final static int FLAG_FILTERED = 0x04000000;
     public final static int FLAG_DISABLE_KEY_REPEAT = 0x08000000;
 
-    public final static int FLAG_WOKE_HERE = 0x10000000;
-    public final static int FLAG_BRIGHT_HERE = 0x20000000;
+    public final static int FLAG_INTERACTIVE = 0x20000000;
     public final static int FLAG_PASS_TO_USER = 0x40000000;
 
     // Flags used for indicating whether the internal and/or external input devices
@@ -744,11 +743,10 @@
      * because it's the most fragile.
      * @param event The key event.
      * @param policyFlags The policy flags associated with the key.
-     * @param isScreenOn True if the screen is already on
      *
      * @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
      */
-    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
+    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
 
     /**
      * Called from the input reader thread before a motion is enqueued when the screen is off.
@@ -761,7 +759,7 @@
      *
      * @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
      */
-    public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags);
+    public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags);
 
     /**
      * Called from the input dispatcher thread before a key is dispatched to a window.
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/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 81d36a4..85168fd 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1691,6 +1691,9 @@
      * thread of this WebView. Care is therefore required to maintain thread
      * safety.</li>
      * <li> The Java object's fields are not accessible.</li>
+     * <li> For applications targeted to API level {@link android.os.Build.VERSION_CODES#L}
+     * and above, methods of injected Java objects are enumerable from
+     * JavaScript.</li>
      * </ul>
      *
      * @param object the Java object to inject into this WebView's JavaScript
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_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 36c8357..30d3e0c 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -127,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);
@@ -209,8 +195,6 @@
     { "nSetup", "(JII)V", (void*) android_view_ThreadedRenderer_setup },
     { "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/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/drawable-hdpi/scrubber_track_qntm_alpha.9.png b/core/res/res/drawable-hdpi/scrubber_track_qntm_alpha.9.png
new file mode 100644
index 0000000..32ddf7a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrubber_track_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_track_qntm_alpha.9.png b/core/res/res/drawable-mdpi/scrubber_track_qntm_alpha.9.png
new file mode 100644
index 0000000..db9e172
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_track_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_track_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/scrubber_track_qntm_alpha.9.png
new file mode 100644
index 0000000..805cb29
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/scrubber_track_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_track_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/scrubber_track_qntm_alpha.9.png
new file mode 100644
index 0000000..c3791fc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_track_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable/scrubber_control_selector_quantum.xml b/core/res/res/drawable/scrubber_control_selector_quantum.xml
index e31c2c1..e34f64a 100644
--- a/core/res/res/drawable/scrubber_control_selector_quantum.xml
+++ b/core/res/res/drawable/scrubber_control_selector_quantum.xml
@@ -15,12 +15,16 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="true" android:state_pressed="true">
+    <item android:state_enabled="false">
+        <bitmap android:src="@drawable/scrubber_control_off_qntm_alpha"
+            android:tint="?attr/colorControlNormal" />
+    </item>
+    <item android:state_pressed="true">
         <bitmap android:src="@drawable/scrubber_control_on_pressed_qntm_alpha"
             android:tint="?attr/colorControlActivated" />
     </item>
     <item>
         <bitmap android:src="@drawable/scrubber_control_on_qntm_alpha"
-            android:tint="?attr/colorControlNormal" />
+            android:tint="?attr/colorControlActivated" />
     </item>
 </selector>
diff --git a/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml b/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml
index 7b124ac..d172b05 100644
--- a/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml
+++ b/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml
@@ -15,12 +15,24 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true">
-        <bitmap android:src="@drawable/scrubber_primary_qntm_alpha"
-            android:tint="?attr/colorControlActivated" />
+    <item android:state_enabled="false">
+        <bitmap android:src="@drawable/scrubber_track_qntm_alpha"
+            android:tint="?attr/colorControlNormal" />
     </item>
     <item>
-        <bitmap android:src="@drawable/scrubber_primary_qntm_alpha"
-            android:tint="?attr/colorControlNormal" />
+        <layer-list>
+            <item android:id="@id/background">
+                <bitmap android:src="@drawable/scrubber_track_qntm_alpha"
+                    android:tint="?attr/colorControlNormal" />
+            </item>
+            <item android:id="@id/secondaryProgress">
+                <bitmap android:src="@drawable/scrubber_primary_qntm_alpha"
+                    android:tint="?attr/colorControlNormal" />
+            </item>
+            <item android:id="@id/progress">
+                <bitmap android:src="@drawable/scrubber_primary_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+        </layer-list>
     </item>
 </selector>
diff --git a/core/res/res/layout/volume_adjust.xml b/core/res/res/layout/volume_adjust.xml
index c16a12c..1cf7ca9 100644
--- a/core/res/res/layout/volume_adjust.xml
+++ b/core/res/res/layout/volume_adjust.xml
@@ -15,23 +15,20 @@
 -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="480dp"
+    android:layout_width="448dp"
     android:layout_height="wrap_content">
     <LinearLayout
         android:id="@+id/visible_panel"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:background="@android:drawable/dialog_full_holo_dark"
-        android:orientation="horizontal"
-        >
+        android:orientation="horizontal">
 
         <LinearLayout
             android:id="@+id/slider_group"
             android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_weight="1"
-            android:orientation="vertical"
-            >
+            android:orientation="vertical">
             <!-- Sliders go here -->
         </LinearLayout>
 
@@ -43,8 +40,7 @@
             android:scaleType="fitXY"
             android:layout_gravity="top"
             android:layout_marginTop="16dip"
-            android:layout_marginBottom="16dip"
-            />
+            android:layout_marginBottom="16dip" />
 
         <ImageView
             android:id="@+id/expand_button"
@@ -53,8 +49,7 @@
             android:layout_gravity="top"
             android:padding="16dip"
             android:background="?attr/selectableItemBackground"
-            android:src="@drawable/ic_sysbar_quicksettings"
-            />
+            android:src="@drawable/ic_sysbar_quicksettings" />
 
     </LinearLayout>
 </FrameLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/volume_adjust_item.xml b/core/res/res/layout/volume_adjust_item.xml
index 4a0fbaf..746cf91 100644
--- a/core/res/res/layout/volume_adjust_item.xml
+++ b/core/res/res/layout/volume_adjust_item.xml
@@ -26,16 +26,15 @@
         android:id="@+id/stream_icon"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:padding="16dip"
+        android:paddingLeft="16dip"
         android:background="?attr/selectableItemBackground"
-        />
+        android:contentDescription="@null" />
 
     <SeekBar
         style="?android:attr/seekBarStyle"
         android:id="@+id/seekbar"
-        android:layout_width="300dp"
+        android:layout_width="252dp"
         android:layout_height="wrap_content"
-        android:layout_weight="1"
         android:padding="16dip"
         android:layout_marginEnd="16dip" />
 
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/dimens.xml b/core/res/res/values/dimens.xml
index 94123a2..6b2c788 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -201,7 +201,7 @@
     <dimen name="textview_error_popup_default_width">240dip</dimen>
 
     <!-- Volume panel y offset -->
-    <dimen name="volume_panel_top">80dp</dimen>
+    <dimen name="volume_panel_top">16dp</dimen>
 
     <!-- Default padding to apply to AppWidgetHostViews containing widgets targeting API level 14 and up. -->
     <dimen name="default_app_widget_padding_left">8dp</dimen>
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/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
index 2810c43..3773a49 100644
--- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -44,9 +44,6 @@
  * Documentation pending.
  */
 public class TouchFeedbackDrawable extends LayerDrawable {
-    private static final PorterDuffXfermode DST_ATOP = new PorterDuffXfermode(Mode.DST_ATOP);
-    private static final PorterDuffXfermode DST_IN = new PorterDuffXfermode(Mode.DST_IN);
-
     /** The maximum number of ripples supported. */
     private static final int MAX_RIPPLES = 10;
 
@@ -153,10 +150,8 @@
      * @param tintMode A Porter-Duff blending mode
      */
     public void setTintMode(Mode tintMode) {
-        if (mState.mTintMode != tintMode) {
-            mState.mTintMode = tintMode;
-            invalidateSelf();
-        }
+        mState.setTintMode(tintMode);
+        invalidateSelf();
     }
 
     @Override
@@ -187,8 +182,8 @@
         }
 
         if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_tintMode] == 0) {
-            mState.mTintMode = Drawable.parseTintMode(
-                    a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP);
+            mState.setTintMode(Drawable.parseTintMode(
+                    a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP));
         }
 
         if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_pinned] == 0) {
@@ -238,8 +233,8 @@
         }
 
         if (a.hasValue(R.styleable.TouchFeedbackDrawable_tintMode)) {
-            mState.mTintMode = Drawable.parseTintMode(
-                    a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP);
+            mState.setTintMode(Drawable.parseTintMode(
+                    a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP));
         }
 
         if (a.hasValue(R.styleable.TouchFeedbackDrawable_pinned)) {
@@ -382,8 +377,9 @@
         // If we have ripples and content, we need a masking layer. This will
         // merge DST_ATOP onto (effectively under) the ripple layer.
         if (drewRipples && !projected && rippleRestoreCount >= 0) {
+            final PorterDuffXfermode xfermode = mState.getTintXfermode();
             canvas.saveLayer(bounds.left, bounds.top,
-                    bounds.right, bounds.bottom, getMaskingPaint(DST_ATOP), 0);
+                    bounds.right, bounds.bottom, getMaskingPaint(xfermode), 0);
         }
 
         Drawable mask = null;
@@ -401,7 +397,7 @@
         if (mask != null && drewRipples) {
             // TODO: This will also mask the lower layer, which is bad.
             canvas.saveLayer(bounds.left, bounds.top, bounds.right,
-                    bounds.bottom, getMaskingPaint(DST_IN), 0);
+                    bounds.bottom, getMaskingPaint(mState.mTintXfermode), 0);
             mask.draw(canvas);
         }
 
@@ -459,7 +455,7 @@
     static class TouchFeedbackState extends LayerState {
         int[] mTouchThemeAttrs;
         ColorStateList mTint;
-        Mode mTintMode;
+        PorterDuffXfermode mTintXfermode;
         boolean mPinned;
 
         public TouchFeedbackState(
@@ -469,10 +465,19 @@
             if (orig != null) {
                 mTouchThemeAttrs = orig.mTouchThemeAttrs;
                 mTint = orig.mTint;
-                mTintMode = orig.mTintMode;
+                mTintXfermode = orig.mTintXfermode;
                 mPinned = orig.mPinned;
             }
         }
+        
+        public void setTintMode(Mode mode) {
+            final Mode invertedMode = TouchFeedbackState.invertPorterDuffMode(mode);
+            mTintXfermode = new PorterDuffXfermode(invertedMode);
+        }
+        
+        public PorterDuffXfermode getTintXfermode() {
+            return mTintXfermode;
+        }
 
         @Override
         public boolean canApplyTheme() {
@@ -493,6 +498,33 @@
         public Drawable newDrawable(Resources res, Theme theme) {
             return new TouchFeedbackDrawable(this, res, theme);
         }
+
+        /**
+         * Inverts SRC and DST in PorterDuff blending modes.
+         */
+        private static Mode invertPorterDuffMode(Mode src) {
+            switch (src) {
+                case SRC_ATOP:
+                    return Mode.DST_ATOP;
+                case SRC_IN:
+                    return Mode.DST_IN;
+                case SRC_OUT:
+                    return Mode.DST_OUT;
+                case SRC_OVER:
+                    return Mode.DST_OVER;
+                case DST_ATOP:
+                    return Mode.SRC_ATOP;
+                case DST_IN:
+                    return Mode.SRC_IN;
+                case DST_OUT:
+                    return Mode.SRC_OUT;
+                case DST_OVER:
+                    return Mode.SRC_OVER;
+                default:
+                    // Everything else is agnostic to SRC versus DST.
+                    return src;
+            }
+        }
     }
 
     private TouchFeedbackDrawable(TouchFeedbackState state, Resources res, Theme theme) {
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 c64c169..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);
     }
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index c5122e2..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();
 }
 
@@ -387,6 +384,7 @@
 
 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);
@@ -431,55 +429,17 @@
     }
 }
 
-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) {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index a24162e..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 {
@@ -71,8 +60,6 @@
 
     bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
 
-    void attachFunctor(Functor* functor);
-    void detachFunctor(Functor* functor);
     void invokeFunctor(Functor* functor);
 
     void runWithGlContext(RenderTask* task);
@@ -85,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;
@@ -100,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 372d0d0..cf6c8db 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -30,7 +30,7 @@
 namespace uirenderer {
 namespace renderthread {
 
-DrawFrameTask::DrawFrameTask() : mContext(0), mTaskMode(MODE_INVALID), mRenderNode(0) {
+DrawFrameTask::DrawFrameTask() : mContext(0), mRenderNode(0) {
 }
 
 DrawFrameTask::~DrawFrameTask() {
@@ -69,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);
@@ -97,11 +88,6 @@
     // canUnblockUiThread is temporary until WebView has a solution for syncing frame state
     bool canUnblockUiThread = syncFrameState();
 
-    if (mTaskMode == MODE_STATE_ONLY) {
-        unblockUiThread();
-        return;
-    }
-
     // Grab a copy of everything we need
     Rect dirtyCopy(mDirty);
     sp<RenderNode> renderNode = mRenderNode;
@@ -125,12 +111,9 @@
     bool hasFunctors = false;
     mContext->processLayerUpdates(&mLayers, &hasFunctors);
 
-    // If we don't have an mRenderNode this is a state flush only
-    if (mRenderNode.get()) {
-        TreeInfo info = {0};
-        mRenderNode->prepareTree(info);
-        hasFunctors |= info.hasFunctors;
-    }
+    TreeInfo info = {0};
+    mRenderNode->prepareTree(info);
+    hasFunctors |= info.hasFunctors;
 
     return !hasFunctors;
 }
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index a512408..055d4cf 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -56,18 +56,11 @@
     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 postAndWait(RenderThread* renderThread);
     bool syncFrameState();
     void unblockUiThread();
     static void drawRenderNode(CanvasContext* context, RenderNode* renderNode, Rect* dirty);
@@ -80,7 +73,6 @@
     /*********************************************
      *  Single frame data
      *********************************************/
-    TaskMode mTaskMode;
     sp<RenderNode> mRenderNode;
     Rect mDirty;
 
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 49b9aca..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;
@@ -149,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 1ad3c85..3eb8ed8 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -67,8 +67,6 @@
             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/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/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index eb09335..aa4e69a 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -17,10 +17,12 @@
 package com.android.systemui.recent;
 
 import android.app.ActivityManager;
+import android.app.AppGlobals;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
@@ -30,7 +32,9 @@
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
@@ -162,9 +166,14 @@
             intent.setComponent(origActivity);
         }
         final PackageManager pm = mContext.getPackageManager();
+        final IPackageManager ipm = AppGlobals.getPackageManager();
         intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
                 | Intent.FLAG_ACTIVITY_NEW_TASK);
-        final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
+        ResolveInfo resolveInfo = null;
+        try {
+            resolveInfo = ipm.resolveIntent(intent, null, 0, userId);
+        } catch (RemoteException re) {
+        }
         if (resolveInfo != null) {
             final ActivityInfo info = resolveInfo.activityInfo;
             final String title = info.loadLabel(pm).toString();
@@ -192,7 +201,11 @@
         final PackageManager pm = mContext.getPackageManager();
         Bitmap thumbnail = am.getTaskTopThumbnail(td.persistentTaskId);
         Drawable icon = getFullResIcon(td.resolveInfo, pm);
-
+        if (td.userId != UserHandle.myUserId()) {
+            // Need to badge the icon
+            final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+            icon = um.getBadgedDrawableForUser(icon, new UserHandle(td.userId));
+        }
         if (DEBUG) Log.v(TAG, "Loaded bitmap for task "
                 + td + ": " + thumbnail);
         synchronized (td) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index 3c34e90..fd0f6d1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -192,8 +192,9 @@
                                     " forceLoad: " + forceLoadTask);
                     // Load the application icon
                     if (loadIcon == null || forceLoadTask) {
-                        ActivityInfo info = ssp.getActivityInfo(t.key.baseIntent.getComponent());
-                        Drawable icon = ssp.getActivityIcon(info);
+                        ActivityInfo info = ssp.getActivityInfo(t.key.baseIntent.getComponent(),
+                                t.userId);
+                        Drawable icon = ssp.getActivityIcon(info, t.userId);
                         if (!mCancelled) {
                             if (icon != null) {
                                 Console.log(Constants.DebugFlags.App.TaskDataLoader,
@@ -411,7 +412,7 @@
         int taskCount = tasks.size();
         for (int i = 0; i < taskCount; i++) {
             ActivityManager.RecentTaskInfo t = tasks.get(i);
-            ActivityInfo info = ssp.getActivityInfo(t.baseIntent.getComponent());
+            ActivityInfo info = ssp.getActivityInfo(t.baseIntent.getComponent(), t.userId);
             String activityLabel = (t.activityLabel == null ? ssp.getActivityLabel(info) :
                     t.activityLabel.toString());
             Bitmap activityIcon = t.activityIcon;
@@ -437,7 +438,7 @@
                     }
                 }
                 if (task.applicationIcon == null) {
-                    task.applicationIcon = ssp.getActivityIcon(info);
+                    task.applicationIcon = ssp.getActivityIcon(info, task.userId);
                     if (task.applicationIcon != null) {
                         mApplicationIconCache.put(task.key, task.applicationIcon);
                     } else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
index 505238d..7f0d9ee 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -18,14 +18,19 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
+import android.app.AppGlobals;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -38,6 +43,8 @@
 public class SystemServicesProxy {
     ActivityManager mAm;
     PackageManager mPm;
+    IPackageManager mIpm;
+    UserManager mUm;
     String mPackage;
 
     Bitmap mDummyIcon;
@@ -46,6 +53,8 @@
     public SystemServicesProxy(Context context) {
         mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
         mPm = context.getPackageManager();
+        mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        mIpm = AppGlobals.getPackageManager();
         mPackage = context.getPackageName();
 
         if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
@@ -142,14 +151,19 @@
         mAm.removeTask(taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
     }
 
-    /** Returns the activity info for a given component name */
-    public ActivityInfo getActivityInfo(ComponentName cn) {
-        if (mPm == null) return null;
+    /**
+     * Returns the activity info for a given component name.
+     * 
+     * @param ComponentName The component name of the activity.
+     * @param userId The userId of the user that this is for.
+     */
+    public ActivityInfo getActivityInfo(ComponentName cn, int userId) {
+        if (mIpm == null) return null;
         if (Constants.DebugFlags.App.EnableSystemServicesProxy) return null;
 
         try {
-            return mPm.getActivityInfo(cn, PackageManager.GET_META_DATA);
-        } catch (PackageManager.NameNotFoundException e) {
+            return mIpm.getActivityInfo(cn, PackageManager.GET_META_DATA, userId);
+        } catch (RemoteException e) {
             e.printStackTrace();
             return null;
         }
@@ -167,15 +181,22 @@
         return info.loadLabel(mPm).toString();
     }
 
-    /** Returns the activity icon */
-    public Drawable getActivityIcon(ActivityInfo info) {
-        if (mPm == null) return null;
+    /**
+     * Returns the activity icon for the ActivityInfo for a user, badging if
+     * necessary.
+     */
+    public Drawable getActivityIcon(ActivityInfo info, int userId) {
+        if (mPm == null || mUm == null) return null;
 
         // If we are mocking, then return a mock label
         if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
             return new ColorDrawable(0xFF666666);
         }
 
-        return info.loadIcon(mPm);
+        Drawable icon = info.loadIcon(mPm);
+        if (userId != UserHandle.myUserId()) {
+            icon = mUm.getBadgedDrawableForUser(icon, new UserHandle(userId));
+        }
+        return icon;
     }
 }
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 189f358..ff062f6c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -37,25 +37,33 @@
     public static class TaskKey {
         public final int id;
         public final Intent baseIntent;
+        public final int userId;
 
-        public TaskKey(int id, Intent intent) {
+        public TaskKey(int id, Intent intent, int userId) {
             this.id = id;
             this.baseIntent = intent;
+            this.userId = userId;
         }
 
         @Override
         public boolean equals(Object o) {
-            return hashCode() == o.hashCode();
+            if (!(o instanceof TaskKey)) {
+                return false;
+            }
+            return id == ((TaskKey) o).id
+                    && userId == ((TaskKey) o).userId;
         }
 
         @Override
         public int hashCode() {
-            return id;
+            return (id << 5) + userId;
         }
 
         @Override
         public String toString() {
-            return "Task.Key: " + id + ", " + baseIntent.getComponent().getPackageName();
+            return "Task.Key: " + id + ", "
+                    + "u" + userId + ", "
+                    + baseIntent.getComponent().getPackageName();
         }
     }
 
@@ -75,7 +83,7 @@
 
     public Task(int id, boolean isActive, Intent intent, String activityTitle,
                 Bitmap activityIcon, int userId) {
-        this.key = new TaskKey(id, intent);
+        this.key = new TaskKey(id, intent, userId);
         this.activityLabel = activityTitle;
         this.activityIcon = activityIcon;
         this.isActive = isActive;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index f1299fe..2f135ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -138,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;
@@ -880,7 +881,7 @@
             }
         }
         entry.row = row;
-        entry.row.setRowHeight(mRowHeight);
+        entry.row.setHeightRange(mRowMinHeight, mRowMaxHeight);
         entry.content = content;
         entry.expanded = contentViewLocal;
         entry.expandedPublic = publicViewLocal;
@@ -1055,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);
                     }
@@ -1218,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);
             }
         }
 
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/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 f3dd7e3..841f3ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -2641,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/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ccdacea..216f6a4 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -986,7 +986,7 @@
         initializeHdmiState();
 
         // Match current screen state.
-        if (mPowerManager.isScreenOn()) {
+        if (mPowerManager.isInteractive()) {
             screenTurningOn(null);
         } else {
             screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
@@ -2357,7 +2357,7 @@
     }
 
     private boolean interceptFallback(WindowState win, KeyEvent fallbackEvent, int policyFlags) {
-        int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags, true);
+        int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags);
         if ((actions & ACTION_PASS_TO_USER) != 0) {
             long delayMillis = interceptKeyBeforeDispatching(
                     win, fallbackEvent, policyFlags);
@@ -3801,12 +3801,13 @@
 
     /** {@inheritDoc} */
     @Override
-    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
+    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
         if (!mSystemBooted) {
             // If we have not yet booted, don't let key events do anything.
             return 0;
         }
 
+        final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
         final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
         final boolean canceled = event.isCanceled();
         final int keyCode = event.getKeyCode();
@@ -3818,7 +3819,7 @@
         // This will prevent any keys other than the power button from waking the screen
         // when the keyguard is hidden by another activity.
         final boolean keyguardActive = (mKeyguardDelegate == null ? false :
-                                            (isScreenOn ?
+                                            (interactive ?
                                                 mKeyguardDelegate.isShowingAndNotHidden() :
                                                 mKeyguardDelegate.isShowing()));
 
@@ -3830,7 +3831,7 @@
 
         if (DEBUG_INPUT) {
             Log.d(TAG, "interceptKeyTq keycode=" + keyCode
-                    + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive
+                    + " interactive=" + interactive + " keyguardActive=" + keyguardActive
                     + " policyFlags=" + Integer.toHexString(policyFlags));
         }
 
@@ -3839,18 +3840,11 @@
             performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
         }
 
-        // Basic policy based on screen state and keyguard.
-        // FIXME: This policy isn't quite correct.  We shouldn't care whether the screen
-        //        is on or off, really.  We should care about whether the device is in an
-        //        interactive state or is in suspend pretending to be "off".
-        //        The primary screen might be turned off due to proximity sensor or
-        //        because we are presenting media on an auxiliary screen or remotely controlling
-        //        the device some other way (which is why we have an exemption here for injected
-        //        events).
+        // Basic policy based on interactive state.
         int result;
         boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
                 | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
-        if (isScreenOn || (isInjected && !isWakeKey)) {
+        if (interactive || (isInjected && !isWakeKey)) {
             // When the screen is on or if the key is injected pass the key to the application.
             result = ACTION_PASS_TO_USER;
         } else {
@@ -3875,7 +3869,7 @@
             case KeyEvent.KEYCODE_VOLUME_MUTE: {
                 if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
                     if (down) {
-                        if (isScreenOn && !mVolumeDownKeyTriggered
+                        if (interactive && !mVolumeDownKeyTriggered
                                 && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
                             mVolumeDownKeyTriggered = true;
                             mVolumeDownKeyTime = event.getDownTime();
@@ -3889,7 +3883,7 @@
                     }
                 } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
                     if (down) {
-                        if (isScreenOn && !mVolumeUpKeyTriggered
+                        if (interactive && !mVolumeUpKeyTriggered
                                 && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
                             mVolumeUpKeyTriggered = true;
                             cancelPendingPowerKeyAction();
@@ -3957,7 +3951,7 @@
                             Log.w(TAG, "ITelephony threw RemoteException", ex);
                         }
                     }
-                    interceptPowerKeyDown(!isScreenOn || hungUp);
+                    interceptPowerKeyDown(!interactive || hungUp);
                 } else {
                     if (interceptPowerKeyUp(canceled)) {
                         if ((mEndcallBehavior
@@ -3979,12 +3973,12 @@
             case KeyEvent.KEYCODE_POWER: {
                 result &= ~ACTION_PASS_TO_USER;
                 if (down) {
-                    boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
+                    boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive,
                             event.getDownTime(), isImmersiveMode(mLastSystemUiFlags));
                     if (panic) {
                         mHandler.post(mRequestTransientNav);
                     }
-                    if (isScreenOn && !mPowerKeyTriggered
+                    if (interactive && !mPowerKeyTriggered
                             && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
                         mPowerKeyTriggered = true;
                         mPowerKeyTime = event.getDownTime();
@@ -4001,7 +3995,7 @@
                                 telephonyService.silenceRinger();
                             } else if ((mIncallPowerBehavior
                                     & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
-                                    && telephonyService.isOffhook() && isScreenOn) {
+                                    && telephonyService.isOffhook() && interactive) {
                                 // Otherwise, if "Power button ends call" is enabled,
                                 // the Power button will hang up any current active call.
                                 hungUp = telephonyService.endCall();
@@ -4010,7 +4004,7 @@
                             Log.w(TAG, "ITelephony threw RemoteException", ex);
                         }
                     }
-                    interceptPowerKeyDown(!isScreenOn || hungUp
+                    interceptPowerKeyDown(!interactive || hungUp
                             || mVolumeDownKeyTriggered || mVolumeUpKeyTriggered);
                 } else {
                     mPowerKeyTriggered = false;
@@ -4143,15 +4137,12 @@
 
     /** {@inheritDoc} */
     @Override
-    public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
-        int result = 0;
-
-        final boolean isWakeMotion = (policyFlags
-                & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
-        if (isWakeMotion) {
-            mPowerManager.wakeUp(whenNanos / 1000000);
-        }
-        return result;
+    public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags) {
+        // We already know this is a wake motion so just wake up.
+        // Note that we would observe policyFlags containing
+        // FLAG_WAKE and FLAG_INTERACTIVE here.
+        mPowerManager.wakeUp(whenNanos / 1000000);
+        return 0;
     }
 
     void dispatchMediaKeyWithWakeLock(KeyEvent event) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index c3db55e..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,
diff --git a/services/core/java/com/android/server/display/DisplayBlanker.java b/services/core/java/com/android/server/display/DisplayBlanker.java
new file mode 100644
index 0000000..eb0ae6a
--- /dev/null
+++ b/services/core/java/com/android/server/display/DisplayBlanker.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+/**
+ * Interface used to update the actual display state.
+ */
+public interface DisplayBlanker {
+    void requestDisplayState(int state);
+}
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 9ec1122..a5f9822 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -107,15 +107,9 @@
     }
 
     /**
-     * Blanks the display, if supported.
+     * Sets the display state, if supported.
      */
-    public void blankLocked() {
-    }
-
-    /**
-     * Unblanks the display, if supported.
-     */
-    public void unblankLocked() {
+    public void requestDisplayStateLocked(int state) {
     }
 
     /**
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 75f1f53..a77443d 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -176,6 +176,11 @@
     public String address;
 
     /**
+     * Display state.
+     */
+    public int state = Display.STATE_ON;
+
+    /**
      * The UID of the application that owns this display, or zero if it is owned by the system.
      * <p>
      * If the display is private, then only the owner can use it.
@@ -219,6 +224,7 @@
                 && rotation == other.rotation
                 && type == other.type
                 && Objects.equal(address, other.address)
+                && state == other.state
                 && ownerUid == other.ownerUid
                 && Objects.equal(ownerPackageName, other.ownerPackageName);
     }
@@ -241,6 +247,7 @@
         rotation = other.rotation;
         type = other.type;
         address = other.address;
+        state = other.state;
         ownerUid = other.ownerUid;
         ownerPackageName = other.ownerPackageName;
     }
@@ -260,6 +267,7 @@
         if (address != null) {
             sb.append(", address ").append(address);
         }
+        sb.append(", state ").append(Display.stateToString(state));
         if (ownerUid != 0 || ownerPackageName != null) {
             sb.append(", owner ").append(ownerPackageName);
             sb.append(" (uid ").append(ownerUid).append(")");
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 693f7d8..071417b 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -121,10 +121,6 @@
     private static final int MSG_REQUEST_TRAVERSAL = 4;
     private static final int MSG_UPDATE_VIEWPORT = 5;
 
-    private static final int DISPLAY_BLANK_STATE_UNKNOWN = 0;
-    private static final int DISPLAY_BLANK_STATE_BLANKED = 1;
-    private static final int DISPLAY_BLANK_STATE_UNBLANKED = 2;
-
     private final Context mContext;
     private final DisplayManagerHandler mHandler;
     private final Handler mUiHandler;
@@ -176,8 +172,9 @@
     // Display power controller.
     private DisplayPowerController mDisplayPowerController;
 
-    // Set to true if all displays have been blanked by the power manager.
-    private int mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNKNOWN;
+    // The overall display state, independent of changes that might influence one
+    // display or another in particular.
+    private int mGlobalDisplayState = Display.STATE_UNKNOWN;
 
     // Set to true when there are pending display changes that have yet to be applied
     // to the surface flinger state.
@@ -315,21 +312,11 @@
         }
     }
 
-    private void blankAllDisplaysFromPowerManagerInternal() {
+    private void requestGlobalDisplayStateInternal(int state) {
         synchronized (mSyncRoot) {
-            if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_BLANKED) {
-                mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_BLANKED;
-                updateAllDisplayBlankingLocked();
-                scheduleTraversalLocked(false);
-            }
-        }
-    }
-
-    private void unblankAllDisplaysFromPowerManagerInternal() {
-        synchronized (mSyncRoot) {
-            if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_UNBLANKED) {
-                mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNBLANKED;
-                updateAllDisplayBlankingLocked();
+            if (mGlobalDisplayState != state) {
+                mGlobalDisplayState = state;
+                updateGlobalDisplayStateLocked();
                 scheduleTraversalLocked(false);
             }
         }
@@ -616,7 +603,7 @@
 
         mDisplayDevices.add(device);
         addLogicalDisplayLocked(device);
-        updateDisplayBlankingLocked(device);
+        updateDisplayStateLocked(device);
         scheduleTraversalLocked(false);
     }
 
@@ -655,27 +642,20 @@
         scheduleTraversalLocked(false);
     }
 
-    private void updateAllDisplayBlankingLocked() {
+    private void updateGlobalDisplayStateLocked() {
         final int count = mDisplayDevices.size();
         for (int i = 0; i < count; i++) {
             DisplayDevice device = mDisplayDevices.get(i);
-            updateDisplayBlankingLocked(device);
+            updateDisplayStateLocked(device);
         }
     }
 
-    private void updateDisplayBlankingLocked(DisplayDevice device) {
+    private void updateDisplayStateLocked(DisplayDevice device) {
         // Blank or unblank the display immediately to match the state requested
-        // by the power manager (if known).
+        // by the display power controller (if known).
         DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
         if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
-            switch (mAllDisplayBlankStateFromPowerManager) {
-                case DISPLAY_BLANK_STATE_BLANKED:
-                    device.blankLocked();
-                    break;
-                case DISPLAY_BLANK_STATE_UNBLANKED:
-                    device.unblankLocked();
-                    break;
-            }
+            device.requestDisplayStateLocked(mGlobalDisplayState);
         }
     }
 
@@ -816,9 +796,7 @@
                     + device.getDisplayDeviceInfoLocked());
             return;
         }
-        boolean isBlanked = (mAllDisplayBlankStateFromPowerManager == DISPLAY_BLANK_STATE_BLANKED)
-                && (info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0;
-        display.configureDisplayInTransactionLocked(device, isBlanked);
+        display.configureDisplayInTransactionLocked(device, info.state == Display.STATE_OFF);
 
         // Update the viewports if needed.
         if (!mDefaultViewport.valid
@@ -897,8 +875,7 @@
             pw.println("  mOnlyCode=" + mOnlyCore);
             pw.println("  mSafeMode=" + mSafeMode);
             pw.println("  mPendingTraversal=" + mPendingTraversal);
-            pw.println("  mAllDisplayBlankStateFromPowerManager="
-                    + mAllDisplayBlankStateFromPowerManager);
+            pw.println("  mGlobalDisplayState=" + Display.stateToString(mGlobalDisplayState));
             pw.println("  mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId);
             pw.println("  mDefaultViewport=" + mDefaultViewport);
             pw.println("  mExternalTouchViewport=" + mExternalTouchViewport);
@@ -1322,11 +1299,26 @@
 
     private final class LocalService extends DisplayManagerInternal {
         @Override
-        public void initPowerManagement(DisplayPowerCallbacks callbacks, Handler handler,
+        public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler,
                 SensorManager sensorManager) {
             synchronized (mSyncRoot) {
+                DisplayBlanker blanker = new DisplayBlanker() {
+                    @Override
+                    public void requestDisplayState(int state) {
+                        // The order of operations is important for legacy reasons.
+                        if (state == Display.STATE_OFF) {
+                            requestGlobalDisplayStateInternal(state);
+                        }
+
+                        callbacks.onDisplayStateChange(state);
+
+                        if (state != Display.STATE_OFF) {
+                            requestGlobalDisplayStateInternal(state);
+                        }
+                    }
+                };
                 mDisplayPowerController = new DisplayPowerController(
-                        mContext, callbacks, handler, sensorManager);
+                        mContext, callbacks, handler, sensorManager, blanker);
             }
         }
 
@@ -1343,16 +1335,6 @@
         }
 
         @Override
-        public void blankAllDisplaysFromPowerManager() {
-            blankAllDisplaysFromPowerManagerInternal();
-        }
-
-        @Override
-        public void unblankAllDisplaysFromPowerManager() {
-            unblankAllDisplaysFromPowerManagerInternal();
-        }
-
-        @Override
         public DisplayInfo getDisplayInfo(int displayId) {
             return getDisplayInfoInternal(displayId, Process.myUid());
         }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 62fb02a..1f38eb6 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -42,6 +42,7 @@
 import android.util.Slog;
 import android.util.Spline;
 import android.util.TimeUtils;
+import android.view.Display;
 
 import java.io.PrintWriter;
 
@@ -122,6 +123,9 @@
     // The sensor manager.
     private final SensorManager mSensorManager;
 
+    // The display blanker.
+    private final DisplayBlanker mBlanker;
+
     // The proximity sensor, or null if not available or needed.
     private Sensor mProximitySensor;
 
@@ -225,13 +229,15 @@
      * Creates the display power controller.
      */
     public DisplayPowerController(Context context,
-            DisplayPowerCallbacks callbacks, Handler handler, SensorManager sensorManager) {
+            DisplayPowerCallbacks callbacks, Handler handler,
+            SensorManager sensorManager, DisplayBlanker blanker) {
         mHandler = new DisplayControllerHandler(handler.getLooper());
         mCallbacks = callbacks;
 
         mBatteryStats = BatteryStatsService.getService();
         mLights = LocalServices.getService(LightsManager.class);
         mSensorManager = sensorManager;
+        mBlanker = blanker;
 
         final Resources resources = context.getResources();
 
@@ -366,8 +372,11 @@
     }
 
     private void initialize() {
-        mPowerState = new DisplayPowerState(new ElectronBeam(), mCallbacks,
-                mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT));
+        // Initialize the power state object for the default display.
+        // In the future, we might manage multiple displays independently.
+        mPowerState = new DisplayPowerState(mBlanker,
+                mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
+                new ElectronBeam(Display.DEFAULT_DISPLAY));
 
         mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
                 mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
@@ -384,7 +393,7 @@
 
         // Initialize screen state for battery stats.
         try {
-            if (mPowerState.isScreenOn()) {
+            if (mPowerState.getScreenState() != Display.STATE_OFF) {
                 mBatteryStats.noteScreenOn();
             } else {
                 mBatteryStats.noteScreenOff();
@@ -523,7 +532,7 @@
         // Animate the screen on or off unless blocked.
         if (mScreenOffBecauseOfProximity) {
             // Screen off due to proximity.
-            setScreenOn(false);
+            setScreenState(Display.STATE_OFF);
             unblockScreenOn();
         } else if (mPowerRequest.wantScreenOnAny()) {
             // Want screen on.
@@ -534,7 +543,8 @@
                 // Turn the screen on.  The contents of the screen may not yet
                 // be visible if the electron beam has not been dismissed because
                 // its last frame of animation is solid black.
-                setScreenOn(true);
+                setScreenState(mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE
+                        ? Display.STATE_DOZING : Display.STATE_ON);
 
                 if (mPowerRequest.blockScreenOn
                         && mPowerState.getElectronBeamLevel() == 0.0f) {
@@ -567,12 +577,12 @@
             if (!mElectronBeamOnAnimator.isStarted()) {
                 if (!mElectronBeamOffAnimator.isStarted()) {
                     if (mPowerState.getElectronBeamLevel() == 0.0f) {
-                        setScreenOn(false);
+                        setScreenState(Display.STATE_OFF);
                     } else if (mPowerState.prepareElectronBeam(
                             mElectronBeamFadesConfig ?
                                     ElectronBeam.MODE_FADE :
                                             ElectronBeam.MODE_COOL_DOWN)
-                            && mPowerState.isScreenOn()) {
+                            && mPowerState.getScreenState() != Display.STATE_OFF) {
                         mElectronBeamOffAnimator.start();
                     } else {
                         mElectronBeamOffAnimator.end();
@@ -610,9 +620,9 @@
     private void blockScreenOn() {
         if (!mScreenOnWasBlocked) {
             mScreenOnWasBlocked = true;
+            mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
             if (DEBUG) {
                 Slog.d(TAG, "Blocked screen on.");
-                mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
             }
         }
     }
@@ -627,11 +637,11 @@
         }
     }
 
-    private void setScreenOn(boolean on) {
-        if (mPowerState.isScreenOn() != on) {
-            mPowerState.setScreenOn(on);
+    private void setScreenState(int state) {
+        if (mPowerState.getScreenState() != state) {
+            mPowerState.setScreenState(state);
             try {
-                if (on) {
+                if (state != Display.STATE_OFF) {
                     mBatteryStats.noteScreenOn();
                 } else {
                     mBatteryStats.noteScreenOff();
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index e1416d7..a5f8849 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -18,7 +18,6 @@
 
 import com.android.server.lights.Light;
 
-import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Looper;
@@ -27,6 +26,7 @@
 import android.util.IntProperty;
 import android.util.Slog;
 import android.view.Choreographer;
+import android.view.Display;
 
 import java.io.PrintWriter;
 
@@ -54,12 +54,12 @@
 
     private final Handler mHandler;
     private final Choreographer mChoreographer;
-    private final ElectronBeam mElectronBeam;
-    private final DisplayPowerCallbacks mCallbacks;
+    private final DisplayBlanker mBlanker;
     private final Light mBacklight;
+    private final ElectronBeam mElectronBeam;
     private final PhotonicModulator mPhotonicModulator;
 
-    private boolean mScreenOn;
+    private int mScreenState;
     private int mScreenBrightness;
     private boolean mScreenReady;
     private boolean mScreenUpdatePending;
@@ -71,13 +71,12 @@
 
     private Runnable mCleanListener;
 
-    public DisplayPowerState(ElectronBeam electronBean,
-            DisplayPowerCallbacks callbacks, Light backlight) {
+    public DisplayPowerState(DisplayBlanker blanker, Light backlight, ElectronBeam electronBeam) {
         mHandler = new Handler(true /*async*/);
         mChoreographer = Choreographer.getInstance();
-        mElectronBeam = electronBean;
-        mCallbacks = callbacks;
+        mBlanker = blanker;
         mBacklight = backlight;
+        mElectronBeam = electronBeam;
         mPhotonicModulator = new PhotonicModulator();
 
         // At boot time, we know that the screen is on and the electron beam
@@ -86,7 +85,7 @@
         // Although we set the brightness to full on here, the display power controller
         // will reset the brightness to a new level immediately before the changes
         // actually have a chance to be applied.
-        mScreenOn = true;
+        mScreenState = Display.STATE_ON;
         mScreenBrightness = PowerManager.BRIGHTNESS_ON;
         scheduleScreenUpdate();
 
@@ -122,25 +121,25 @@
     };
 
     /**
-     * Sets whether the screen is on or off.
+     * Sets whether the screen is on, off, or dozing.
      */
-    public void setScreenOn(boolean on) {
-        if (mScreenOn != on) {
+    public void setScreenState(int state) {
+        if (mScreenState != state) {
             if (DEBUG) {
-                Slog.d(TAG, "setScreenOn: on=" + on);
+                Slog.d(TAG, "setScreenState: state=" + state);
             }
 
-            mScreenOn = on;
+            mScreenState = state;
             mScreenReady = false;
             scheduleScreenUpdate();
         }
     }
 
     /**
-     * Returns true if the screen is on.
+     * Gets the desired screen state.
      */
-    public boolean isScreenOn() {
-        return mScreenOn;
+    public int getScreenState() {
+        return mScreenState;
     }
 
     /**
@@ -155,7 +154,7 @@
             }
 
             mScreenBrightness = brightness;
-            if (mScreenOn) {
+            if (mScreenState != Display.STATE_OFF) {
                 mScreenReady = false;
                 scheduleScreenUpdate();
             }
@@ -219,7 +218,7 @@
             }
 
             mElectronBeamLevel = level;
-            if (mScreenOn) {
+            if (mScreenState != Display.STATE_OFF) {
                 mScreenReady = false;
                 scheduleScreenUpdate(); // update backlight brightness
             }
@@ -256,7 +255,7 @@
     public void dump(PrintWriter pw) {
         pw.println();
         pw.println("Display Power State:");
-        pw.println("  mScreenOn=" + mScreenOn);
+        pw.println("  mScreenState=" + Display.stateToString(mScreenState));
         pw.println("  mScreenBrightness=" + mScreenBrightness);
         pw.println("  mScreenReady=" + mScreenReady);
         pw.println("  mScreenUpdatePending=" + mScreenUpdatePending);
@@ -302,8 +301,9 @@
         public void run() {
             mScreenUpdatePending = false;
 
-            int brightness = mScreenOn && mElectronBeamLevel > 0f ? mScreenBrightness : 0;
-            if (mPhotonicModulator.setState(mScreenOn, brightness)) {
+            int brightness = mScreenState != Display.STATE_OFF
+                    && mElectronBeamLevel > 0f ? mScreenBrightness : 0;
+            if (mPhotonicModulator.setState(mScreenState, brightness)) {
                 if (DEBUG) {
                     Slog.d(TAG, "Screen ready");
                 }
@@ -335,26 +335,26 @@
      * Updates the state of the screen and backlight asynchronously on a separate thread.
      */
     private final class PhotonicModulator {
-        private static final boolean INITIAL_SCREEN_ON = false; // unknown, assume off
+        private static final int INITIAL_SCREEN_STATE = Display.STATE_OFF; // unknown, assume off
         private static final int INITIAL_BACKLIGHT = -1; // unknown
 
         private final Object mLock = new Object();
 
-        private boolean mPendingOn = INITIAL_SCREEN_ON;
+        private int mPendingState = INITIAL_SCREEN_STATE;
         private int mPendingBacklight = INITIAL_BACKLIGHT;
-        private boolean mActualOn = INITIAL_SCREEN_ON;
+        private int mActualState = INITIAL_SCREEN_STATE;
         private int mActualBacklight = INITIAL_BACKLIGHT;
         private boolean mChangeInProgress;
 
-        public boolean setState(boolean on, int backlight) {
+        public boolean setState(int state, int backlight) {
             synchronized (mLock) {
-                if (on != mPendingOn || backlight != mPendingBacklight) {
+                if (state != mPendingState || backlight != mPendingBacklight) {
                     if (DEBUG) {
-                        Slog.d(TAG, "Requesting new screen state: on=" + on
-                                + ", backlight=" + backlight);
+                        Slog.d(TAG, "Requesting new screen state: state="
+                                + Display.stateToString(state) + ", backlight=" + backlight);
                     }
 
-                    mPendingOn = on;
+                    mPendingState = state;
                     mPendingBacklight = backlight;
 
                     if (!mChangeInProgress) {
@@ -369,9 +369,9 @@
         public void dump(PrintWriter pw) {
             pw.println();
             pw.println("Photonic Modulator State:");
-            pw.println("  mPendingOn=" + mPendingOn);
+            pw.println("  mPendingState=" + Display.stateToString(mPendingState));
             pw.println("  mPendingBacklight=" + mPendingBacklight);
-            pw.println("  mActualOn=" + mActualOn);
+            pw.println("  mActualState=" + Display.stateToString(mActualState));
             pw.println("  mActualBacklight=" + mActualBacklight);
             pw.println("  mChangeInProgress=" + mChangeInProgress);
         }
@@ -381,35 +381,35 @@
             public void run() {
                 // Apply pending changes until done.
                 for (;;) {
-                    final boolean on;
-                    final boolean onChanged;
+                    final int state;
+                    final boolean stateChanged;
                     final int backlight;
                     final boolean backlightChanged;
                     synchronized (mLock) {
-                        on = mPendingOn;
-                        onChanged = (on != mActualOn);
+                        state = mPendingState;
+                        stateChanged = (state != mActualState);
                         backlight = mPendingBacklight;
                         backlightChanged = (backlight != mActualBacklight);
-                        if (!onChanged && !backlightChanged) {
+                        if (!stateChanged && !backlightChanged) {
                             mChangeInProgress = false;
                             break;
                         }
-                        mActualOn = on;
+                        mActualState = state;
                         mActualBacklight = backlight;
                     }
 
                     if (DEBUG) {
-                        Slog.d(TAG, "Updating screen state: on=" + on
-                                + ", backlight=" + backlight);
+                        Slog.d(TAG, "Updating screen state: state="
+                                + Display.stateToString(state) + ", backlight=" + backlight);
                     }
-                    if (onChanged && on) {
-                        mCallbacks.unblankAllDisplays();
+                    if (stateChanged && state != Display.STATE_OFF) {
+                        mBlanker.requestDisplayState(state);
                     }
                     if (backlightChanged) {
                         mBacklight.setBrightness(backlight);
                     }
-                    if (onChanged && !on) {
-                        mCallbacks.blankAllDisplays();
+                    if (stateChanged && state == Display.STATE_OFF) {
+                        mBlanker.requestDisplayState(state);
                     }
                 }
 
diff --git a/services/core/java/com/android/server/display/ElectronBeam.java b/services/core/java/com/android/server/display/ElectronBeam.java
index 13816bb..18e4049 100644
--- a/services/core/java/com/android/server/display/ElectronBeam.java
+++ b/services/core/java/com/android/server/display/ElectronBeam.java
@@ -35,7 +35,6 @@
 import android.os.Looper;
 import android.util.FloatMath;
 import android.util.Slog;
-import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.Surface.OutOfResourcesException;
 import android.view.Surface;
@@ -74,6 +73,8 @@
     // See code for details.
     private static final int DEJANK_FRAMES = 3;
 
+    private final int mDisplayId;
+
     // Set to true when the animation context has been fully prepared.
     private boolean mPrepared;
     private int mMode;
@@ -118,8 +119,8 @@
      */
     public static final int MODE_FADE = 2;
 
-
-    public ElectronBeam() {
+    public ElectronBeam(int displayId) {
+        mDisplayId = displayId;
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
     }
 
@@ -139,7 +140,7 @@
 
         // Get the display size and layer stack.
         // This is not expected to change while the electron beam surface is showing.
-        DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(Display.DEFAULT_DISPLAY);
+        DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
         mDisplayLayerStack = displayInfo.layerStack;
         mDisplayWidth = displayInfo.getNaturalWidth();
         mDisplayHeight = displayInfo.getNaturalHeight();
@@ -528,7 +529,8 @@
             mSurface = new Surface();
             mSurface.copyFrom(mSurfaceControl);
 
-            mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal, mSurfaceControl);
+            mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
+                    mDisplayId, mSurfaceControl);
             mSurfaceLayout.onDisplayTransaction();
         } finally {
             SurfaceControl.closeTransaction();
@@ -687,11 +689,13 @@
      */
     private static final class NaturalSurfaceLayout implements DisplayTransactionListener {
         private final DisplayManagerInternal mDisplayManagerInternal;
+        private final int mDisplayId;
         private SurfaceControl mSurfaceControl;
 
         public NaturalSurfaceLayout(DisplayManagerInternal displayManagerInternal,
-                SurfaceControl surfaceControl) {
+                int displayId, SurfaceControl surfaceControl) {
             mDisplayManagerInternal = displayManagerInternal;
+            mDisplayId = displayId;
             mSurfaceControl = surfaceControl;
             mDisplayManagerInternal.registerDisplayTransactionListener(this);
         }
@@ -710,8 +714,7 @@
                     return;
                 }
 
-                DisplayInfo displayInfo =
-                        mDisplayManagerInternal.getDisplayInfo(Display.DEFAULT_DISPLAY);
+                DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
                 switch (displayInfo.rotation) {
                     case Surface.ROTATION_0:
                         mSurfaceControl.setPosition(0, 0);
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 02be477..2c8f1b4 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -101,7 +101,7 @@
 
         private DisplayDeviceInfo mInfo;
         private boolean mHavePendingChanges;
-        private boolean mBlanked;
+        private int mState = Display.STATE_UNKNOWN;
 
         public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId,
                 SurfaceControl.PhysicalDisplayInfo phys) {
@@ -134,6 +134,7 @@
                 mInfo.width = mPhys.width;
                 mInfo.height = mPhys.height;
                 mInfo.refreshRate = mPhys.refreshRate;
+                mInfo.state = mState;
 
                 // Assume that all built-in displays that have secure output (eg. HDCP) also
                 // support compositing from gralloc protected buffers.
@@ -177,15 +178,16 @@
         }
 
         @Override
-        public void blankLocked() {
-            mBlanked = true;
-            SurfaceControl.blankDisplay(getDisplayTokenLocked());
-        }
-
-        @Override
-        public void unblankLocked() {
-            mBlanked = false;
-            SurfaceControl.unblankDisplay(getDisplayTokenLocked());
+        public void requestDisplayStateLocked(int state) {
+            if (mState != state) {
+                if (state == Display.STATE_OFF && mState != Display.STATE_OFF) {
+                    SurfaceControl.blankDisplay(getDisplayTokenLocked());
+                } else if (state != Display.STATE_OFF && mState == Display.STATE_OFF) {
+                    SurfaceControl.unblankDisplay(getDisplayTokenLocked());
+                }
+                mState = state;
+                updateDeviceInfoLocked();
+            }
         }
 
         @Override
@@ -193,7 +195,12 @@
             super.dumpLocked(pw);
             pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId);
             pw.println("mPhys=" + mPhys);
-            pw.println("mBlanked=" + mBlanked);
+            pw.println("mState=" + Display.stateToString(mState));
+        }
+
+        private void updateDeviceInfoLocked() {
+            mInfo = null;
+            sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
         }
     }
 
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index c26c438..d61a35b 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -114,6 +114,7 @@
                 mInfo.copyFrom(mOverrideDisplayInfo);
                 mInfo.layerStack = mBaseDisplayInfo.layerStack;
                 mInfo.name = mBaseDisplayInfo.name;
+                mInfo.state = mBaseDisplayInfo.state;
             } else {
                 mInfo.copyFrom(mBaseDisplayInfo);
             }
@@ -212,6 +213,7 @@
             mBaseDisplayInfo.logicalDensityDpi = deviceInfo.densityDpi;
             mBaseDisplayInfo.physicalXDpi = deviceInfo.xDpi;
             mBaseDisplayInfo.physicalYDpi = deviceInfo.yDpi;
+            mBaseDisplayInfo.state = deviceInfo.state;
             mBaseDisplayInfo.smallestNominalAppWidth = deviceInfo.width;
             mBaseDisplayInfo.smallestNominalAppHeight = deviceInfo.height;
             mBaseDisplayInfo.largestNominalAppWidth = deviceInfo.width;
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 007acf7..bfd8372c 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -194,12 +194,14 @@
         private final int mDensityDpi;
         private final boolean mSecure;
 
-        private Surface mSurface;
+        private int mState;
         private SurfaceTexture mSurfaceTexture;
+        private Surface mSurface;
         private DisplayDeviceInfo mInfo;
 
         public OverlayDisplayDevice(IBinder displayToken, String name,
-                int width, int height, float refreshRate, int densityDpi, boolean secure,
+                int width, int height, float refreshRate,
+                int densityDpi, boolean secure, int state,
                 SurfaceTexture surfaceTexture) {
             super(OverlayDisplayAdapter.this, displayToken);
             mName = name;
@@ -208,6 +210,7 @@
             mRefreshRate = refreshRate;
             mDensityDpi = densityDpi;
             mSecure = secure;
+            mState = state;
             mSurfaceTexture = surfaceTexture;
         }
 
@@ -230,6 +233,11 @@
             }
         }
 
+        public void setStateLocked(int state) {
+            mState = state;
+            mInfo = null;
+        }
+
         @Override
         public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
             if (mInfo == null) {
@@ -247,6 +255,7 @@
                 }
                 mInfo.type = Display.TYPE_OVERLAY;
                 mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
+                mInfo.state = mState;
             }
             return mInfo;
         }
@@ -288,11 +297,12 @@
 
         // Called on the UI thread.
         @Override
-        public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate) {
+        public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate, int state) {
             synchronized (getSyncRoot()) {
                 IBinder displayToken = SurfaceControl.createDisplay(mName, mSecure);
                 mDevice = new OverlayDisplayDevice(displayToken, mName,
-                        mWidth, mHeight, refreshRate, mDensityDpi, mSecure, surfaceTexture);
+                        mWidth, mHeight, refreshRate, mDensityDpi, mSecure,
+                        state, surfaceTexture);
 
                 sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
             }
@@ -309,6 +319,17 @@
             }
         }
 
+        // Called on the UI thread.
+        @Override
+        public void onStateChanged(int state) {
+            synchronized (getSyncRoot()) {
+                if (mDevice != null) {
+                    mDevice.setStateLocked(state);
+                    sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_CHANGED);
+                }
+            }
+        }
+
         public void dumpLocked(PrintWriter pw) {
             pw.println("  " + mName + ":");
             pw.println("    mWidth=" + mWidth);
diff --git a/services/core/java/com/android/server/display/OverlayDisplayWindow.java b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
index f1dd60a..06891f3 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayWindow.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
@@ -282,6 +282,7 @@
             if (displayId == mDefaultDisplay.getDisplayId()) {
                 if (updateDefaultDisplayInfo()) {
                     relayout();
+                    mListener.onStateChanged(mDefaultDisplayInfo.state);
                 } else {
                     dismiss();
                 }
@@ -301,7 +302,8 @@
         @Override
         public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
                 int width, int height) {
-            mListener.onWindowCreated(surfaceTexture, mDefaultDisplayInfo.refreshRate);
+            mListener.onWindowCreated(surfaceTexture, mDefaultDisplayInfo.refreshRate,
+                    mDefaultDisplayInfo.state);
         }
 
         @Override
@@ -370,7 +372,9 @@
      * Watches for significant changes in the overlay display window lifecycle.
      */
     public interface Listener {
-        public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate);
+        public void onWindowCreated(SurfaceTexture surfaceTexture,
+                float refreshRate, int state);
         public void onWindowDestroyed();
+        public void onStateChanged(int state);
     }
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecDevice.java
index 64b51c9..baae1d99 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecDevice.java
@@ -182,11 +182,49 @@
     }
 
     /**
+     * Send &lt;Active Source&gt; command. The default implementation does nothing. Should be
+     * overriden by subclass.
+     */
+    public void sendActiveSource(int physicalAddress) {
+        logWarning("<Active Source> not valid for the device type: " + mType
+                + " address:" + physicalAddress);
+    }
+
+    /**
+     * Send &lt;Inactive Source&gt; command. The default implementation does nothing. Should be
+     * overriden by subclass.
+     */
+    public void sendInactiveSource(int physicalAddress) {
+        logWarning("<Inactive Source> not valid for the device type: " + mType
+                + " address:" + physicalAddress);
+    }
+
+    /**
+     * Send &lt;Image View On&gt; command. The default implementation does nothing. Should be
+     * overriden by subclass.
+     */
+    public void sendImageViewOn() {
+        logWarning("<Image View On> not valid for the device type: " + mType);
+    }
+
+    /**
+     * Send &lt;Text View On&gt; command. The default implementation does nothing. Should be
+     * overriden by subclass.
+     */
+    public void sendTextViewOn() {
+        logWarning("<Text View On> not valid for the device type: " + mType);
+    }
+
+    /**
      * Check if the connected sink device is in powered-on state. The default implementation
      * simply returns false. Should be overriden by subclass to report the correct state.
      */
     public boolean isSinkDeviceOn() {
-        Log.w(TAG, "Not valid for the device type: " + mType);
+        logWarning("isSinkDeviceOn() not valid for the device type: " + mType);
         return false;
     }
+
+    private void logWarning(String msg) {
+        Log.w(TAG, msg);
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java
index 0310264..f8cf11d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java
@@ -66,14 +66,11 @@
         // 1) Response for the queried power status request arrives. Update the status.
         // 2) Broadcast or direct <Standby> command from TV, which is sent as TV itself is going
         //    into standby mode too.
-        // 3) Broadcast <Report Physical Address> command from TV, which is sent while it boots up.
         if (opcode == HdmiCec.MESSAGE_REPORT_POWER_STATUS) {
             mSinkDevicePowerStatus = params[0];
         } else if (srcAddress == HdmiCec.ADDR_TV) {
             if (opcode == HdmiCec.MESSAGE_STANDBY) {
                 mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_STANDBY;
-            } else if (opcode == HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS) {
-                mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_ON;
             }
         }
         super.handleMessage(srcAddress, dstAddress, opcode, params);
@@ -95,4 +92,38 @@
     public boolean isSinkDeviceOn() {
         return mSinkDevicePowerStatus == HdmiCec.POWER_STATUS_ON;
     }
+
+    @Override
+    public void sendActiveSource(int physicalAddress) {
+        setIsActiveSource(true);
+        byte[] param = new byte[] {
+                (byte) ((physicalAddress >> 8) & 0xff),
+                (byte) (physicalAddress & 0xff)
+        };
+        getService().sendMessage(getType(), HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_ACTIVE_SOURCE,
+                param);
+    }
+
+    @Override
+    public void sendInactiveSource(int physicalAddress) {
+        setIsActiveSource(false);
+        byte[] param = new byte[] {
+                (byte) ((physicalAddress >> 8) & 0xff),
+                (byte) (physicalAddress & 0xff)
+        };
+        getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_INACTIVE_SOURCE,
+                param);
+    }
+
+    @Override
+    public void sendImageViewOn() {
+        getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_IMAGE_VIEW_ON,
+                HdmiCecService.EMPTY_PARAM);
+    }
+
+    @Override
+    public void sendTextViewOn() {
+        getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_TEXT_VIEW_ON,
+                HdmiCecService.EMPTY_PARAM);
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecService.java b/services/core/java/com/android/server/hdmi/HdmiCecService.java
index aa496c5..0a4c719 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecService.java
@@ -277,14 +277,7 @@
             enforceAccessPermission();
             synchronized (mLock) {
                 HdmiCecDevice device = getLogicalDeviceLocked(b);
-                device.setIsActiveSource(true);
-                int physicalAddress = nativeGetPhysicalAddress(mNativePtr);
-                byte[] param = new byte[] {
-                    (byte) ((physicalAddress >> 8) & 0xff),
-                    (byte) (physicalAddress & 0xff)
-                };
-                nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_BROADCAST,
-                        HdmiCec.MESSAGE_ACTIVE_SOURCE, param);
+                device.sendActiveSource(nativeGetPhysicalAddress(mNativePtr));
             }
         }
 
@@ -293,9 +286,7 @@
             enforceAccessPermission();
             synchronized (mLock) {
                 HdmiCecDevice device = getLogicalDeviceLocked(b);
-                device.setIsActiveSource(false);
-                nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_BROADCAST,
-                        HdmiCec.MESSAGE_INACTIVE_SOURCE, EMPTY_PARAM);
+                device.sendInactiveSource(nativeGetPhysicalAddress(mNativePtr));
             }
         }
 
@@ -304,8 +295,7 @@
             enforceAccessPermission();
             synchronized (mLock) {
                 HdmiCecDevice device = getLogicalDeviceLocked(b);
-                nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_TV,
-                        HdmiCec.MESSAGE_IMAGE_VIEW_ON, EMPTY_PARAM);
+                device.sendImageViewOn();
             }
         }
 
@@ -314,8 +304,16 @@
             enforceAccessPermission();
             synchronized (mLock) {
                 HdmiCecDevice device = getLogicalDeviceLocked(b);
-                nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_TV,
-                        HdmiCec.MESSAGE_TEXT_VIEW_ON, EMPTY_PARAM);
+                device.sendTextViewOn();
+            }
+        }
+
+        public void sendGiveDevicePowerStatus(IBinder b, int address) {
+            enforceAccessPermission();
+            synchronized (mLock) {
+                HdmiCecDevice device = getLogicalDeviceLocked(b);
+                nativeSendMessage(mNativePtr, device.getType(), address,
+                        HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS, EMPTY_PARAM);
             }
         }
 
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 316bd57..54cb035 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -185,6 +185,7 @@
             InputChannel fromChannel, InputChannel toChannel);
     private static native void nativeSetPointerSpeed(long ptr, int speed);
     private static native void nativeSetShowTouches(long ptr, boolean enabled);
+    private static native void nativeSetInteractive(long ptr, boolean interactive);
     private static native void nativeReloadCalibration(long ptr);
     private static native void nativeVibrate(long ptr, int deviceId, long[] pattern,
             int repeat, int token);
@@ -1404,14 +1405,13 @@
     }
 
     // Native callback.
-    private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
-        return mWindowManagerCallbacks.interceptKeyBeforeQueueing(
-                event, policyFlags, isScreenOn);
+    private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
+        return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
     }
 
     // Native callback.
-    private int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
-        return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff(
+    private int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags) {
+        return mWindowManagerCallbacks.interceptWakeMotionBeforeQueueing(
                 whenNanos, policyFlags);
     }
 
@@ -1570,9 +1570,9 @@
         public long notifyANR(InputApplicationHandle inputApplicationHandle,
                 InputWindowHandle inputWindowHandle, String reason);
 
-        public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
+        public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
 
-        public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags);
+        public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags);
 
         public long interceptKeyBeforeDispatching(InputWindowHandle focus,
                 KeyEvent event, int policyFlags);
@@ -1740,5 +1740,10 @@
         public boolean injectInputEvent(InputEvent event, int displayId, int mode) {
             return injectInputEventInternal(event, displayId, mode);
         }
+
+        @Override
+        public void setInteractive(boolean interactive) {
+            nativeSetInteractive(mPtr, interactive);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index eb7cc4c..855ae23 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1730,7 +1730,7 @@
     private void updateScreenOn() {
         synchronized (mRulesLock) {
             try {
-                mScreenOn = mPowerManager.isScreenOn();
+                mScreenOn = mPowerManager.isInteractive();
             } catch (RemoteException e) {
                 // ignored; service lives in system_server
             }
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index f72efff..d84e8e1 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -28,6 +28,7 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.hardware.input.InputManagerInternal;
 import android.media.AudioManager;
 import android.media.Ringtone;
 import android.media.RingtoneManager;
@@ -86,6 +87,7 @@
     private final ScreenOnBlocker mScreenOnBlocker;
     private final WindowManagerPolicy mPolicy;
     private final ActivityManagerInternal mActivityManagerInternal;
+    private final InputManagerInternal mInputManagerInternal;
 
     private final NotifierHandler mHandler;
     private final Intent mScreenOnIntent;
@@ -121,6 +123,7 @@
         mScreenOnBlocker = screenOnBlocker;
         mPolicy = policy;
         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+        mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
 
         mHandler = new NotifierHandler(looper);
         mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
@@ -232,73 +235,58 @@
     }
 
     /**
-     * Called when the device is waking up from sleep and the
-     * display is about to be turned on.
+     * Notifies that the device is changing interactive state.
      */
-    public void onWakeUpStarted() {
+    public void onInteractiveStateChangeStarted(boolean interactive, int reason) {
         if (DEBUG) {
-            Slog.d(TAG, "onWakeUpStarted");
+            Slog.d(TAG, "onInteractiveChangeStarted: interactive=" + interactive
+                    + ", reason=" + reason);
         }
 
         synchronized (mLock) {
-            if (mActualPowerState != POWER_STATE_AWAKE) {
-                mActualPowerState = POWER_STATE_AWAKE;
-                mPendingWakeUpBroadcast = true;
-                if (!mScreenOnBlockerAcquired) {
-                    mScreenOnBlockerAcquired = true;
-                    mScreenOnBlocker.acquire();
+            if (interactive) {
+                // Waking up...
+                if (mActualPowerState != POWER_STATE_AWAKE) {
+                    mActualPowerState = POWER_STATE_AWAKE;
+                    mPendingWakeUpBroadcast = true;
+                    if (!mScreenOnBlockerAcquired) {
+                        mScreenOnBlockerAcquired = true;
+                        mScreenOnBlocker.acquire();
+                    }
+                    updatePendingBroadcastLocked();
                 }
-                updatePendingBroadcastLocked();
+            } else {
+                // Going to sleep...
+                mLastGoToSleepReason = reason;
             }
+            mInputManagerInternal.setInteractive(interactive);
         }
     }
 
     /**
-     * Called when the device has finished waking up from sleep
-     * and the display has been turned on.
+     * Notifies that the device has finished changing interactive state.
      */
-    public void onWakeUpFinished() {
+    public void onInteractiveStateChangeFinished(boolean interactive) {
         if (DEBUG) {
-            Slog.d(TAG, "onWakeUpFinished");
-        }
-    }
-
-    /**
-     * Called when the device is going to sleep.
-     */
-    public void onGoToSleepStarted(int reason) {
-        if (DEBUG) {
-            Slog.d(TAG, "onGoToSleepStarted");
+            Slog.d(TAG, "onInteractiveChangeFinished");
         }
 
         synchronized (mLock) {
-            mLastGoToSleepReason = reason;
-        }
-    }
-
-    /**
-     * Called when the device has finished going to sleep and the
-     * display has been turned off.
-     *
-     * This is a good time to make transitions that we don't want the user to see,
-     * such as bringing the key guard to focus.  There's no guarantee for this,
-     * however because the user could turn the device on again at any time.
-     * Some things may need to be protected by other mechanisms that defer screen on.
-     */
-    public void onGoToSleepFinished() {
-        if (DEBUG) {
-            Slog.d(TAG, "onGoToSleepFinished");
-        }
-
-        synchronized (mLock) {
-            if (mActualPowerState != POWER_STATE_ASLEEP) {
-                mActualPowerState = POWER_STATE_ASLEEP;
-                mPendingGoToSleepBroadcast = true;
-                if (mUserActivityPending) {
-                    mUserActivityPending = false;
-                    mHandler.removeMessages(MSG_USER_ACTIVITY);
+            if (!interactive) {
+                // Finished going to sleep...
+                // This is a good time to make transitions that we don't want the user to see,
+                // such as bringing the key guard to focus.  There's no guarantee for this,
+                // however because the user could turn the device on again at any time.
+                // Some things may need to be protected by other mechanisms that defer screen on.
+                if (mActualPowerState != POWER_STATE_ASLEEP) {
+                    mActualPowerState = POWER_STATE_ASLEEP;
+                    mPendingGoToSleepBroadcast = true;
+                    if (mUserActivityPending) {
+                        mUserActivityPending = false;
+                        mHandler.removeMessages(MSG_USER_ACTIVITY);
+                    }
+                    updatePendingBroadcastLocked();
                 }
-                updatePendingBroadcastLocked();
             }
         }
     }
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 90363d7..82cef7f 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -62,6 +62,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.TimeUtils;
+import android.view.Display;
 import android.view.WindowManagerPolicy;
 
 import java.io.FileDescriptor;
@@ -209,6 +210,10 @@
     // A bitfield that summarizes the state of all active wakelocks.
     private int mWakeLockSummary;
 
+    // True if the device is in an interactive state.
+    private boolean mInteractive;
+    private boolean mInteractiveChanging;
+
     // If true, instructs the display controller to wait for the proximity sensor to
     // go negative before turning the screen on.
     private boolean mRequestWaitForNegativeProximity;
@@ -217,11 +222,6 @@
     private long mLastWakeTime;
     private long mLastSleepTime;
 
-    // True if we need to send a wake up or go to sleep finished notification
-    // when the display is ready.
-    private boolean mSendWakeUpFinishedNotificationWhenReady;
-    private boolean mSendGoToSleepFinishedNotificationWhenReady;
-
     // Timestamp of the last call to user activity.
     private long mLastUserActivityTime;
     private long mLastUserActivityTimeNoChangeLights;
@@ -265,11 +265,11 @@
 
     // True if auto-suspend mode is enabled.
     // Refer to autosuspend.h.
-    private boolean mAutoSuspendModeEnabled;
+    private boolean mHalAutoSuspendModeEnabled;
 
     // True if interactive mode is enabled.
     // Refer to power.h.
-    private boolean mInteractiveModeEnabled;
+    private boolean mHalInteractiveModeEnabled;
 
     // True if the device is plugged into a power source.
     private boolean mIsPowered;
@@ -289,10 +289,10 @@
     private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
 
     // True to decouple auto-suspend mode from the display state.
-    private boolean mDecoupleAutoSuspendModeFromDisplayConfig;
+    private boolean mDecoupleHalAutoSuspendModeFromDisplayConfig;
 
     // True to decouple interactive mode from the display state.
-    private boolean mDecoupleInteractiveModeFromDisplayConfig;
+    private boolean mDecoupleHalInteractiveModeFromDisplayConfig;
 
     // True if the device should wake up when plugged or unplugged.
     private boolean mWakeUpWhenPluggedOrUnpluggedConfig;
@@ -397,7 +397,6 @@
 
     private native void nativeInit();
 
-    private static native void nativeSetPowerState(boolean screenOn, boolean screenBright);
     private static native void nativeAcquireSuspendBlocker(String name);
     private static native void nativeReleaseSuspendBlocker(String name);
     private static native void nativeSetInteractive(boolean enable);
@@ -412,13 +411,17 @@
             mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");
             mDisplaySuspendBlocker.acquire();
             mHoldingDisplaySuspendBlocker = true;
+            mHalAutoSuspendModeEnabled = false;
+            mHalInteractiveModeEnabled = true;
 
             mScreenOnBlocker = new ScreenOnBlockerImpl();
             mWakefulness = WAKEFULNESS_AWAKE;
-        }
+            mInteractive = true;
 
-        nativeInit();
-        nativeSetPowerState(true, true);
+            nativeInit();
+            nativeSetAutoSuspend(false);
+            nativeSetInteractive(true);
+        }
     }
 
     @Override
@@ -446,14 +449,6 @@
 
         Watchdog.getInstance().addMonitor(this);
         Watchdog.getInstance().addThread(mHandler);
-
-        // Forcibly turn the screen on at boot so that it is in a known power state.
-        // We do this in init() rather than in the constructor because setting the
-        // screen state requires a call into surface flinger which then needs to call back
-        // into the activity manager to check permissions.  Unfortunately the
-        // activity manager is not running when the constructor is called, so we
-        // have to defer setting the screen state until this point.
-        mDisplayPowerCallbacks.unblankAllDisplays();
     }
 
     void setPolicy(WindowManagerPolicy policy) {
@@ -547,9 +542,9 @@
     private void readConfigurationLocked() {
         final Resources resources = mContext.getResources();
 
-        mDecoupleAutoSuspendModeFromDisplayConfig = resources.getBoolean(
+        mDecoupleHalAutoSuspendModeFromDisplayConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_powerDecoupleAutoSuspendModeFromDisplay);
-        mDecoupleInteractiveModeFromDisplayConfig = resources.getBoolean(
+        mDecoupleHalInteractiveModeFromDisplayConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_powerDecoupleInteractiveModeFromDisplay);
         mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_unplugTurnsOnScreen);
@@ -867,11 +862,6 @@
         return false;
     }
 
-    // Called from native code.
-    private void wakeUpFromNative(long eventTime) {
-        wakeUpInternal(eventTime);
-    }
-
     private void wakeUpInternal(long eventTime) {
         synchronized (mLock) {
             if (wakeUpNoUpdateLocked(eventTime)) {
@@ -902,26 +892,16 @@
                 break;
         }
 
-        if (mWakefulness != WAKEFULNESS_DREAMING) {
-            sendPendingNotificationsLocked();
-            mNotifier.onWakeUpStarted();
-            mSendWakeUpFinishedNotificationWhenReady = true;
-        }
-
         mLastWakeTime = eventTime;
-        mWakefulness = WAKEFULNESS_AWAKE;
         mDirty |= DIRTY_WAKEFULNESS;
+        mWakefulness = WAKEFULNESS_AWAKE;
+        setInteractiveStateLocked(true, 0);
 
         userActivityNoUpdateLocked(
                 eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
         return true;
     }
 
-    // Called from native code.
-    private void goToSleepFromNative(long eventTime, int reason) {
-        goToSleepInternal(eventTime, reason);
-    }
-
     private void goToSleepInternal(long eventTime, int reason) {
         synchronized (mLock) {
             if (goToSleepNoUpdateLocked(eventTime, reason)) {
@@ -958,14 +938,11 @@
                 break;
         }
 
-        sendPendingNotificationsLocked();
-        mNotifier.onGoToSleepStarted(reason);
-        mSendGoToSleepFinishedNotificationWhenReady = true;
-
         mLastSleepTime = eventTime;
         mDirty |= DIRTY_WAKEFULNESS;
         mWakefulness = WAKEFULNESS_DOZING;
         mSandmanSummoned = true;
+        setInteractiveStateLocked(false, reason);
 
         // Report the number of wake locks that will be cleared by going to sleep.
         int numWakeLocksCleared = 0;
@@ -1007,6 +984,7 @@
         mDirty |= DIRTY_WAKEFULNESS;
         mWakefulness = WAKEFULNESS_DREAMING;
         mSandmanSummoned = true;
+        setInteractiveStateLocked(true, 0);
         return true;
     }
 
@@ -1025,9 +1003,27 @@
 
         mDirty |= DIRTY_WAKEFULNESS;
         mWakefulness = WAKEFULNESS_ASLEEP;
+        setInteractiveStateLocked(false, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
         return true;
     }
 
+    private void setInteractiveStateLocked(boolean interactive, int reason) {
+        if (mInteractive != interactive) {
+            finishInteractiveStateChangeLocked();
+
+            mInteractive = interactive;
+            mInteractiveChanging = true;
+            mNotifier.onInteractiveStateChangeStarted(interactive, reason);
+        }
+    }
+
+    private void finishInteractiveStateChangeLocked() {
+        if (mInteractiveChanging) {
+            mNotifier.onInteractiveStateChangeFinished(mInteractive);
+            mInteractiveChanging = false;
+        }
+    }
+
     /**
      * Updates the global power state based on dirty bits recorded in mDirty.
      *
@@ -1071,7 +1067,7 @@
 
         // Phase 3: Send notifications, if needed.
         if (mDisplayReady) {
-            sendPendingNotificationsLocked();
+            finishInteractiveStateChangeLocked();
         }
 
         // Phase 4: Update suspend blocker.
@@ -1080,17 +1076,6 @@
         updateSuspendBlockerLocked();
     }
 
-    private void sendPendingNotificationsLocked() {
-        if (mSendWakeUpFinishedNotificationWhenReady) {
-            mSendWakeUpFinishedNotificationWhenReady = false;
-            mNotifier.onWakeUpFinished();
-        }
-        if (mSendGoToSleepFinishedNotificationWhenReady) {
-            mSendGoToSleepFinishedNotificationWhenReady = false;
-            mNotifier.onGoToSleepFinished();
-        }
-    }
-
     /**
      * Updates the value of mIsPowered.
      * Sets DIRTY_IS_POWERED if a change occurred.
@@ -1210,48 +1195,45 @@
                         mWakeLockSummary |= WAKE_LOCK_CPU;
                         break;
                     case PowerManager.FULL_WAKE_LOCK:
-                        if (mWakefulness == WAKEFULNESS_AWAKE
-                                || mWakefulness == WAKEFULNESS_DREAMING) {
-                            mWakeLockSummary |= WAKE_LOCK_CPU
-                                    | WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
-                        }
-                        if (mWakefulness == WAKEFULNESS_AWAKE) {
-                            mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
-                        }
+                        mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
                         break;
                     case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
-                        if (mWakefulness == WAKEFULNESS_AWAKE
-                                || mWakefulness == WAKEFULNESS_DREAMING) {
-                            mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_BRIGHT;
-                        }
-                        if (mWakefulness == WAKEFULNESS_AWAKE) {
-                            mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
-                        }
+                        mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT;
                         break;
                     case PowerManager.SCREEN_DIM_WAKE_LOCK:
-                        if (mWakefulness == WAKEFULNESS_AWAKE
-                                || mWakefulness == WAKEFULNESS_DREAMING) {
-                            mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_DIM;
-                        }
-                        if (mWakefulness == WAKEFULNESS_AWAKE) {
-                            mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
-                        }
+                        mWakeLockSummary |= WAKE_LOCK_SCREEN_DIM;
                         break;
                     case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
-                        if (mWakefulness == WAKEFULNESS_AWAKE
-                                || mWakefulness == WAKEFULNESS_DREAMING
-                                || mWakefulness == WAKEFULNESS_DOZING) {
-                            mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
-                        }
+                        mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
                         break;
                     case PowerManager.DOZE_WAKE_LOCK:
-                        if (mWakefulness == WAKEFULNESS_DOZING) {
-                            mWakeLockSummary |= WAKE_LOCK_DOZE;
-                        }
+                        mWakeLockSummary |= WAKE_LOCK_DOZE;
                         break;
                 }
             }
 
+            // Cancel wake locks that make no sense based on the current state.
+            if (mWakefulness != WAKEFULNESS_DOZING) {
+                mWakeLockSummary &= ~WAKE_LOCK_DOZE;
+            }
+            if (mWakefulness == WAKEFULNESS_ASLEEP
+                    || (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
+                mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
+                        | WAKE_LOCK_BUTTON_BRIGHT);
+                if (mWakefulness == WAKEFULNESS_ASLEEP) {
+                    mWakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;
+                }
+            }
+
+            // Infer implied wake locks where necessary based on the current state.
+            if ((mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0) {
+                if (mWakefulness == WAKEFULNESS_AWAKE) {
+                    mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE;
+                } else if (mWakefulness == WAKEFULNESS_DREAMING) {
+                    mWakeLockSummary |= WAKE_LOCK_CPU;
+                }
+            }
+
             if (DEBUG_SPEW) {
                 Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness="
                         + wakefulnessToString(mWakefulness)
@@ -1269,12 +1251,14 @@
      */
     private void updateUserActivitySummaryLocked(long now, int dirty) {
         // Update the status of the user activity timeout timer.
-        if ((dirty & (DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
+        if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
+                | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
             mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
 
             long nextTimeout = 0;
             if (mWakefulness == WAKEFULNESS_AWAKE
-                    || mWakefulness == WAKEFULNESS_DREAMING) {
+                    || mWakefulness == WAKEFULNESS_DREAMING
+                    || mWakefulness == WAKEFULNESS_DOZING) {
                 final int screenOffTimeout = getScreenOffTimeoutLocked();
                 final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
 
@@ -1598,8 +1582,6 @@
                 | DIRTY_SETTINGS | DIRTY_SCREEN_ON_BLOCKER_RELEASED)) != 0) {
             final int newScreenState = getDesiredScreenPowerStateLocked();
             mDisplayPowerRequest.screenState = newScreenState;
-            nativeSetPowerState(isScreenOnLocked(),
-                    newScreenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT);
 
             int screenBrightness = mScreenBrightnessSettingDefault;
             float screenAutoBrightnessAdjustment = 0.0f;
@@ -1681,7 +1663,7 @@
 
     private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks =
             new DisplayManagerInternal.DisplayPowerCallbacks() {
-        private boolean mBlanked;
+        private int mDisplayState = Display.STATE_UNKNOWN;
 
         @Override
         public void onStateChanged() {
@@ -1712,6 +1694,33 @@
         }
 
         @Override
+        public void onDisplayStateChange(int state) {
+            // This method is only needed to support legacy display blanking behavior
+            // where the display's power state is coupled to suspend or to the power HAL.
+            // The order of operations matters here.
+            synchronized (mLock) {
+                if (mDisplayState != state) {
+                    mDisplayState = state;
+                    if (state == Display.STATE_OFF) {
+                        if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
+                            setHalInteractiveModeLocked(false);
+                        }
+                        if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+                            setHalAutoSuspendModeLocked(true);
+                        }
+                    } else {
+                        if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+                            setHalAutoSuspendModeLocked(false);
+                        }
+                        if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
+                            setHalInteractiveModeLocked(true);
+                        }
+                    }
+                }
+            }
+        }
+
+        @Override
         public void acquireSuspendBlocker() {
             mDisplaySuspendBlocker.acquire();
         }
@@ -1722,37 +1731,9 @@
         }
 
         @Override
-        public void blankAllDisplays() {
-            synchronized (this) {
-                mBlanked = true;
-                mDisplayManagerInternal.blankAllDisplaysFromPowerManager();
-                if (!mDecoupleInteractiveModeFromDisplayConfig) {
-                    setInteractiveModeLocked(false);
-                }
-                if (!mDecoupleAutoSuspendModeFromDisplayConfig) {
-                    setAutoSuspendModeLocked(true);
-                }
-            }
-        }
-
-        @Override
-        public void unblankAllDisplays() {
-            synchronized (this) {
-                if (!mDecoupleAutoSuspendModeFromDisplayConfig) {
-                    setAutoSuspendModeLocked(false);
-                }
-                if (!mDecoupleInteractiveModeFromDisplayConfig) {
-                    setInteractiveModeLocked(true);
-                }
-                mDisplayManagerInternal.unblankAllDisplaysFromPowerManager();
-                mBlanked = false;
-            }
-        }
-
-        @Override
         public String toString() {
             synchronized (this) {
-                return "blanked=" + mBlanked;
+                return "state=" + Display.stateToString(mDisplayState);
             }
         }
     };
@@ -1773,11 +1754,11 @@
 
         // Disable auto-suspend if needed.
         if (!autoSuspend) {
-            if (mDecoupleAutoSuspendModeFromDisplayConfig) {
-                setAutoSuspendModeLocked(false);
+            if (mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+                setHalAutoSuspendModeLocked(false);
             }
-            if (mDecoupleInteractiveModeFromDisplayConfig) {
-                setInteractiveModeLocked(true);
+            if (mDecoupleHalInteractiveModeFromDisplayConfig) {
+                setHalInteractiveModeLocked(true);
             }
         }
 
@@ -1803,11 +1784,11 @@
 
         // Enable auto-suspend if needed.
         if (autoSuspend) {
-            if (mDecoupleInteractiveModeFromDisplayConfig) {
-                setInteractiveModeLocked(false);
+            if (mDecoupleHalInteractiveModeFromDisplayConfig) {
+                setHalInteractiveModeLocked(false);
             }
-            if (mDecoupleAutoSuspendModeFromDisplayConfig) {
-                setAutoSuspendModeLocked(true);
+            if (mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+                setHalAutoSuspendModeLocked(true);
             }
         }
     }
@@ -1834,42 +1815,32 @@
         return false;
     }
 
-    private void setAutoSuspendModeLocked(boolean enable) {
-        if (enable != mAutoSuspendModeEnabled) {
+    private void setHalAutoSuspendModeLocked(boolean enable) {
+        if (enable != mHalAutoSuspendModeEnabled) {
             if (DEBUG) {
-                Slog.d(TAG, "Setting auto-suspend mode to " + enable);
+                Slog.d(TAG, "Setting HAL auto-suspend mode to " + enable);
             }
-            mAutoSuspendModeEnabled = enable;
+            mHalAutoSuspendModeEnabled = enable;
             nativeSetAutoSuspend(enable);
         }
     }
 
-    private void setInteractiveModeLocked(boolean enable) {
-        if (enable != mInteractiveModeEnabled) {
+    private void setHalInteractiveModeLocked(boolean enable) {
+        if (enable != mHalInteractiveModeEnabled) {
             if (DEBUG) {
-                Slog.d(TAG, "Setting interactive mode to " + enable);
+                Slog.d(TAG, "Setting HAL interactive mode to " + enable);
             }
-            mInteractiveModeEnabled = enable;
+            mHalInteractiveModeEnabled = enable;
             nativeSetInteractive(enable);
         }
     }
 
-    private boolean isScreenOnInternal() {
+    private boolean isInteractiveInternal() {
         synchronized (mLock) {
-            // XXX This is a temporary hack to let certain parts of the system pretend the
-            // screen is still on even when dozing and we would normally want to report
-            // screen off.  Will be removed when the window manager is modified to use
-            // the true blanking state of the display.
-            return isScreenOnLocked()
-                    || mWakefulness == WAKEFULNESS_DOZING;
+            return mInteractive;
         }
     }
 
-    private boolean isScreenOnLocked() {
-        return mWakefulness == WAKEFULNESS_AWAKE
-                || mWakefulness == WAKEFULNESS_DREAMING;
-    }
-
     private void handleBatteryStateChangedLocked() {
         mDirty |= DIRTY_BATTERY_STATE;
         updatePowerStateLocked();
@@ -2090,6 +2061,7 @@
             pw.println("Power Manager State:");
             pw.println("  mDirty=0x" + Integer.toHexString(mDirty));
             pw.println("  mWakefulness=" + wakefulnessToString(mWakefulness));
+            pw.println("  mInteractive=" + mInteractive);
             pw.println("  mIsPowered=" + mIsPowered);
             pw.println("  mPlugType=" + mPlugType);
             pw.println("  mBatteryLevel=" + mBatteryLevel);
@@ -2099,8 +2071,8 @@
             pw.println("  mProximityPositive=" + mProximityPositive);
             pw.println("  mBootCompleted=" + mBootCompleted);
             pw.println("  mSystemReady=" + mSystemReady);
-            pw.println("  mAutoSuspendModeEnabled=" + mAutoSuspendModeEnabled);
-            pw.println("  mInteactiveModeEnabled=" + mInteractiveModeEnabled);
+            pw.println("  mHalAutoSuspendModeEnabled=" + mHalAutoSuspendModeEnabled);
+            pw.println("  mHalInteractiveModeEnabled=" + mHalInteractiveModeEnabled);
             pw.println("  mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
             pw.println("  mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary));
             pw.println("  mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
@@ -2108,10 +2080,6 @@
             pw.println("  mSandmanSummoned=" + mSandmanSummoned);
             pw.println("  mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
             pw.println("  mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime));
-            pw.println("  mSendWakeUpFinishedNotificationWhenReady="
-                    + mSendWakeUpFinishedNotificationWhenReady);
-            pw.println("  mSendGoToSleepFinishedNotificationWhenReady="
-                    + mSendGoToSleepFinishedNotificationWhenReady);
             pw.println("  mLastUserActivityTime=" + TimeUtils.formatUptime(mLastUserActivityTime));
             pw.println("  mLastUserActivityTimeNoChangeLights="
                     + TimeUtils.formatUptime(mLastUserActivityTimeNoChangeLights));
@@ -2121,10 +2089,10 @@
 
             pw.println();
             pw.println("Settings and Configuration:");
-            pw.println("  mDecoupleAutoSuspendModeFromDisplayConfig="
-                    + mDecoupleAutoSuspendModeFromDisplayConfig);
-            pw.println("  mDecoupleInteractiveModeFromDisplayConfig="
-                    + mDecoupleInteractiveModeFromDisplayConfig);
+            pw.println("  mDecoupleHalAutoSuspendModeFromDisplayConfig="
+                    + mDecoupleHalAutoSuspendModeFromDisplayConfig);
+            pw.println("  mDecoupleHalInteractiveModeFromDisplayConfig="
+                    + mDecoupleHalInteractiveModeFromDisplayConfig);
             pw.println("  mWakeUpWhenPluggedOrUnpluggedConfig="
                     + mWakeUpWhenPluggedOrUnpluggedConfig);
             pw.println("  mSuspendWhenScreenOffDueToProximityConfig="
@@ -2725,10 +2693,10 @@
         }
 
         @Override // Binder call
-        public boolean isScreenOn() {
+        public boolean isInteractive() {
             final long ident = Binder.clearCallingIdentity();
             try {
-                return isScreenOnInternal();
+                return isInteractiveInternal();
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 4aae5c1..b27c8d6 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -355,17 +355,16 @@
     /* Provides an opportunity for the window manager policy to intercept early key
      * processing as soon as the key has been read from the device. */
     @Override
-    public int interceptKeyBeforeQueueing(
-            KeyEvent event, int policyFlags, boolean isScreenOn) {
-        return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags, isScreenOn);
+    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
+        return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
     }
 
     /* Provides an opportunity for the window manager policy to intercept early
      * motion event processing when the screen is off since these events are normally
      * dropped. */
     @Override
-    public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
-        return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(whenNanos, policyFlags);
+    public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags) {
+        return mService.mPolicy.interceptWakeMotionBeforeQueueing(whenNanos, policyFlags);
     }
 
     /* Provides an opportunity for the window manager policy to process a key before
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/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
index a00aaa8..54c9755 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
@@ -204,6 +204,11 @@
     } else {
         ALOGV("Logical Address Allocation success: %d", addr);
         mLogicalDevices.insert(std::pair<cec_device_type_t, cec_logical_address_t>(type, addr));
+
+        // Broadcast <Report Physical Address> when a new logical address was allocated to let
+        // other devices discover the new logical device and its logical - physical address
+        // association.
+        sendReportPhysicalAddress();
     }
     return addr;
 }
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index b3247ff..4085991 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -71,7 +71,7 @@
     jmethodID notifyANR;
     jmethodID filterInputEvent;
     jmethodID interceptKeyBeforeQueueing;
-    jmethodID interceptMotionBeforeQueueingWhenScreenOff;
+    jmethodID interceptWakeMotionBeforeQueueing;
     jmethodID interceptKeyBeforeDispatching;
     jmethodID dispatchUnhandledKey;
     jmethodID checkInjectEventsPermission;
@@ -189,6 +189,7 @@
     void setSystemUiVisibility(int32_t visibility);
     void setPointerSpeed(int32_t speed);
     void setShowTouches(bool enabled);
+    void setInteractive(bool interactive);
     void reloadCalibration();
 
     /* --- InputReaderPolicyInterface implementation --- */
@@ -214,7 +215,6 @@
     virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle);
     virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags);
     virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig);
-    virtual bool isKeyRepeatEnabled();
     virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
     virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags);
     virtual nsecs_t interceptKeyBeforeDispatching(
@@ -262,14 +262,12 @@
         wp<PointerController> pointerController;
     } mLocked;
 
+    volatile bool mInteractive;
+
     void updateInactivityTimeoutLocked(const sp<PointerController>& controller);
     void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags);
     void ensureSpriteControllerLocked();
 
-    // Power manager interactions.
-    bool isScreenOn();
-    bool isScreenBright();
-
     static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
 
     static inline JNIEnv* jniEnv() {
@@ -281,7 +279,7 @@
 
 NativeInputManager::NativeInputManager(jobject contextObj,
         jobject serviceObj, const sp<Looper>& looper) :
-        mLooper(looper) {
+        mLooper(looper), mInteractive(true) {
     JNIEnv* env = jniEnv();
 
     mContextObj = env->NewGlobalRef(contextObj);
@@ -637,11 +635,6 @@
     }
 }
 
-bool NativeInputManager::isKeyRepeatEnabled() {
-    // Only enable automatic key repeating when the screen is on.
-    return isScreenOn();
-}
-
 void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
     Vector<sp<InputWindowHandle> > windowHandles;
 
@@ -753,19 +746,15 @@
             InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
 }
 
+void NativeInputManager::setInteractive(bool interactive) {
+    mInteractive = interactive;
+}
+
 void NativeInputManager::reloadCalibration() {
     mInputManager->getReader()->requestRefreshConfiguration(
             InputReaderConfiguration::TOUCH_AFFINE_TRANSFORMATION);
 }
 
-bool NativeInputManager::isScreenOn() {
-    return android_server_PowerManagerService_isScreenOn();
-}
-
-bool NativeInputManager::isScreenBright() {
-    return android_server_PowerManagerService_isScreenBright();
-}
-
 TouchAffineTransformation NativeInputManager::getTouchAffineTransformation(
         JNIEnv *env, jfloatArray matrixArr) {
     ScopedFloatArrayRO matrix(env, matrixArr);
@@ -841,18 +830,18 @@
     // - Ignore untrusted events and pass them along.
     // - Ask the window manager what to do with normal events and trusted injected events.
     // - For normal events wake and brighten the screen if currently off or dim.
+    if (mInteractive) {
+        policyFlags |= POLICY_FLAG_INTERACTIVE;
+    }
     if ((policyFlags & POLICY_FLAG_TRUSTED)) {
         nsecs_t when = keyEvent->getEventTime();
-        bool isScreenOn = this->isScreenOn();
-        bool isScreenBright = this->isScreenBright();
-
         JNIEnv* env = jniEnv();
         jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
         jint wmActions;
         if (keyEventObj) {
             wmActions = env->CallIntMethod(mServiceObj,
                     gServiceClassInfo.interceptKeyBeforeQueueing,
-                    keyEventObj, policyFlags, isScreenOn);
+                    keyEventObj, policyFlags);
             if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
                 wmActions = 0;
             }
@@ -863,16 +852,6 @@
             wmActions = 0;
         }
 
-        if (!(policyFlags & POLICY_FLAG_INJECTED)) {
-            if (!isScreenOn) {
-                policyFlags |= POLICY_FLAG_WOKE_HERE;
-            }
-
-            if (!isScreenBright) {
-                policyFlags |= POLICY_FLAG_BRIGHT_HERE;
-            }
-        }
-
         handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
     } else {
         policyFlags |= POLICY_FLAG_PASS_TO_USER;
@@ -885,24 +864,22 @@
     // - No special filtering for injected events required at this time.
     // - Filter normal events based on screen state.
     // - For normal events brighten (but do not wake) the screen if currently dim.
+    if (mInteractive) {
+        policyFlags |= POLICY_FLAG_INTERACTIVE;
+    }
     if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) {
-        if (isScreenOn()) {
+        if (policyFlags & POLICY_FLAG_INTERACTIVE) {
             policyFlags |= POLICY_FLAG_PASS_TO_USER;
-
-            if (!isScreenBright()) {
-                policyFlags |= POLICY_FLAG_BRIGHT_HERE;
-            }
-        } else {
+        } else if (policyFlags & (POLICY_FLAG_WAKE | POLICY_FLAG_WAKE_DROPPED)) {
             JNIEnv* env = jniEnv();
             jint wmActions = env->CallIntMethod(mServiceObj,
-                        gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
+                        gServiceClassInfo.interceptWakeMotionBeforeQueueing,
                         when, policyFlags);
             if (checkAndClearExceptionFromCallback(env,
-                    "interceptMotionBeforeQueueingWhenScreenOff")) {
+                    "interceptWakeMotionBeforeQueueing")) {
                 wmActions = 0;
             }
 
-            policyFlags |= POLICY_FLAG_WOKE_HERE | POLICY_FLAG_BRIGHT_HERE;
             handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
         }
     } else {
@@ -1285,6 +1262,13 @@
     im->setShowTouches(enabled);
 }
 
+static void nativeSetInteractive(JNIEnv* env,
+        jclass clazz, jlong ptr, jboolean interactive) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+    im->setInteractive(interactive);
+}
+
 static void nativeReloadCalibration(JNIEnv* env, jclass clazz, jlong ptr) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
     im->reloadCalibration();
@@ -1395,6 +1379,8 @@
             (void*) nativeSetPointerSpeed },
     { "nativeSetShowTouches", "(JZ)V",
             (void*) nativeSetShowTouches },
+    { "nativeSetInteractive", "(JZ)V",
+            (void*) nativeSetInteractive },
     { "nativeReloadCalibration", "(J)V",
             (void*) nativeReloadCalibration },
     { "nativeVibrate", "(JI[JII)V",
@@ -1453,11 +1439,10 @@
             "filterInputEvent", "(Landroid/view/InputEvent;I)Z");
 
     GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeQueueing, clazz,
-            "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;IZ)I");
+            "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;I)I");
 
-    GET_METHOD_ID(gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
-            clazz,
-            "interceptMotionBeforeQueueingWhenScreenOff", "(JI)I");
+    GET_METHOD_ID(gServiceClassInfo.interceptWakeMotionBeforeQueueing, clazz,
+            "interceptWakeMotionBeforeQueueing", "(JI)I");
 
     GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeDispatching, clazz,
             "interceptKeyBeforeDispatching",
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index dbf5439..33e0bd7 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -42,8 +42,6 @@
 // ----------------------------------------------------------------------------
 
 static struct {
-    jmethodID wakeUpFromNative;
-    jmethodID goToSleepFromNative;
     jmethodID userActivityFromNative;
 } gPowerManagerServiceClassInfo;
 
@@ -52,10 +50,6 @@
 static jobject gPowerManagerServiceObj;
 static struct power_module* gPowerModule;
 
-static Mutex gPowerManagerLock;
-static bool gScreenOn;
-static bool gScreenBright;
-
 static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];
 
 // Throttling interval for user activity calls.
@@ -73,16 +67,6 @@
     return false;
 }
 
-bool android_server_PowerManagerService_isScreenOn() {
-    AutoMutex _l(gPowerManagerLock);
-    return gScreenOn;
-}
-
-bool android_server_PowerManagerService_isScreenBright() {
-    AutoMutex _l(gPowerManagerLock);
-    return gScreenBright;
-}
-
 void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
     // Tell the power HAL when user activity occurs.
     if (gPowerModule && gPowerModule->powerHint) {
@@ -114,28 +98,6 @@
     }
 }
 
-void android_server_PowerManagerService_wakeUp(nsecs_t eventTime) {
-    if (gPowerManagerServiceObj) {
-        JNIEnv* env = AndroidRuntime::getJNIEnv();
-
-        env->CallVoidMethod(gPowerManagerServiceObj,
-                gPowerManagerServiceClassInfo.wakeUpFromNative,
-                nanoseconds_to_milliseconds(eventTime));
-        checkAndClearExceptionFromCallback(env, "wakeUpFromNative");
-    }
-}
-
-void android_server_PowerManagerService_goToSleep(nsecs_t eventTime) {
-    if (gPowerManagerServiceObj) {
-        JNIEnv* env = AndroidRuntime::getJNIEnv();
-
-        env->CallVoidMethod(gPowerManagerServiceObj,
-                gPowerManagerServiceClassInfo.goToSleepFromNative,
-                nanoseconds_to_milliseconds(eventTime), 0);
-        checkAndClearExceptionFromCallback(env, "goToSleepFromNative");
-    }
-}
-
 // ----------------------------------------------------------------------------
 
 static void nativeInit(JNIEnv* env, jobject obj) {
@@ -150,13 +112,6 @@
     }
 }
 
-static void nativeSetPowerState(JNIEnv* env,
-        jclass clazz, jboolean screenOn, jboolean screenBright) {
-    AutoMutex _l(gPowerManagerLock);
-    gScreenOn = screenOn;
-    gScreenBright = screenBright;
-}
-
 static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
     ScopedUtfChars name(env, nameStr);
     acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
@@ -207,8 +162,6 @@
     /* name, signature, funcPtr */
     { "nativeInit", "()V",
             (void*) nativeInit },
-    { "nativeSetPowerState", "(ZZ)V",
-            (void*) nativeSetPowerState },
     { "nativeAcquireSuspendBlocker", "(Ljava/lang/String;)V",
             (void*) nativeAcquireSuspendBlocker },
     { "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V",
@@ -243,12 +196,6 @@
     jclass clazz;
     FIND_CLASS(clazz, "com/android/server/power/PowerManagerService");
 
-    GET_METHOD_ID(gPowerManagerServiceClassInfo.wakeUpFromNative, clazz,
-            "wakeUpFromNative", "(J)V");
-
-    GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleepFromNative, clazz,
-            "goToSleepFromNative", "(JI)V");
-
     GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivityFromNative, clazz,
             "userActivityFromNative", "(JII)V");
 
@@ -256,8 +203,6 @@
     for (int i = 0; i <= USER_ACTIVITY_EVENT_LAST; i++) {
         gLastEventTime[i] = LLONG_MIN;
     }
-    gScreenOn = true;
-    gScreenBright = true;
     gPowerManagerServiceObj = NULL;
     gPowerModule = NULL;
     return 0;
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.h b/services/core/jni/com_android_server_power_PowerManagerService.h
index b48e546..f5fd3d6 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.h
+++ b/services/core/jni/com_android_server_power_PowerManagerService.h
@@ -24,11 +24,7 @@
 
 namespace android {
 
-extern bool android_server_PowerManagerService_isScreenOn();
-extern bool android_server_PowerManagerService_isScreenBright();
 extern void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType);
-extern void android_server_PowerManagerService_wakeUp(nsecs_t eventTime);
-extern void android_server_PowerManagerService_goToSleep(nsecs_t eventTime);
 
 } // namespace android
 
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 8b9f718..8392672 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -216,7 +216,7 @@
         expectLastCall().atLeastOnce();
 
         // expect to answer screen status during systemReady()
-        expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
+        expect(mPowerManager.isInteractive()).andReturn(true).atLeastOnce();
         expect(mNetworkManager.isBandwidthControlEnabled()).andReturn(true).atLeastOnce();
         expectCurrentTime();
 
@@ -331,7 +331,7 @@
         verifyAndReset();
 
         // now turn screen off and verify REJECT rule
-        expect(mPowerManager.isScreenOn()).andReturn(false).atLeastOnce();
+        expect(mPowerManager.isInteractive()).andReturn(false).atLeastOnce();
         expectSetUidNetworkRules(UID_A, true);
         expectSetUidForeground(UID_A, false);
         future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
@@ -341,7 +341,7 @@
         verifyAndReset();
 
         // and turn screen back on, verify ALLOW rule restored
-        expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
+        expect(mPowerManager.isInteractive()).andReturn(true).atLeastOnce();
         expectSetUidNetworkRules(UID_A, false);
         expectSetUidForeground(UID_A, true);
         future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
diff --git a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
index bf35db4..a0b2d1a 100644
--- a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
+++ b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
@@ -97,6 +97,7 @@
         setLowProfile(true);
         setFullscreen(true);
         setContentView(R.layout.dream);
+        setScreenBright(false);
 
         mAlarmClock = (TextView)findViewById(R.id.alarm_clock);
 
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..4dd1446 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 clearWindowContentFrameStats(IBinder token) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public WindowContentFrameStats getWindowContentFrameStats(IBinder token) {
+        // TODO Auto-generated method stub
+        return null;
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index b9f2ed9..4eb70aa 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -28,7 +28,7 @@
 public class BridgePowerManager implements IPowerManager {
 
     @Override
-    public boolean isScreenOn() throws RemoteException {
+    public boolean isInteractive() throws RemoteException {
         return true;
     }