Merge "Improvements to power manager turning on screen."
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 0934cd0..785db98 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -79,6 +79,8 @@
     private static final String TAG = "PowerManagerService";
     static final String PARTIAL_NAME = "PowerManagerService";
 
+    static final boolean DEBUG_SCREEN_ON = false;
+
     private static final boolean LOG_PARTIAL_WL = false;
 
     // Indicates whether touch-down cycles should be logged as part of the
@@ -162,6 +164,8 @@
     private final int[] mBroadcastQueue = new int[] { -1, -1, -1 };
     private final int[] mBroadcastWhy = new int[3];
     private boolean mPreparingForScreenOn = false;
+    private boolean mSkippedScreenOn = false;
+    private boolean mInitialized = false;
     private int mPartialCount = 0;
     private int mPowerState;
     // mScreenOffReason can be WindowManagerPolicy.OFF_BECAUSE_OF_USER,
@@ -557,6 +561,9 @@
         nativeInit();
         synchronized (mLocks) {
             updateNativePowerStateLocked();
+            // We make sure to start out with the screen on due to user activity.
+            // (They did just boot their device, after all.)
+            forceUserActivityLocked();
         }
     }
 
@@ -1123,7 +1130,8 @@
                     + " " + ((mNextTimeout-now)/1000) + "s from now");
             pw.println("  mDimScreen=" + mDimScreen
                     + " mStayOnConditions=" + mStayOnConditions
-                    + " mPreparingForScreenOn=" + mPreparingForScreenOn);
+                    + " mPreparingForScreenOn=" + mPreparingForScreenOn
+                    + " mSkippedScreenOn=" + mSkippedScreenOn);
             pw.println("  mScreenOffReason=" + mScreenOffReason
                     + " mUserState=" + mUserState);
             pw.println("  mBroadcastQueue={" + mBroadcastQueue[0] + ',' + mBroadcastQueue[1]
@@ -1312,8 +1320,16 @@
         }
     }
 
-    private void sendNotificationLocked(boolean on, int why)
-    {
+    private void sendNotificationLocked(boolean on, int why) {
+        if (!mInitialized) {
+            // No notifications sent until first initialization is done.
+            // This is so that when we are moving from our initial state
+            // which looks like the screen was off to it being on, we do not
+            // go through the process of waiting for the higher-level user
+            // space to be ready before turning up the display brightness.
+            // (And also do not send needless broadcasts about the screen.)
+            return;
+        }
         if (!on) {
             mStillNeedSleepNotification = false;
         }
@@ -1360,7 +1376,9 @@
 
         // The broadcast queue has changed; make sure the screen is on if it
         // is now possible for it to be.
-        updateNativePowerStateLocked();
+        if (mSkippedScreenOn) {
+            updateLightsLocked(mPowerState, SCREEN_ON_BIT);
+        }
 
         // Now send the message.
         if (index >= 0) {
@@ -1380,7 +1398,7 @@
                     synchronized (mLocks) {
                         if (mPreparingForScreenOn) {
                             mPreparingForScreenOn = false;
-                            updateNativePowerStateLocked();
+                            updateLightsLocked(mPowerState, SCREEN_ON_BIT);
                             EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP,
                                     4, mBroadcastWakeLock.mCount);
                             mBroadcastWakeLock.release();
@@ -1453,7 +1471,7 @@
                         synchronized (mLocks) {
                             EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3,
                                     mBroadcastWakeLock.mCount);
-                            updateNativePowerStateLocked();
+                            updateLightsLocked(mPowerState, SCREEN_ON_BIT);
                             mBroadcastWakeLock.release();
                         }
                     }
@@ -1646,6 +1664,11 @@
         };
 
     private int setScreenStateLocked(boolean on) {
+        if (DEBUG_SCREEN_ON) {
+            RuntimeException e = new RuntimeException("here");
+            e.fillInStackTrace();
+            Slog.i(TAG, "Set screen state: " + on, e);
+        }
         int err = Power.setScreenState(on);
         if (err == 0) {
             mLastScreenOnTime = (on ? SystemClock.elapsedRealtime() : 0);
@@ -1696,7 +1719,7 @@
             } else {
                 newState &= ~BATTERY_LOW_BIT;
             }
-            if (newState == mPowerState) {
+            if (newState == mPowerState && mInitialized) {
                 return;
             }
 
@@ -1722,10 +1745,7 @@
                          + " newBatteryLow=" + ((newState & BATTERY_LOW_BIT) != 0));
             }
 
-            if (mPowerState != newState) {
-                updateLightsLocked(newState, 0);
-                mPowerState = (mPowerState & ~LIGHTS_MASK) | (newState & LIGHTS_MASK);
-            }
+            final boolean stateChanged = mPowerState != newState;
 
             if (oldScreenOn != newScreenOn) {
                 if (newScreenOn) {
@@ -1777,10 +1797,24 @@
                     EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, reason,
                             mTotalTouchDownTime, mTouchCycles);
                     if (err == 0) {
-                        mPowerState |= SCREEN_ON_BIT;
                         sendNotificationLocked(true, -1);
+                        // Update the lights *after* taking care of turning the
+                        // screen on, so we do this after our notifications are
+                        // enqueued and thus will delay turning on the screen light
+                        // until the windows are correctly displayed.
+                        if (stateChanged) {
+                            updateLightsLocked(newState, 0);
+                        }
+                        mPowerState |= SCREEN_ON_BIT;
                     }
+
                 } else {
+                    // Update the lights *before* taking care of turning the
+                    // screen off, so we can initiate any animations that are desired.
+                    if (stateChanged) {
+                        updateLightsLocked(newState, 0);
+                    }
+
                     // cancel light sensor task
                     mHandler.removeCallbacks(mAutoBrightnessTask);
                     mLightSensorPendingDecrease = false;
@@ -1803,30 +1837,20 @@
                         mLastTouchDown = 0;
                     }
                 }
+            } else if (stateChanged) {
+                // Screen on/off didn't change, but lights may have.
+                updateLightsLocked(newState, 0);
             }
-            
+
+            mPowerState = (mPowerState & ~LIGHTS_MASK) | (newState & LIGHTS_MASK);
+
             updateNativePowerStateLocked();
+
+            mInitialized = true;
         }
     }
-    
+
     private void updateNativePowerStateLocked() {
-        if ((mPowerState & SCREEN_ON_BIT) != 0) {
-            // Don't turn screen on until we know we are really ready to.
-            // This is to avoid letting the screen go on before things like the
-            // lock screen have been displayed.
-            if (mPreparingForScreenOn) {
-                // Currently waiting for confirmation from the policy that it
-                // is okay to turn on the screen.  Don't allow the screen to go
-                // on until that is done.
-                return;
-            }
-            for (int i=0; i<mBroadcastQueue.length; i++) {
-                if (mBroadcastQueue[i] == 1) {
-                    // A screen on is currently enqueued.
-                    return;
-                }
-            }
-        }
         nativeSetPowerState(
                 (mPowerState & SCREEN_ON_BIT) != 0,
                 (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT);
@@ -1852,8 +1876,43 @@
                 mBatteryService.getBatteryLevel() <= Power.LOW_BATTERY_THRESHOLD);
     }
 
+    private boolean shouldDeferScreenOnLocked() {
+        if (mPreparingForScreenOn) {
+            // Currently waiting for confirmation from the policy that it
+            // is okay to turn on the screen.  Don't allow the screen to go
+            // on until that is done.
+            if (DEBUG_SCREEN_ON) Slog.i(TAG,
+                    "updateLights: delaying screen on due to mPreparingForScreenOn");
+            return true;
+        } else {
+            // If there is a screen-on command in the notification queue, we
+            // can't turn the screen on until it has been processed (and we
+            // have set mPreparingForScreenOn) or it has been dropped.
+            for (int i=0; i<mBroadcastQueue.length; i++) {
+                if (mBroadcastQueue[i] == 1) {
+                    if (DEBUG_SCREEN_ON) Slog.i(TAG,
+                            "updateLights: delaying screen on due to notification queue");
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     private void updateLightsLocked(int newState, int forceState) {
         final int oldState = mPowerState;
+
+        // If the screen is not currently on, we will want to delay actually
+        // turning the lights on if we are still getting the UI put up.
+        if ((oldState&SCREEN_ON_BIT) == 0 || mSkippedScreenOn) {
+            // Don't turn screen on until we know we are really ready to.
+            // This is to avoid letting the screen go on before things like the
+            // lock screen have been displayed.
+            if ((mSkippedScreenOn=shouldDeferScreenOnLocked())) {
+                newState &= ~(SCREEN_ON_BIT|SCREEN_BRIGHT_BIT);
+            }
+        }
+
         if ((newState & SCREEN_ON_BIT) != 0) {
             // Only turn on the buttons or keyboard if the screen is also on.
             // We should never see the buttons on but not the screen.
@@ -1960,6 +2019,13 @@
             }
             mScreenBrightness.setTargetLocked(brightness, steps,
                     INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue);
+            if (DEBUG_SCREEN_ON) {
+                RuntimeException e = new RuntimeException("here");
+                e.fillInStackTrace();
+                Slog.i(TAG, "Setting screen brightness: " + brightness, e);
+                mScreenBrightness.setTargetLocked(brightness, steps,
+                        INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue);
+            }
         }
 
         if (mSpew) {