Automated import from //branches/master/...@140851,140851
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 5c7ab93..890c58c 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -135,8 +135,8 @@
 
     private boolean mDoneBooting = false;
     private int mStayOnConditions = 0;
-    private int mNotificationQueue = -1;
-    private int mNotificationWhy;
+    private int[] mBroadcastQueue = new int[] { -1, -1, -1 };
+    private int[] mBroadcastWhy = new int[3];
     private int mPartialCount = 0;
     private int mPowerState;
     private boolean mOffBecauseOfUser;
@@ -170,6 +170,7 @@
             = new BrightnessState(KEYBOARD_BRIGHT_BIT);
     private final BrightnessState mButtonBrightness
             = new BrightnessState(BUTTON_BRIGHT_BIT);
+    private boolean mStillNeedSleepNotification;
     private boolean mIsPowered = false;
     private IActivityManager mActivityService;
     private IBatteryStats mBatteryStats;
@@ -390,7 +391,7 @@
         mHandler = new Handler();
 
         mBroadcastWakeLock = new UnsynchronizedWakeLock(
-                                PowerManager.PARTIAL_WAKE_LOCK, "sleep_notification", true);
+                                PowerManager.PARTIAL_WAKE_LOCK, "sleep_broadcast", true);
         mStayOnWhilePluggedInScreenDimLock = new UnsynchronizedWakeLock(
                                 PowerManager.SCREEN_DIM_WAKE_LOCK, "StayOnWhilePluggedIn Screen Dim", false);
         mStayOnWhilePluggedInPartialLock = new UnsynchronizedWakeLock(
@@ -798,8 +799,10 @@
                 + " mStayOnConditions=" + mStayOnConditions);
         pw.println("  mOffBecauseOfUser=" + mOffBecauseOfUser
                 + " mUserState=" + mUserState);
-        pw.println("  mNotificationQueue=" + mNotificationQueue
-                + " mNotificationWhy=" + mNotificationWhy);
+        pw.println("  mBroadcastQueue={" + mBroadcastQueue[0] + ',' + mBroadcastQueue[1]
+                + ',' + mBroadcastQueue[2] + "}");
+        pw.println("  mBroadcastWhy={" + mBroadcastWhy[0] + ',' + mBroadcastWhy[1]
+                + ',' + mBroadcastWhy[2] + "}");
         pw.println("  mPokey=" + mPokey + " mPokeAwakeonSet=" + mPokeAwakeOnSet);
         pw.println("  mKeyboardVisible=" + mKeyboardVisible
                 + " mUserActivityAllowed=" + mUserActivityAllowed);
@@ -924,29 +927,52 @@
 
     private void sendNotificationLocked(boolean on, int why)
     {
-                    
-        if (!on) {
-            mNotificationWhy = why;
+        // Add to the queue.
+        int index = 0;
+        while (mBroadcastQueue[index] != -1) {
+            index++;
         }
+        mBroadcastQueue[index] = on ? 1 : 0;
+        mBroadcastWhy[index] = why;
 
-        int value = on ? 1 : 0;
-        if (mNotificationQueue == -1) {
-            // empty
-            // Acquire the broadcast wake lock before changing the power
-            // state. It will be release after the broadcast is sent.
-            mBroadcastWakeLock.acquire();
-            EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_SEND, mBroadcastWakeLock.mCount);
-            mNotificationQueue = value;
-            mHandler.post(mNotificationTask);
-        } else if (mNotificationQueue != value) {
-            // it's a pair, so cancel it
-            mNotificationQueue = -1;
-            mHandler.removeCallbacks(mNotificationTask);
+        // If we added it position 2, then there is a pair that can be stripped.
+        // If we added it position 1 and we're turning the screen off, we can strip
+        // the pair and do nothing, because the screen is already off, and therefore
+        // keyguard has already been enabled.
+        // However, if we added it at position 1 and we're turning it on, then position
+        // 0 was to turn it off, and we can't strip that, because keyguard needs to come
+        // on, so have to run the queue then.
+        if (index == 2) {
+            // Also, while we're collapsing them, if it's going to be an "off," and one
+            // is off because of user, then use that, regardless of whether it's the first
+            // or second one.
+            if (!on && why == WindowManagerPolicy.OFF_BECAUSE_OF_USER) {
+                mBroadcastWhy[0] = WindowManagerPolicy.OFF_BECAUSE_OF_USER;
+            }
+            mBroadcastQueue[0] = on ? 1 : 0;
+            mBroadcastQueue[1] = -1;
+            mBroadcastQueue[2] = -1;
+            index = 0;
+        }
+        if (index == 1 && !on) {
+            mBroadcastQueue[0] = -1;
+            mBroadcastQueue[1] = -1;
+            index = -1;
+            // The wake lock was being held, but we're not actually going to do any
+            // broadcasts, so release the wake lock.
             EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 1, mBroadcastWakeLock.mCount);
             mBroadcastWakeLock.release();
-        } else {
-            // else, same so do nothing -- maybe we should warn?
-            Log.w(TAG, "Duplicate notification: on=" + on + " why=" + why);
+        }
+
+        // Now send the message.
+        if (index >= 0) {
+            // Acquire the broadcast wake lock before changing the power
+            // state. It will be release after the broadcast is sent.
+            // We always increment the ref count for each notification in the queue
+            // and always decrement when that notification is handled.
+            mBroadcastWakeLock.acquire();
+            EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_SEND, mBroadcastWakeLock.mCount);
+            mHandler.post(mNotificationTask);
         }
     }
 
@@ -954,64 +980,69 @@
     {
         public void run()
         {
-            int value;
-            int why;
-            WindowManagerPolicy policy;
-            synchronized (mLocks) {
-                policy = getPolicyLocked();
-                value = mNotificationQueue;
-                why = mNotificationWhy;
-                mNotificationQueue = -1;
-            }
-            if (value == 1) {
-                mScreenOnStart = SystemClock.uptimeMillis();
-                
-                policy.screenTurnedOn();
-                try {
-                    ActivityManagerNative.getDefault().wakingUp();
-                } catch (RemoteException e) {
-                    // ignore it
+            while (true) {
+                int value;
+                int why;
+                WindowManagerPolicy policy;
+                synchronized (mLocks) {
+                    value = mBroadcastQueue[0];
+                    why = mBroadcastWhy[0];
+                    for (int i=0; i<2; i++) {
+                        mBroadcastQueue[i] = mBroadcastQueue[i+1];
+                        mBroadcastWhy[i] = mBroadcastWhy[i+1];
+                    }
+                    policy = getPolicyLocked();
                 }
+                if (value == 1) {
+                    mScreenOnStart = SystemClock.uptimeMillis();
+                    
+                    policy.screenTurnedOn();
+                    try {
+                        ActivityManagerNative.getDefault().wakingUp();
+                    } catch (RemoteException e) {
+                        // ignore it
+                    }
 
-                if (mSpew) {
-                    Log.d(TAG, "mBroadcastWakeLock=" + mBroadcastWakeLock);
-                }
-                if (mContext != null && ActivityManagerNative.isSystemReady()) {
-                    mContext.sendOrderedBroadcast(mScreenOnIntent, null,
-                            mScreenOnBroadcastDone, mHandler, 0, null, null);
-                } else {
-                    synchronized (mLocks) {
-                        EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 2,
-                                mBroadcastWakeLock.mCount);
-                        mBroadcastWakeLock.release();
+                    if (mSpew) {
+                        Log.d(TAG, "mBroadcastWakeLock=" + mBroadcastWakeLock);
+                    }
+                    if (mContext != null && ActivityManagerNative.isSystemReady()) {
+                        mContext.sendOrderedBroadcast(mScreenOnIntent, null,
+                                mScreenOnBroadcastDone, mHandler, 0, null, null);
+                    } else {
+                        synchronized (mLocks) {
+                            EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 2,
+                                    mBroadcastWakeLock.mCount);
+                            mBroadcastWakeLock.release();
+                        }
                     }
                 }
-            }
-            else if (value == 0) {
-                mScreenOffStart = SystemClock.uptimeMillis();
-                
-                policy.screenTurnedOff(why);
-                try {
-                    ActivityManagerNative.getDefault().goingToSleep();
-                } catch (RemoteException e) {
-                    // ignore it.
-                }
+                else if (value == 0) {
+                    mScreenOffStart = SystemClock.uptimeMillis();
+                    
+                    policy.screenTurnedOff(why);
+                    try {
+                        ActivityManagerNative.getDefault().goingToSleep();
+                    } catch (RemoteException e) {
+                        // ignore it.
+                    }
 
-                if (mContext != null && ActivityManagerNative.isSystemReady()) {
-                    mContext.sendOrderedBroadcast(mScreenOffIntent, null,
-                            mScreenOffBroadcastDone, mHandler, 0, null, null);
-                } else {
-                    synchronized (mLocks) {
-                        EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 3,
-                                mBroadcastWakeLock.mCount);
-                        mBroadcastWakeLock.release();
+                    if (mContext != null && ActivityManagerNative.isSystemReady()) {
+                        mContext.sendOrderedBroadcast(mScreenOffIntent, null,
+                                mScreenOffBroadcastDone, mHandler, 0, null, null);
+                    } else {
+                        synchronized (mLocks) {
+                            EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 3,
+                                    mBroadcastWakeLock.mCount);
+                            mBroadcastWakeLock.release();
+                        }
                     }
                 }
-            }
-            else {
-                // If we're in this case, then this handler is running for a previous
-                // paired transaction.  mBroadcastWakeLock will already have been released
-                // in sendNotificationLocked.
+                else {
+                    // If we're in this case, then this handler is running for a previous
+                    // paired transaction.  mBroadcastWakeLock will already have been released.
+                    break;
+                }
             }
         }
     };
@@ -1235,6 +1266,14 @@
 
             if (oldScreenOn != newScreenOn) {
                 if (newScreenOn) {
+                    // When the user presses the power button, we need to always send out the
+                    // notification that it's going to sleep so the keyguard goes on.  But
+                    // we can't do that until the screen fades out, so we don't show the keyguard
+                    // too early.
+                    if (mStillNeedSleepNotification) {
+                        sendNotificationLocked(false, WindowManagerPolicy.OFF_BECAUSE_OF_USER);
+                    }
+
                     // Turn on the screen UNLESS there was a prior
                     // preventScreenOn(true) request.  (Note that the lifetime
                     // of a single preventScreenOn() request is limited to 5
@@ -1290,7 +1329,7 @@
                     }
                     mPowerState &= ~SCREEN_ON_BIT;
                     if (!mScreenBrightness.animating) {
-                        err = screenOffFinishedAnimating(becauseOfUser);
+                        err = screenOffFinishedAnimatingLocked(becauseOfUser);
                     } else {
                         mOffBecauseOfUser = becauseOfUser;
                         err = 0;
@@ -1301,7 +1340,7 @@
         }
     }
     
-    private int screenOffFinishedAnimating(boolean becauseOfUser) {
+    private int screenOffFinishedAnimatingLocked(boolean becauseOfUser) {
         // I don't think we need to check the current state here because all of these
         // Power.setScreenState and sendNotificationLocked can both handle being 
         // called multiple times in the same state. -joeo
@@ -1345,10 +1384,12 @@
             if (ANIMATE_KEYBOARD_LIGHTS) {
                 if ((newState & KEYBOARD_BRIGHT_BIT) == 0) {
                     mKeyboardBrightness.setTargetLocked(Power.BRIGHTNESS_OFF,
-                            ANIM_STEPS, INITIAL_KEYBOARD_BRIGHTNESS);
+                            ANIM_STEPS, INITIAL_KEYBOARD_BRIGHTNESS,
+                            preferredBrightness);
                 } else {
                     mKeyboardBrightness.setTargetLocked(preferredBrightness,
-                            ANIM_STEPS, INITIAL_KEYBOARD_BRIGHTNESS);
+                            ANIM_STEPS, INITIAL_KEYBOARD_BRIGHTNESS,
+                            Power.BRIGHTNESS_OFF);
                 }
                 startAnimation = true;
             } else {
@@ -1364,10 +1405,12 @@
             if (ANIMATE_BUTTON_LIGHTS) {
                 if ((newState & BUTTON_BRIGHT_BIT) == 0) {
                     mButtonBrightness.setTargetLocked(Power.BRIGHTNESS_OFF,
-                            ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS);
+                            ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
+                            preferredBrightness);
                 } else {
                     mButtonBrightness.setTargetLocked(preferredBrightness,
-                            ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS);
+                            ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
+                            Power.BRIGHTNESS_OFF);
                 }
                 startAnimation = true;
             } else {
@@ -1381,6 +1424,23 @@
 
         if ((difference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) {
             if (ANIMATE_SCREEN_LIGHTS) {
+                int nominalCurrentValue;
+                switch (oldState & (SCREEN_BRIGHT_BIT|SCREEN_ON_BIT)) {
+                    case SCREEN_BRIGHT_BIT | SCREEN_ON_BIT:
+                        nominalCurrentValue = preferredBrightness;
+                        break;
+                    case SCREEN_ON_BIT:
+                        nominalCurrentValue = Power.BRIGHTNESS_DIM;
+                        break;
+                    case 0:
+                        nominalCurrentValue = Power.BRIGHTNESS_OFF;
+                        break;
+                    case SCREEN_BRIGHT_BIT:
+                    default:
+                        // not possible
+                        nominalCurrentValue = (int)mScreenBrightness.curValue;
+                        break;
+                }
                 if ((newState & SCREEN_BRIGHT_BIT) == 0) {
                     // dim or turn off backlight, depending on if the screen is on
                     // the scale is because the brightness ramp isn't linear and this biases
@@ -1398,7 +1458,7 @@
                             steps = (int)(ANIM_STEPS*ratio*scale);
                         }
                         mScreenBrightness.setTargetLocked(Power.BRIGHTNESS_OFF,
-                                steps, INITIAL_SCREEN_BRIGHTNESS);
+                                steps, INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue);
                     } else {
                         int steps;
                         if ((oldState & SCREEN_ON_BIT) != 0) {
@@ -1417,11 +1477,11 @@
                             mScreenOffTime = SystemClock.elapsedRealtime();
                         }
                         mScreenBrightness.setTargetLocked(Power.BRIGHTNESS_DIM,
-                                steps, INITIAL_SCREEN_BRIGHTNESS);
+                                steps, INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue);
                     }
                 } else {
                     mScreenBrightness.setTargetLocked(preferredBrightness,
-                            ANIM_STEPS, INITIAL_SCREEN_BRIGHTNESS);
+                            ANIM_STEPS, INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue);
                 }
                 startAnimation = true;
             } else {
@@ -1502,16 +1562,20 @@
                     + " delta=" + delta);
         }
         
-        void setTargetLocked(int target, int stepsToTarget, int initialValue) {
+        void setTargetLocked(int target, int stepsToTarget, int initialValue,
+                int nominalCurrentValue) {
             if (!initialized) {
                 initialized = true;
                 curValue = (float)initialValue;
             }
             targetValue = target;
-            delta = (targetValue-curValue) / stepsToTarget;
+            delta = (targetValue-nominalCurrentValue) / stepsToTarget;
             if (mSpew) {
+                String noticeMe = nominalCurrentValue == curValue ? "" : "  ******************";
                 Log.i(TAG, "Setting target " + mask + ": cur=" + curValue
-                        + " target=" + targetValue + " delta=" + delta);
+                        + " target=" + targetValue + " delta=" + delta
+                        + " nominalCurrentValue=" + nominalCurrentValue
+                        + noticeMe);
             }
             animating = true;
         }
@@ -1543,7 +1607,7 @@
             animating = more;
             if (!more) {
                 if (mask == SCREEN_BRIGHT_BIT && curIntValue == Power.BRIGHTNESS_OFF) {
-                    screenOffFinishedAnimating(mOffBecauseOfUser);
+                    screenOffFinishedAnimatingLocked(mOffBecauseOfUser);
                 }
             }
             return more;
@@ -1695,6 +1759,7 @@
                 }
             }
             EventLog.writeEvent(LOG_POWER_SLEEP_REQUESTED, numCleared);
+            mStillNeedSleepNotification = true;
             mUserState = SCREEN_OFF;
             setPowerState(SCREEN_OFF, false, true);
             cancelTimerLocked();