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

* commit '6907304024f1c31d2d2dcf783588a6dd8865ecd8':
  Reduce latency from doze to screen on.
This commit is contained in:
Jeff Brown
2014-10-01 15:16:19 +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.
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.
private long mScreenOnBlockStartRealTime;
@@ -633,22 +636,42 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
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.
animateScreenStateChange(state, performScreenOffTransition);
// Report whether the display is ready for use and all changes have been applied.
if (mustNotify
&& mPendingScreenOnUnblocker == null
// Animate the screen brightness when the screen is on or dozing.
// Skip the animation when the screen is off or suspended.
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()
&& !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) {
if (!mPendingRequestChangedLocked) {
mDisplayReadyLocked = true;
@@ -660,6 +683,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
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
@@ -723,6 +755,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
private void animateScreenBrightness(int target, int rate) {
if (DEBUG) {
Slog.d(TAG, "Animating brightness: target=" + target +", rate=" + rate);
}
if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
try {
mBatteryStats.noteScreenBrightness(target);

View File

@@ -80,6 +80,7 @@ final class DisplayPowerState {
mBacklight = backlight;
mColorFade = electronBeam;
mPhotonicModulator = new PhotonicModulator();
mPhotonicModulator.start();
// 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,
@@ -336,7 +337,7 @@ final class DisplayPowerState {
/**
* 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_BACKLIGHT = -1; // unknown
@@ -361,7 +362,7 @@ final class DisplayPowerState {
if (!mChangeInProgress) {
mChangeInProgress = true;
AsyncTask.THREAD_POOL_EXECUTOR.execute(mTask);
mLock.notifyAll();
}
}
return !mChangeInProgress;
@@ -369,75 +370,78 @@ final class DisplayPowerState {
}
public void dump(PrintWriter pw) {
pw.println();
pw.println("Photonic Modulator State:");
pw.println(" mPendingState=" + Display.stateToString(mPendingState));
pw.println(" mPendingBacklight=" + mPendingBacklight);
pw.println(" mActualState=" + Display.stateToString(mActualState));
pw.println(" mActualBacklight=" + mActualBacklight);
pw.println(" mChangeInProgress=" + mChangeInProgress);
synchronized (mLock) {
pw.println();
pw.println("Photonic Modulator State:");
pw.println(" mPendingState=" + Display.stateToString(mPendingState));
pw.println(" mPendingBacklight=" + mPendingBacklight);
pw.println(" mActualState=" + Display.stateToString(mActualState));
pw.println(" mActualBacklight=" + mActualBacklight);
pw.println(" mChangeInProgress=" + mChangeInProgress);
}
}
private final Runnable mTask = new Runnable() {
@Override
public void run() {
// Apply pending changes until done.
for (;;) {
final int state;
final boolean stateChanged;
final int backlight;
final boolean backlightChanged;
synchronized (mLock) {
state = mPendingState;
stateChanged = (state != mActualState);
backlight = mPendingBacklight;
backlightChanged = (backlight != mActualBacklight);
if (!stateChanged && !backlightChanged) {
mChangeInProgress = false;
break;
}
mActualState = state;
mActualBacklight = backlight;
}
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);
@Override
public void run() {
for (;;) {
// Get pending change.
final int state;
final boolean stateChanged;
final int backlight;
final boolean backlightChanged;
synchronized (mLock) {
state = mPendingState;
stateChanged = (state != mActualState);
backlight = mPendingBacklight;
backlightChanged = (backlight != mActualBacklight);
if (!stateChanged && !backlightChanged) {
// All changed applied, notify outer class and wait for more.
mChangeInProgress = false;
postScreenUpdateThreadSafe();
try {
mLock.wait();
} catch (InterruptedException ex) { }
continue;
}
mActualState = state;
mActualBacklight = backlight;
}
// Let the outer class know that all changes have been applied.
postScreenUpdateThreadSafe();
}
private void requestDisplayState(int state) {
Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestDisplayState("
+ Display.stateToString(state) + ")");
try {
mBlanker.requestDisplayState(state);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
// Apply pending change.
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);
}
}
}
private void setBrightness(int backlight) {
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setBrightness(" + backlight + ")");
try {
mBacklight.setBrightness(backlight);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
private void requestDisplayState(int state) {
Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestDisplayState("
+ Display.stateToString(state) + ")");
try {
mBlanker.requestDisplayState(state);
} 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.
*
* If this is the first time the property is being set, the value jumps
* directly to the target.
* If this is the first time the property is being set or if the rate is 0,
* the value jumps directly to the target.
*
* @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.
*/
public boolean animateTo(int target, int rate) {
// Immediately jump to the target the first time.
if (mFirstTime) {
mFirstTime = false;
mProperty.setValue(mObject, target);
mCurrentValue = target;
return true;
if (mFirstTime || rate <= 0) {
if (mFirstTime || target != mCurrentValue) {
mFirstTime = false;
mRate = 0;
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.
@@ -88,7 +100,7 @@ final class RampAnimator<T> {
mAnimating = true;
mAnimatedValue = mCurrentValue;
mLastFrameTimeNanos = System.nanoTime();
postCallback();
postAnimationCallback();
}
return changed;
@@ -108,11 +120,15 @@ final class RampAnimator<T> {
mListener = listener;
}
private void postCallback() {
mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mCallback, null);
private void postAnimationCallback() {
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
public void run() {
final long frameTimeNanos = mChoreographer.getFrameTimeNanos();
@@ -144,7 +160,7 @@ final class RampAnimator<T> {
}
if (mTargetValue != mCurrentValue) {
postCallback();
postAnimationCallback();
} else {
mAnimating = false;
if (mListener != null) {