Merge "Tell PhoneWindowManager when we start/finish interactive changes." into mnc-dev
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index eebcd84..57121ddd 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -945,17 +945,30 @@
public int focusChangedLw(WindowState lastFocus, WindowState newFocus);
/**
- * Called when the device is waking up.
+ * Called when the device has started waking up.
*/
- public void wakingUp();
+ public void startedWakingUp();
/**
- * Called when the device is going to sleep.
- *
- * @param why {@link #OFF_BECAUSE_OF_USER} or
- * {@link #OFF_BECAUSE_OF_TIMEOUT}.
+ * Called when the device has finished waking up.
*/
- public void goingToSleep(int why);
+ public void finishedWakingUp();
+
+ /**
+ * Called when the device has started going to sleep.
+ *
+ * @param why {@link #OFF_BECAUSE_OF_USER}, {@link #OFF_BECAUSE_OF_ADMIN},
+ * or {@link #OFF_BECAUSE_OF_TIMEOUT}.
+ */
+ public void startedGoingToSleep(int why);
+
+ /**
+ * Called when the device has finished going to sleep.
+ *
+ * @param why {@link #OFF_BECAUSE_OF_USER}, {@link #OFF_BECAUSE_OF_ADMIN},
+ * or {@link #OFF_BECAUSE_OF_TIMEOUT}.
+ */
+ public void finishedGoingToSleep(int why);
/**
* Called when the device is about to turn on the screen to show content.
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 6a63aab..a1e1aef 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1455,7 +1455,8 @@
// Match current screen state.
if (!mPowerManager.isInteractive()) {
- goingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
+ startedGoingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
+ finishedGoingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
}
mWindowManagerInternal.registerAppTransitionListener(
@@ -5233,9 +5234,15 @@
// Called on the PowerManager's Notifier thread.
@Override
- public void goingToSleep(int why) {
+ public void startedGoingToSleep(int why) {
+ if (DEBUG_WAKEUP) Slog.i(TAG, "Started going to sleep... (why=" + why + ")");
+ }
+
+ // Called on the PowerManager's Notifier thread.
+ @Override
+ public void finishedGoingToSleep(int why) {
EventLog.writeEvent(70000, 0);
- if (DEBUG_WAKEUP) Slog.i(TAG, "Going to sleep...");
+ if (DEBUG_WAKEUP) Slog.i(TAG, "Finished going to sleep... (why=" + why + ")");
// 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.
@@ -5252,24 +5259,11 @@
}
}
- private void wakeUpFromPowerKey(long eventTime) {
- wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey);
- }
-
- private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode) {
- if (!wakeInTheaterMode && isTheaterModeEnabled()) {
- return false;
- }
-
- mPowerManager.wakeUp(wakeTime);
- return true;
- }
-
// Called on the PowerManager's Notifier thread.
@Override
- public void wakingUp() {
+ public void startedWakingUp() {
EventLog.writeEvent(70000, 1);
- if (DEBUG_WAKEUP) Slog.i(TAG, "Waking up...");
+ if (DEBUG_WAKEUP) Slog.i(TAG, "Started waking up...");
// Since goToSleep performs these functions synchronously, we must
// do the same here. We cannot post this work to a handler because
@@ -5297,6 +5291,25 @@
}
}
+ // Called on the PowerManager's Notifier thread.
+ @Override
+ public void finishedWakingUp() {
+ if (DEBUG_WAKEUP) Slog.i(TAG, "Finished waking up...");
+ }
+
+ private void wakeUpFromPowerKey(long eventTime) {
+ wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey);
+ }
+
+ private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode) {
+ if (!wakeInTheaterMode && isTheaterModeEnabled()) {
+ return false;
+ }
+
+ mPowerManager.wakeUp(wakeTime);
+ return true;
+ }
+
private void finishKeyguardDrawn() {
synchronized (mLock) {
if (!mAwake || mKeyguardDrawComplete) {
@@ -5789,7 +5802,7 @@
synchronized (mLock) {
mSystemBooted = true;
}
- wakingUp();
+ startedWakingUp();
screenTurningOn(null);
}
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index fd98010..5a391f4 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -95,11 +95,19 @@
private final Intent mScreenOffIntent;
private final Intent mScreenBrightnessBoostIntent;
- // The current interactive state.
- private int mActualInteractiveState;
- private int mLastReason;
+ // The current interactive state. This is set as soon as an interactive state
+ // transition begins so as to capture the reason that it happened. At some point
+ // this state will propagate to the pending state then eventually to the
+ // broadcasted state over the course of reporting the transition asynchronously.
+ private boolean mInteractive = true;
+ private int mInteractiveChangeReason;
+ private boolean mInteractiveChanging;
- // True if there is a pending transition that needs to be reported.
+ // The pending interactive state that we will eventually want to broadcast.
+ // This is designed so that we can collapse redundant sequences of awake/sleep
+ // transition pairs while still guaranteeing that at least one transition is observed
+ // whenever this happens.
+ private int mPendingInteractiveState;
private boolean mPendingWakeUpBroadcast;
private boolean mPendingGoToSleepBroadcast;
@@ -244,45 +252,17 @@
/**
* Notifies that the device is changing wakefulness.
+ * This function may be called even if the previous change hasn't finished in
+ * which case it will assume that the state did not fully converge before the
+ * next transition began and will recover accordingly.
*/
- public void onWakefulnessChangeStarted(int wakefulness, int reason) {
+ public void onWakefulnessChangeStarted(final int wakefulness, int reason) {
+ final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
if (DEBUG) {
Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness
- + ", reason=" + reason);
+ + ", reason=" + reason + ", interactive=" + interactive);
}
- // 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() {
@@ -292,65 +272,132 @@
}
});
- // Handle changes in the overall interactive state.
- boolean interactiveChanged = false;
- synchronized (mLock) {
- // Broadcast interactive state changes.
- if (interactive) {
- // Waking up...
- 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();
- }
- });
- updatePendingBroadcastLocked();
- }
- } else {
- // 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.
- interactiveChanged = (mActualInteractiveState != INTERACTIVE_STATE_ASLEEP);
- if (interactiveChanged) {
- mActualInteractiveState = INTERACTIVE_STATE_ASLEEP;
- mPendingGoToSleepBroadcast = true;
- if (mUserActivityPending) {
- mUserActivityPending = false;
- mHandler.removeMessages(MSG_USER_ACTIVITY);
- }
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- int why = WindowManagerPolicy.OFF_BECAUSE_OF_USER;
- switch (reason) {
- case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
- why = WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;
- break;
- case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
- why = WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
- break;
- }
- EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);
- mPolicy.goingToSleep(why);
- }
- });
- updatePendingBroadcastLocked();
- }
+ // Handle any early interactive state changes.
+ // Finish pending incomplete ones from a previous cycle.
+ if (mInteractive != interactive) {
+ // Finish up late behaviors if needed.
+ if (mInteractiveChanging) {
+ handleLateInteractiveChange();
}
- }
- // Notify battery stats.
- if (interactiveChanged) {
+ // Start input as soon as we start waking up or going to sleep.
+ mInputManagerInternal.setInteractive(interactive);
+
+ // Notify battery stats.
try {
mBatteryStats.noteInteractive(interactive);
} catch (RemoteException ex) { }
+
+ // Handle early behaviors.
+ mInteractive = interactive;
+ mInteractiveChangeReason = reason;
+ mInteractiveChanging = true;
+ handleEarlyInteractiveChange();
+ }
+ }
+
+ /**
+ * Notifies that the device has finished changing wakefulness.
+ */
+ public void onWakefulnessChangeFinished() {
+ if (DEBUG) {
+ Slog.d(TAG, "onWakefulnessChangeFinished");
+ }
+
+ if (mInteractiveChanging) {
+ mInteractiveChanging = false;
+ handleLateInteractiveChange();
+ }
+ }
+
+ /**
+ * Handle early interactive state changes such as getting applications or the lock
+ * screen running and ready for the user to see (such as when turning on the screen).
+ */
+ private void handleEarlyInteractiveChange() {
+ synchronized (mLock) {
+ if (mInteractive) {
+ // Waking up...
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
+ mPolicy.startedWakingUp();
+ }
+ });
+
+ // Send interactive broadcast.
+ mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
+ mPendingWakeUpBroadcast = true;
+ updatePendingBroadcastLocked();
+ } else {
+ // Going to sleep...
+ // Tell the policy that we started going to sleep.
+ final int why = translateOffReason(mInteractiveChangeReason);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mPolicy.startedGoingToSleep(why);
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ * Handle late 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.
+ */
+ private void handleLateInteractiveChange() {
+ synchronized (mLock) {
+ if (mInteractive) {
+ // Finished waking up...
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mPolicy.finishedWakingUp();
+ }
+ });
+ } else {
+ // 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.
+
+ // Cancel pending user activity.
+ if (mUserActivityPending) {
+ mUserActivityPending = false;
+ mHandler.removeMessages(MSG_USER_ACTIVITY);
+ }
+
+ // Tell the policy we finished going to sleep.
+ final int why = translateOffReason(mInteractiveChangeReason);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);
+ mPolicy.finishedGoingToSleep(why);
+ }
+ });
+
+ // Send non-interactive broadcast.
+ mPendingInteractiveState = INTERACTIVE_STATE_ASLEEP;
+ mPendingGoToSleepBroadcast = true;
+ updatePendingBroadcastLocked();
+ }
+ }
+ }
+
+ private static int translateOffReason(int reason) {
+ switch (reason) {
+ case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
+ return WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;
+ case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
+ return WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
+ default:
+ return WindowManagerPolicy.OFF_BECAUSE_OF_USER;
}
}
@@ -367,6 +414,7 @@
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
+
/**
* Called when there has been user activity.
*/
@@ -407,9 +455,9 @@
private void updatePendingBroadcastLocked() {
if (!mBroadcastInProgress
- && mActualInteractiveState != INTERACTIVE_STATE_UNKNOWN
+ && mPendingInteractiveState != INTERACTIVE_STATE_UNKNOWN
&& (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
- || mActualInteractiveState != mBroadcastedInteractiveState)) {
+ || mPendingInteractiveState != mBroadcastedInteractiveState)) {
mBroadcastInProgress = true;
mSuspendBlocker.acquire();
Message msg = mHandler.obtainMessage(MSG_BROADCAST);
@@ -444,7 +492,7 @@
} else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) {
// Broadcasted power state is awake. Send asleep if needed.
if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
- || mActualInteractiveState == INTERACTIVE_STATE_ASLEEP) {
+ || mPendingInteractiveState == INTERACTIVE_STATE_ASLEEP) {
mPendingGoToSleepBroadcast = false;
mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;
} else {
@@ -454,7 +502,7 @@
} else {
// Broadcasted power state is asleep. Send awake if needed.
if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
- || mActualInteractiveState == INTERACTIVE_STATE_AWAKE) {
+ || mPendingInteractiveState == INTERACTIVE_STATE_AWAKE) {
mPendingWakeUpBroadcast = false;
mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
} else {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 1b5391e..c1fe984 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -1217,8 +1217,6 @@
private void setWakefulnessLocked(int wakefulness, int reason) {
if (mWakefulness != wakefulness) {
- finishWakefulnessChangeLocked();
-
mWakefulness = wakefulness;
mWakefulnessChanging = true;
mDirty |= DIRTY_WAKEFULNESS;
@@ -1226,10 +1224,14 @@
}
}
- private void finishWakefulnessChangeLocked() {
- if (mWakefulnessChanging) {
- mNotifier.onWakefulnessChangeFinished(mWakefulness);
+ private void finishWakefulnessChangeIfNeededLocked() {
+ if (mWakefulnessChanging && mDisplayReady) {
+ if (mWakefulness == WAKEFULNESS_DOZING
+ && (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) {
+ return; // wait until dream has enabled dozing
+ }
mWakefulnessChanging = false;
+ mNotifier.onWakefulnessChangeFinished();
}
}
@@ -1280,9 +1282,7 @@
updateDreamLocked(dirtyPhase2, displayBecameReady);
// Phase 4: Send notifications, if needed.
- if (mDisplayReady) {
- finishWakefulnessChangeLocked();
- }
+ finishWakefulnessChangeIfNeededLocked();
// Phase 5: Update suspend blocker.
// Because we might release the last suspend blocker here, we need to make sure