Merge "Allow focusable in touch mode views to ignore touchscreen focus blocks" into lmp-dev
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index e58c54d..99af2e7 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -19,6 +19,7 @@
 import android.hardware.SensorManager;
 import android.os.Handler;
 import android.os.PowerManager;
+import android.view.Display;
 import android.view.DisplayInfo;
 
 /**
@@ -132,13 +133,19 @@
      * have to micro-manage screen off animations, auto-brightness and other effects.
      */
     public static final class DisplayPowerRequest {
-        public static final int SCREEN_STATE_OFF = 0;
-        public static final int SCREEN_STATE_DOZE = 1;
-        public static final int SCREEN_STATE_DIM = 2;
-        public static final int SCREEN_STATE_BRIGHT = 3;
+        // Policy: Turn screen off as if the user pressed the power button
+        // including playing a screen off animation if applicable.
+        public static final int POLICY_OFF = 0;
+        // Policy: Enable dozing and always-on display functionality.
+        public static final int POLICY_DOZE = 1;
+        // Policy: Make the screen dim when the user activity timeout is
+        // about to expire.
+        public static final int POLICY_DIM = 2;
+        // Policy: Make the screen bright as usual.
+        public static final int POLICY_BRIGHT = 3;
 
-        // The requested minimum screen power state: off, doze, dim or bright.
-        public int screenState;
+        // The basic overall policy to apply: off, doze, dim or bright.
+        public int policy;
 
         // If true, the proximity sensor overrides the screen state when an object is
         // nearby, turning it off temporarily until the object is moved away.
@@ -169,44 +176,39 @@
         // visible to the user.
         public boolean blockScreenOn;
 
+        // Overrides the policy for adjusting screen brightness and state while dozing.
+        public int dozeScreenBrightness;
+        public int dozeScreenState;
+
         public DisplayPowerRequest() {
-            screenState = SCREEN_STATE_BRIGHT;
+            policy = POLICY_BRIGHT;
             useProximitySensor = false;
             screenBrightness = PowerManager.BRIGHTNESS_ON;
             screenAutoBrightnessAdjustment = 0.0f;
             useAutoBrightness = false;
             blockScreenOn = false;
+            dozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
+            dozeScreenState = Display.STATE_UNKNOWN;
         }
 
         public DisplayPowerRequest(DisplayPowerRequest other) {
             copyFrom(other);
         }
 
-        // Returns true if we want the screen on in any mode, including doze.
-        public boolean wantScreenOnAny() {
-            return screenState != SCREEN_STATE_OFF;
-        }
-
-        // Returns true if we want the screen on in a normal mode, excluding doze.
-        // This is usually what we want to tell the rest of the system.  For compatibility
-        // reasons, we pretend the screen is off when dozing.
-        public boolean wantScreenOnNormal() {
-            return screenState == SCREEN_STATE_DIM || screenState == SCREEN_STATE_BRIGHT;
-        }
-
-        public boolean wantLightSensorEnabled() {
-            // Specifically, we don't want the light sensor while dozing.
-            return useAutoBrightness && wantScreenOnNormal();
+        public boolean isBrightOrDim() {
+            return policy == POLICY_BRIGHT || policy == POLICY_DIM;
         }
 
         public void copyFrom(DisplayPowerRequest other) {
-            screenState = other.screenState;
+            policy = other.policy;
             useProximitySensor = other.useProximitySensor;
             screenBrightness = other.screenBrightness;
             screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment;
             useAutoBrightness = other.useAutoBrightness;
             blockScreenOn = other.blockScreenOn;
             lowPowerMode = other.lowPowerMode;
+            dozeScreenBrightness = other.dozeScreenBrightness;
+            dozeScreenState = other.dozeScreenState;
         }
 
         @Override
@@ -217,13 +219,15 @@
 
         public boolean equals(DisplayPowerRequest other) {
             return other != null
-                    && screenState == other.screenState
+                    && policy == other.policy
                     && useProximitySensor == other.useProximitySensor
                     && screenBrightness == other.screenBrightness
                     && screenAutoBrightnessAdjustment == other.screenAutoBrightnessAdjustment
                     && useAutoBrightness == other.useAutoBrightness
                     && blockScreenOn == other.blockScreenOn
-                    && lowPowerMode == other.lowPowerMode;
+                    && lowPowerMode == other.lowPowerMode
+                    && dozeScreenBrightness == other.dozeScreenBrightness
+                    && dozeScreenState == other.dozeScreenState;
         }
 
         @Override
@@ -233,13 +237,30 @@
 
         @Override
         public String toString() {
-            return "screenState=" + screenState
+            return "policy=" + policyToString(policy)
                     + ", useProximitySensor=" + useProximitySensor
                     + ", screenBrightness=" + screenBrightness
                     + ", screenAutoBrightnessAdjustment=" + screenAutoBrightnessAdjustment
                     + ", useAutoBrightness=" + useAutoBrightness
                     + ", blockScreenOn=" + blockScreenOn
-                    + ", lowPowerMode=" + lowPowerMode;
+                    + ", lowPowerMode=" + lowPowerMode
+                    + ", dozeScreenBrightness=" + dozeScreenBrightness
+                    + ", dozeScreenState=" + Display.stateToString(dozeScreenState);
+        }
+
+        public static String policyToString(int policy) {
+            switch (policy) {
+                case POLICY_OFF:
+                    return "OFF";
+                case POLICY_DOZE:
+                    return "DOZE";
+                case POLICY_DIM:
+                    return "DIM";
+                case POLICY_BRIGHT:
+                    return "BRIGHT";
+                default:
+                    return Integer.toString(policy);
+            }
         }
     }
 
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 92e80a5..dda6d27 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -263,6 +263,12 @@
      */
     public static final int BRIGHTNESS_OFF = 0;
 
+    /**
+     * Brightness value for default policy handling by the system.
+     * @hide
+     */
+    public static final int BRIGHTNESS_DEFAULT = -1;
+
     // Note: Be sure to update android.os.BatteryStats and PowerManager.h
     // if adding or modifying user activity event constants.
 
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 08a15eb..14f4a83 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -16,6 +16,8 @@
 
 package android.os;
 
+import android.view.Display;
+
 /**
  * Power manager local system service interface.
  *
@@ -53,6 +55,17 @@
      */
     public abstract void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis);
 
+    /**
+     * Used by the dream manager to override certain properties while dozing.
+     *
+     * @param screenState The overridden screen state, or {@link Display.STATE_UNKNOWN}
+     * to disable the override.
+     * @param screenBrightness The overridden screen brightness, or
+     * {@link PowerManager#BRIGHTNESS_DEFAULT} to disable the override.
+     */
+    public abstract void setDozeOverrideFromDreamManager(
+            int screenState, int screenBrightness);
+
     public abstract boolean getLowPowerModeEnabled();
 
     public abstract void registerLowPowerModeObserver(LowPowerModeListener listener);
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 5fa542a..5cf8aa6 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -27,10 +27,13 @@
 import android.graphics.drawable.ColorDrawable;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.PowerManager;
+import android.os.RemoteException;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Slog;
 import android.view.ActionMode;
+import android.view.Display;
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -42,6 +45,7 @@
 import android.view.WindowManagerGlobal;
 import android.view.WindowManager.LayoutParams;
 import android.view.accessibility.AccessibilityEvent;
+import android.util.MathUtils;
 
 import com.android.internal.policy.PolicyManager;
 import com.android.internal.util.DumpUtils;
@@ -133,8 +137,11 @@
  *     android:exported="true"
  *     android:icon="@drawable/my_icon"
  *     android:label="@string/my_dream_label"
- *     android:permission="android.permission.BIND_DREAM_SERVICE" >
- *  ...
+ *     android:permission="android.permission.BIND_DREAM_SERVICE">
+ *   <intent-filter>
+ *     <action android:name=”android.service.dreams.DreamService” />
+ *     <category android:name=”android.intent.category.DEFAULT” />
+ *   </intent-filter>
  * </service>
  * </pre>
  */
@@ -177,6 +184,8 @@
     private boolean mDozing;
     private boolean mWindowless;
     private DozeHardware mDozeHardware;
+    private int mDozeScreenState = Display.STATE_UNKNOWN;
+    private int mDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
 
     private boolean mDebug = false;
 
@@ -560,7 +569,7 @@
      *
      * @return True if this dream can doze.
      * @see #startDozing
-     * @hide experimental
+     * @hide For use by system UI components only.
      */
     public boolean canDoze() {
         return mCanDoze;
@@ -593,13 +602,19 @@
      * </p>
      *
      * @see #stopDozing
-     * @hide experimental
+     * @hide For use by system UI components only.
      */
     public void startDozing() {
         if (mCanDoze && !mDozing) {
             mDozing = true;
+            updateDoze();
+        }
+    }
+
+    private void updateDoze() {
+        if (mDozing) {
             try {
-                mSandman.startDozing(mWindowToken);
+                mSandman.startDozing(mWindowToken, mDozeScreenState, mDozeScreenBrightness);
             } catch (RemoteException ex) {
                 // system server died
             }
@@ -615,7 +630,7 @@
      * </p>
      *
      * @see #startDozing
-     * @hide experimental
+     * @hide For use by system UI components only.
      */
     public void stopDozing() {
         if (mDozing) {
@@ -636,7 +651,7 @@
      * @return True if the dream is dozing.
      *
      * @see #setDozing(boolean)
-     * @hide experimental
+     * @hide For use by system UI components only.
      */
     public boolean isDozing() {
         return mDozing;
@@ -649,7 +664,7 @@
      * @return An instance of {@link DozeHardware} or null if this device does not offer
      * hardware support for dozing.
      *
-     * @hide experimental
+     * @hide For use by system UI components only.
      */
     public DozeHardware getDozeHardware() {
         if (mCanDoze && mDozeHardware == null && mWindowToken != null) {
@@ -666,11 +681,116 @@
     }
 
     /**
+     * Gets the screen state to use while dozing.
+     *
+     * @return The screen state to use while dozing, such as {@link Display#STATE_ON},
+     * {@link Display#STATE_DOZE}, {@link Display#STATE_DOZE_SUSPEND},
+     * or {@link Display#STATE_OFF}, or {@link Display#STATE_UNKNOWN} for the default
+     * behavior.
+     *
+     * @see #setDozeScreenState
+     * @hide For use by system UI components only.
+     */
+    public int getDozeScreenState() {
+        return mDozeScreenState;
+    }
+
+    /**
+     * Sets the screen state to use while dozing.
+     * <p>
+     * The value of this property determines the power state of the primary display
+     * once {@link #startDozing} has been called.  The default value is
+     * {@link Display#STATE_UNKNOWN} which lets the system decide.
+     * The dream may set a different state before starting to doze and may
+     * perform transitions between states while dozing to conserve power and
+     * achieve various effects.
+     * </p><p>
+     * It is recommended that the state be set to {@link Display#STATE_DOZE_SUSPEND}
+     * once the dream has completely finished drawing and before it releases its wakelock
+     * to allow the display hardware to be fully suspended.  While suspended, the
+     * display will preserve its on-screen contents or hand off control to dedicated
+     * doze hardware if the devices supports it.  If the doze suspend state is
+     * used, the dream must make sure to set the mode back
+     * to {@link Display#STATE_DOZE} or {@link Display#STATE_ON} before drawing again
+     * since the display updates may be ignored and not seen by the user otherwise.
+     * </p><p>
+     * The set of available display power states and their behavior while dozing is
+     * hardware dependent and may vary across devices.  The dream may therefore
+     * need to be modified or configured to correctly support the hardware.
+     * </p>
+     *
+     * @param state The screen state to use while dozing, such as {@link Display#STATE_ON},
+     * {@link Display#STATE_DOZE}, {@link Display#STATE_DOZE_SUSPEND},
+     * or {@link Display#STATE_OFF}, or {@link Display#STATE_UNKNOWN} for the default
+     * behavior.
+     *
+     * @hide For use by system UI components only.
+     */
+    public void setDozeScreenState(int state) {
+        if (mDozeScreenState != state) {
+            mDozeScreenState = state;
+            updateDoze();
+        }
+    }
+
+    /**
+     * Gets the screen brightness to use while dozing.
+     *
+     * @return The screen brightness while dozing as a value between
+     * {@link PowerManager#BRIGHTNESS_OFF} (0) and {@link PowerManager#BRIGHTNESS_ON} (255),
+     * or {@link PowerManager#BRIGHTNESS_DEFAULT} (-1) to ask the system to apply
+     * its default policy based on the screen state.
+     *
+     * @see #setDozeScreenBrightness
+     * @hide For use by system UI components only.
+     */
+    public int getDozeScreenBrightness() {
+        return mDozeScreenBrightness;
+    }
+
+    /**
+     * Sets the screen brightness to use while dozing.
+     * <p>
+     * The value of this property determines the power state of the primary display
+     * once {@link #startDozing} has been called.  The default value is
+     * {@link PowerManager#BRIGHTNESS_DEFAULT} which lets the system decide.
+     * The dream may set a different brightness before starting to doze and may adjust
+     * the brightness while dozing to conserve power and achieve various effects.
+     * </p><p>
+     * Note that dream may specify any brightness in the full 0-255 range, including
+     * values that are less than the minimum value for manual screen brightness
+     * adjustments by the user.  In particular, the value may be set to 0 which may
+     * turn off the backlight entirely while still leaving the screen on although
+     * this behavior is device dependent and not guaranteed.
+     * </p><p>
+     * The available range of display brightness values and their behavior while dozing is
+     * hardware dependent and may vary across devices.  The dream may therefore
+     * need to be modified or configured to correctly support the hardware.
+     * </p>
+     *
+     * @param brightness The screen brightness while dozing as a value between
+     * {@link PowerManager#BRIGHTNESS_OFF} (0) and {@link PowerManager#BRIGHTNESS_ON} (255),
+     * or {@link PowerManager#BRIGHTNESS_DEFAULT} (-1) to ask the system to apply
+     * its default policy based on the screen state.
+     *
+     * @hide For use by system UI components only.
+     */
+    public void setDozeScreenBrightness(int brightness) {
+        if (brightness != PowerManager.BRIGHTNESS_DEFAULT) {
+            brightness = clampAbsoluteBrightness(brightness);
+        }
+        if (mDozeScreenBrightness != brightness) {
+            mDozeScreenBrightness = brightness;
+            updateDoze();
+        }
+    }
+
+    /**
      * Called when this Dream is constructed.
      */
     @Override
     public void onCreate() {
-        if (mDebug) Slog.v(TAG, "onCreate() on thread " + Thread.currentThread().getId());
+        if (mDebug) Slog.v(TAG, "onCreate()");
         super.onCreate();
     }
 
@@ -844,8 +964,6 @@
             return;
         }
 
-        if (mDebug) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId());
-
         mWindowToken = windowToken;
         mCanDoze = canDoze;
         if (mWindowless && !mCanDoze) {
@@ -963,7 +1081,17 @@
         if (isScreenBright()) pw.print(" bright");
         if (isWindowless()) pw.print(" windowless");
         if (isDozing()) pw.print(" dozing");
+        else if (canDoze()) pw.print(" candoze");
         pw.println();
+        if (canDoze()) {
+            pw.println("  doze hardware: " + mDozeHardware);
+            pw.println("  doze screen state: " + Display.stateToString(mDozeScreenState));
+            pw.println("  doze screen brightness: " + mDozeScreenBrightness);
+        }
+    }
+
+    private static int clampAbsoluteBrightness(int value) {
+        return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
     }
 
     private final class DreamServiceWrapper extends IDreamService.Stub {
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index 9608a4d..648426c 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -32,7 +32,7 @@
     void testDream(in ComponentName componentName);
     boolean isDreaming();
     void finishSelf(in IBinder token, boolean immediate);
-    void startDozing(in IBinder token);
+    void startDozing(in IBinder token, int screenState, int screenBrightness);
     void stopDozing(in IBinder token);
     IDozeHardware getDozeHardware(in IBinder token);
-}
\ No newline at end of file
+}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index b17fa4a..154d227 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -831,4 +831,13 @@
                 return Integer.toString(state);
         }
     }
+
+    /**
+     * Returns true if display updates may be suspended while in the specified
+     * display power state.
+     * @hide
+     */
+    public static boolean isSuspendedState(int state) {
+        return state == STATE_OFF || state == STATE_DOZE_SUSPEND;
+    }
 }
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 4740cae..45d3771 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -26,7 +26,6 @@
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
-import android.hardware.display.DisplayManagerInternal;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -199,9 +198,10 @@
         return mScreenAutoBrightness;
     }
 
-    public void updatePowerState(DisplayManagerInternal.DisplayPowerRequest request) {
-        if (setScreenAutoBrightnessAdjustment(request.screenAutoBrightnessAdjustment)
-                | setLightSensorEnabled(request.wantLightSensorEnabled())) {
+    public void configure(boolean enable, float adjustment) {
+        boolean changed = setLightSensorEnabled(enable);
+        changed |= setScreenAutoBrightnessAdjustment(adjustment);
+        if (changed) {
             updateAutoBrightness(false /*sendUpdate*/);
         }
     }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index a361e10..09221a3e 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -213,9 +213,11 @@
     // The elapsed real time when the screen on was blocked.
     private long mScreenOnBlockStartRealTime;
 
-    // True if the screen auto-brightness value is actually being used to
-    // set the display brightness.
-    private boolean mUsingScreenAutoBrightness;
+    // Remembers whether certain kinds of brightness adjustments
+    // were recently applied so that we can decide how to transition.
+    private boolean mAppliedAutoBrightness;
+    private boolean mAppliedDimming;
+    private boolean mAppliedLowPower;
 
     // The controller for the automatic brightness level.
     private AutomaticBrightnessController mAutomaticBrightnessController;
@@ -428,7 +430,6 @@
         // Update the power state request.
         final boolean mustNotify;
         boolean mustInitialize = false;
-        boolean wasDimOrDoze = false;
         boolean autoBrightnessAdjustmentChanged = false;
 
         synchronized (mLock) {
@@ -444,8 +445,6 @@
                 mPendingRequestChangedLocked = false;
                 mustInitialize = true;
             } else if (mPendingRequestChangedLocked) {
-                wasDimOrDoze = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM
-                        || mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE);
                 autoBrightnessAdjustmentChanged = (mPowerRequest.screenAutoBrightnessAdjustment
                         != mPendingRequestLocked.screenAutoBrightnessAdjustment);
                 mPowerRequest.copyFrom(mPendingRequestLocked);
@@ -463,10 +462,32 @@
             initialize();
         }
 
+        // Compute the basic display state using the policy.
+        // We might override this below based on other factors.
+        int state;
+        int brightness = PowerManager.BRIGHTNESS_DEFAULT;
+        switch (mPowerRequest.policy) {
+            case DisplayPowerRequest.POLICY_OFF:
+                state = Display.STATE_OFF;
+                break;
+            case DisplayPowerRequest.POLICY_DOZE:
+                if (mPowerRequest.dozeScreenState != Display.STATE_UNKNOWN) {
+                    state = mPowerRequest.dozeScreenState;
+                } else {
+                    state = Display.STATE_DOZE;
+                }
+                brightness = mPowerRequest.dozeScreenBrightness;
+                break;
+            case DisplayPowerRequest.POLICY_DIM:
+            case DisplayPowerRequest.POLICY_BRIGHT:
+            default:
+                state = Display.STATE_ON;
+                break;
+        }
+
         // Apply the proximity sensor.
         if (mProximitySensor != null) {
-            if (mPowerRequest.useProximitySensor
-                    && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
+            if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) {
                 setProximitySensorEnabled(true);
                 if (!mScreenOffBecauseOfProximity
                         && mProximity == PROXIMITY_POSITIVE) {
@@ -476,7 +497,7 @@
             } else if (mWaitingForNegativeProximity
                     && mScreenOffBecauseOfProximity
                     && mProximity == PROXIMITY_POSITIVE
-                    && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
+                    && state != Display.STATE_OFF) {
                 setProximitySensorEnabled(true);
             } else {
                 setProximitySensorEnabled(false);
@@ -490,63 +511,89 @@
         } else {
             mWaitingForNegativeProximity = false;
         }
-
-        // Turn on the light sensor if needed.
-        if (mAutomaticBrightnessController != null) {
-            mAutomaticBrightnessController.updatePowerState(mPowerRequest);
+        if (mScreenOffBecauseOfProximity) {
+            state = Display.STATE_OFF;
         }
 
-        // Set the screen brightness.
-        if (mPowerRequest.wantScreenOnAny()) {
-            int target;
-            boolean slow;
-            int screenAutoBrightness = mAutomaticBrightnessController != null ?
-                    mAutomaticBrightnessController.getAutomaticScreenBrightness() : -1;
-            if (screenAutoBrightness >= 0 && mPowerRequest.useAutoBrightness) {
-                // Use current auto-brightness value.
-                target = screenAutoBrightness;
-                slow = mUsingScreenAutoBrightness && !autoBrightnessAdjustmentChanged;
-                mUsingScreenAutoBrightness = true;
+        // Use zero brightness when screen is off.
+        if (state == Display.STATE_OFF) {
+            brightness = PowerManager.BRIGHTNESS_OFF;
+        }
+
+        // Use default brightness when dozing unless overridden.
+        if (brightness < 0 && (state == Display.STATE_DOZE
+                || state == Display.STATE_DOZE_SUSPEND)) {
+            brightness = mScreenBrightnessDozeConfig;
+        }
+
+        // Configure auto-brightness.
+        boolean autoBrightnessEnabled = false;
+        if (mAutomaticBrightnessController != null) {
+            autoBrightnessEnabled = mPowerRequest.useAutoBrightness
+                    && state == Display.STATE_ON && brightness < 0;
+            mAutomaticBrightnessController.configure(autoBrightnessEnabled,
+                    mPowerRequest.screenAutoBrightnessAdjustment);
+        }
+
+        // Apply auto-brightness.
+        boolean slowChange = false;
+        if (brightness < 0) {
+            if (autoBrightnessEnabled) {
+                brightness = mAutomaticBrightnessController.getAutomaticScreenBrightness();
+            }
+            if (brightness >= 0) {
+                // Use current auto-brightness value and slowly adjust to changes.
+                brightness = clampScreenBrightness(brightness);
+                if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
+                    slowChange = true; // slowly adapt to auto-brightness
+                }
+                mAppliedAutoBrightness = true;
             } else {
-                // Light sensor is disabled or not ready yet.
-                // Use the current brightness setting from the request, which is expected
-                // provide a nominal default value for the case where auto-brightness
-                // is not ready yet.
-                target = mPowerRequest.screenBrightness;
-                slow = false;
-                mUsingScreenAutoBrightness = false;
+                mAppliedAutoBrightness = false;
             }
-            if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE) {
-                // Dim quickly to the doze state.
-                target = mScreenBrightnessDozeConfig;
-                slow = false;
-            } else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
-                // Dim quickly by at least some minimum amount.
-                target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,
-                        mScreenBrightnessDimConfig);
-                slow = false;
-            } else if (wasDimOrDoze) {
-                // Brighten quickly.
-                slow = false;
-            }
-            // If low power mode is enabled, brightness level
-            // would be scaled down to half
-            if (mPowerRequest.lowPowerMode) {
-                target = target/2;
-            }
-            animateScreenBrightness(clampScreenBrightness(target),
-                    slow ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
         } else {
-            // Screen is off.  Don't bother changing the brightness.
-            mUsingScreenAutoBrightness = false;
+            mAppliedAutoBrightness = false;
+        }
+
+        // Apply manual brightness.
+        // Use the current brightness setting from the request, which is expected
+        // provide a nominal default value for the case where auto-brightness
+        // is not ready yet.
+        if (brightness < 0) {
+            brightness = clampScreenBrightness(mPowerRequest.screenBrightness);
+        }
+
+        // Apply dimming by at least some minimum amount when user activity
+        // timeout is about to expire.
+        if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
+            brightness = Math.max(Math.min(brightness - SCREEN_DIM_MINIMUM_REDUCTION,
+                    mScreenBrightnessDimConfig), mScreenBrightnessRangeMinimum);
+            if (!mAppliedDimming) {
+                slowChange = false;
+            }
+            mAppliedDimming = true;
+        }
+
+        // If low power mode is enabled, cut the brightness level by half
+        // as long as it is above the minimum threshold.
+        if (mPowerRequest.lowPowerMode) {
+            if (brightness > mScreenBrightnessRangeMinimum) {
+                brightness = Math.max(brightness / 2, mScreenBrightnessRangeMinimum);
+            }
+            if (!mAppliedLowPower) {
+                slowChange = false;
+            }
+            mAppliedLowPower = true;
+        }
+
+        // Animate the screen brightness when the screen is on.
+        if (state != Display.STATE_OFF) {
+            animateScreenBrightness(brightness, slowChange
+                    ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
         }
 
         // Animate the screen on or off unless blocked.
-        if (mScreenOffBecauseOfProximity) {
-            // Screen off due to proximity.
-            setScreenState(Display.STATE_OFF);
-            unblockScreenOn();
-        } else if (mPowerRequest.wantScreenOnAny()) {
+        if (state == Display.STATE_ON) {
             // Want screen on.
             // Wait for previous off animation to complete beforehand.
             // It is relatively short but if we cancel it and switch to the
@@ -555,21 +602,14 @@
                 // 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.
-
-                if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE) {
-                    if (!mScreenBrightnessRampAnimator.isAnimating()) {
-                        setScreenState(Display.STATE_DOZE);
-                    }
-                } else {
-                    setScreenState(Display.STATE_ON);
-                }
-
+                setScreenState(Display.STATE_ON);
                 if (mPowerRequest.blockScreenOn
                         && mPowerState.getElectronBeamLevel() == 0.0f) {
                     blockScreenOn();
                 } else {
                     unblockScreenOn();
-                    if (USE_ELECTRON_BEAM_ON_ANIMATION) {
+                    if (USE_ELECTRON_BEAM_ON_ANIMATION && mPowerRequest.isBrightOrDim()) {
+                        // Perform screen on animation.
                         if (!mElectronBeamOnAnimator.isStarted()) {
                             if (mPowerState.getElectronBeamLevel() == 1.0f) {
                                 mPowerState.dismissElectronBeam();
@@ -583,28 +623,59 @@
                             }
                         }
                     } else {
+                        // Skip screen on animation.
                         mPowerState.setElectronBeamLevel(1.0f);
                         mPowerState.dismissElectronBeam();
                     }
                 }
             }
+        } else if (state == Display.STATE_DOZE) {
+            // Want screen dozing.
+            // Wait for brightness animation to complete beforehand when entering doze
+            // from screen on.
+            unblockScreenOn();
+            if (!mScreenBrightnessRampAnimator.isAnimating()
+                    || mPowerState.getScreenState() != Display.STATE_ON) {
+                // Set screen state and dismiss the black surface without fanfare.
+                setScreenState(state);
+                mPowerState.setElectronBeamLevel(1.0f);
+                mPowerState.dismissElectronBeam();
+            }
+        } else if (state == Display.STATE_DOZE_SUSPEND) {
+            // Want screen dozing and suspended.
+            // Wait for brightness animation to complete beforehand unless already
+            // suspended because we may not be able to change it after suspension.
+            unblockScreenOn();
+            if (!mScreenBrightnessRampAnimator.isAnimating()
+                    || mPowerState.getScreenState() == Display.STATE_DOZE_SUSPEND) {
+                // Set screen state and dismiss the black surface without fanfare.
+                setScreenState(state);
+                mPowerState.setElectronBeamLevel(1.0f);
+                mPowerState.dismissElectronBeam();
+            }
         } else {
             // Want screen off.
             // Wait for previous on animation to complete beforehand.
             unblockScreenOn();
             if (!mElectronBeamOnAnimator.isStarted()) {
-                if (!mElectronBeamOffAnimator.isStarted()) {
-                    if (mPowerState.getElectronBeamLevel() == 0.0f) {
-                        setScreenState(Display.STATE_OFF);
-                    } else if (mPowerState.prepareElectronBeam(
-                            mElectronBeamFadesConfig ?
-                                    ElectronBeam.MODE_FADE :
-                                            ElectronBeam.MODE_COOL_DOWN)
-                            && mPowerState.getScreenState() != Display.STATE_OFF) {
-                        mElectronBeamOffAnimator.start();
-                    } else {
-                        mElectronBeamOffAnimator.end();
+                if (mPowerRequest.policy == DisplayPowerRequest.POLICY_OFF) {
+                    // Perform screen off animation.
+                    if (!mElectronBeamOffAnimator.isStarted()) {
+                        if (mPowerState.getElectronBeamLevel() == 0.0f) {
+                            setScreenState(Display.STATE_OFF);
+                        } else if (mPowerState.prepareElectronBeam(
+                                mElectronBeamFadesConfig ?
+                                        ElectronBeam.MODE_FADE :
+                                                ElectronBeam.MODE_COOL_DOWN)
+                                && mPowerState.getScreenState() != Display.STATE_OFF) {
+                            mElectronBeamOffAnimator.start();
+                        } else {
+                            mElectronBeamOffAnimator.end();
+                        }
                     }
+                } else {
+                    // Skip screen off animation.
+                    setScreenState(Display.STATE_OFF);
                 }
             }
         }
@@ -856,7 +927,9 @@
         pw.println("  mPendingProximityDebounceTime="
                 + TimeUtils.formatUptime(mPendingProximityDebounceTime));
         pw.println("  mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
-        pw.println("  mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness);
+        pw.println("  mAppliedAutoBrightness=" + mAppliedAutoBrightness);
+        pw.println("  mAppliedDimming=" + mAppliedDimming);
+        pw.println("  mAppliedLowPower=" + mAppliedLowPower);
 
         pw.println("  mScreenBrightnessRampAnimator.isAnimating()=" +
                 mScreenBrightnessRampAnimator.isAnimating());
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index a5f8849..4821e74 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -402,13 +402,14 @@
                         Slog.d(TAG, "Updating screen state: state="
                                 + Display.stateToString(state) + ", backlight=" + backlight);
                     }
-                    if (stateChanged && state != Display.STATE_OFF) {
+                    boolean suspending = Display.isSuspendedState(state);
+                    if (stateChanged && !suspending) {
                         mBlanker.requestDisplayState(state);
                     }
                     if (backlightChanged) {
                         mBacklight.setBrightness(backlight);
                     }
-                    if (stateChanged && state == Display.STATE_OFF) {
+                    if (stateChanged && suspending) {
                         mBlanker.requestDisplayState(state);
                     }
                 }
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 4ccf73b..107a6f6 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -38,6 +38,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.PowerManager;
+import android.os.PowerManagerInternal;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -48,6 +49,7 @@
 import android.service.dreams.IDreamManager;
 import android.text.TextUtils;
 import android.util.Slog;
+import android.view.Display;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -71,6 +73,7 @@
     private final DreamHandler mHandler;
     private final DreamController mController;
     private final PowerManager mPowerManager;
+    private final PowerManagerInternal mPowerManagerInternal;
     private final PowerManager.WakeLock mDozeWakeLock;
     private final McuHal mMcuHal; // synchronized on self
 
@@ -81,6 +84,8 @@
     private boolean mCurrentDreamCanDoze;
     private boolean mCurrentDreamIsDozing;
     private boolean mCurrentDreamIsWaking;
+    private int mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
+    private int mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
     private DozeHardwareWrapper mCurrentDreamDozeHardware;
 
     public DreamManagerService(Context context) {
@@ -90,6 +95,7 @@
         mController = new DreamController(context, mHandler, mControllerListener);
 
         mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        mPowerManagerInternal = getLocalService(PowerManagerInternal.class);
         mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG);
 
         mMcuHal = McuHal.open();
@@ -134,6 +140,9 @@
         pw.println("mCurrentDreamCanDoze=" + mCurrentDreamCanDoze);
         pw.println("mCurrentDreamIsDozing=" + mCurrentDreamIsDozing);
         pw.println("mCurrentDreamIsWaking=" + mCurrentDreamIsWaking);
+        pw.println("mCurrentDreamDozeScreenState="
+                + Display.stateToString(mCurrentDreamDozeScreenState));
+        pw.println("mCurrentDreamDozeScreenBrightness=" + mCurrentDreamDozeScreenBrightness);
         pw.println("mCurrentDreamDozeHardware=" + mCurrentDreamDozeHardware);
         pw.println("getDozeComponent()=" + getDozeComponent());
         pw.println();
@@ -213,16 +222,24 @@
         }
     }
 
-    private void startDozingInternal(IBinder token) {
+    private void startDozingInternal(IBinder token, int screenState,
+            int screenBrightness) {
         if (DEBUG) {
-            Slog.d(TAG, "Dream requested to start dozing: " + token);
+            Slog.d(TAG, "Dream requested to start dozing: " + token
+                    + ", screenState=" + screenState
+                    + ", screenBrightness=" + screenBrightness);
         }
 
         synchronized (mLock) {
-            if (mCurrentDreamToken == token && mCurrentDreamCanDoze
-                    && !mCurrentDreamIsDozing) {
-                mCurrentDreamIsDozing = true;
-                mDozeWakeLock.acquire();
+            if (mCurrentDreamToken == token && mCurrentDreamCanDoze) {
+                mCurrentDreamDozeScreenState = screenState;
+                mCurrentDreamDozeScreenBrightness = screenBrightness;
+                mPowerManagerInternal.setDozeOverrideFromDreamManager(
+                        screenState, screenBrightness);
+                if (!mCurrentDreamIsDozing) {
+                    mCurrentDreamIsDozing = true;
+                    mDozeWakeLock.acquire();
+                }
             }
         }
     }
@@ -236,6 +253,8 @@
             if (mCurrentDreamToken == token && mCurrentDreamIsDozing) {
                 mCurrentDreamIsDozing = false;
                 mDozeWakeLock.release();
+                mPowerManagerInternal.setDozeOverrideFromDreamManager(
+                        Display.STATE_UNKNOWN, PowerManager.BRIGHTNESS_DEFAULT);
             }
         }
     }
@@ -399,6 +418,8 @@
             mCurrentDreamIsDozing = false;
             mDozeWakeLock.release();
         }
+        mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
+        mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
         if (mCurrentDreamDozeHardware != null) {
             mCurrentDreamDozeHardware.release();
             mCurrentDreamDozeHardware = null;
@@ -593,7 +614,7 @@
         }
 
         @Override // Binder call
-        public void startDozing(IBinder token) {
+        public void startDozing(IBinder token, int screenState, int screenBrightness) {
             // Requires no permission, called by Dream from an arbitrary process.
             if (token == null) {
                 throw new IllegalArgumentException("token must not be null");
@@ -601,7 +622,7 @@
 
             final long ident = Binder.clearCallingIdentity();
             try {
-                startDozingInternal(token);
+                startDozingInternal(token, screenState, screenBrightness);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 4b1e8eb..8c52fad 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -404,6 +404,12 @@
     // Use NaN to disable.
     private float mTemporaryScreenAutoBrightnessAdjustmentSettingOverride = Float.NaN;
 
+    // The screen state to use while dozing.
+    private int mDozeScreenStateOverrideFromDreamManager = Display.STATE_UNKNOWN;
+
+    // The screen brightness to use while dozing.
+    private int mDozeScreenBrightnessOverrideFromDreamManager = PowerManager.BRIGHTNESS_DEFAULT;
+
     // Time when we last logged a warning about calling userActivity() without permission.
     private long mLastWarningAboutUserActivityPermission = Long.MIN_VALUE;
 
@@ -1370,11 +1376,12 @@
                 if (mUserActivitySummary == 0
                         && mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
                     nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
-                    if (now < nextTimeout
-                            && mDisplayPowerRequest.wantScreenOnNormal()) {
-                        mUserActivitySummary = mDisplayPowerRequest.screenState
-                                == DisplayPowerRequest.SCREEN_STATE_BRIGHT ?
-                                USER_ACTIVITY_SCREEN_BRIGHT : USER_ACTIVITY_SCREEN_DIM;
+                    if (now < nextTimeout) {
+                        if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_BRIGHT) {
+                            mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
+                        } else if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
+                            mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
+                        }
                     }
                 }
                 if (mUserActivitySummary != 0) {
@@ -1631,7 +1638,7 @@
         if (mWakefulness != WAKEFULNESS_DREAMING
                 || !mDreamsSupportedConfig
                 || !mDreamsEnabledSetting
-                || !mDisplayPowerRequest.wantScreenOnNormal()
+                || !mDisplayPowerRequest.isBrightOrDim()
                 || !mBootCompleted) {
             return false;
         }
@@ -1672,8 +1679,7 @@
         if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
                 | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
                 | DIRTY_SETTINGS | DIRTY_SCREEN_ON_BLOCKER_RELEASED)) != 0) {
-            final int newScreenState = getDesiredScreenPowerStateLocked();
-            mDisplayPowerRequest.screenState = newScreenState;
+            mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked();
 
             int screenBrightness = mScreenBrightnessSettingDefault;
             float screenAutoBrightnessAdjustment = 0.0f;
@@ -1713,13 +1719,22 @@
 
             mDisplayPowerRequest.lowPowerMode = mLowPowerModeEnabled;
 
+            if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
+                mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
+                mDisplayPowerRequest.dozeScreenBrightness =
+                        mDozeScreenBrightnessOverrideFromDreamManager;
+            } else {
+                mDisplayPowerRequest.dozeScreenState = Display.STATE_UNKNOWN;
+                mDisplayPowerRequest.dozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
+            }
+
             mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
                     mRequestWaitForNegativeProximity);
             mRequestWaitForNegativeProximity = false;
 
             if (DEBUG_SPEW) {
                 Slog.d(TAG, "updateScreenStateLocked: mDisplayReady=" + mDisplayReady
-                        + ", newScreenState=" + newScreenState
+                        + ", policy=" + mDisplayPowerRequest.policy
                         + ", mWakefulness=" + mWakefulness
                         + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
                         + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
@@ -1737,22 +1752,22 @@
         return value >= -1.0f && value <= 1.0f;
     }
 
-    private int getDesiredScreenPowerStateLocked() {
+    private int getDesiredScreenPolicyLocked() {
         if (mWakefulness == WAKEFULNESS_ASLEEP) {
-            return DisplayPowerRequest.SCREEN_STATE_OFF;
+            return DisplayPowerRequest.POLICY_OFF;
         }
 
         if ((mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
-            return DisplayPowerRequest.SCREEN_STATE_DOZE;
+            return DisplayPowerRequest.POLICY_DOZE;
         }
 
         if ((mWakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0
                 || (mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0
                 || !mBootCompleted) {
-            return DisplayPowerRequest.SCREEN_STATE_BRIGHT;
+            return DisplayPowerRequest.POLICY_BRIGHT;
         }
 
-        return DisplayPowerRequest.SCREEN_STATE_DIM;
+        return DisplayPowerRequest.POLICY_DIM;
     }
 
     private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks =
@@ -1895,7 +1910,7 @@
         if (!mDisplayReady) {
             return true;
         }
-        if (mDisplayPowerRequest.wantScreenOnNormal()) {
+        if (mDisplayPowerRequest.isBrightOrDim()) {
             // If we asked for the screen to be on but it is off due to the proximity
             // sensor then we may suspend but only if the configuration allows it.
             // On some hardware it may not be safe to suspend because the proximity
@@ -2103,6 +2118,19 @@
         }
     }
 
+    private void setDozeOverrideFromDreamManagerInternal(
+            int screenState, int screenBrightness) {
+        synchronized (mLock) {
+            if (mDozeScreenStateOverrideFromDreamManager != screenState
+                    || mDozeScreenBrightnessOverrideFromDreamManager != screenBrightness) {
+                mDozeScreenStateOverrideFromDreamManager = screenState;
+                mDozeScreenBrightnessOverrideFromDreamManager = screenBrightness;
+                mDirty |= DIRTY_SETTINGS;
+                updatePowerStateLocked();
+            }
+        }
+    }
+
     private void powerHintInternal(int hintId, int data) {
         nativeSendPowerHint(hintId, data);
     }
@@ -2257,6 +2285,10 @@
                     + mTemporaryScreenBrightnessSettingOverride);
             pw.println("  mTemporaryScreenAutoBrightnessAdjustmentSettingOverride="
                     + mTemporaryScreenAutoBrightnessAdjustmentSettingOverride);
+            pw.println("  mDozeScreenStateOverrideFromDreamManager="
+                    + mDozeScreenStateOverrideFromDreamManager);
+            pw.println("  mDozeScreenBrightnessOverrideFromDreamManager="
+                    + mDozeScreenBrightnessOverrideFromDreamManager);
             pw.println("  mScreenBrightnessSettingMinimum=" + mScreenBrightnessSettingMinimum);
             pw.println("  mScreenBrightnessSettingMaximum=" + mScreenBrightnessSettingMaximum);
             pw.println("  mScreenBrightnessSettingDefault=" + mScreenBrightnessSettingDefault);
@@ -3026,63 +3058,44 @@
     }
 
     private final class LocalService extends PowerManagerInternal {
-        /**
-         * Used by the window manager to override the screen brightness based on the
-         * current foreground activity.
-         *
-         * This method must only be called by the window manager.
-         *
-         * @param brightness The overridden brightness, or -1 to disable the override.
-         */
         @Override
-        public void setScreenBrightnessOverrideFromWindowManager(int brightness) {
-            mContext.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.DEVICE_POWER, null);
-
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                setScreenBrightnessOverrideFromWindowManagerInternal(brightness);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
+        public void setScreenBrightnessOverrideFromWindowManager(int screenBrightness) {
+            if (screenBrightness < PowerManager.BRIGHTNESS_DEFAULT
+                    || screenBrightness > PowerManager.BRIGHTNESS_ON) {
+                screenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
             }
+            setScreenBrightnessOverrideFromWindowManagerInternal(screenBrightness);
         }
 
-        /**
-         * Used by the window manager to override the button brightness based on the
-         * current foreground activity.
-         *
-         * This method must only be called by the window manager.
-         *
-         * @param brightness The overridden brightness, or -1 to disable the override.
-         */
         @Override
-        public void setButtonBrightnessOverrideFromWindowManager(int brightness) {
+        public void setButtonBrightnessOverrideFromWindowManager(int screenBrightness) {
             // Do nothing.
             // Button lights are not currently supported in the new implementation.
-            mContext.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.DEVICE_POWER, null);
         }
 
-        /**
-         * Used by the window manager to override the user activity timeout based on the
-         * current foreground activity.  It can only be used to make the timeout shorter
-         * than usual, not longer.
-         *
-         * This method must only be called by the window manager.
-         *
-         * @param timeoutMillis The overridden timeout, or -1 to disable the override.
-         */
+        @Override
+        public void setDozeOverrideFromDreamManager(int screenState, int screenBrightness) {
+            switch (screenState) {
+                case Display.STATE_UNKNOWN:
+                case Display.STATE_OFF:
+                case Display.STATE_DOZE:
+                case Display.STATE_DOZE_SUSPEND:
+                case Display.STATE_ON:
+                    break;
+                default:
+                    screenState = Display.STATE_UNKNOWN;
+                    break;
+            }
+            if (screenBrightness < PowerManager.BRIGHTNESS_DEFAULT
+                    || screenBrightness > PowerManager.BRIGHTNESS_ON) {
+                screenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
+            }
+            setDozeOverrideFromDreamManagerInternal(screenState, screenBrightness);
+        }
+
         @Override
         public void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis) {
-            mContext.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.DEVICE_POWER, null);
-
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                setUserActivityTimeoutOverrideFromWindowManagerInternal(timeoutMillis);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
+            setUserActivityTimeoutOverrideFromWindowManagerInternal(timeoutMillis);
         }
 
         @Override
diff --git a/tests/DozeTest/AndroidManifest.xml b/tests/DozeTest/AndroidManifest.xml
index c199f69..03778d6 100644
--- a/tests/DozeTest/AndroidManifest.xml
+++ b/tests/DozeTest/AndroidManifest.xml
@@ -22,7 +22,8 @@
             android:name="DozeTestDream"
             android:exported="true"
             android:icon="@drawable/ic_app"
-            android:label="@string/doze_dream_name">
+            android:label="@string/doze_dream_name"
+            android:permission="android.permission.BIND_DREAM_SERVICE">
             <!-- Commented out to prevent this dream from appearing in the list of
                  dreams that the user can select via the Settings application.
             <intent-filter>
diff --git a/tests/DozeTest/res/layout/dream.xml b/tests/DozeTest/res/layout/dream.xml
index 1c8fd3f..bced230 100644
--- a/tests/DozeTest/res/layout/dream.xml
+++ b/tests/DozeTest/res/layout/dream.xml
@@ -18,7 +18,8 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:gravity="center_vertical"
-        android:orientation="vertical">
+        android:orientation="vertical"
+        android:background="#bb2288">
     <TextView
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
diff --git a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
index a0b2d1a..f72e331 100644
--- a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
+++ b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
@@ -22,11 +22,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.os.Handler;
 import android.os.PowerManager;
 import android.service.dreams.DozeHardware;
 import android.service.dreams.DreamService;
 import android.text.format.DateFormat;
 import android.util.Log;
+import android.view.Display;
 import android.widget.TextView;
 
 import java.util.Date;
@@ -51,10 +53,16 @@
     // Doesn't mean anything.  Real hardware won't handle it.
     private static final String TEST_PING_MESSAGE = "test.ping";
 
+    // Not all hardware supports dozing.  We should use Display.STATE_DOZE but
+    // for testing purposes it is convenient to use Display.STATE_ON so the
+    // test still works on hardware that does not support dozing.
+    private static final int DISPLAY_STATE_WHEN_DOZING = Display.STATE_ON;
+
     private PowerManager mPowerManager;
     private PowerManager.WakeLock mWakeLock;
     private AlarmManager mAlarmManager;
     private PendingIntent mAlarmIntent;
+    private Handler mHandler = new Handler();
 
     private TextView mAlarmClock;
 
@@ -64,6 +72,8 @@
     private boolean mDreaming;
     private DozeHardware mDozeHardware;
 
+    private long mLastTime = Long.MIN_VALUE;
+
     @Override
     public void onCreate() {
         super.onCreate();
@@ -80,6 +90,8 @@
         registerReceiver(mAlarmReceiver, filter);
         mAlarmIntent = PendingIntent.getBroadcast(this, 0, intent,
                 PendingIntent.FLAG_CANCEL_CURRENT);
+
+        setDozeScreenState(DISPLAY_STATE_WHEN_DOZING);
     }
 
     @Override
@@ -143,13 +155,33 @@
         if (mDreaming) {
             long now = System.currentTimeMillis();
             now -= now % 60000; // back up to last minute boundary
+            if (mLastTime == now) {
+                return;
+            }
 
+            mLastTime = now;
             mTime.setTime(now);
             mAlarmClock.setText(mTimeFormat.format(mTime));
 
             mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, now + 60000, mAlarmIntent);
 
-            mWakeLock.acquire(UPDATE_TIME_TIMEOUT);
+            mWakeLock.acquire(UPDATE_TIME_TIMEOUT + 5000 /*for testing brightness*/);
+
+            // flash the screen a bit to test these functions
+            setDozeScreenState(DISPLAY_STATE_WHEN_DOZING);
+            setDozeScreenBrightness(200);
+            mHandler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    setDozeScreenBrightness(50);
+                }
+            }, 2000);
+            mHandler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    setDozeScreenState(Display.STATE_OFF);
+                }
+            }, 5000);
         }
     }