am f24687e2: Merge "Plumb display power state through display manager." into klp-modular-dev

* commit 'f24687e2731811fd0e3803b691fd47a659f89329':
  Plumb display power state through display manager.
diff --git a/api/current.txt b/api/current.txt
index 66f2a47..869a892 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -18321,7 +18321,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);
@@ -26544,6 +26545,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
@@ -26551,6 +26553,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 {
@@ -26885,7 +26891,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
@@ -28949,7 +28955,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/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 65e2268..95e27e2 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1414,15 +1414,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/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/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 56176a4..92af1a5 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -37,8 +37,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 86ef479..646bfef 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -582,21 +582,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/view/Display.java b/core/java/android/view/Display.java
index 7d310a2..c4494f4 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}
@@ -628,6 +658,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
      */
@@ -718,5 +761,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 8944207..5f840d3 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/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 437ccfb..7b389c0 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1167,9 +1167,13 @@
 
     /**
      * 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;
-    
+
     /**
      * This mask is set if the key event was generated by a software keyboard.
      */
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 74dda77..893db89 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -86,8 +86,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
@@ -735,11 +734,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.
@@ -752,7 +750,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/libs/input/InputDispatcher.cpp b/libs/input/InputDispatcher.cpp
index be85cfc..22d1871 100644
--- a/libs/input/InputDispatcher.cpp
+++ b/libs/input/InputDispatcher.cpp
@@ -248,10 +248,10 @@
 void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
     nsecs_t currentTime = now();
 
-    // Reset the key repeat timer whenever we disallow key events, even if the next event
-    // is not a key.  This is to ensure that we abort a key repeat if the device is just coming
-    // out of sleep.
-    if (!mPolicy->isKeyRepeatEnabled()) {
+    // Reset the key repeat timer whenever normal dispatch is suspended while the
+    // device is in a non-interactive state.  This is to ensure that we abort a key
+    // repeat if the device is just coming out of sleep.
+    if (!mDispatchEnabled) {
         resetKeyRepeatLocked();
     }
 
@@ -1135,30 +1135,6 @@
 
     // For security reasons, we defer updating the touch state until we are sure that
     // event injection will be allowed.
-    //
-    // FIXME In the original code, screenWasOff could never be set to true.
-    //       The reason is that the POLICY_FLAG_WOKE_HERE
-    //       and POLICY_FLAG_BRIGHT_HERE flags were set only when preprocessing raw
-    //       EV_KEY, EV_REL and EV_ABS events.  As it happens, the touch event was
-    //       actually enqueued using the policyFlags that appeared in the final EV_SYN
-    //       events upon which no preprocessing took place.  So policyFlags was always 0.
-    //       In the new native input dispatcher we're a bit more careful about event
-    //       preprocessing so the touches we receive can actually have non-zero policyFlags.
-    //       Unfortunately we obtain undesirable behavior.
-    //
-    //       Here's what happens:
-    //
-    //       When the device dims in anticipation of going to sleep, touches
-    //       in windows which have FLAG_TOUCHABLE_WHEN_WAKING cause
-    //       the device to brighten and reset the user activity timer.
-    //       Touches on other windows (such as the launcher window)
-    //       are dropped.  Then after a moment, the device goes to sleep.  Oops.
-    //
-    //       Also notice how screenWasOff was being initialized using POLICY_FLAG_BRIGHT_HERE
-    //       instead of POLICY_FLAG_WOKE_HERE...
-    //
-    bool screenWasOff = false; // original policy: policyFlags & POLICY_FLAG_BRIGHT_HERE;
-
     int32_t displayId = entry->displayId;
     int32_t action = entry->action;
     int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
@@ -1243,10 +1219,7 @@
                     isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
                             | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
                     if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
-                        if (! screenWasOff
-                                || (flags & InputWindowInfo::FLAG_TOUCHABLE_WHEN_WAKING)) {
-                            newTouchedWindowHandle = windowHandle;
-                        }
+                        newTouchedWindowHandle = windowHandle;
                         break; // found touched window, exit window loop
                     }
                 }
@@ -2409,10 +2382,6 @@
 
     mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
 
-    if (policyFlags & POLICY_FLAG_WOKE_HERE) {
-        flags |= AKEY_EVENT_FLAG_WOKE_HERE;
-    }
-
     bool needWake;
     { // acquire lock
         mLock.lock();
@@ -2592,10 +2561,6 @@
             mPolicy->interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags);
         }
 
-        if (policyFlags & POLICY_FLAG_WOKE_HERE) {
-            flags |= AKEY_EVENT_FLAG_WOKE_HERE;
-        }
-
         mLock.lock();
         firstInjectedEntry = new KeyEntry(keyEvent->getEventTime(),
                 keyEvent->getDeviceId(), keyEvent->getSource(),
diff --git a/libs/input/InputDispatcher.h b/libs/input/InputDispatcher.h
index 29854b2..9439124 100644
--- a/libs/input/InputDispatcher.h
+++ b/libs/input/InputDispatcher.h
@@ -211,9 +211,6 @@
     /* Gets the input dispatcher configuration. */
     virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;
 
-    /* Returns true if automatic key repeating is enabled. */
-    virtual bool isKeyRepeatEnabled() = 0;
-
     /* Filters an input event.
      * Return true to dispatch the event unmodified, false to consume the event.
      * A filter can also transform and inject events later by passing POLICY_FLAG_FILTERED
diff --git a/libs/input/tests/InputDispatcher_test.cpp b/libs/input/tests/InputDispatcher_test.cpp
index fc89a9b..7aac6ed 100644
--- a/libs/input/tests/InputDispatcher_test.cpp
+++ b/libs/input/tests/InputDispatcher_test.cpp
@@ -65,10 +65,6 @@
         *outConfig = mConfig;
     }
 
-    virtual bool isKeyRepeatEnabled() {
-        return true;
-    }
-
     virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) {
         return true;
     }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index f3fce11..2a4e059 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -2363,7 +2363,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);
@@ -3802,12 +3802,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();
@@ -3819,7 +3820,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()));
 
@@ -3831,7 +3832,7 @@
 
         if (DEBUG_INPUT) {
             Log.d(TAG, "interceptKeyTq keycode=" + keyCode
-                    + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive
+                    + " interactive=" + interactive + " keyguardActive=" + keyguardActive
                     + " policyFlags=" + Integer.toHexString(policyFlags));
         }
 
@@ -3840,18 +3841,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 {
@@ -3876,7 +3870,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();
@@ -3890,7 +3884,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();
@@ -3958,7 +3952,7 @@
                             Log.w(TAG, "ITelephony threw RemoteException", ex);
                         }
                     }
-                    interceptPowerKeyDown(!isScreenOn || hungUp);
+                    interceptPowerKeyDown(!interactive || hungUp);
                 } else {
                     if (interceptPowerKeyUp(canceled)) {
                         if ((mEndcallBehavior
@@ -3980,9 +3974,9 @@
             case KeyEvent.KEYCODE_POWER: {
                 result &= ~ACTION_PASS_TO_USER;
                 if (down) {
-                    mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn, event.getDownTime(),
+                    mImmersiveModeConfirmation.onPowerKeyDown(interactive, event.getDownTime(),
                             isImmersiveMode(mLastSystemUiFlags));
-                    if (isScreenOn && !mPowerKeyTriggered
+                    if (interactive && !mPowerKeyTriggered
                             && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
                         mPowerKeyTriggered = true;
                         mPowerKeyTime = event.getDownTime();
@@ -4008,7 +4002,7 @@
                             Log.w(TAG, "ITelephony threw RemoteException", ex);
                         }
                     }
-                    interceptPowerKeyDown(!isScreenOn || hungUp
+                    interceptPowerKeyDown(!interactive || hungUp
                             || mVolumeDownKeyTriggered || mVolumeUpKeyTriggered);
                 } else {
                     mPowerKeyTriggered = false;
@@ -4141,15 +4135,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/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 dcf7da2..7abf88c 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -45,6 +45,7 @@
 import android.util.Slog;
 import android.util.Spline;
 import android.util.TimeUtils;
+import android.view.Display;
 
 import java.io.PrintWriter;
 
@@ -185,6 +186,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;
 
@@ -349,7 +353,8 @@
      * 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;
 
@@ -357,6 +362,7 @@
         mLights = LocalServices.getService(LightsManager.class);
         mTwilight = LocalServices.getService(TwilightManager.class);
         mSensorManager = sensorManager;
+        mBlanker = blanker;
 
         final Resources resources = context.getResources();
 
@@ -520,8 +526,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);
@@ -670,7 +679,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.
@@ -681,7 +690,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) {
@@ -714,12 +724,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();
@@ -752,9 +762,9 @@
     private void blockScreenOn() {
         if (!mScreenOnWasBlocked) {
             mScreenOnWasBlocked = true;
+            mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
             if (DEBUG) {
                 Slog.d(TAG, "Blocked screen on.");
-                mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
             }
         }
     }
@@ -769,11 +779,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 cb8f3e2..b8bf484 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -102,7 +102,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) {
@@ -135,6 +135,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.
@@ -172,15 +173,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
@@ -188,7 +190,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 7e357c0..5499af6 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/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index e49382e..a32f7c1 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -183,6 +183,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 nativeVibrate(long ptr, int deviceId, long[] pattern,
             int repeat, int token);
     private static native void nativeCancelVibrate(long ptr, int deviceId, int token);
@@ -1360,14 +1361,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);
     }
 
@@ -1526,9 +1526,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);
@@ -1696,5 +1696,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 19d53cb..6224ed3 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;
@@ -85,6 +86,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;
@@ -120,6 +122,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);
@@ -194,73 +197,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 6b2ca4c..7138c3e 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);
@@ -411,13 +410,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
@@ -445,14 +448,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) {
@@ -546,9 +541,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);
@@ -854,11 +849,6 @@
         return false;
     }
 
-    // Called from native code.
-    private void wakeUpFromNative(long eventTime) {
-        wakeUpInternal(eventTime);
-    }
-
     private void wakeUpInternal(long eventTime) {
         synchronized (mLock) {
             if (wakeUpNoUpdateLocked(eventTime)) {
@@ -889,26 +879,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)) {
@@ -945,14 +925,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;
@@ -994,6 +971,7 @@
         mDirty |= DIRTY_WAKEFULNESS;
         mWakefulness = WAKEFULNESS_DREAMING;
         mSandmanSummoned = true;
+        setInteractiveStateLocked(true, 0);
         return true;
     }
 
@@ -1012,9 +990,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.
      *
@@ -1058,7 +1054,7 @@
 
         // Phase 3: Send notifications, if needed.
         if (mDisplayReady) {
-            sendPendingNotificationsLocked();
+            finishInteractiveStateChangeLocked();
         }
 
         // Phase 4: Update suspend blocker.
@@ -1067,17 +1063,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.
@@ -1197,48 +1182,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)
@@ -1256,12 +1238,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);
 
@@ -1585,8 +1569,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;
@@ -1668,7 +1650,7 @@
 
     private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks =
             new DisplayManagerInternal.DisplayPowerCallbacks() {
-        private boolean mBlanked;
+        private int mDisplayState = Display.STATE_UNKNOWN;
 
         @Override
         public void onStateChanged() {
@@ -1699,6 +1681,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();
         }
@@ -1709,37 +1718,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);
             }
         }
     };
@@ -1760,11 +1741,11 @@
 
         // Disable auto-suspend if needed.
         if (!autoSuspend) {
-            if (mDecoupleAutoSuspendModeFromDisplayConfig) {
-                setAutoSuspendModeLocked(false);
+            if (mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+                setHalAutoSuspendModeLocked(false);
             }
-            if (mDecoupleInteractiveModeFromDisplayConfig) {
-                setInteractiveModeLocked(true);
+            if (mDecoupleHalInteractiveModeFromDisplayConfig) {
+                setHalInteractiveModeLocked(true);
             }
         }
 
@@ -1790,11 +1771,11 @@
 
         // Enable auto-suspend if needed.
         if (autoSuspend) {
-            if (mDecoupleInteractiveModeFromDisplayConfig) {
-                setInteractiveModeLocked(false);
+            if (mDecoupleHalInteractiveModeFromDisplayConfig) {
+                setHalInteractiveModeLocked(false);
             }
-            if (mDecoupleAutoSuspendModeFromDisplayConfig) {
-                setAutoSuspendModeLocked(true);
+            if (mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+                setHalAutoSuspendModeLocked(true);
             }
         }
     }
@@ -1821,42 +1802,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();
@@ -2061,6 +2032,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);
@@ -2070,8 +2042,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);
@@ -2079,10 +2051,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));
@@ -2092,10 +2060,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="
@@ -2684,10 +2652,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/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 3fccf53..a4f4a0b 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -69,7 +69,7 @@
     jmethodID notifyANR;
     jmethodID filterInputEvent;
     jmethodID interceptKeyBeforeQueueing;
-    jmethodID interceptMotionBeforeQueueingWhenScreenOff;
+    jmethodID interceptWakeMotionBeforeQueueing;
     jmethodID interceptKeyBeforeDispatching;
     jmethodID dispatchUnhandledKey;
     jmethodID checkInjectEventsPermission;
@@ -181,6 +181,7 @@
     void setSystemUiVisibility(int32_t visibility);
     void setPointerSpeed(int32_t speed);
     void setShowTouches(bool enabled);
+    void setInteractive(bool interactive);
 
     /* --- InputReaderPolicyInterface implementation --- */
 
@@ -201,7 +202,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(
@@ -249,14 +249,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() {
@@ -268,7 +266,7 @@
 
 NativeInputManager::NativeInputManager(jobject contextObj,
         jobject serviceObj, const sp<Looper>& looper) :
-        mLooper(looper) {
+        mLooper(looper), mInteractive(true) {
     JNIEnv* env = jniEnv();
 
     mContextObj = env->NewGlobalRef(contextObj);
@@ -624,11 +622,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;
 
@@ -740,12 +733,8 @@
             InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
 }
 
-bool NativeInputManager::isScreenOn() {
-    return android_server_PowerManagerService_isScreenOn();
-}
-
-bool NativeInputManager::isScreenBright() {
-    return android_server_PowerManagerService_isScreenBright();
+void NativeInputManager::setInteractive(bool interactive) {
+    mInteractive = interactive;
 }
 
 bool NativeInputManager::filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) {
@@ -786,18 +775,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;
             }
@@ -808,16 +797,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;
@@ -830,24 +809,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 {
@@ -1230,6 +1207,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 nativeVibrate(JNIEnv* env,
         jclass clazz, jlong ptr, jint deviceId, jlongArray patternObj,
         jint repeat, jint token) {
@@ -1335,6 +1319,8 @@
             (void*) nativeSetPointerSpeed },
     { "nativeSetShowTouches", "(JZ)V",
             (void*) nativeSetShowTouches },
+    { "nativeSetInteractive", "(JZ)V",
+            (void*) nativeSetInteractive },
     { "nativeVibrate", "(JI[JII)V",
             (void*) nativeVibrate },
     { "nativeCancelVibrate", "(JII)V",
@@ -1391,11 +1377,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 151e134..af09861 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());
@@ -195,8 +150,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",
@@ -229,12 +182,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");
 
@@ -242,8 +189,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 0808b80..fb8153f 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/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);