OSDN Git Service

Fix window manager policy state when waking from doze.
authorJeff Brown <jeffbrown@google.com>
Tue, 23 Sep 2014 03:14:39 +0000 (20:14 -0700)
committerJeff Brown <jeffbrown@google.com>
Tue, 23 Sep 2014 16:38:05 +0000 (09:38 -0700)
Once upon a time when the world was fresh and new, the heavens
had an easy rhythm.  Day and night.  Night and day.  In the day,
the pixel fairies would cavort and play in the bright gardens
with narry a mark of shadow or gloom.  In the night, they would
rest peacefully, dreaming no dreams and knowing no fear.

Then one night a fairy dreamed the first dream.  At first
the dream was peaceful, full of colors and delight, hopes and
memories.  Then all at once, jarringly, it awoke in bright
daylight.  The pixel fairy knew fear, for the world had changed
and it was unprepared.

Time passed and the pixel fairies grew accustomed to their
fate, day and night, night and day, sometimes dreaming, until
there came a night when a fairy did not sleep.  It roamed
the land in a dreamless doze, lost and afraid amid a grim haze
of grey and darkness.  The fairy despaired.  It wanted no
part of this place.  It pretended for a time to be awake but
the bright daylight would not come.  It pretended for a time to
be dreaming but the colors and memories would not come.
That is when the fairy wished for oblivion.  Then just as
suddenly, it awoke in the daylight.  It fell to the ground,
stunned as if it had forgotten how to walk in the too bright
daylight.

Though the world again grew softer and kinder in time, the pixel
fairies were never the same.  For the night is dark and full
of terrors.

---

It used to be easy.  Screen on and screen off could explain almost
everything about the state of the device but it's different now with
ambient display.  We need to be able to wait for all windows to be
drawn even in the case where the device is still nominally asleep.
In truth, the window manager policy which drives a lot of these
interactions is a thicket of outdated assumptions.

Added a new method to tell the window manager policy when the screen
is being turned off so that it can correctly account for changes
to the interactive state (wakeUp and goingToSleep) and screen state
(screenTurningOn and screenTurnedOff).  Now we can independently
poke keyguard during interactive state changes and we can apply
screen on blocking during screen state changes.

Moved the code which manages screen on blocking (which is what
ensures the UI has fully drawn before revealing screen contents)
from the power manager to the display manager since the display
manager is in a better position to accurately track the state of
the screen, particularly when the screen is being turned off.

Fixed a bunch of synchronization issues.  Previously some work
had been moved to a handler without considering what might
happen if it became reordered relative to other work happening
elsewhere.  Documented the desired behavior in the code to
prevent this from happening again.

There's still a bunch of stuff in here that isn't quite right,
particularly the assumption that there's only one screen, but
it's good enough for now.  Hopefully there aren't too many bugs.

Bug: 17605802
Change-Id: Ic7319e09948c8a3cda014d7e169c964a3ad86f14

core/java/android/view/WindowManagerPolicy.java
policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
services/core/java/com/android/server/display/DisplayPowerController.java
services/core/java/com/android/server/power/Notifier.java
services/core/java/com/android/server/power/PowerManagerService.java
services/core/java/com/android/server/wm/WindowManagerService.java

index d458ee4..673f075 100644 (file)
@@ -955,14 +955,19 @@ public interface WindowManagerPolicy {
      */
     public void screenTurningOn(ScreenOnListener screenOnListener);
 
+    /**
+     * Called when the device has turned the screen off.
+     */
+    public void screenTurnedOff();
+
     public interface ScreenOnListener {
         void onScreenOn();
     }
 
     /**
-     * Return whether the system is awake.
+     * Return whether the default display is on and not blocked by a black surface.
      */
-    public boolean isAwake();
+    public boolean isScreenOn();
 
     /**
      * Tell the policy that the lid switch has changed state.
index aa49d37..006f5db 100644 (file)
@@ -199,7 +199,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
      */
     private WindowState mKeyguardScrim;
     private boolean mKeyguardHidden;
-    private boolean mKeyguardDrawn;
+    private boolean mKeyguardDrawnOnce;
 
     /* Table of Application Launch keys.  Maps from key codes to intent categories.
      *
@@ -284,10 +284,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
 
     boolean mBootMessageNeedsHiding;
     KeyguardServiceDelegate mKeyguardDelegate;
-    // The following are only accessed on the mHandler thread.
-    boolean mKeyguardDrawComplete;
-    boolean mWindowManagerDrawComplete;
-    ScreenOnListener mScreenOnListener;
     final Runnable mWindowManagerDrawCallback = new Runnable() {
         @Override
         public void run() {
@@ -351,8 +347,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
     boolean mLidControlsSleep;
     int mShortPressOnPowerBehavior = -1;
     int mLongPressOnPowerBehavior = -1;
-    boolean mAwakeEarly = false;
-    boolean mAwakeFully = false;
+    boolean mAwake;
+    boolean mScreenOnEarly;
+    boolean mScreenOnFully;
+    ScreenOnListener mScreenOnListener;
+    boolean mKeyguardDrawComplete;
+    boolean mWindowManagerDrawComplete;
     boolean mOrientationSensorEnabled = false;
     int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
     boolean mHasSoftInput = false;
@@ -543,12 +543,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
     private static final int MSG_KEYGUARD_DRAWN_COMPLETE = 5;
     private static final int MSG_KEYGUARD_DRAWN_TIMEOUT = 6;
     private static final int MSG_WINDOW_MANAGER_DRAWN_COMPLETE = 7;
-    private static final int MSG_WAKING_UP = 8;
     private static final int MSG_DISPATCH_SHOW_RECENTS = 9;
     private static final int MSG_DISPATCH_SHOW_GLOBAL_ACTIONS = 10;
     private static final int MSG_HIDE_BOOT_MESSAGE = 11;
     private static final int MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK = 12;
-    private static final int MSG_SCREEN_TURNING_ON = 13;
 
     private class PolicyHandler extends Handler {
         @Override
@@ -584,18 +582,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                     if (DEBUG_WAKEUP) Slog.w(TAG, "Setting mWindowManagerDrawComplete");
                     finishWindowsDrawn();
                     break;
-                case MSG_WAKING_UP:
-                    handleWakingUp();
-                    break;
                 case MSG_HIDE_BOOT_MESSAGE:
                     handleHideBootMessage();
                     break;
                 case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK:
                     launchVoiceAssistWithWakeLock(msg.arg1 != 0);
                     break;
-                case MSG_SCREEN_TURNING_ON:
-                    handleScreenTurningOn((ScreenOnListener)msg.obj);
-                    break;
             }
         }
     }
@@ -766,11 +758,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
         }
         //Could have been invoked due to screen turning on or off or
         //change of the currently visible window's orientation
-        if (localLOGV) Slog.v(TAG, "Screen status="+mAwakeEarly+
-                ", current orientation="+mCurrentAppOrientation+
-                ", SensorEnabled="+mOrientationSensorEnabled);
+        if (localLOGV) Slog.v(TAG, "mScreenOnEarly=" + mScreenOnEarly
+                + ", mAwake=" + mAwake + ", mCurrentAppOrientation=" + mCurrentAppOrientation
+                + ", mOrientationSensorEnabled=" + mOrientationSensorEnabled);
         boolean disable = true;
-        if (mAwakeEarly) {
+        if (mScreenOnEarly && mAwake) {
             if (needSensorRunningLp()) {
                 disable = false;
                 //enable listener if not already enabled
@@ -1332,7 +1324,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
     }
 
     private boolean shouldEnableWakeGestureLp() {
-        return mWakeGestureEnabledSetting && !mAwakeEarly
+        return mWakeGestureEnabledSetting && !mAwake
                 && (!mLidControlsSleep || mLidState != LID_CLOSED)
                 && mWakeGestureListener.isSupported();
     }
@@ -4728,45 +4720,51 @@ public class PhoneWindowManager implements WindowManagerPolicy {
         }
     }
 
+    // Called on the PowerManager's Notifier thread.
     @Override
     public void goingToSleep(int why) {
         EventLog.writeEvent(70000, 0);
         if (DEBUG_WAKEUP) Slog.i(TAG, "Going to sleep...");
+
+        // We must get this work done here because the power manager will drop
+        // the wake lock and let the system suspend once this function returns.
         synchronized (mLock) {
-            mAwakeEarly = false;
-            mAwakeFully = false;
-        }
-        if (mKeyguardDelegate != null) {
-            mKeyguardDelegate.onScreenTurnedOff(why);
-        }
-        synchronized (mLock) {
+            mAwake = false;
+            mKeyguardDrawComplete = false;
             updateWakeGestureListenerLp();
             updateOrientationListenerLp();
             updateLockScreenTimeout();
         }
+
+        if (mKeyguardDelegate != null) {
+            mKeyguardDelegate.onScreenTurnedOff(why);
+        }
     }
 
+    // Called on the PowerManager's Notifier thread.
     @Override
     public void wakingUp() {
         EventLog.writeEvent(70000, 1);
         if (DEBUG_WAKEUP) Slog.i(TAG, "Waking up...");
-        mHandler.obtainMessage(MSG_WAKING_UP).sendToTarget();
-    }
 
-    // Called on the mHandler thread.
-    private void handleWakingUp() {
+        // Since goToSleep performs these functions synchronously, we must
+        // do the same here.  We cannot post this work to a handler because
+        // that might cause it to become reordered with respect to what
+        // may happen in a future call to goToSleep.
         synchronized (mLock) {
-            mAwakeEarly = true;
+            mAwake = true;
+            mKeyguardDrawComplete = false;
+            if (mKeyguardDelegate != null) {
+                mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
+                mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT, 1000);
+            }
+
             updateWakeGestureListenerLp();
             updateOrientationListenerLp();
             updateLockScreenTimeout();
         }
 
-        mKeyguardDrawComplete = false;
-        mWindowManagerDrawComplete = false; // wait for later call to screenTurningOn
         if (mKeyguardDelegate != null) {
-            mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
-            mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT, 1000);
             mKeyguardDelegate.onScreenTurnedOn(mKeyguardDelegateCallback);
             // ... eventually calls finishKeyguardDrawn
         } else {
@@ -4775,94 +4773,130 @@ public class PhoneWindowManager implements WindowManagerPolicy {
         }
     }
 
-    // Called on the mHandler thread.
     private void finishKeyguardDrawn() {
-        if (!mKeyguardDrawComplete) {
+        synchronized (mLock) {
+            if (!mAwake || mKeyguardDrawComplete) {
+                return; // spurious
+            }
+
             mKeyguardDrawComplete = true;
-            mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
-            finishScreenTurningOn();
+            if (mKeyguardDelegate != null) {
+                mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
+            }
         }
+
+        finishScreenTurningOn();
     }
 
+    // Called on the DisplayManager's DisplayPowerController thread.
+    @Override
+    public void screenTurnedOff() {
+        if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turned off...");
+
+        synchronized (mLock) {
+            mScreenOnEarly = false;
+            mScreenOnFully = false;
+            mWindowManagerDrawComplete = false;
+            mScreenOnListener = null;
+            updateOrientationListenerLp();
+        }
+    }
+
+    // Called on the DisplayManager's DisplayPowerController thread.
     @Override
     public void screenTurningOn(final ScreenOnListener screenOnListener) {
-        EventLog.writeEvent(70000, 1);
         if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");
-        mHandler.obtainMessage(MSG_SCREEN_TURNING_ON, screenOnListener).sendToTarget();
-    }
 
-    // Called on the mHandler thread.
-    private void handleScreenTurningOn(ScreenOnListener screenOnListener) {
-        mScreenOnListener = screenOnListener;
+        synchronized (mLock) {
+            mScreenOnEarly = true;
+            mScreenOnFully = false;
+            mWindowManagerDrawComplete = false;
+            mScreenOnListener = screenOnListener;
+            updateOrientationListenerLp();
+        }
 
-        mWindowManagerDrawComplete = false;
         mWindowManagerInternal.waitForAllWindowsDrawn(mWindowManagerDrawCallback,
                 WAITING_FOR_DRAWN_TIMEOUT);
         // ... eventually calls finishWindowsDrawn
     }
 
-    // Called on the mHandler thread.
     private void finishWindowsDrawn() {
-        if (!mWindowManagerDrawComplete) {
+        synchronized (mLock) {
+            if (!mScreenOnEarly || mWindowManagerDrawComplete) {
+                return; // spurious
+            }
+
             mWindowManagerDrawComplete = true;
-            finishScreenTurningOn();
         }
+
+        finishScreenTurningOn();
     }
 
-    // Called on the mHandler thread.
     private void finishScreenTurningOn() {
-        if (DEBUG_WAKEUP) Slog.d(TAG,
-                "finishScreenTurningOn: mAwakeEarly=" + mAwakeEarly
-                        + " mKeyguardDrawComplete=" + mKeyguardDrawComplete
-                        + " mWindowManagerDrawComplete=" + mWindowManagerDrawComplete);
-        boolean awake;
+        final ScreenOnListener listener;
+        final boolean enableScreen;
         synchronized (mLock) {
-            if ((mAwakeEarly && !mKeyguardDrawComplete)
-                    || !mWindowManagerDrawComplete) {
-                return;
-            }
+            if (DEBUG_WAKEUP) Slog.d(TAG,
+                    "finishScreenTurningOn: mAwake=" + mAwake
+                            + ", mScreenOnEarly=" + mScreenOnEarly
+                            + ", mScreenOnFully=" + mScreenOnFully
+                            + ", mKeyguardDrawComplete=" + mKeyguardDrawComplete
+                            + ", mWindowManagerDrawComplete=" + mWindowManagerDrawComplete);
 
-            if (mAwakeEarly) {
-                mAwakeFully = true;
+            if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
+                    || (mAwake && !mKeyguardDrawComplete)) {
+                return; // spurious or not ready yet
             }
-            awake = mAwakeFully;
-        }
 
-        if (DEBUG_WAKEUP) Slog.i(TAG, "Finished screen turning on...");
-
-        if (mScreenOnListener != null) {
-            mScreenOnListener.onScreenOn();
+            if (DEBUG_WAKEUP) Slog.i(TAG, "Finished screen turning on...");
+            listener = mScreenOnListener;
             mScreenOnListener = null;
+            mScreenOnFully = true;
+
+            // Remember the first time we draw the keyguard so we know when we're done with
+            // the main part of booting and can enable the screen and hide boot messages.
+            if (!mKeyguardDrawnOnce && mAwake) {
+                mKeyguardDrawnOnce = true;
+                enableScreen = true;
+                if (mBootMessageNeedsHiding) {
+                    mBootMessageNeedsHiding = false;
+                    hideBootMessages();
+                }
+            } else {
+                enableScreen = false;
+            }
         }
 
-        if (awake) {
-            setKeyguardDrawnFirstTime();
+        if (listener != null) {
+            listener.onScreenOn();
+        }
 
-            if (mBootMessageNeedsHiding) {
-                handleHideBootMessage();
-                mBootMessageNeedsHiding = false;
+        if (enableScreen) {
+            try {
+                mWindowManager.enableScreenIfNeeded();
+            } catch (RemoteException unhandled) {
             }
         }
     }
 
     private void handleHideBootMessage() {
-        if (mBootMsgDialog == null) {
-            if (DEBUG_WAKEUP) Slog.d(TAG, "handleHideBootMessage: boot message not up");
-            return;
+        synchronized (mLock) {
+            if (!mKeyguardDrawnOnce) {
+                mBootMessageNeedsHiding = true;
+                return; // keyguard hasn't drawn the first time yet, not done booting
+            }
         }
-        if (!mKeyguardDrawComplete || !mWindowManagerDrawComplete) {
-            if (DEBUG_WAKEUP) Slog.d(TAG, "handleHideBootMessage: deferring until keyguard ready");
-            mBootMessageNeedsHiding = true;
-            return;
+
+        if (mBootMsgDialog != null) {
+            if (DEBUG_WAKEUP) Slog.d(TAG, "handleHideBootMessage: dismissing");
+            mBootMsgDialog.dismiss();
+            mBootMsgDialog = null;
         }
-        if (DEBUG_WAKEUP) Slog.d(TAG, "handleHideBootMessage: dismissing");
-        mBootMsgDialog.dismiss();
-        mBootMsgDialog = null;
     }
 
     @Override
-    public boolean isAwake() {
-        return mAwakeFully;
+    public boolean isScreenOn() {
+        return mScreenOnFully;
     }
 
     /** {@inheritDoc} */
@@ -4936,20 +4970,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
         }
     }
 
-    private void setKeyguardDrawnFirstTime() {
-        synchronized (mLock) {
-            mKeyguardDrawn = true;
-        }
-        try {
-            mWindowManager.enableScreenIfNeeded();
-        } catch (RemoteException unhandled) {
-        }
-    }
-
     @Override
     public boolean isKeyguardDrawnLw() {
         synchronized (mLock) {
-            return mKeyguardDrawn;
+            return mKeyguardDrawnOnce;
         }
     }
 
@@ -5380,7 +5404,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
 
     private void updateLockScreenTimeout() {
         synchronized (mScreenLockTimeout) {
-            boolean enable = (mAllowLockscreenWhenOn && mAwakeEarly &&
+            boolean enable = (mAllowLockscreenWhenOn && mAwake &&
                     mKeyguardDelegate != null && mKeyguardDelegate.isSecure());
             if (mLockScreenTimerActive != enable) {
                 if (enable) {
@@ -5918,9 +5942,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                 pw.print("mShortPressOnPowerBehavior="); pw.print(mShortPressOnPowerBehavior);
                 pw.print(" mLongPressOnPowerBehavior="); pw.println(mLongPressOnPowerBehavior);
         pw.print(prefix); pw.print("mHasSoftInput="); pw.println(mHasSoftInput);
-        pw.print(prefix); pw.print("mAwakeEarly="); pw.print(mAwakeEarly);
-                pw.print(" mAwakeFully="); pw.print(mAwakeFully);
-                pw.print(" mOrientationSensorEnabled="); pw.println(mOrientationSensorEnabled);
+        pw.print(prefix); pw.print("mAwake="); pw.println(mAwake);
+        pw.print(prefix); pw.print("mScreenOnEarly="); pw.print(mScreenOnEarly);
+                pw.print(" mScreenOnFully="); pw.println(mScreenOnFully);
+        pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete);
+                pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete);
+        pw.print(prefix); pw.print("mOrientationSensorEnabled=");
+                pw.println(mOrientationSensorEnabled);
         pw.print(prefix); pw.print("mOverscanScreen=("); pw.print(mOverscanScreenLeft);
                 pw.print(","); pw.print(mOverscanScreenTop);
                 pw.print(") "); pw.print(mOverscanScreenWidth);
index 67d9776..e2a548a 100644 (file)
@@ -43,6 +43,7 @@ import android.util.Slog;
 import android.util.Spline;
 import android.util.TimeUtils;
 import android.view.Display;
+import android.view.WindowManagerPolicy;
 
 import java.io.PrintWriter;
 
@@ -65,7 +66,7 @@ import java.io.PrintWriter;
  * does not need to worry about holding a suspend blocker unless it happens
  * independently of the display ready signal.
    *
- * For debugging, you can make the electron beam and brightness animations run
+ * For debugging, you can make the color fade and brightness animations run
  * slower by changing the "animator duration scale" option in Development Settings.
  */
 final class DisplayPowerController implements AutomaticBrightnessController.Callbacks {
@@ -76,13 +77,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
 
     private static final String SCREEN_ON_BLOCKED_TRACE_NAME = "Screen on blocked";
 
-    // If true, uses the electron beam on animation.
+    // If true, uses the color fade on animation.
     // We might want to turn this off if we cannot get a guarantee that the screen
     // actually turns on and starts showing new content after the call to set the
     // screen state returns.  Playing the animation can also be somewhat slow.
     private static final boolean USE_COLOR_FADE_ON_ANIMATION = false;
 
-
     // The minimum reduction in brightness when dimmed.
     private static final int SCREEN_DIM_MINIMUM_REDUCTION = 10;
 
@@ -91,6 +91,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
 
     private static final int MSG_UPDATE_POWER_STATE = 1;
     private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
+    private static final int MSG_SCREEN_ON_UNBLOCKED = 3;
 
     private static final int PROXIMITY_UNKNOWN = -1;
     private static final int PROXIMITY_NEGATIVE = 0;
@@ -127,6 +128,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
     // The sensor manager.
     private final SensorManager mSensorManager;
 
+    // The window manager policy.
+    private final WindowManagerPolicy mWindowManagerPolicy;
+
     // The display blanker.
     private final DisplayBlanker mBlanker;
 
@@ -152,7 +156,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
     private boolean mUseSoftwareAutoBrightnessConfig;
 
     // True if we should fade the screen while turning it off, false if we should play
-    // a stylish electron beam animation instead.
+    // a stylish color fade animation instead.
     private boolean mColorFadeFadesConfig;
 
     // The pending power request.
@@ -214,8 +218,14 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
     // When the screen turns on again, we report user activity to the power manager.
     private boolean mScreenOffBecauseOfProximity;
 
-    // True if the screen on is being blocked.
-    private boolean mScreenOnWasBlocked;
+    // The currently active screen on unblocker.  This field is non-null whenever
+    // we are waiting for a callback to release it and unblock the screen.
+    private ScreenOnUnblocker mPendingScreenOnUnblocker;
+
+    // True if we were in the process of turning off the screen.
+    // This allows us to recover more gracefully from situations where we abort
+    // turning off the screen.
+    private boolean mPendingScreenOff;
 
     // The elapsed real time when the screen on was blocked.
     private long mScreenOnBlockStartRealTime;
@@ -246,6 +256,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
         mBatteryStats = BatteryStatsService.getService();
         mLights = LocalServices.getService(LightsManager.class);
         mSensorManager = sensorManager;
+        mWindowManagerPolicy = LocalServices.getService(WindowManagerPolicy.class);
         mBlanker = blanker;
         mContext = context;
 
@@ -633,7 +644,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
 
         // Report whether the display is ready for use and all changes have been applied.
         if (mustNotify
-                && !mScreenOnWasBlocked
+                && mPendingScreenOnUnblocker == null
                 && !mColorFadeOnAnimator.isStarted()
                 && !mColorFadeOffAnimator.isStarted()
                 && !mScreenBrightnessRampAnimator.isAnimating()
@@ -657,32 +668,53 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
     }
 
     private void blockScreenOn() {
-        if (!mScreenOnWasBlocked) {
+        if (mPendingScreenOnUnblocker == null) {
             Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
-            mScreenOnWasBlocked = true;
+            mPendingScreenOnUnblocker = new ScreenOnUnblocker();
             mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
             Slog.i(TAG, "Blocking screen on until initial contents have been drawn.");
         }
     }
 
     private void unblockScreenOn() {
-        if (mScreenOnWasBlocked) {
-            mScreenOnWasBlocked = false;
+        if (mPendingScreenOnUnblocker != null) {
+            mPendingScreenOnUnblocker = null;
             long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;
             Slog.i(TAG, "Unblocked screen on after " + delay + " ms");
             Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
         }
     }
 
-    private void setScreenState(int state) {
+    private boolean setScreenState(int state) {
         if (mPowerState.getScreenState() != state) {
+            final boolean wasOn = (mPowerState.getScreenState() != Display.STATE_OFF);
             mPowerState.setScreenState(state);
+
+            // Tell battery stats about the transition.
             try {
                 mBatteryStats.noteScreenState(state);
             } catch (RemoteException ex) {
                 // same process
             }
+
+            // Tell the window manager what's happening.
+            // Temporarily block turning the screen on until the window manager is ready
+            // by leaving a black surface covering the screen.  This surface is essentially
+            // the final state of the color fade animation.
+            boolean isOn = (state != Display.STATE_OFF);
+            if (wasOn && !isOn) {
+                unblockScreenOn();
+                mWindowManagerPolicy.screenTurnedOff();
+            } else if (!wasOn && isOn) {
+                if (mPowerState.getColorFadeLevel() == 0.0f) {
+                    blockScreenOn();
+                } else {
+                    unblockScreenOn();
+                }
+                mWindowManagerPolicy.screenTurningOn(mPendingScreenOnUnblocker);
+            }
         }
+        return mPendingScreenOnUnblocker == null;
     }
 
     private int clampScreenBrightness(int value) {
@@ -707,21 +739,21 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
             return;
         }
 
-        // Temporarily block turning the screen on if requested and there is already a
-        // black surface covering the screen.
-        if (mPowerRequest.blockScreenOn
-                && mPowerState.getColorFadeLevel() == 0.0f
-                && target != Display.STATE_OFF) {
-            blockScreenOn();
-            return;
+        // If we were in the process of turning off the screen but didn't quite
+        // finish.  Then finish up now to prevent a jarring transition back
+        // to screen on if we skipped blocking screen on as usual.
+        if (mPendingScreenOff && target != Display.STATE_OFF) {
+            setScreenState(Display.STATE_OFF);
+            mPendingScreenOff = false;
         }
 
         if (target == Display.STATE_ON) {
             // Want screen on.  The contents of the screen may not yet
-            // be visible if the electron beam has not been dismissed because
+            // be visible if the color fade has not been dismissed because
             // its last frame of animation is solid black.
-            unblockScreenOn();
-            setScreenState(Display.STATE_ON);
+            if (!setScreenState(Display.STATE_ON)) {
+                return; // screen on blocked
+            }
             if (USE_COLOR_FADE_ON_ANIMATION && mPowerRequest.isBrightOrDim()) {
                 // Perform screen on animation.
                 if (mPowerState.getColorFadeLevel() == 1.0f) {
@@ -749,9 +781,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
                 return;
             }
 
-            // Set screen state and dismiss the black surface without fanfare.
-            unblockScreenOn();
-            setScreenState(Display.STATE_DOZE);
+            // Set screen state.
+            if (!setScreenState(Display.STATE_DOZE)) {
+                return; // screen on blocked
+            }
+
+            // Dismiss the black surface without fanfare.
             mPowerState.setColorFadeLevel(1.0f);
             mPowerState.dismissColorFade();
         } else if (target == Display.STATE_DOZE_SUSPEND) {
@@ -763,18 +798,26 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
                 return;
             }
 
-            // Set screen state and dismiss the black surface without fanfare.
-            unblockScreenOn();
-            setScreenState(Display.STATE_DOZE_SUSPEND);
+            // If not already suspending, temporarily set the state to doze until the
+            // screen on is unblocked, then suspend.
+            if (mPowerState.getScreenState() != Display.STATE_DOZE_SUSPEND) {
+                if (!setScreenState(Display.STATE_DOZE)) {
+                    return; // screen on blocked
+                }
+                setScreenState(Display.STATE_DOZE_SUSPEND); // already on so can't block
+            }
+
+            // Dismiss the black surface without fanfare.
             mPowerState.setColorFadeLevel(1.0f);
             mPowerState.dismissColorFade();
         } else {
             // Want screen off.
-            unblockScreenOn();
+            mPendingScreenOff = true;
             if (mPowerState.getColorFadeLevel() == 0.0f) {
                 // Turn the screen off.
                 // A black surface is already hiding the contents of the screen.
                 setScreenState(Display.STATE_OFF);
+                mPendingScreenOff = false;
             } else if (performScreenOffTransition
                     && mPowerState.prepareColorFade(mContext,
                             mColorFadeFadesConfig ?
@@ -968,6 +1011,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
         pw.println("  mAppliedAutoBrightness=" + mAppliedAutoBrightness);
         pw.println("  mAppliedDimming=" + mAppliedDimming);
         pw.println("  mAppliedLowPower=" + mAppliedLowPower);
+        pw.println("  mPendingScreenOnUnblocker=" + mPendingScreenOnUnblocker);
+        pw.println("  mPendingScreenOff=" + mPendingScreenOff);
 
         pw.println("  mScreenBrightnessRampAnimator.isAnimating()=" +
                 mScreenBrightnessRampAnimator.isAnimating());
@@ -1052,6 +1097,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
                 case MSG_PROXIMITY_SENSOR_DEBOUNCED:
                     debounceProximitySensor();
                     break;
+
+                case MSG_SCREEN_ON_UNBLOCKED:
+                    if (mPendingScreenOnUnblocker == msg.obj) {
+                        unblockScreenOn();
+                        updatePowerState();
+                    }
+                    break;
             }
         }
     }
@@ -1072,4 +1124,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
             // Not used.
         }
     };
+
+    private final class ScreenOnUnblocker implements WindowManagerPolicy.ScreenOnListener {
+        @Override
+        public void onScreenOn() {
+            Message msg = mHandler.obtainMessage(MSG_SCREEN_ON_UNBLOCKED, this);
+            msg.setAsynchronous(true);
+            mHandler.sendMessage(msg);
+        }
+    }
 }
index c720668..94a628d 100644 (file)
@@ -84,7 +84,6 @@ final class Notifier {
     private final IBatteryStats mBatteryStats;
     private final IAppOpsService mAppOps;
     private final SuspendBlocker mSuspendBlocker;
-    private final ScreenOnBlocker mScreenOnBlocker;
     private final WindowManagerPolicy mPolicy;
     private final ActivityManagerInternal mActivityManagerInternal;
     private final InputManagerInternal mInputManagerInternal;
@@ -110,18 +109,13 @@ final class Notifier {
     // True if a user activity message should be sent.
     private boolean mUserActivityPending;
 
-    // The currently active screen on listener. This field is non-null whenever the
-    // ScreenOnBlocker has been acquired and we are awaiting a callback to release it.
-    private ScreenOnUnblocker mPendingScreenOnUnblocker;
-
     public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
-            IAppOpsService appOps, SuspendBlocker suspendBlocker, ScreenOnBlocker screenOnBlocker,
+            IAppOpsService appOps, SuspendBlocker suspendBlocker,
             WindowManagerPolicy policy) {
         mContext = context;
         mBatteryStats = batteryStats;
         mAppOps = appOps;
         mSuspendBlocker = suspendBlocker;
-        mScreenOnBlocker = screenOnBlocker;
         mPolicy = policy;
         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
         mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
@@ -333,21 +327,6 @@ final class Notifier {
     }
 
     /**
-     * Notifies that screen is about to be turned on (any state other than off).
-     */
-    public void onScreenTurningOn() {
-        synchronized (mLock) {
-            final ScreenOnUnblocker unblocker = blockScreenOnLocked();
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mPolicy.screenTurningOn(unblocker);
-                }
-            });
-        }
-    }
-
-    /**
      * Called when there has been user activity.
      */
     public void onUserActivity(int event, int uid) {
@@ -470,26 +449,6 @@ final class Notifier {
         }
     }
 
-    private ScreenOnUnblocker blockScreenOnLocked() {
-        if (mPendingScreenOnUnblocker == null) {
-            mScreenOnBlocker.acquire();
-        }
-        mPendingScreenOnUnblocker = new ScreenOnUnblocker();
-        return mPendingScreenOnUnblocker;
-    }
-
-    private final class ScreenOnUnblocker implements WindowManagerPolicy.ScreenOnListener {
-        @Override
-        public void onScreenOn() {
-            synchronized (mLock) {
-                if (mPendingScreenOnUnblocker == this) {
-                    mPendingScreenOnUnblocker = null;
-                    mScreenOnBlocker.release();
-                }
-            }
-        }
-    }
-
     private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
index 71e059a..4f41bee 100644 (file)
@@ -88,8 +88,6 @@ public final class PowerManagerService extends SystemService
     private static final int MSG_USER_ACTIVITY_TIMEOUT = 1;
     // Message: Sent when the device enters or exits a dreaming or dozing state.
     private static final int MSG_SANDMAN = 2;
-    // Message: Sent when the screen on blocker is released.
-    private static final int MSG_SCREEN_ON_BLOCKER_RELEASED = 3;
 
     // Dirty bit: mWakeLocks changed
     private static final int DIRTY_WAKE_LOCKS = 1 << 0;
@@ -111,10 +109,8 @@ public final class PowerManagerService extends SystemService
     private static final int DIRTY_BATTERY_STATE = 1 << 8;
     // Dirty bit: proximity state changed
     private static final int DIRTY_PROXIMITY_POSITIVE = 1 << 9;
-    // Dirty bit: screen on blocker state became held or unheld
-    private static final int DIRTY_SCREEN_ON_BLOCKER_RELEASED = 1 << 10;
     // Dirty bit: dock state changed
-    private static final int DIRTY_DOCK_STATE = 1 << 11;
+    private static final int DIRTY_DOCK_STATE = 1 << 10;
 
     // Wakefulness: The device is asleep and can only be awoken by a call to wakeUp().
     // The screen should be off or in the process of being turned off by the display controller.
@@ -244,10 +240,6 @@ public final class PowerManagerService extends SystemService
     // True if the display suspend blocker has been acquired.
     private boolean mHoldingDisplaySuspendBlocker;
 
-    // The screen on blocker used to keep the screen from turning on while the lock
-    // screen is coming up.
-    private final ScreenOnBlockerImpl mScreenOnBlocker;
-
     // True if systemReady() has been called.
     private boolean mSystemReady;
 
@@ -451,7 +443,6 @@ public final class PowerManagerService extends SystemService
             mHalAutoSuspendModeEnabled = false;
             mHalInteractiveModeEnabled = true;
 
-            mScreenOnBlocker = new ScreenOnBlockerImpl();
             mWakefulness = WAKEFULNESS_AWAKE;
             mInteractive = true;
 
@@ -505,7 +496,7 @@ public final class PowerManagerService extends SystemService
             mBatteryStats = BatteryStatsService.getService();
             mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,
                     mAppOps, createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
-                    mScreenOnBlocker, mPolicy);
+                    mPolicy);
 
             mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
                     createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"),
@@ -1745,13 +1736,6 @@ public final class PowerManagerService extends SystemService
         return true;
     }
 
-    private void handleScreenOnBlockerReleased() {
-        synchronized (mLock) {
-            mDirty |= DIRTY_SCREEN_ON_BLOCKER_RELEASED;
-            updatePowerStateLocked();
-        }
-    }
-
     /**
      * Updates the display power state asynchronously.
      * When the update is finished, mDisplayReady will be set to true.  The display
@@ -1766,8 +1750,7 @@ public final class PowerManagerService extends SystemService
         final boolean oldDisplayReady = mDisplayReady;
         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) {
-            boolean wasBlockerNeeded = isScreenOnBlockerNeededLocked(mDisplayPowerRequest);
+                | DIRTY_SETTINGS)) != 0) {
             mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked();
 
             int screenBrightness = mScreenBrightnessSettingDefault;
@@ -1815,12 +1798,6 @@ public final class PowerManagerService extends SystemService
                 mDisplayPowerRequest.dozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
             }
 
-            if (!wasBlockerNeeded && isScreenOnBlockerNeededLocked(mDisplayPowerRequest)
-                    && !mScreenOnBlocker.isHeld()) {
-                mNotifier.onScreenTurningOn();
-            }
-            mDisplayPowerRequest.blockScreenOn = mScreenOnBlocker.isHeld();
-
             mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
                     mRequestWaitForNegativeProximity);
             mRequestWaitForNegativeProximity = false;
@@ -1837,17 +1814,6 @@ public final class PowerManagerService extends SystemService
         return mDisplayReady && !oldDisplayReady;
     }
 
-    private static boolean isScreenOnBlockerNeededLocked(DisplayPowerRequest req) {
-        switch (req.policy) {
-            case DisplayPowerRequest.POLICY_OFF:
-                return false;
-            case DisplayPowerRequest.POLICY_DOZE:
-                return req.dozeScreenState != Display.STATE_OFF;
-            default:
-                return true;
-        }
-    }
-
     private static boolean isValidBrightness(int value) {
         return value >= 0 && value <= 255;
     }
@@ -2420,9 +2386,6 @@ public final class PowerManagerService extends SystemService
             }
 
             pw.println();
-            pw.println("Screen On Blocker: " + mScreenOnBlocker);
-
-            pw.println();
             pw.println("Display Power: " + mDisplayPowerCallbacks);
 
             wcd = mWirelessChargerDetector;
@@ -2530,9 +2493,6 @@ public final class PowerManagerService extends SystemService
                 case MSG_SANDMAN:
                     handleSandman();
                     break;
-                case MSG_SCREEN_ON_BLOCKER_RELEASED:
-                    handleScreenOnBlockerReleased();
-                    break;
             }
         }
     }
@@ -2709,56 +2669,6 @@ public final class PowerManagerService extends SystemService
         }
     }
 
-    private final class ScreenOnBlockerImpl implements ScreenOnBlocker {
-        private static final String TRACE_NAME = "ScreenOnBlocker";
-
-        private int mNestCount;
-
-        public boolean isHeld() {
-            synchronized (this) {
-                return mNestCount != 0;
-            }
-        }
-
-        @Override
-        public void acquire() {
-            synchronized (this) {
-                mNestCount += 1;
-                if (DEBUG || true) {
-                    Slog.d(TAG, "Screen on blocked: mNestCount=" + mNestCount);
-                }
-                if (mNestCount == 1) {
-                    Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_NAME, 0);
-                }
-            }
-        }
-
-        @Override
-        public void release() {
-            synchronized (this) {
-                mNestCount -= 1;
-                if (mNestCount == 0) {
-                    if (DEBUG || true) {
-                        Slog.d(TAG, "Screen on unblocked: mNestCount=" + mNestCount);
-                    }
-                    mHandler.sendEmptyMessage(MSG_SCREEN_ON_BLOCKER_RELEASED);
-                    Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_NAME, 0);
-                } else if (mNestCount < 0) {
-                    Slog.wtf(TAG, "Screen on blocker was released without being acquired!",
-                            new Throwable());
-                    mNestCount = 0;
-                }
-            }
-        }
-
-        @Override
-        public String toString() {
-            synchronized (this) {
-                return "held=" + (mNestCount != 0) + ", mNestCount=" + mNestCount;
-            }
-        }
-    }
-
     private final class BinderService extends IPowerManager.Stub {
         @Override // Binder call
         public void acquireWakeLockWithUid(IBinder lock, int flags, String tag,
index a4edc86..8445b04 100644 (file)
@@ -3474,7 +3474,7 @@ public class WindowManagerService extends IWindowManager.Stub
     }
 
     boolean okToDisplay() {
-        return !mDisplayFrozen && mDisplayEnabled && mPolicy.isAwake();
+        return !mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn();
     }
 
     AppWindowToken findAppWindowToken(IBinder token) {
@@ -10397,7 +10397,7 @@ public class WindowManagerService extends IWindowManager.Stub
             return;
         }
 
-        if (!mDisplayReady || !mPolicy.isAwake()) {
+        if (!mDisplayReady || !mPolicy.isScreenOn()) {
             // No need to freeze the screen before the system is ready or if
             // the screen is off.
             return;