am f0245cb2: am 69073040: am 62434d6a: Merge "Reduce latency from doze to screen on." into lmp-dev

* commit 'f0245cb2e3058e74ad1df7a169ae663d31565ce5':
  Reduce latency from doze to screen on.
This commit is contained in:
Jeff Brown
2014-10-01 17:02:36 +00:00
committed by Android Git Automerger
3 changed files with 142 additions and 87 deletions

View File

@@ -227,6 +227,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// turning off the screen. // turning off the screen.
private boolean mPendingScreenOff; private boolean mPendingScreenOff;
// True if we have unfinished business and are holding a suspend blocker.
private boolean mUnfinishedBusiness;
// The elapsed real time when the screen on was blocked. // The elapsed real time when the screen on was blocked.
private long mScreenOnBlockStartRealTime; private long mScreenOnBlockStartRealTime;
@@ -633,22 +636,42 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mAppliedLowPower = true; mAppliedLowPower = true;
} }
// Animate the screen brightness when the screen is on.
if (state != Display.STATE_OFF) {
animateScreenBrightness(brightness, slowChange
? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
}
// Animate the screen state change unless already animating. // Animate the screen state change unless already animating.
animateScreenStateChange(state, performScreenOffTransition); animateScreenStateChange(state, performScreenOffTransition);
// Report whether the display is ready for use and all changes have been applied. // Animate the screen brightness when the screen is on or dozing.
if (mustNotify // Skip the animation when the screen is off or suspended.
&& mPendingScreenOnUnblocker == null final int actualState = mPowerState.getScreenState();
if (actualState == Display.STATE_ON || actualState == Display.STATE_DOZE) {
animateScreenBrightness(brightness,
slowChange ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
} else {
animateScreenBrightness(brightness, 0);
}
// Determine whether the display is ready for use in the newly requested state.
// Note that we do not wait for the brightness ramp animation to complete before
// reporting the display is ready because we only need to ensure the screen is in the
// right power state even as it continues to converge on the desired brightness.
final boolean ready = mPendingScreenOnUnblocker == null
&& !mColorFadeOnAnimator.isStarted() && !mColorFadeOnAnimator.isStarted()
&& !mColorFadeOffAnimator.isStarted() && !mColorFadeOffAnimator.isStarted()
&& !mScreenBrightnessRampAnimator.isAnimating() && mPowerState.waitUntilClean(mCleanListener);
&& mPowerState.waitUntilClean(mCleanListener)) { final boolean finished = ready
&& !mScreenBrightnessRampAnimator.isAnimating();
// Grab a wake lock if we have unfinished business.
if (!finished && !mUnfinishedBusiness) {
if (DEBUG) {
Slog.d(TAG, "Unfinished business...");
}
mCallbacks.acquireSuspendBlocker();
mUnfinishedBusiness = true;
}
// Notify the power manager when ready.
if (ready && mustNotify) {
// Send state change.
synchronized (mLock) { synchronized (mLock) {
if (!mPendingRequestChangedLocked) { if (!mPendingRequestChangedLocked) {
mDisplayReadyLocked = true; mDisplayReadyLocked = true;
@@ -660,6 +683,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
} }
sendOnStateChangedWithWakelock(); sendOnStateChangedWithWakelock();
} }
// Release the wake lock when we have no unfinished business.
if (finished && mUnfinishedBusiness) {
if (DEBUG) {
Slog.d(TAG, "Finished business...");
}
mUnfinishedBusiness = false;
mCallbacks.releaseSuspendBlocker();
}
} }
@Override @Override
@@ -723,6 +755,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
} }
private void animateScreenBrightness(int target, int rate) { private void animateScreenBrightness(int target, int rate) {
if (DEBUG) {
Slog.d(TAG, "Animating brightness: target=" + target +", rate=" + rate);
}
if (mScreenBrightnessRampAnimator.animateTo(target, rate)) { if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
try { try {
mBatteryStats.noteScreenBrightness(target); mBatteryStats.noteScreenBrightness(target);

View File

@@ -80,6 +80,7 @@ final class DisplayPowerState {
mBacklight = backlight; mBacklight = backlight;
mColorFade = electronBeam; mColorFade = electronBeam;
mPhotonicModulator = new PhotonicModulator(); mPhotonicModulator = new PhotonicModulator();
mPhotonicModulator.start();
// At boot time, we know that the screen is on and the electron beam // At boot time, we know that the screen is on and the electron beam
// animation is not playing. We don't know the screen's brightness though, // animation is not playing. We don't know the screen's brightness though,
@@ -336,7 +337,7 @@ final class DisplayPowerState {
/** /**
* Updates the state of the screen and backlight asynchronously on a separate thread. * Updates the state of the screen and backlight asynchronously on a separate thread.
*/ */
private final class PhotonicModulator { private final class PhotonicModulator extends Thread {
private static final int INITIAL_SCREEN_STATE = Display.STATE_OFF; // unknown, assume off private static final int INITIAL_SCREEN_STATE = Display.STATE_OFF; // unknown, assume off
private static final int INITIAL_BACKLIGHT = -1; // unknown private static final int INITIAL_BACKLIGHT = -1; // unknown
@@ -361,7 +362,7 @@ final class DisplayPowerState {
if (!mChangeInProgress) { if (!mChangeInProgress) {
mChangeInProgress = true; mChangeInProgress = true;
AsyncTask.THREAD_POOL_EXECUTOR.execute(mTask); mLock.notifyAll();
} }
} }
return !mChangeInProgress; return !mChangeInProgress;
@@ -369,75 +370,78 @@ final class DisplayPowerState {
} }
public void dump(PrintWriter pw) { public void dump(PrintWriter pw) {
pw.println(); synchronized (mLock) {
pw.println("Photonic Modulator State:"); pw.println();
pw.println(" mPendingState=" + Display.stateToString(mPendingState)); pw.println("Photonic Modulator State:");
pw.println(" mPendingBacklight=" + mPendingBacklight); pw.println(" mPendingState=" + Display.stateToString(mPendingState));
pw.println(" mActualState=" + Display.stateToString(mActualState)); pw.println(" mPendingBacklight=" + mPendingBacklight);
pw.println(" mActualBacklight=" + mActualBacklight); pw.println(" mActualState=" + Display.stateToString(mActualState));
pw.println(" mChangeInProgress=" + mChangeInProgress); pw.println(" mActualBacklight=" + mActualBacklight);
pw.println(" mChangeInProgress=" + mChangeInProgress);
}
} }
private final Runnable mTask = new Runnable() { @Override
@Override public void run() {
public void run() { for (;;) {
// Apply pending changes until done. // Get pending change.
for (;;) { final int state;
final int state; final boolean stateChanged;
final boolean stateChanged; final int backlight;
final int backlight; final boolean backlightChanged;
final boolean backlightChanged; synchronized (mLock) {
synchronized (mLock) { state = mPendingState;
state = mPendingState; stateChanged = (state != mActualState);
stateChanged = (state != mActualState); backlight = mPendingBacklight;
backlight = mPendingBacklight; backlightChanged = (backlight != mActualBacklight);
backlightChanged = (backlight != mActualBacklight); if (!stateChanged && !backlightChanged) {
if (!stateChanged && !backlightChanged) { // All changed applied, notify outer class and wait for more.
mChangeInProgress = false; mChangeInProgress = false;
break; postScreenUpdateThreadSafe();
} try {
mActualState = state; mLock.wait();
mActualBacklight = backlight; } catch (InterruptedException ex) { }
} continue;
if (DEBUG) {
Slog.d(TAG, "Updating screen state: state="
+ Display.stateToString(state) + ", backlight=" + backlight);
}
boolean suspending = Display.isSuspendedState(state);
if (stateChanged && !suspending) {
requestDisplayState(state);
}
if (backlightChanged) {
setBrightness(backlight);
}
if (stateChanged && suspending) {
requestDisplayState(state);
} }
mActualState = state;
mActualBacklight = backlight;
} }
// Let the outer class know that all changes have been applied. // Apply pending change.
postScreenUpdateThreadSafe(); if (DEBUG) {
} Slog.d(TAG, "Updating screen state: state="
+ Display.stateToString(state) + ", backlight=" + backlight);
private void requestDisplayState(int state) { }
Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestDisplayState(" boolean suspending = Display.isSuspendedState(state);
+ Display.stateToString(state) + ")"); if (stateChanged && !suspending) {
try { requestDisplayState(state);
mBlanker.requestDisplayState(state); }
} finally { if (backlightChanged) {
Trace.traceEnd(Trace.TRACE_TAG_POWER); setBrightness(backlight);
}
if (stateChanged && suspending) {
requestDisplayState(state);
} }
} }
}
private void setBrightness(int backlight) { private void requestDisplayState(int state) {
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setBrightness(" + backlight + ")"); Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestDisplayState("
try { + Display.stateToString(state) + ")");
mBacklight.setBrightness(backlight); try {
} finally { mBlanker.requestDisplayState(state);
Trace.traceEnd(Trace.TRACE_TAG_POWER); } finally {
} Trace.traceEnd(Trace.TRACE_TAG_POWER);
} }
}; }
private void setBrightness(int backlight) {
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setBrightness(" + backlight + ")");
try {
mBacklight.setBrightness(backlight);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
} }
} }

View File

@@ -50,20 +50,32 @@ final class RampAnimator<T> {
/** /**
* Starts animating towards the specified value. * Starts animating towards the specified value.
* *
* If this is the first time the property is being set, the value jumps * If this is the first time the property is being set or if the rate is 0,
* directly to the target. * the value jumps directly to the target.
* *
* @param target The target value. * @param target The target value.
* @param rate The convergence rate, in units per second. * @param rate The convergence rate in units per second, or 0 to set the value immediately.
* @return True if the target differs from the previous target. * @return True if the target differs from the previous target.
*/ */
public boolean animateTo(int target, int rate) { public boolean animateTo(int target, int rate) {
// Immediately jump to the target the first time. // Immediately jump to the target the first time.
if (mFirstTime) { if (mFirstTime || rate <= 0) {
mFirstTime = false; if (mFirstTime || target != mCurrentValue) {
mProperty.setValue(mObject, target); mFirstTime = false;
mCurrentValue = target; mRate = 0;
return true; mTargetValue = target;
mCurrentValue = target;
mProperty.setValue(mObject, target);
if (mAnimating) {
mAnimating = false;
cancelAnimationCallback();
}
if (mListener != null) {
mListener.onAnimationEnd();
}
return true;
}
return false;
} }
// Adjust the rate based on the closest target. // Adjust the rate based on the closest target.
@@ -88,7 +100,7 @@ final class RampAnimator<T> {
mAnimating = true; mAnimating = true;
mAnimatedValue = mCurrentValue; mAnimatedValue = mCurrentValue;
mLastFrameTimeNanos = System.nanoTime(); mLastFrameTimeNanos = System.nanoTime();
postCallback(); postAnimationCallback();
} }
return changed; return changed;
@@ -108,11 +120,15 @@ final class RampAnimator<T> {
mListener = listener; mListener = listener;
} }
private void postCallback() { private void postAnimationCallback() {
mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mCallback, null); mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimationCallback, null);
} }
private final Runnable mCallback = new Runnable() { private void cancelAnimationCallback() {
mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, mAnimationCallback, null);
}
private final Runnable mAnimationCallback = new Runnable() {
@Override // Choreographer callback @Override // Choreographer callback
public void run() { public void run() {
final long frameTimeNanos = mChoreographer.getFrameTimeNanos(); final long frameTimeNanos = mChoreographer.getFrameTimeNanos();
@@ -144,7 +160,7 @@ final class RampAnimator<T> {
} }
if (mTargetValue != mCurrentValue) { if (mTargetValue != mCurrentValue) {
postCallback(); postAnimationCallback();
} else { } else {
mAnimating = false; mAnimating = false;
if (mListener != null) { if (mListener != null) {