Support keeping activities resumed while dozing.

If the lock screen is not shown, then let activities keep running
while dozing.  This is important to support ambient mode on watches
since it allows the home app to keep running.

To make this possible, we need to inform the activity manager about
the exact wakefulness state, not just the overall boolean
interactive state.

Bug: 18284212
Change-Id: Ia35c99127ce51ffc178f3a2f51fca67d24061c71
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 2a17fa6..d56dc1e 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -23,8 +23,8 @@
  */
 public abstract class ActivityManagerInternal {
     // Called by the power manager.
-    public abstract void goingToSleep();
-    public abstract void wakingUp();
+    public abstract void onWakefulnessChanged(int wakefulness);
+
     public abstract int startIsolatedProcess(String entryPoint, String[] mainArgs,
             String processName, String abiOverride, int uid, Runnable crashHandler);
 }
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 14f4a83..6b6f540 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -25,6 +25,58 @@
  */
 public abstract class PowerManagerInternal {
     /**
+     * Wakefulness: The device is asleep.  It 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.
+     * The device typically passes through the dozing state first.
+     */
+    public static final int WAKEFULNESS_ASLEEP = 0;
+
+    /**
+     * Wakefulness: The device is fully awake.  It can be put to sleep by a call to goToSleep().
+     * When the user activity timeout expires, the device may start dreaming or go to sleep.
+     */
+    public static final int WAKEFULNESS_AWAKE = 1;
+
+    /**
+     * Wakefulness: The device is dreaming.  It can be awoken by a call to wakeUp(),
+     * which ends the dream.  The device goes to sleep when goToSleep() is called, when
+     * the dream ends or when unplugged.
+     * User activity may brighten the screen but does not end the dream.
+     */
+    public static final int WAKEFULNESS_DREAMING = 2;
+
+    /**
+     * Wakefulness: The device is dozing.  It is almost asleep but is allowing a special
+     * low-power "doze" dream to run which keeps the display on but lets the application
+     * processor be suspended.  It can be awoken by a call to wakeUp() which ends the dream.
+     * The device fully goes to sleep if the dream cannot be started or ends on its own.
+     */
+    public static final int WAKEFULNESS_DOZING = 3;
+
+    public static String wakefulnessToString(int wakefulness) {
+        switch (wakefulness) {
+            case WAKEFULNESS_ASLEEP:
+                return "Asleep";
+            case WAKEFULNESS_AWAKE:
+                return "Awake";
+            case WAKEFULNESS_DREAMING:
+                return "Dreaming";
+            case WAKEFULNESS_DOZING:
+                return "Dozing";
+            default:
+                return Integer.toString(wakefulness);
+        }
+    }
+
+    /**
+     * Returns true if the wakefulness state represents an interactive state
+     * as defined by {@link android.os.PowerManager#isInteractive}.
+     */
+    public static boolean isInteractive(int wakefulness) {
+        return wakefulness == WAKEFULNESS_AWAKE || wakefulness == WAKEFULNESS_DREAMING;
+    }
+
+    /**
      * Used by the window manager to override the screen brightness based on the
      * current foreground activity.
      *
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8dfb321..385a318 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -172,6 +172,7 @@
 import android.os.Message;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
+import android.os.PowerManagerInternal;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -948,9 +949,9 @@
     private boolean mRunningVoice = false;
 
     /**
-     * State of external calls telling us if the device is asleep.
+     * State of external calls telling us if the device is awake or asleep.
      */
-    private boolean mWentToSleep = false;
+    private int mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
 
     /**
      * State of external call telling us if the lock screen is shown.
@@ -6309,7 +6310,7 @@
                 mWindowManager.keyguardWaitingForActivityDrawn();
                 if (mLockScreenShown) {
                     mLockScreenShown = false;
-                    comeOutOfSleepIfNeededLocked();
+                    updateSleepIfNeededLocked();
                 }
             }
         } finally {
@@ -10052,32 +10053,55 @@
         return mSleeping;
     }
 
-    void goingToSleep() {
+    void onWakefulnessChanged(int wakefulness) {
         synchronized(this) {
-            mWentToSleep = true;
-            goToSleepIfNeededLocked();
+            mWakefulness = wakefulness;
+            updateSleepIfNeededLocked();
         }
     }
 
     void finishRunningVoiceLocked() {
         if (mRunningVoice) {
             mRunningVoice = false;
-            goToSleepIfNeededLocked();
+            updateSleepIfNeededLocked();
         }
     }
 
-    void goToSleepIfNeededLocked() {
-        if (mWentToSleep && !mRunningVoice) {
-            if (!mSleeping) {
-                mSleeping = true;
-                mStackSupervisor.goingToSleepLocked();
+    void updateSleepIfNeededLocked() {
+        if (mSleeping && !shouldSleepLocked()) {
+            mSleeping = false;
+            mStackSupervisor.comeOutOfSleepIfNeededLocked();
+        } else if (!mSleeping && shouldSleepLocked()) {
+            mSleeping = true;
+            mStackSupervisor.goingToSleepLocked();
 
-                // Initialize the wake times of all processes.
-                checkExcessivePowerUsageLocked(false);
-                mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
-                Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
-                mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
-            }
+            // Initialize the wake times of all processes.
+            checkExcessivePowerUsageLocked(false);
+            mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
+            Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
+            mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
+        }
+    }
+
+    private boolean shouldSleepLocked() {
+        // Resume applications while running a voice interactor.
+        if (mRunningVoice) {
+            return false;
+        }
+
+        switch (mWakefulness) {
+            case PowerManagerInternal.WAKEFULNESS_AWAKE:
+            case PowerManagerInternal.WAKEFULNESS_DREAMING:
+                // If we're interactive but applications are already paused then defer
+                // resuming them until the lock screen is hidden.
+                return mSleeping && mLockScreenShown;
+            case PowerManagerInternal.WAKEFULNESS_DOZING:
+                // If we're dozing then pause applications whenever the lock screen is shown.
+                return mLockScreenShown;
+            case PowerManagerInternal.WAKEFULNESS_ASLEEP:
+            default:
+                // If we're asleep then pause applications unconditionally.
+                return true;
         }
     }
 
@@ -10134,31 +10158,16 @@
     }
 
     void logLockScreen(String msg) {
-        if (DEBUG_LOCKSCREEN) Slog.d(TAG, Debug.getCallers(2) + ":" + msg +
-                " mLockScreenShown=" + mLockScreenShown + " mWentToSleep=" +
-                mWentToSleep + " mSleeping=" + mSleeping);
-    }
-
-    private void comeOutOfSleepIfNeededLocked() {
-        if ((!mWentToSleep && !mLockScreenShown) || mRunningVoice) {
-            if (mSleeping) {
-                mSleeping = false;
-                mStackSupervisor.comeOutOfSleepIfNeededLocked();
-            }
-        }
-    }
-
-    void wakingUp() {
-        synchronized(this) {
-            mWentToSleep = false;
-            comeOutOfSleepIfNeededLocked();
-        }
+        if (DEBUG_LOCKSCREEN) Slog.d(TAG, Debug.getCallers(2) + ":" + msg
+                + " mLockScreenShown=" + mLockScreenShown + " mWakefulness="
+                + PowerManagerInternal.wakefulnessToString(mWakefulness)
+                + " mSleeping=" + mSleeping);
     }
 
     void startRunningVoiceLocked() {
         if (!mRunningVoice) {
             mRunningVoice = true;
-            comeOutOfSleepIfNeededLocked();
+            updateSleepIfNeededLocked();
         }
     }
 
@@ -10178,7 +10187,7 @@
             try {
                 if (DEBUG_LOCKSCREEN) logLockScreen(" shown=" + shown);
                 mLockScreenShown = shown;
-                comeOutOfSleepIfNeededLocked();
+                updateSleepIfNeededLocked();
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -12943,13 +12952,10 @@
             }
         }
         if (dumpPackage == null) {
-            if (mSleeping || mWentToSleep || mLockScreenShown) {
-                pw.println("  mSleeping=" + mSleeping + " mWentToSleep=" + mWentToSleep
-                        + " mLockScreenShown " + mLockScreenShown);
-            }
-            if (mShuttingDown || mRunningVoice) {
-                pw.print("  mShuttingDown=" + mShuttingDown + " mRunningVoice=" + mRunningVoice);
-            }
+            pw.println("  mWakefulness="
+                    + PowerManagerInternal.wakefulnessToString(mWakefulness));
+            pw.println("  mSleeping=" + mSleeping + " mLockScreenShown=" + mLockScreenShown);
+            pw.print("  mShuttingDown=" + mShuttingDown + " mRunningVoice=" + mRunningVoice);
         }
         if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
                 || mOrigWaitForDebugger) {
@@ -19041,13 +19047,8 @@
 
     private final class LocalService extends ActivityManagerInternal {
         @Override
-        public void goingToSleep() {
-            ActivityManagerService.this.goingToSleep();
-        }
-
-        @Override
-        public void wakingUp() {
-            ActivityManagerService.this.wakingUp();
+        public void onWakefulnessChanged(int wakefulness) {
+            ActivityManagerService.this.onWakefulnessChanged(wakefulness);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 94a628d..1349926 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -38,6 +38,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.PowerManagerInternal;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -70,9 +71,9 @@
 
     private static final boolean DEBUG = false;
 
-    private static final int POWER_STATE_UNKNOWN = 0;
-    private static final int POWER_STATE_AWAKE = 1;
-    private static final int POWER_STATE_ASLEEP = 2;
+    private static final int INTERACTIVE_STATE_UNKNOWN = 0;
+    private static final int INTERACTIVE_STATE_AWAKE = 1;
+    private static final int INTERACTIVE_STATE_ASLEEP = 2;
 
     private static final int MSG_USER_ACTIVITY = 1;
     private static final int MSG_BROADCAST = 2;
@@ -92,17 +93,17 @@
     private final Intent mScreenOnIntent;
     private final Intent mScreenOffIntent;
 
-    // The current power state.
-    private int mActualPowerState;
-    private int mLastGoToSleepReason;
+    // The current interactive state.
+    private int mActualInteractiveState;
+    private int mLastReason;
 
     // True if there is a pending transition that needs to be reported.
     private boolean mPendingWakeUpBroadcast;
     private boolean mPendingGoToSleepBroadcast;
 
-    // The currently broadcasted power state.  This reflects what other parts of the
+    // The currently broadcasted interactive state.  This reflects what other parts of the
     // system have observed.
-    private int mBroadcastedPowerState;
+    private int mBroadcastedInteractiveState;
     private boolean mBroadcastInProgress;
     private long mBroadcastStartTime;
 
@@ -236,62 +237,83 @@
     }
 
     /**
-     * Notifies that the device is changing interactive state.
+     * Notifies that the device is changing wakefulness.
      */
-    public void onInteractiveStateChangeStarted(boolean interactive, final int reason) {
+    public void onWakefulnessChangeStarted(int wakefulness, int reason) {
         if (DEBUG) {
-            Slog.d(TAG, "onInteractiveChangeStarted: interactive=" + interactive
+            Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness
                     + ", reason=" + reason);
         }
 
+        // We handle interactive state changes once they start so that the system can
+        // set everything up or the user to begin interacting with applications.
+        final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
+        if (interactive) {
+            handleWakefulnessChange(wakefulness, interactive, reason);
+        } else {
+            mLastReason = reason;
+        }
+
+        // Start input as soon as we start waking up or going to sleep.
+        mInputManagerInternal.setInteractive(interactive);
+    }
+
+    /**
+     * Notifies that the device has finished changing wakefulness.
+     */
+    public void onWakefulnessChangeFinished(int wakefulness) {
+        if (DEBUG) {
+            Slog.d(TAG, "onWakefulnessChangeFinished: wakefulness=" + wakefulness);
+        }
+
+        // Handle interactive state changes once they are finished so that the system can
+        // finish pending transitions (such as turning the screen off) before causing
+        // applications to change state visibly.
+        final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
+        if (!interactive) {
+            handleWakefulnessChange(wakefulness, interactive, mLastReason);
+        }
+    }
+
+    private void handleWakefulnessChange(final int wakefulness, boolean interactive,
+            final int reason) {
+        // Tell the activity manager about changes in wakefulness, not just interactivity.
+        // It needs more granularity than other components.
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mActivityManagerInternal.onWakefulnessChanged(wakefulness);
+            }
+        });
+
+        // Handle changes in the overall interactive state.
+        boolean interactiveChanged = false;
         synchronized (mLock) {
+            // Broadcast interactive state changes.
             if (interactive) {
                 // Waking up...
-                if (mActualPowerState != POWER_STATE_AWAKE) {
-                    mActualPowerState = POWER_STATE_AWAKE;
+                interactiveChanged = (mActualInteractiveState != INTERACTIVE_STATE_AWAKE);
+                if (interactiveChanged) {
+                    mActualInteractiveState = INTERACTIVE_STATE_AWAKE;
                     mPendingWakeUpBroadcast = true;
                     mHandler.post(new Runnable() {
                         @Override
                         public void run() {
                             EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
                             mPolicy.wakingUp();
-                            mActivityManagerInternal.wakingUp();
                         }
                     });
                     updatePendingBroadcastLocked();
                 }
             } else {
                 // Going to sleep...
-                mLastGoToSleepReason = reason;
-            }
-        }
-
-        mInputManagerInternal.setInteractive(interactive);
-
-        if (interactive) {
-            try {
-                mBatteryStats.noteInteractive(true);
-            } catch (RemoteException ex) { }
-        }
-    }
-
-    /**
-     * Notifies that the device has finished changing interactive state.
-     */
-    public void onInteractiveStateChangeFinished(boolean interactive) {
-        if (DEBUG) {
-            Slog.d(TAG, "onInteractiveChangeFinished");
-        }
-
-        synchronized (mLock) {
-            if (!interactive) {
-                // Finished going to sleep...
                 // This is a good time to make transitions that we don't want the user to see,
                 // such as bringing the key guard to focus.  There's no guarantee for this,
                 // however because the user could turn the device on again at any time.
                 // Some things may need to be protected by other mechanisms that defer screen on.
-                if (mActualPowerState != POWER_STATE_ASLEEP) {
-                    mActualPowerState = POWER_STATE_ASLEEP;
+                interactiveChanged = (mActualInteractiveState != INTERACTIVE_STATE_ASLEEP);
+                if (interactiveChanged) {
+                    mActualInteractiveState = INTERACTIVE_STATE_ASLEEP;
                     mPendingGoToSleepBroadcast = true;
                     if (mUserActivityPending) {
                         mUserActivityPending = false;
@@ -301,7 +323,7 @@
                         @Override
                         public void run() {
                             int why = WindowManagerPolicy.OFF_BECAUSE_OF_USER;
-                            switch (mLastGoToSleepReason) {
+                            switch (reason) {
                                 case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
                                     why = WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;
                                     break;
@@ -311,7 +333,6 @@
                             }
                             EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);
                             mPolicy.goingToSleep(why);
-                            mActivityManagerInternal.goingToSleep();
                         }
                     });
                     updatePendingBroadcastLocked();
@@ -319,9 +340,10 @@
             }
         }
 
-        if (!interactive) {
+        // Notify battery stats.
+        if (interactiveChanged) {
             try {
-                mBatteryStats.noteInteractive(false);
+                mBatteryStats.noteInteractive(interactive);
             } catch (RemoteException ex) { }
         }
     }
@@ -366,9 +388,9 @@
 
     private void updatePendingBroadcastLocked() {
         if (!mBroadcastInProgress
-                && mActualPowerState != POWER_STATE_UNKNOWN
+                && mActualInteractiveState != INTERACTIVE_STATE_UNKNOWN
                 && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
-                        || mActualPowerState != mBroadcastedPowerState)) {
+                        || mActualInteractiveState != mBroadcastedInteractiveState)) {
             mBroadcastInProgress = true;
             mSuspendBlocker.acquire();
             Message msg = mHandler.obtainMessage(MSG_BROADCAST);
@@ -396,16 +418,16 @@
     private void sendNextBroadcast() {
         final int powerState;
         synchronized (mLock) {
-            if (mBroadcastedPowerState == POWER_STATE_UNKNOWN) {
+            if (mBroadcastedInteractiveState == INTERACTIVE_STATE_UNKNOWN) {
                 // Broadcasted power state is unknown.  Send wake up.
                 mPendingWakeUpBroadcast = false;
-                mBroadcastedPowerState = POWER_STATE_AWAKE;
-            } else if (mBroadcastedPowerState == POWER_STATE_AWAKE) {
+                mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
+            } else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) {
                 // Broadcasted power state is awake.  Send asleep if needed.
                 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
-                        || mActualPowerState == POWER_STATE_ASLEEP) {
+                        || mActualInteractiveState == INTERACTIVE_STATE_ASLEEP) {
                     mPendingGoToSleepBroadcast = false;
-                    mBroadcastedPowerState = POWER_STATE_ASLEEP;
+                    mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;
                 } else {
                     finishPendingBroadcastLocked();
                     return;
@@ -413,9 +435,9 @@
             } else {
                 // Broadcasted power state is asleep.  Send awake if needed.
                 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
-                        || mActualPowerState == POWER_STATE_AWAKE) {
+                        || mActualInteractiveState == INTERACTIVE_STATE_AWAKE) {
                     mPendingWakeUpBroadcast = false;
-                    mBroadcastedPowerState = POWER_STATE_AWAKE;
+                    mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
                 } else {
                     finishPendingBroadcastLocked();
                     return;
@@ -423,12 +445,12 @@
             }
 
             mBroadcastStartTime = SystemClock.uptimeMillis();
-            powerState = mBroadcastedPowerState;
+            powerState = mBroadcastedInteractiveState;
         }
 
         EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);
 
-        if (powerState == POWER_STATE_AWAKE) {
+        if (powerState == INTERACTIVE_STATE_AWAKE) {
             sendWakeUpBroadcast();
         } else {
             sendGoToSleepBroadcast();
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index fd14d49..545a7fd 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -61,7 +61,6 @@
 import android.provider.Settings;
 import android.service.dreams.DreamManagerInternal;
 import android.util.EventLog;
-import android.util.Log;
 import android.util.Slog;
 import android.util.TimeUtils;
 import android.view.Display;
@@ -73,6 +72,11 @@
 
 import libcore.util.Objects;
 
+import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
+import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
+import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
+import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
+
 /**
  * The power manager service is responsible for coordinating power management
  * functions on the device.
@@ -116,24 +120,6 @@
     // Dirty bit: brightness boost changed
     private static final int DIRTY_SCREEN_BRIGHTNESS_BOOST = 1 << 11;
 
-    // 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.
-    // The device typically passes through the dozing state first.
-    private static final int WAKEFULNESS_ASLEEP = 0;
-    // Wakefulness: The device is fully awake.  It can be put to sleep by a call to goToSleep().
-    // When the user activity timeout expires, the device may start dreaming or go to sleep.
-    private static final int WAKEFULNESS_AWAKE = 1;
-    // Wakefulness: The device is dreaming.  It can be awoken by a call to wakeUp(),
-    // which ends the dream.  The device goes to sleep when goToSleep() is called, when
-    // the dream ends or when unplugged.
-    // User activity may brighten the screen but does not end the dream.
-    private static final int WAKEFULNESS_DREAMING = 2;
-    // Wakefulness: The device is dozing.  It is almost asleep but is allowing a special
-    // low-power "doze" dream to run which keeps the display on but lets the application
-    // processor be suspended.  It can be awoken by a call to wakeUp() which ends the dream.
-    // The device fully goes to sleep if the dream cannot be started or ends on its own.
-    private static final int WAKEFULNESS_DOZING = 3;
-
     // Summarizes the state of all active wakelocks.
     private static final int WAKE_LOCK_CPU = 1 << 0;
     private static final int WAKE_LOCK_SCREEN_BRIGHT = 1 << 1;
@@ -187,6 +173,7 @@
     // Indicates whether the device is awake or asleep or somewhere in between.
     // This is distinct from the screen power state, which is managed separately.
     private int mWakefulness;
+    private boolean mWakefulnessChanging;
 
     // True if the sandman has just been summoned for the first time since entering the
     // dreaming or dozing state.  Indicates whether a new dream should begin.
@@ -205,10 +192,6 @@
     // A bitfield that summarizes the state of all active wakelocks.
     private int mWakeLockSummary;
 
-    // True if the device is in an interactive state.
-    private boolean mInteractive;
-    private boolean mInteractiveChanging;
-
     // If true, instructs the display controller to wait for the proximity sensor to
     // go negative before turning the screen on.
     private boolean mRequestWaitForNegativeProximity;
@@ -467,7 +450,6 @@
             mHalInteractiveModeEnabled = true;
 
             mWakefulness = WAKEFULNESS_AWAKE;
-            mInteractive = true;
 
             nativeInit();
             nativeSetAutoSuspend(false);
@@ -1047,9 +1029,7 @@
             }
 
             mLastWakeTime = eventTime;
-            mDirty |= DIRTY_WAKEFULNESS;
-            mWakefulness = WAKEFULNESS_AWAKE;
-            setInteractiveStateLocked(true, 0);
+            setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);
 
             userActivityNoUpdateLocked(
                     eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
@@ -1109,10 +1089,8 @@
             }
 
             mLastSleepTime = eventTime;
-            mDirty |= DIRTY_WAKEFULNESS;
-            mWakefulness = WAKEFULNESS_DOZING;
             mSandmanSummoned = true;
-            setInteractiveStateLocked(false, reason);
+            setWakefulnessLocked(WAKEFULNESS_DOZING, reason);
 
             // Report the number of wake locks that will be cleared by going to sleep.
             int numWakeLocksCleared = 0;
@@ -1161,10 +1139,8 @@
         try {
             Slog.i(TAG, "Nap time (uid " + uid +")...");
 
-            mDirty |= DIRTY_WAKEFULNESS;
-            mWakefulness = WAKEFULNESS_DREAMING;
             mSandmanSummoned = true;
-            setInteractiveStateLocked(true, 0);
+            setWakefulnessLocked(WAKEFULNESS_DREAMING, 0);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_POWER);
         }
@@ -1187,29 +1163,28 @@
         try {
             Slog.i(TAG, "Sleeping (uid " + uid +")...");
 
-            mDirty |= DIRTY_WAKEFULNESS;
-            mWakefulness = WAKEFULNESS_ASLEEP;
-            setInteractiveStateLocked(false, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
+            setWakefulnessLocked(WAKEFULNESS_ASLEEP, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_POWER);
         }
         return true;
     }
 
-    private void setInteractiveStateLocked(boolean interactive, int reason) {
-        if (mInteractive != interactive) {
-            finishInteractiveStateChangeLocked();
+    private void setWakefulnessLocked(int wakefulness, int reason) {
+        if (mWakefulness != wakefulness) {
+            finishWakefulnessChangeLocked();
 
-            mInteractive = interactive;
-            mInteractiveChanging = true;
-            mNotifier.onInteractiveStateChangeStarted(interactive, reason);
+            mWakefulness = wakefulness;
+            mWakefulnessChanging = true;
+            mDirty |= DIRTY_WAKEFULNESS;
+            mNotifier.onWakefulnessChangeStarted(wakefulness, reason);
         }
     }
 
-    private void finishInteractiveStateChangeLocked() {
-        if (mInteractiveChanging) {
-            mNotifier.onInteractiveStateChangeFinished(mInteractive);
-            mInteractiveChanging = false;
+    private void finishWakefulnessChangeLocked() {
+        if (mWakefulnessChanging) {
+            mNotifier.onWakefulnessChangeFinished(mWakefulness);
+            mWakefulnessChanging = false;
         }
     }
 
@@ -1261,7 +1236,7 @@
 
             // Phase 4: Send notifications, if needed.
             if (mDisplayReady) {
-                finishInteractiveStateChangeLocked();
+                finishWakefulnessChangeLocked();
             }
 
             // Phase 5: Update suspend blocker.
@@ -1450,7 +1425,7 @@
 
             if (DEBUG_SPEW) {
                 Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness="
-                        + wakefulnessToString(mWakefulness)
+                        + PowerManagerInternal.wakefulnessToString(mWakefulness)
                         + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
             }
         }
@@ -1527,7 +1502,7 @@
 
             if (DEBUG_SPEW) {
                 Slog.d(TAG, "updateUserActivitySummaryLocked: mWakefulness="
-                        + wakefulnessToString(mWakefulness)
+                        + PowerManagerInternal.wakefulnessToString(mWakefulness)
                         + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
                         + ", nextTimeout=" + TimeUtils.formatUptime(nextTimeout));
             }
@@ -2150,7 +2125,7 @@
 
     private boolean isInteractiveInternal() {
         synchronized (mLock) {
-            return mInteractive;
+            return PowerManagerInternal.isInteractive(mWakefulness);
         }
     }
 
@@ -2428,8 +2403,8 @@
         synchronized (mLock) {
             pw.println("Power Manager State:");
             pw.println("  mDirty=0x" + Integer.toHexString(mDirty));
-            pw.println("  mWakefulness=" + wakefulnessToString(mWakefulness));
-            pw.println("  mInteractive=" + mInteractive);
+            pw.println("  mWakefulness=" + PowerManagerInternal.wakefulnessToString(mWakefulness));
+            pw.println("  mWakefulnessChanging=" + mWakefulnessChanging);
             pw.println("  mIsPowered=" + mIsPowered);
             pw.println("  mPlugType=" + mPlugType);
             pw.println("  mBatteryLevel=" + mBatteryLevel);
@@ -2564,21 +2539,6 @@
         return suspendBlocker;
     }
 
-    private static String wakefulnessToString(int wakefulness) {
-        switch (wakefulness) {
-            case WAKEFULNESS_ASLEEP:
-                return "Asleep";
-            case WAKEFULNESS_AWAKE:
-                return "Awake";
-            case WAKEFULNESS_DREAMING:
-                return "Dreaming";
-            case WAKEFULNESS_DOZING:
-                return "Dozing";
-            default:
-                return Integer.toString(wakefulness);
-        }
-    }
-
     private static WorkSource copyWorkSource(WorkSource workSource) {
         return workSource != null ? new WorkSource(workSource) : null;
     }